riemann-monitors 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ce2a724b0e9f58a3428fb402dc313167eefbd0b5
4
+ data.tar.gz: ae4f41b34dbf278b6ab92c0dd89c2f6e5cd5ccf6
5
+ SHA512:
6
+ metadata.gz: 3972340ad48aa5142ba96583d98edc771881db39bd48e0f747bfbfff473003975fe60638b0de8acbf5f7ab51508e7d3dba2d7214ad857c90b9156a4a63112f1c
7
+ data.tar.gz: a862891b8187f2947d4e490eb1c0b69db6c44a108648470a454edb0266e3a6c6bcbe5f37322993ed5bbaa1c288c3618058e6fb7aea368684c09aec840101afd3
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2011 Kyle Kingsbury
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.adoc ADDED
@@ -0,0 +1,75 @@
1
+ = riemann-monitors
2
+ Chris Riddoch <riddochc@gmail.com>
3
+ :language: ruby
4
+ :homepage: https://github.com/riddochc/riemann-monitors
5
+ :revnumber: 0.0.1
6
+ :revdate: 2016-05-29
7
+
8
+ == Description
9
+
10
+ Tiny programs to submit events to Riemann.
11
+
12
+ This is a polite fork of riemann-tools, using my riemann-ruby-experiments gem
13
+ instead of riemann-ruby-client. As a result, events can be batched together
14
+ to be sent in one message to a Riemann server. Additionally, more control
15
+ over the TCP socket options is given, and UDP isn't supported (yet?), because
16
+ this gem primarily uses net_ruby_client.
17
+
18
+ == Requirements
19
+
20
+ * Ruby 2.0 or higher (currently only tested on 2.3)
21
+ * A riemann server to talk to
22
+
23
+ == Installation
24
+
25
+ gem install riemann-monitors
26
+
27
+ == Use
28
+
29
+ riemann-health
30
+
31
+ This defaults to connecting to a Riemann server listening on 127.0.0.1, TCP port 5555.
32
+
33
+ == Riemann-tools programs
34
+
35
+ This repository contains a number of different programs, mostly identical to those
36
+ in `riemann-tools`.
37
+
38
+ riemann-httpstatus:: Monitoring results of periodic HTTP requests.
39
+ riemann-apache-status:: Apache monitoring.
40
+ riemann-dir-files-count:: File counts.
41
+ riemann-freeswitch:: FreeSwitch monitoring.
42
+ riemann-memcached:: Monitor Memcache.
43
+ riemann-proc:: Linux process monitoring.
44
+ riemann-bench:: Load testing for Riemann.
45
+ riemann-dir-space:: Directory space monitoring.
46
+ riemann-haproxy:: Monitor HAProxy.
47
+ riemann-net:: Network interface monitoring.
48
+ riemann-varnish:: Monitor Varnish.
49
+ riemann-cloudant:: Cloudant monitoring.
50
+ riemann-diskstats:: Disk statistics.
51
+ riemann-health:: General CPU, memory, disk and load monitoring.
52
+ riemann-nginx-status:: Monitor Nginx.
53
+ riemann-zookeeper:: Monitor Zookeeper.
54
+ riemann-consul:: Monitor Consul.
55
+ riemann-fd:: Linux file descriptor use.
56
+ riemann-kvminstance:: Monitor KVM instances.
57
+ riemann-ntp:: Monitor NTP
58
+
59
+ The "stand-alone" tools offered in `riemann-tools` aren't included for now.
60
+
61
+ == Contributing
62
+
63
+ Pull requests, please.
64
+
65
+ == Contributors
66
+
67
+ git shortlog -n
68
+
69
+ == License
70
+
71
+ The MIT License
72
+
73
+ Copyright (c) 2016 Chris Riddoch
74
+ Copyright (c) 2011-2016 Kyle Kingsbury
75
+
data/Rakefile ADDED
@@ -0,0 +1,125 @@
1
+ # vim: syntax=ruby
2
+
3
+ require 'yaml'
4
+ require 'find'
5
+ require 'asciidoctor'
6
+ require 'erb'
7
+
8
+ def installed_gem_version(name)
9
+ IO.popen(["gem", "list", "-l", name], 'r') do |io|
10
+ # this regex is using lookahead/behind to match things within \( and \), non-greedily.
11
+ io.readlines.grep(/^#{name}\s/).first[/(?<=\().*?(?=\))/].split(', ').first
12
+ end
13
+ end
14
+
15
+ def filtered_project_files()
16
+ Dir.chdir __dir__ do
17
+ Find.find(".").reject {|f| !File.file?(f) || f =~ %r{^\./(.git|tmp)} || f =~ %r{\.(so|gem)$} }.map {|f| f.sub %r{^\./}, '' }
18
+ end
19
+ end
20
+
21
+ adoc = Asciidoctor.load_file("README.adoc")
22
+ summary = adoc.sections.find {|s| s.name == "Description" }.blocks[0].content.gsub(/\n/, ' ')
23
+ description = adoc.sections.find {|s| s.name == "Description" }.blocks[1].content.gsub(/\n/, ' ')
24
+ config = YAML.load_file(File.join(__dir__, "project.yaml"))
25
+ project = config.fetch('name', File.split(File.expand_path(__dir__)).last)
26
+ toplevel_module = config.fetch('toplevel_module') { project.capitalize }
27
+ version = adoc.attributes['revnumber']
28
+ dependencies = config.fetch('dependencies', {})
29
+ if dependencies.nil?
30
+ dependencies = {}
31
+ end
32
+ dev_dependencies = config.fetch('dev-dependencies', {})
33
+ if dev_dependencies.nil?
34
+ dev_dependencies = {}
35
+ end
36
+ license = config.fetch('license') { "LGPL-3.0" }
37
+ executables = Dir.glob(File.join(__dir__, "bin", "*")).map {|f| File.basename(f) }
38
+ #["rake", "asciidoctor", "yard", "pry", "rspec", "rspec-sequel-formatter", "#{project}-tests"]
39
+ ["rake", "asciidoctor", "yard", "pry", "rspec"].each do |dep|
40
+ dev_dependencies[dep] = dev_dependencies.fetch(dep) {|d| "=#{installed_gem_version(d)}" }
41
+ end
42
+
43
+ gemspec_template = <<GEMSPEC
44
+ Gem::Specification.new do |s|
45
+ s.name = "<%= project %>"
46
+ s.version = "<%= version %>"
47
+ s.licenses = ["<%= license %>"]
48
+ s.platform = Gem::Platform::RUBY
49
+ s.summary = "<%= summary %>"
50
+ s.description = "<%= description %>"
51
+ s.authors = ["<%= adoc.author %>"]
52
+ s.email = "<%= adoc.attributes['email'] %>"
53
+ s.date = "<%= Date.today %>"
54
+ s.files = [<%= all_files.map{|f| '"' + f + '"' }.join(",\n ") %>]
55
+ s.homepage = "<%= adoc.attributes['homepage'] %>"
56
+ s.bindir = "bin"
57
+ s.executables = [<%= executables.map{|f| '"' + f + '"' }.join(",\n ") %>]
58
+
59
+ % dependencies.each_pair do |req, vers|
60
+ s.add_dependency "<%= req %>", "<%= vers %>"
61
+ % end
62
+
63
+ % dev_dependencies.each_pair do |req, vers|
64
+ s.add_development_dependency "<%= req %>", "<%= vers %>"
65
+ % end
66
+ end
67
+ GEMSPEC
68
+
69
+ task default: [:gen_version, :gemspec, :gemfile, :build]
70
+
71
+ task :gen_version do
72
+ File.open(File.join("lib", project, "version.rb"), 'w') {|f|
73
+ f.puts "module #{toplevel_module}"
74
+ major, minor, tiny = *version.split(/\./).map {|p| p.to_i }
75
+ f.puts ' VERSION = "' + version + '"'
76
+ f.puts " VERSION_MAJOR = #{major}"
77
+ f.puts " VERSION_MINOR = #{minor}"
78
+ f.puts " VERSION_TINY = #{tiny}"
79
+ f.puts "end"
80
+ }
81
+ end
82
+
83
+ task :gemspec => [:gen_version] do
84
+ files_in_git = IO.popen(["git", "ls-files"], 'r') { |io| io.readlines.map {|l| l.chomp } }
85
+ all_files = filtered_project_files()
86
+ if all_files - files_in_git
87
+ puts "Looks like there's some files uncommitted."
88
+ end
89
+
90
+ requires = all_files.grep(/\.rb$/).
91
+ map {|f| File.readlines(f).grep (/^\s*require(?!_relative)/) }.
92
+ flatten.
93
+ map {|line| line.split(/['"]/).at(1).split('/').at(0) }.
94
+ uniq
95
+
96
+ missing_deps = requires - dependencies.keys
97
+ if missing_deps.length > 0
98
+ puts "There may be some dependencies not listed for the gemspec:"
99
+ puts missing_deps.join(", ")
100
+ end
101
+
102
+ File.open(project + ".gemspec", 'w') do |f|
103
+ erb = ERB.new(gemspec_template, nil, "%<>")
104
+ f.write(erb.result(binding))
105
+ end
106
+ end
107
+
108
+ task :gemfile do
109
+ File.open("Gemfile", 'w') do |f|
110
+ f.puts "source 'https://rubygems.org"
111
+ f.puts "gemspec"
112
+ end
113
+ end
114
+
115
+ task :build => [:clean, :gemspec, :gemfile] do
116
+ system "gem build #{project}.gemspec"
117
+ end
118
+
119
+ task :install => [:build] do
120
+ system "gem install ./#{project}-#{version}.gem"
121
+ end
122
+
123
+ task :clean do
124
+ rm_f "./#{project}-#{version}.gem"
125
+ end
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Collects Apache metrics and submits them to Riemann
4
+ # More information can be found at http://httpd.apache.org/docs/2.4/mod/mod_status.html
5
+
6
+ # Removes whitespace from 'Total Accesses' and 'Total kBytes' for output to graphite
7
+
8
+ require_relative "../lib/riemann-monitors"
9
+
10
+ class Riemann::Monitors::ApacheStatus
11
+ include Riemann::Monitors
12
+ require 'net/http'
13
+ require 'uri'
14
+
15
+ opt :uri, 'Apache Server Status URI', :default => 'http://localhost/server-status'
16
+
17
+ def initialize
18
+ @uri = URI.parse(opts[:uri]) + '?auto'
19
+ # Sample Response with ExtendedStatus On
20
+ # Total Accesses: 20643
21
+ # Total kBytes: 36831
22
+ # CPULoad: .0180314
23
+ # Uptime: 43868
24
+ # ReqPerSec: .470571
25
+ # BytesPerSec: 859.737
26
+ # BytesPerReq: 1827.01
27
+ # BusyWorkers: 6
28
+ # IdleWorkers: 94
29
+ # Scoreboard: ___K_____K____________W_
30
+
31
+ @scoreboard_map = { '_' => 'waiting', 'S' => 'starting', 'R' => 'reading', 'W' => 'sending',
32
+ 'K' => 'keepalive', 'D' => 'dns', 'C' => 'closing', 'L' => 'logging', 'G' => 'graceful',
33
+ 'I' => 'idle', '.' => 'open' }
34
+ end
35
+
36
+
37
+ def get_scoreboard_metrics(response)
38
+ results = Hash.new(0)
39
+
40
+ response.slice! 'Scoreboard: '
41
+ response.each_char do |char|
42
+ results[char] += 1
43
+ end
44
+ Hash[results.map { |k, v| [@scoreboard_map[k], v] }]
45
+ end
46
+
47
+ def report_metrics(metrics)
48
+ metrics.each do |k, v|
49
+ report(
50
+ :service => "httpd #{k}",
51
+ :metric => v.to_f,
52
+ :state => 'ok',
53
+ :tags => ['httpd']
54
+ )
55
+ end
56
+ end
57
+
58
+ def get_connection
59
+ response = nil
60
+ begin
61
+ response = Net::HTTP.get(@uri)
62
+ rescue => e
63
+ report(
64
+ :service => 'httpd health',
65
+ :state => 'critical',
66
+ :description => 'Httpd connection error: #{e.class} - #{e.message}',
67
+ :tags => ['httpd']
68
+ )
69
+ else
70
+ report(
71
+ :service => 'httpd health',
72
+ :state => 'ok',
73
+ :description => 'Httpd connection status ok',
74
+ :tags => ['httpd']
75
+ )
76
+ end
77
+ response
78
+ end
79
+
80
+ def tick
81
+ unless (response = get_connection).nil?
82
+ response.each_line do |line|
83
+ metrics = Hash.new
84
+
85
+ if line =~ /Scoreboard/
86
+ metrics = get_scoreboard_metrics(line.strip)
87
+ else
88
+ key, value = line.strip.split(':')
89
+ metrics[key.gsub(/\s/, '')] = value
90
+ end
91
+ report_metrics(metrics)
92
+ end
93
+ end
94
+ end
95
+
96
+ end
97
+
98
+ Riemann::Monitors::ApacheStatus.run
data/bin/riemann-bench ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Connects to a server (first arg) and populates it with a constant stream of
4
+ # events for testing.
5
+
6
+ require_relative "../lib/riemann-monitors"
7
+ require 'pp'
8
+
9
+ class Riemann::Monitors::Bench
10
+ include Riemann::Monitors
11
+
12
+ attr_accessor :client, :hosts, :services, :states
13
+ def initialize
14
+ @hosts = [nil] + (0...10).map { |i| "host#{i}" }
15
+ @hosts = %w(a b c d e f g h i j)
16
+ @services = %w(test1 test2 test3 foo bar baz xyzzy attack cat treat)
17
+ @states = {}
18
+ end
19
+
20
+ def evolve(state)
21
+ m = state[:metric] + (rand - 0.5) * 0.1
22
+ m = [[0,m].max, 1].min
23
+
24
+ s = case m
25
+ when 0...0.75
26
+ 'ok'
27
+ when 0.75...0.9
28
+ 'warning'
29
+ when 0.9..1.0
30
+ 'critical'
31
+ end
32
+
33
+ {
34
+ :metric => m,
35
+ :state => s,
36
+ :host => state[:host],
37
+ :service => state[:service],
38
+ :description => "at #{Time.now}"
39
+ }
40
+
41
+ end
42
+
43
+ def tick
44
+ # pp @states
45
+ hosts.product(services).each do |id|
46
+ client << (states[id] = evolve(states[id]))
47
+ end
48
+ end
49
+
50
+ def run
51
+ start
52
+ loop do
53
+ sleep 0.05
54
+ tick
55
+ end
56
+ end
57
+
58
+ def start
59
+ hosts.product(services).each do |host, service|
60
+ states[[host, service]] = {
61
+ :metric => 0.5,
62
+ :state => 'ok',
63
+ :description => "Starting up",
64
+ :host => host,
65
+ :service => service
66
+ }
67
+ end
68
+ end
69
+ end
70
+
71
+ Riemann::Bench.new.run
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Gathers load balancer statistics from Cloudant.com (shared cluster) and submits them to Riemann.
4
+
5
+ require File.expand_path('../../lib/riemann/tools', __FILE__)
6
+
7
+ class Riemann::Monitors::Cloudant
8
+ include Riemann::Monitors
9
+ require 'net/http'
10
+ require 'json'
11
+
12
+ opt :cloudant_username, "Cloudant username", :type => :string, :required => true
13
+ opt :cloudant_password, "Cloudant pasword", :type => :string, :required => true
14
+
15
+ def tick
16
+ json = JSON.parse(get_json().body)
17
+ json.each do |node|
18
+ return if node['svname'] == 'BACKEND' # this is just a sum of all nodes.
19
+
20
+ ns = "cloudant #{node['pxname']}"
21
+ cluster_name = node['tracked'].split('.')[0] # ie: meritage.cloudant.com
22
+
23
+ # report health of each node.
24
+ report(
25
+ :service => ns,
26
+ :state => (node['status'] == 'UP' ? 'ok' : 'critical'),
27
+ :tags => ['cloudant', cluster_name]
28
+ )
29
+
30
+ # report property->metric of each node.
31
+ node.each do |property, metric|
32
+ unless ['pxname', 'svname', 'status', 'tracked'].include?(property)
33
+ report(
34
+ :host => node['tracked'],
35
+ :service => "#{ns} #{property}",
36
+ :metric => metric.to_f,
37
+ :state => (node['status'] == 'UP' ? 'ok' : 'critical'),
38
+ :tags => ['cloudant', cluster_name]
39
+ )
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+
46
+ def get_json
47
+ http = Net::HTTP.new('cloudant.com', 443)
48
+ http.use_ssl = true
49
+ http.start do |h|
50
+ get = Net::HTTP::Get.new('/api/load_balancer')
51
+ get.basic_auth opts[:cloudant_username], opts[:cloudant_password]
52
+ h.request get
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ Riemann::Monitors::Cloudant.run
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Reports service and node status to riemann
4
+
5
+ require File.expand_path('../../lib/riemann/tools', __FILE__)
6
+ require 'socket'
7
+ require 'net/http'
8
+ require 'uri'
9
+ require 'json'
10
+
11
+ class Riemann::Monitors::ConsulHealth
12
+ include Riemann::Monitors
13
+
14
+ opt :consul_host, "Consul API Host (default to localhost)", :default => "localhost"
15
+ opt :consul_port, "Consul API Host (default to 8500)", :default => "8500"
16
+ opt :prefix, "prefix to use for all service names when reporting", :default => "consul "
17
+ opt :minimum_services_per_node, "minimum services per node (default: 0)", :default => 0
18
+
19
+ def initialize
20
+
21
+ @hostname = opts[:consul_host]
22
+ @prefix = opts[:prefix]
23
+ @minimum_services_per_node = opts[:minimum_services_per_node]
24
+ @underlying_ip = IPSocket.getaddress(@hostname)
25
+ @consul_leader_url = URI.parse("http://" + opts[:consul_host] + ":" + opts[:consul_port] + "/v1/status/leader")
26
+ @consul_services_url = URI.parse("http://" + opts[:consul_host] + ":" + opts[:consul_port] + "/v1/catalog/services")
27
+ @consul_nodes_url = URI.parse("http://" + opts[:consul_host] + ":" + opts[:consul_port] + "/v1/catalog/nodes")
28
+ @consul_health_url_prefix = "http://" + opts[:consul_host] + ":" + opts[:consul_port] + "/v1/health/service/"
29
+
30
+ @last_services_read = Hash.new
31
+
32
+ end
33
+
34
+ def alert(hostname, service, state, metric, description)
35
+
36
+ opts = { :host => hostname,
37
+ :service => service.to_s,
38
+ :state => state.to_s,
39
+ :metric => metric,
40
+ :description => description }
41
+
42
+ report(opts)
43
+ end
44
+
45
+ def get(url)
46
+ Net::HTTP.get_response(url).body
47
+ end
48
+
49
+ def tick
50
+
51
+ leader = get(@consul_leader_url)
52
+ leader_hostname = URI.parse("http://" + leader[1..-2]).hostname
53
+
54
+ if (leader_hostname == @underlying_ip)
55
+ nodes = JSON.parse(get(@consul_nodes_url))
56
+ services = JSON.parse(get(@consul_services_url))
57
+ services_by_nodes = Hash.new
58
+
59
+ for node in nodes
60
+ node_name = node["Node"]
61
+ services_by_nodes[node_name] = 0
62
+ end
63
+
64
+
65
+ # For every service
66
+ for service in services
67
+ service_name = service[0]
68
+ health_url = URI.parse(@consul_health_url_prefix + service_name)
69
+ health_nodes = JSON.parse(get(health_url))
70
+
71
+ totalCount = 0
72
+ okCount = 0
73
+
74
+ for node in health_nodes
75
+ hostname = node["Node"]["Node"]
76
+ ok = node["Checks"].all? {|check| check["Status"] == "passing"}
77
+ alert(hostname, "#{@prefix}#{service_name}", ok ? :ok : :critical, ok ? 1 : 0, JSON.generate(node))
78
+ totalCount += 1
79
+ okCount += ok ? 1 : 0
80
+
81
+ last_services_by_nodes = services_by_nodes[hostname].to_i
82
+ services_by_nodes[hostname] = last_services_by_nodes + 1
83
+ end
84
+
85
+ if (@last_services_read[service_name] != nil)
86
+ lastOk = @last_services_read[service_name]
87
+ if (lastOk != okCount)
88
+ alert("total", "#{@prefix}#{service_name}-count", okCount >= lastOk ? :ok : :critical, okCount, "Number of passing #{service_name} is: #{okCount}/#{totalCount}, Last time it was: #{lastOk}")
89
+ end
90
+ end
91
+
92
+ @last_services_read[service_name] = okCount
93
+
94
+ end
95
+
96
+ # For every node
97
+ for node,count in services_by_nodes
98
+ alert(node, "#{@prefix}total-services", (count >= @minimum_services_per_node) ? :ok : :critical, count, "#{count} services in the specified node")
99
+ end
100
+
101
+ end
102
+
103
+ end
104
+ end
105
+
106
+ Riemann::Monitors::ConsulHealth.run
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Gets the number of files present on a directory and submits it to riemann
4
+
5
+ require_relative "../lib/riemann-monitors"
6
+
7
+ class Riemann::Monitors::DirFilesCount
8
+ include Riemann::Monitors
9
+
10
+ opt :directory, "", :default => '/var/log'
11
+ opt :service_prefix, "The first part of the service name, before the directory path", :default => "dir-files-count"
12
+ opt :warning, "Dir files number warning threshold", :type => Integer
13
+ opt :critical, "Dir files number critical threshold", :type => Integer
14
+ opt :alert_on_missing, "Send a critical metric if the directory is missing?", :default => true
15
+
16
+ def initialize
17
+ @dir = opts.fetch(:directory)
18
+ @service_prefix = opts.fetch(:service_prefix)
19
+ @warning = opts.fetch(:warning, nil)
20
+ @critical = opts.fetch(:critical, nil)
21
+ @alert_on_missing = opts.fetch(:alert_on_missing)
22
+ end
23
+
24
+ def tick
25
+ if Dir.exists?(@dir)
26
+ metric = Dir.entries(@dir).size - 2
27
+ report(
28
+ :service => "#{@service_prefix} #{@dir}",
29
+ :metric => metric,
30
+ :state => state(metric),
31
+ :tags => ['dir_files_count']
32
+ )
33
+ elsif @alert_on_missing
34
+ report(
35
+ :service => "#{@service_prefix} #{@dir} missing",
36
+ :description => "#{@service_prefix} #{@dir} does not exist",
37
+ :metric => metric,
38
+ :state => 'critical',
39
+ :tags => ['dir_files_count']
40
+ )
41
+ end
42
+ end
43
+
44
+ def state(metric)
45
+ if @critical && metric > @critical
46
+ 'critical'
47
+ elsif @warning && metric > @warning
48
+ 'warning'
49
+ else
50
+ 'ok'
51
+ end
52
+ end
53
+ end
54
+
55
+ Riemann::Monitors::DirFilesCount.run
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Gathers the space used by a directory and submits it to riemann
4
+
5
+ require_relative "../lib/riemann-monitors"
6
+
7
+ class Riemann::Monitors::DirSpace
8
+ include Riemann::Monitors
9
+
10
+ opt :directory, "", :default => '/var/log'
11
+ opt :service_prefix, "The first part of the service name, before the directory path", :default => "dir-space"
12
+ opt :warning, "Dir space warning threshold (in bytes)", :type => Integer
13
+ opt :critical, "Dir space critical threshold (in bytes)", :type => Integer
14
+ opt :alert_on_missing, "Send a critical metric if the directory is missing?", :default => true
15
+
16
+ def initialize
17
+ @dir = opts.fetch(:directory)
18
+ @service_prefix = opts.fetch(:service_prefix)
19
+ @warning = opts.fetch(:warning, nil)
20
+ @critical = opts.fetch(:critical, nil)
21
+ @alert_on_missing = opts.fetch(:alert_on_missing)
22
+ end
23
+
24
+ def tick
25
+ if Dir.exists?(@dir)
26
+ metric = `du '#{@dir}'`.lines.to_a.last.split("\t")[0].to_i
27
+ report(
28
+ :service => "#{@service_prefix} #{@dir}",
29
+ :metric => metric,
30
+ :state => state(metric),
31
+ :tags => ['dir_space']
32
+ )
33
+ elsif @alert_on_missing
34
+ report(
35
+ :service => "#{@service_prefix} #{@dir} missing",
36
+ :description => "#{@service_prefix} #{@dir} does not exist",
37
+ :metric => metric,
38
+ :state => 'critical',
39
+ :tags => ['dir_space']
40
+ )
41
+ end
42
+ end
43
+
44
+ def state(metric)
45
+ if @critical && metric > @critical
46
+ 'critical'
47
+ elsif @warning && metric > @warning
48
+ 'warning'
49
+ else
50
+ 'ok'
51
+ end
52
+ end
53
+ end
54
+
55
+ Riemann::Monitors::DirSpace.run