Commit 063ff34f authored by Paul Asmuth's avatar Paul Asmuth
Browse files

cleaning up

parent 9b543abf
Loading
Loading
Loading
Loading
+0 −207
Original line number Diff line number Diff line
#!/usr/bin/env ruby
require "timeout"
require "socket"

###############################################################################

# Prefix every metric name with this string
METRIC_NAME_PREFIX = "/linux/"

# Report the statistics every 1 second
INTERVAL = 1.0

###############################################################################

if ARGV.length != 2
  puts "usage: #{$0} <host> <port>"
  puts "  Report Linux system stats to FnordMetric Server via statsd"
  puts ""
  puts "example: #{$0} 127.0.0.1 8125"
  exit 1
end

udp = UDPSocket.new
target_host = ARGV[0]
target_port = ARGV[1].to_i

loop do
  last_run = Time.now.to_f
  @samples = []

  # hostname
  @hostname = `hostname`.strip


  # collect CPU load averages

  def report_cpu_load

    if File.exists?("/proc/loadavg")
      loadavg_data = IO::read("/proc/loadavg")

      loadavg = loadavg_data.scan(/([0-9]+[,\.][0-9]+)+/).flatten

      if loadavg.size == 3
        @samples << {
          :metric => "load_avg_1m",
          :value => loadavg[0],
          :labels => {
            :host => @hostname
          }
        }

        @samples << {
          :metric => "load_avg_5m",
          :value => loadavg[1],
          :labels => {
            :host => @hostname
          }
        }

        @samples << {
          :metric => "load_avg_15m",
          :value => loadavg[2],
          :labels => {
            :host => @hostname
          }
        }
      end
    end
  end

  # gather basic memory statistics

  def report_memory_stats
    if File.exists?("/proc/meminfo")
      loadavg_data = IO::read("/proc/meminfo")
      memtotal  = loadavg_data.scan(/MemTotal:\s+ (\d+)\skB/).flatten.first.to_i
      memfree   = loadavg_data.scan(/MemFree:\s+ (\d+)\skB/).flatten.first.to_i
      swaptotal = loadavg_data.scan(/SwapTotal:\s+ (\d+)\skB/).flatten.first.to_i
      swapfree  = loadavg_data.scan(/SwapFree:\s+ (\d+)\skB/).flatten.first.to_i

        @samples << {
          :metric => "memory_total",
          :value => memtotal,
          :labels => {
            :host => @hostname
          }
        }

        @samples << {
          :metric => "memory_free",
          :value => memfree,
          :labels => {
            :host => @hostname
          }
        }

        @samples << {
          :metric => "swap_total",
          :value => swaptotal,
          :labels => {
            :host => @hostname
          }
        }

        @samples << {
          :metric => "swap_free",
          :value => swapfree,
          :labels => {
            :host => @hostname
          }
        }
    end
  end

  # determine disk usage and available space

  def report_disk_stats

    df_input = `df -P`.lines[1..-1]

    if !df_input.empty?
     df_input.each do |single_line|
      elements = single_line.split " "

          @samples << {
          :metric => "disk_used",
          :value => elements[2],
          :labels => {
            :host => @hostname,
            :mount_name => elements[0]
          }
        }

          @samples << {
          :metric => "disk_available",
          :value => elements[3],
          :labels => {
            :host => @hostname,
            :mount_name => elements[0]
          }
        }
     end
    end
  end

  #count open TCP and UDP sockets

  def report_open_sockets

    if File.exists?("/proc/net/tcp")
     tcp_sockets =  %x{wc -l "/proc/net/tcp"}.to_i - 1

      @samples << {
        :metric => "open_tcp_sockets",
        :value => tcp_sockets,
        :labels => {
          :host => @hostname
        }
      }
    end

    if File.exists?("/proc/net/udp")
     tcp_sockets =  %x{wc -l "/proc/net/udp"}.to_i - 1

      @samples << {
        :metric => "open_udp_sockets",
        :value => tcp_sockets,
        :labels => {
          :host => @hostname
        }
      }


    end
  end

  # fill samples array with data

  report_memory_stats
  report_disk_stats
  report_cpu_load
  report_open_sockets

  # send the samples in a single udp packet to FnordMetric server (the combined
  # packet size must be strictly less than or equal to 65535 bytes
  packet = ""
  @samples.each do |sample|
    packet << METRIC_NAME_PREFIX + sample[:metric]
    sample[:labels].each do |k,v|
      packet << "[#{k}=#{v}]"
    end
    packet << ":"
    packet << sample[:value].to_s.gsub(",", ".")
    packet << "\n"
  end

  begin
    udp.send packet, 0, target_host, target_port
  rescue Exception => e
    puts e
  end

  # sleep if we completed executing faster than the requested interval
  sleep_for = (last_run + INTERVAL) - Time.now.to_f
  sleep(sleep_for) if sleep_for > 0
