Class: Rubix::Monitor

Inherits:
Object
  • Object
show all
Defined in:
lib/rubix/monitors/monitor.rb

Overview

A generic monitor class for constructing Zabbix monitors.

This class handles the low-level logic of sleeping, waking up, and sending data to Zabbix.

It’s up to a subclass to determine how to make a measurement.

Here’s an example of a script which measures the uptime of the current machine.

#!/usr/bin/env ruby
# in uptime_monitor
class UptimeMonitor < Rubix::Monitor

  def measure
    return unless `uptime`.chomp =~ /(\d+) days.*(\d+) users.*load average: ([\d\.]+), ([\d\.]+), ([\d\.]+)/

    # can write one value at a time
    write ['uptime', $1.to_i]

    # or can use a block
    write do |data|
      # values can be arrays
      data << ['users', $2.to_i]
      # or hashes
      data << { :key => 'load15', :value => $3.to_i }
      data << { :key => 'load5',  :value => $4.to_i }
      # can even pass a different host
      data << { :key => 'load1',  :value => $5.to_i, :host => 'foobar-host' }
    end
  end
end

UptimeMonitor.run if $0 == __FILE__

See what the script measures by running it directly.

$ ./uptime_monitor

Or have it send its output to another file or FIFO

$ ./uptime_monitor /path/to/some/file

Or have it loop every 30 seconds

$ ./uptime_monitor --loop=30 /path/to/some/file &

Direct Known Subclasses

HttpAvailabilityMonitor, UptimeMonitor

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(settings) ⇒ Monitor

Returns a new instance of Monitor.



92
93
94
# File 'lib/rubix/monitors/monitor.rb', line 92

def initialize settings
  @settings = settings
end

Instance Attribute Details

#settingsObject (readonly)

Instance-level settings that provide logic for running once or looping.



90
91
92
# File 'lib/rubix/monitors/monitor.rb', line 90

def settings
  @settings
end

Class Method Details

.default_settingsObject

Class-level settings and a function to run a monito



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/rubix/monitors/monitor.rb', line 57

def self.default_settings
  @default_settings ||= Configliere::Param.new.tap do |s|
    
    s.use :commandline
    
    s.define :loop,   :description => "Run every this many seconds",                         :required => false, :type => Integer

    # The following options are only used when sending directly
    # with <tt>zabbix_sender</tt>
    s.define :server, :description => "IP of a Zabbix server",                               :required => false, :default => 'localhost'
    s.define :port,   :description => "Port of a Zabbix server",                             :required => false, :default => 10051, :type => Integer
    s.define :host,   :description => "Name of a Zabbix host",                               :required => false, :default => ENV["HOSTNAME"]
    s.define :config, :description => "Local Zabbix agentd configuration file",              :required => false, :default => "/etc/zabbix/zabbix_agentd.conf"
    s.define :send,   :description => "Send data directly to Zabbix using 'zabbix_sender'",  :required => false, :default => false, :type => :boolean
  end
end

.runObject



74
75
76
77
78
79
80
81
82
83
# File 'lib/rubix/monitors/monitor.rb', line 74

def self.run
  settings = default_settings
  begin
    settings.resolve!
  rescue => e
    puts e.message
    exit(1)
  end
  new(settings).run
end

Instance Method Details

#closeObject



211
212
213
214
215
216
217
218
219
220
# File 'lib/rubix/monitors/monitor.rb', line 211

def close
  return unless output
  output.flush
  case
  when stdout?
    return
  else
    output.close
  end
end

#fifo?Boolean

Returns:

  • (Boolean)


184
185
186
# File 'lib/rubix/monitors/monitor.rb', line 184

def fifo?
  !stdout? && File.exist?(output_path) && File.ftype(output_path) == 'fifo'
end

#file?Boolean

Returns:

  • (Boolean)


180
181
182
# File 'lib/rubix/monitors/monitor.rb', line 180

def file?
  !stdout? && (!File.exist?(output_path) || File.ftype(output_path) == 'file')
end

#format_measurement(measurement) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/rubix/monitors/monitor.rb', line 144

def format_measurement measurement
  # <hostname> key <timestamp> value
  [].tap do |vals|
    case measurement
    when Hash
      vals << (measurement[:host].nil? ? '-' : measurement[:host])
      vals << measurement[:key]
      vals << measurement[:timestamp] if measurement[:timestamp]
      
      value = measurement[:value].to_s
      if value.include?(' ')
        value.insert(0,  "'")
        value.insert(-1, "'")
      end
      vals << value
    when Array
      if measurement.length == 2
        vals << '-'
        vals.concat(measurement)
      else
        vals.concat(measurement)
      end
    else
      return
    end
  end.map(&:to_s).join(' ')
end

#loop?Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/rubix/monitors/monitor.rb', line 96

def loop?
  loop_period > 0
end

#loop_periodObject



100
101
102
# File 'lib/rubix/monitors/monitor.rb', line 100

def loop_period
  settings[:loop].to_i
end

#measureObject

Raises:

  • (NotImplementedError)


120
121
122
# File 'lib/rubix/monitors/monitor.rb', line 120

def measure
  raise NotImplementedError.new("Override the 'measure' method in a subclass to conduct a measurement.")
end

#outputObject



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/rubix/monitors/monitor.rb', line 192

def output
  return @output if @output
  case
  when sender?
    @output = Sender.new(:host => settings[:host], :server => settings[:server], :port => settings[:port], :config => settings[:config])
  when stdout?
    @output = $stdout
  when fifo?
    begin
      @output = open(output_path, (File::WRONLY | File::NONBLOCK))
    rescue Errno::ENXIO
      nil
      # FIFO's reader isn't alive...
    end
  else
    @output = File.open(output_path, 'a')
  end
end

#output_pathObject



172
173
174
# File 'lib/rubix/monitors/monitor.rb', line 172

def output_path
  settings.rest && settings.rest.first
end

#runObject



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/rubix/monitors/monitor.rb', line 104

def run
  begin
    if loop?
      while true
        measure
        output.flush if output
        sleep loop_period
      end
    else
      measure
    end
  ensure
    close
  end
end

#sender?Boolean

Returns:

  • (Boolean)


188
189
190
# File 'lib/rubix/monitors/monitor.rb', line 188

def sender?
  settings[:send] == true
end

#stdout?Boolean

Returns:

  • (Boolean)


176
177
178
# File 'lib/rubix/monitors/monitor.rb', line 176

def stdout?
  output_path.nil?
end

#write(measurement = nil, &block) ⇒ Object

Methods for writing data to Zabbix.



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/rubix/monitors/monitor.rb', line 128

def write measurement=nil, &block
  return unless output
  return unless measurement || block_given?
  
  data = [measurement]
  block.call(data) if block_given?

  text = data.compact.map { |measurement| format_measurement(measurement) }.compact.join("\n")

  begin
    output.puts(text)
  rescue Errno::ENXIO
    # FIFO's reader isn't alive...
  end
end