#!/usr/bin/env ruby
Process.setproctitle($0)

# Gathers network interface statistics and submits them to Riemann.

require File.expand_path('../../lib/riemann/tools', __FILE__)

class Riemann::Tools::Net
  include Riemann::Tools

  opt :interfaces, "Interfaces to monitor", :type => :strings, :default => nil
  opt :ignore_interfaces, "Interfaces to ignore", :type => :strings, :default =>['lo']

  def initialize
    @old_state = nil
    @interfaces = opts[:interfaces].map(&:dup) if opts[:interfaces]
    @ignore_interfaces = opts[:ignore_interfaces].map(&:dup)
  end

  def state
    f = File.read('/proc/net/dev')
    state = f.split("\n").inject({}) do |s, line|
      if line =~ /\s*(\w+?):\s*([\s\d]+)\s*/
        iface = $1

        ['rx bytes',
        'rx packets',
        'rx errs',
        'rx drop',
        'rx fifo',
        'rx frame',
        'rx compressed',
        'rx multicast',
        'tx bytes',
        'tx packets',
        'tx errs',
        'tx drops',
        'tx fifo',
        'tx colls',
        'tx carrier',
        'tx compressed'].map do |service|
          "#{iface} #{service}"
        end.zip(
          $2.split(/\s+/).map { |str| str.to_i }
        ).each do |service, value|
          s[service] = value
        end
      end
      
      s
    end

    # Filter interfaces
    if is = @interfaces
      state = state.select do |service, value|
        is.include? service.split(' ').first
      end
    end

    state = state.reject do |service, value|
      @ignore_interfaces.include? service.split(' ').first
    end

    state
  end
  
  def tick
    state = self.state

    if @old_state
      # Report services from `@old_state` that don't exist in `state` as expired
      @old_state.reject { |k| state.has_key?(k) }.each do |service, metric|
        report(:service => service.dup, :state => 'expired')
      end

      # Report delta for services that have values in both `@old_state` and `state`
      state.each do |service, metric|
        next unless @old_state.has_key?(service)

        delta = metric - @old_state[service]
        svc_state = case service
          when /drop$/
            if delta > 0
              'warning'
            else
              'ok'
            end
          when /errs$/
            if delta > 0
              'warning'
            else
              'ok'
            end
          else
            'ok'
          end

        report(
          :service => service.dup,
          :metric => (delta.to_f / opts[:interval]),
          :state => svc_state
        )
      end
    end

    @old_state = state
  end
end
  
Riemann::Tools::Net.run