end
+0 −123
Original line number Diff line number Diff line
<!--
  This file is part of the "FnordMetric" project
    Copyright (c) 2014 Laura Schlimmer
    Copyright (c) 2014 Paul Asmuth, Google Inc.

  FnordMetric is free software: you can redistribute it and/or modify it under
  the terms of the GNU General Public License v3.0. You should have received a
  copy of the GNU General Public License along with this program. If not, see
  <http://www.gnu.org/licenses/>.
-->
<style type="text/css">
</style>

<template id="fnordmetric-plugin-hosts-overview-tpl">
  <h1 class="page_header"><i>Hosts</i> &rsaquo; All Hosts</h1>

  <fn-loader data-loader-type="loader3" data-transparent>
    <fn-table data-per-page="25" data-clickable id="host-list" style="width:100%;">
      <fn-table-column>Hostname</fn-table-column>
      <fn-table-column>Load Avg</fn-table-column>
      <fn-table-column>CPU Util</fn-table-column>
      <fn-table-column>Mem. Total (MB)</fn-table-column>
      <fn-table-column>Mem. Util</fn-table-column>
      <fn-table-column>Disk Total (GB)</fn-table-column>
      <fn-table-column>Disk Util</fn-table-column>
    </fn-table>
  </fn-loader>
</template>

<template id="fnordmetric-plugin-hosts-detail-tpl">
  <h1 class="page_header"></h1>

  <fnordmetric-time-controls>
  </fnordmetric-time-controls>
</template>

<script type="text/javascript">
  var FnordMetricHostsPluginComponent = function() {
    this.openUrl = function(url) {
      this.innerHTML = "";
      var qry = Fnord.parseQueryString(url);

      if (qry.params.view == "detail") {
        this.renderDetailView(qry.params.hostname);
      } else {
        this.renderOverview();
      }
    };

    this.renderOverview = function() {
      var tpl = Fnord.getTemplate("fnordmetric-plugin-hosts", "overview");
      this.innerHTML = "";
      this.appendChild(tpl);

      var table = this.querySelector("#host-list");
      table.addEventListener("fn-table-row-click", function(e) {
        var hostname = e.srcElement.getAttribute("data-hostname");
        var url = "console?plugin=hosts&view=detail&hostname=" + encodeURIComponent(hostname);
        document.querySelector("fnordmetric-app").openUrl(url);
      }, false);

      Fnord.jsonRPC("/rpc", "GroupsService.getMembers", { 
        group: "fnordmetric-hosts-plugin-hostnames"
      }, function(hosts) {
        var kv_keys = [];
        for (var i = 0; i < hosts.length; ++i) {
          kv_keys.push("fnordmetric-hosts-plugin-hostdata~" + hosts[i]);
        }

        Fnord.jsonRPC("/rpc", "KeyValueService.mget", { keys: kv_keys },
            function(host_data) {
          for (var i = 0; i < hosts.length; ++i) {
            var hname = hosts[i];
            var hdata = host_data[i];

            if (hdata.length == 0) {
              console.log("missing data for host", hname);
              continue;
            } else {
              hdata = JSON.parse(hdata);
            }

            var row = table.appendRowFromArray([
                hname,
                hdata.load_avg,
                "Loading...",
                "Loading...",
                "Loading...",
                "Loading...",
                "Loading..." 
            ]);
            row.setAttribute("data-hostname", hname);
          }
        });
      });
    }

    this.renderDetailView = function(hostname) {
      var tpl = Fnord.getTemplate("fnordmetric-plugin-hosts", "detail");
      this.appendChild(tpl);

      this.querySelector("h1").innerHTML = "<i>Hosts</i> &rsaquo; " + hostname;
    }

    this.createdCallback = function() {
      if (this.getAttribute("data-url")) {
        this.openUrl(this.getAttribute("data-url"));
      }
    }

    this.attributeChangedCallback = function(attr, old_val, new_val) {
      if (attr == "data-url") {
        this.openUrl(new_val);
      }
    }
  };

  window.addEventListener("fn-ready", function() {
    Fnord.registerComponent(
        "fnordmetric-plugin-hosts",
        FnordMetricHostsPluginComponent);
  }, false);
