Class: Metrix::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/metrix/cli.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args) ⇒ CLI

Returns a new instance of CLI.



21
22
23
24
25
26
27
28
# File 'lib/metrix/cli.rb', line 21

def initialize(args)
  @args = args
  @system = false
  @interval = 10
  require "syslog/logger"
  Metrix.logger = Syslog::Logger.new("metrix")
  Metrix.logger.level = Logger::INFO
end

Instance Attribute Details

#intervalObject (readonly)

Returns the value of attribute interval.



19
20
21
# File 'lib/metrix/cli.rb', line 19

def interval
  @interval
end

Instance Method Details

#actionObject



34
35
36
# File 'lib/metrix/cli.rb', line 34

def action
  @action ||= parse!
end

#allowed_to_run?Boolean

Returns:

  • (Boolean)


163
164
165
# File 'lib/metrix/cli.rb', line 163

def allowed_to_run?
  !running?
end

#attributesObject



224
225
226
# File 'lib/metrix/cli.rb', line 224

def attributes
  @attributes ||= {}
end

#config_pathObject



238
239
240
# File 'lib/metrix/cli.rb', line 238

def config_path
  @config_path || default_config_path
end

#daemonize?Boolean

Returns:

  • (Boolean)


220
221
222
# File 'lib/metrix/cli.rb', line 220

def daemonize?
  @foreground != true
end

#default_config_pathObject



242
243
244
# File 'lib/metrix/cli.rb', line 242

def default_config_path
  File.expand_path("/etc/metrix.yml")
end

#delete_pidfile!Object



83
84
85
86
# File 'lib/metrix/cli.rb', line 83

def delete_pidfile!
  logger.info "deleteing pidfile #{pid_path}"
  FileUtils.rm_f(pid_path)
end

#elasticsearch_statusObject



179
180
181
# File 'lib/metrix/cli.rb', line 179

def elasticsearch_status
  get_url url_for(:elasticsearch)
end

#enabled?(key) ⇒ Boolean

Returns:

  • (Boolean)


175
176
177
# File 'lib/metrix/cli.rb', line 175

def enabled?(key)
  !!attributes[key]
end

#fetch_metrix(type) ⇒ Object



201
202
203
204
205
206
207
208
209
# File 'lib/metrix/cli.rb', line 201

def fetch_metrix(type)
  return false if !enabled?(type)
  started = Time.now
  logger.info "fetching metrix for #{type}"
  yield
  logger.info "fetched metrix for type #{type} in %.06f" % [Time.now - started]
rescue => err
  logger.error "#{err.message} #{err.backtrace.inspect}"
end

#fetch_resource(key) ⇒ Object



183
184
185
# File 'lib/metrix/cli.rb', line 183

def fetch_resource(key)
  get_url(url_for(key))
end

#get_url(url) ⇒ Object



191
192
193
194
195
196
197
198
199
# File 'lib/metrix/cli.rb', line 191

def get_url(url)
  Timeout.timeout(1) do
    logger.info "fetching URL #{url}"
    started = Time.now
    body = Net::HTTP.get(URI(url))
    logger.info "fetched URL #{url} in %.06f" % [Time.now - started]
    body
  end
end

#load_configs_from_file!Object



228
229
230
231
232
233
234
235
236
# File 'lib/metrix/cli.rb', line 228

def load_configs_from_file!
  require "erb"
  require "yaml"
  hash = YAML.load(ERB.new(File.read(config_path)).result)
  @attributes = hash.inject({}) do |hash, (k, v)|
    hash[k.to_sym] = v
    hash
  end
end

#log_to_stdoutObject



215
216
217
218
# File 'lib/metrix/cli.rb', line 215

def log_to_stdout
  Metrix.logger = Logger.new(STDOUT)
  Metrix.logger.level = Logger::INFO
end

#loggerObject



211
212
213
# File 'lib/metrix/cli.rb', line 211

def logger
  Metrix.logger
end

#optsObject



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/metrix/cli.rb', line 246

def opts
  require "optparse"
  @opts ||= OptionParser.new do |o|
    o.on("-v", "--version") do
      puts "metrix #{Metrix::VERSION}"
      exit
    end

    o.on("-c PATH") do |value|
      @config_path = value
    end

    o.on("-d", "--debug") do |value|
      @foreground = true
      log_to_stdout
      Metrix.logger.level = Logger::DEBUG
    end
  end
end

#parse!Object



30
31
32
# File 'lib/metrix/cli.rb', line 30

def parse!
  @action = opts.parse(@args).first
end

#pid_pathObject



167
168
169
# File 'lib/metrix/cli.rb', line 167

def pid_path
  "/var/run/metrix.pid"
end