</script>
+0 −110
Original line number Diff line number Diff line
#!/usr/bin/env ruby
require "json"
require "net/http"
require 'securerandom'
require "timeout"
require 'uri'

###############################################################################

# Prefix every metric name with this string
METRIC_NAME_PREFIX = "/hosts/"

# Report the statistics every 1 second
INTERVAL = 1.0

###############################################################################

if ARGV.length != 1
  puts "usage: #{$0} <rpc-url>"
  puts "  Report OSX system stats to FnordMetric Server via JSONRPC"
  puts ""
  puts "example: #{$0} http://localhost:8080/rpc"
  exit 1
end

def rpc_call(method, params)
  req = {
    "jsonrpc" => "2.0",
    "method" => method,
    "params" => params,
    "id" => SecureRandom.hex
  }

  puts req.to_json
  return
  begin
    uri = URI.parse(ARGV[0])
    http = Net::HTTP.new(uri.host, uri.port)
    resp = http.post(uri.path, req.to_json, {})

    if resp.code.to_i != 200 || JSON.parse(resp.body).has_key?("error")
      STDERR.puts "RPC failed: " + resp.body
    end
  rescue Exception => e
    STDERR.puts "RPC failed: " + e.to_s
  end
end

loop do
  last_run = Time.now.to_f

  rpc_call "KeyValueService.set", {
    :key => "fnordmetric-hosts-plugin-enabled",
    :value => "true"
  }

  # hostname
  hostname = `hostname`.strip

  # uptime
  uptime = `uptime`.strip.gsub(",", ".")

  # gather load averages
  load_avg = 0.0
  if uptime =~ /load averages?: ([0-9]+[,\.][0-9]+)\s+([0-9]+[,\.][0-9]+)\s+([0-9]+[,\.][0-9]+)/
    load_avg = $1

    rpc_call "MetricService.insertSample", {
      :metric => "load_avg_1m",
      :value => $1,
      :labels => {
        :host => hostname
      }
    }

    rpc_call "MetricService.insertSample", {
      :metric => "load_avg_5m",
      :value => $2,
      :labels => {
        :host => hostname
      }
    }

    rpc_call "MetricService.insertSample", {
      :metric => "load_avg_15m",
      :value => $3,
      :labels => {
        :host => hostname
      }
    }
  end


  rpc_call "GroupsService.addMember", {
    :group => "fnordmetric-hosts-plugin-hostnames",
    :member => hostname
  }

  rpc_call "KeyValueService.set", {
    :key => "fnordmetric-hosts-plugin-hostdata~#{hostname}",
    :value => {
      :uptime => uptime,
      :load_avg => load_avg
    }.to_json
  }

  # sleep if we completed executing faster than the requested interval
  sleep_for = (last_run + INTERVAL) - Time.now.to_f
  sleep(sleep_for) if sleep_for > 0
end