#reporterObject



143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/metrix/cli.rb', line 143

def reporter
  @reporter ||= if attributes[:opentsdb]
    require "metrix/opentsdb"
    uri = URI.parse(attributes[:opentsdb])
    Metrix::OpenTSDB.new(uri.host, uri.port)
  elsif attributes[:graphite]
    require "metrix/graphite"
    uri = URI.parse(attributes[:graphite])
    Metrix::Graphite.new(uri.host, uri.port)
  elsif @foreground == true
    require "metrix/reporter/stdout"
    Metrix::Reporter::Stdout.new
  end
end

#runObject



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/metrix/cli.rb', line 38

def run
  parse!
  case @action
  when "start"
    load_configs_from_file!
    if running?
      logger.warn "refuse to run. seems that #{pid_path} exists!"
      abort "not allowed to run" if running?
    end
    if daemonize?
      pid = Process.fork do
        start
      end
      sleep 1
      Process.detach(pid)
    else
      start
    end
  when "status"
    if File.exists?(pid_path)
      logger.debug "#{pid_path} exists"
      puts "STATUS: running with pid #{File.read(pid_path).strip}"
      exit 0
    else
      logger.debug "#{pid_path} does not exist"
      puts "STATUS: not running"
      exit 1
    end
  when "stop"
    abort "not running!" if !running?
    pid = File.read(pid_path).strip
    logger.info "killing pid #{pid}"
    system "kill #{pid}"
    puts "killed #{pid}"
  when "configtest"
    load_configs_from_file!
    puts "running configtest #{attributes.inspect}"
  when "list_metrics"
    puts Metrix.known_metrics.join("\n")
  else
    logger.warn "action #{action} unknown!"
    abort "action #{action} unknown!"
  end
end

#running?Boolean

Returns:

  • (Boolean)


171
172
173
# File 'lib/metrix/cli.rb', line 171

def running?
  File.exists?(pid_path)
end

#startObject



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/metrix/cli.rb', line 88

def start
  if self.reporter.nil?
    puts "ERROR: at least one reporter must be specified"
    abort opts.to_s
  end
  Signal.trap("TERM") do
    logger.info "terminating..."
    $running = false
  end
  $running = true
  cnt = -1
  started = Time.now
  write_pidfile!(Process.pid)
  while $running
    begin
      cnt += 1
      now = Time.now.utc
      fetch_metrix(:elasticsearch)  { reporter << Metrix::ElasticSearch.new(fetch_resource(:elasticsearch)) }
      fetch_metrix(:mongodb)        { reporter << Metrix::Mongodb.new(fetch_resource(:mongodb)) }
      fetch_metrix(:nginx)          { reporter << Metrix::Nginx.new(fetch_resource(:nginx)) }
      fetch_metrix(:fpm)            { reporter << Metrix::FPM.new(fetch_resource(:fpm)) }
      fetch_metrix(:system)         { reporter << Metrix::System.new(File.read("/proc/stat")) }
      fetch_metrix(:load)           { reporter << Metrix::Load.new(File.read("/proc/loadavg")) }
      fetch_metrix(:memory)         { reporter << Metrix::Memory.new(File.read("/proc/meminfo")) }
      fetch_metrix(:diskstats)      { reporter << Metrix::Diskstats.new(File.read("/proc/diskstats")) }
      fetch_metrix(:df)             { reporter << Metrix::Df.new(`df -k`) }

      fetch_metrix :processes do
        Metrix::ProcessMetric.all.each do |m|
          reporter << m
        end
      end
      reporter.flush
    rescue SystemExit
      $running = false
    rescue => err
      Metrix.logger.error "#{err.message}"
      Metrix.logger.error "#{err.backtrace.inspect}"
    ensure
      begin
        sleep_for = @interval - (Time.now - started - cnt * interval)
        if sleep_for > 0
          Metrix.logger.info "finished run in %.06f, sleeping for %.06f. metrix version: #{Metrix::VERSION}, attributes: #{attributes}" % [Time.now - now, sleep_for]
          sleep sleep_for
        else
          Metrix.logger.info "not sleeping because %.06f is negative" % [sleep_for]
        end
      rescue SystemExit, Interrupt
        $running = false
      end
    end
  end
  delete_pidfile!
end

#url_for(key) ⇒ Object



187
188
189
# File 'lib/metrix/cli.rb', line 187

def url_for(key)
  attributes[key]
end

#write_pidfile!(pid) ⇒ Object



158
159
160
161
# File 'lib/metrix/cli.rb', line 158

def write_pidfile!(pid)
  logger.info "writing #{pid} to #{pid_path}"
  File.open(pid_path, "w") { |f| f.print(pid) }
end