riemann-tools 0.2.13 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. checksums.yaml +5 -5
  2. data/.docker/Dockerfile +7 -0
  3. data/.docker/publish.sh +35 -0
  4. data/.github/dependabot.yml +11 -0
  5. data/.github/workflows/ci.yml +42 -0
  6. data/.github/workflows/codeql-analysis.yml +72 -0
  7. data/.gitignore +6 -0
  8. data/.rspec +2 -0
  9. data/.rubocop.yml +32 -0
  10. data/.travis.yml +31 -0
  11. data/CHANGELOG.md +422 -0
  12. data/Gemfile +6 -0
  13. data/ISSUE_TEMPLATE.md +15 -0
  14. data/README.markdown +14 -15
  15. data/Rakefile +23 -0
  16. data/SECURITY.md +42 -0
  17. data/bin/riemann-apache-status +92 -77
  18. data/bin/riemann-bench +54 -48
  19. data/bin/riemann-cloudant +44 -39
  20. data/bin/riemann-consul +82 -75
  21. data/bin/riemann-dir-files-count +53 -46
  22. data/bin/riemann-dir-space +53 -46
  23. data/bin/riemann-diskstats +78 -74
  24. data/bin/riemann-fd +68 -47
  25. data/bin/riemann-freeswitch +108 -102
  26. data/bin/riemann-haproxy +46 -39
  27. data/bin/riemann-health +4 -335
  28. data/bin/riemann-kvminstance +18 -12
  29. data/bin/riemann-memcached +35 -28
  30. data/bin/riemann-net +4 -103
  31. data/bin/riemann-nginx-status +74 -66
  32. data/bin/riemann-ntp +4 -32
  33. data/bin/riemann-portcheck +40 -30
  34. data/bin/riemann-proc +96 -89
  35. data/bin/riemann-varnish +51 -44
  36. data/bin/riemann-zookeeper +38 -33
  37. data/lib/riemann/tools/health.rb +347 -0
  38. data/lib/riemann/tools/net.rb +104 -0
  39. data/lib/riemann/tools/ntp.rb +41 -0
  40. data/lib/riemann/tools/utils.rb +17 -0
  41. data/lib/riemann/tools/version.rb +7 -0
  42. data/lib/riemann/tools.rb +40 -33
  43. data/riemann-tools.gemspec +42 -0
  44. data/tools/riemann-aws/LICENSE +21 -0
  45. data/tools/riemann-aws/README.md +54 -0
  46. data/tools/riemann-aws/Rakefile +37 -0
  47. data/tools/riemann-aws/bin/riemann-aws-billing +93 -0
  48. data/tools/riemann-aws/bin/riemann-aws-rds-status +68 -0
  49. data/tools/riemann-aws/bin/riemann-aws-sqs-status +50 -0
  50. data/tools/riemann-aws/bin/riemann-aws-status +83 -0
  51. data/tools/riemann-aws/bin/riemann-elb-metrics +168 -0
  52. data/tools/riemann-aws/bin/riemann-s3-list +87 -0
  53. data/tools/riemann-aws/bin/riemann-s3-status +102 -0
  54. data/tools/riemann-chronos/LICENSE +21 -0
  55. data/tools/riemann-chronos/README.md +10 -0
  56. data/tools/riemann-chronos/Rakefile +37 -0
  57. data/tools/riemann-chronos/bin/riemann-chronos +161 -0
  58. data/tools/riemann-docker/LICENSE +21 -0
  59. data/tools/riemann-docker/README.md +10 -0
  60. data/tools/riemann-docker/Rakefile +36 -0
  61. data/tools/riemann-docker/bin/riemann-docker +206 -0
  62. data/tools/riemann-elasticsearch/LICENSE +21 -0
  63. data/tools/riemann-elasticsearch/README.md +10 -0
  64. data/tools/riemann-elasticsearch/Rakefile +37 -0
  65. data/tools/riemann-elasticsearch/bin/riemann-elasticsearch +174 -0
  66. data/tools/riemann-marathon/LICENSE +21 -0
  67. data/tools/riemann-marathon/README.md +10 -0
  68. data/tools/riemann-marathon/Rakefile +37 -0
  69. data/tools/riemann-marathon/bin/riemann-marathon +163 -0
  70. data/tools/riemann-mesos/LICENSE +21 -0
  71. data/tools/riemann-mesos/README.md +10 -0
  72. data/tools/riemann-mesos/Rakefile +37 -0
  73. data/tools/riemann-mesos/bin/riemann-mesos +146 -0
  74. data/tools/riemann-munin/LICENSE +21 -0
  75. data/tools/riemann-munin/README.md +10 -0
  76. data/tools/riemann-munin/Rakefile +36 -0
  77. data/tools/riemann-munin/bin/riemann-munin +43 -0
  78. data/tools/riemann-rabbitmq/LICENSE +21 -0
  79. data/tools/riemann-rabbitmq/README.md +10 -0
  80. data/tools/riemann-rabbitmq/Rakefile +37 -0
  81. data/tools/riemann-rabbitmq/bin/riemann-rabbitmq +273 -0
  82. data/tools/riemann-riak/LICENSE +21 -0
  83. data/tools/riemann-riak/README.md +10 -0
  84. data/tools/riemann-riak/Rakefile +36 -0
  85. data/tools/riemann-riak/bin/riemann-riak +323 -0
  86. data/tools/riemann-riak/bin/riemann-riak-keys +13 -0
  87. data/tools/riemann-riak/bin/riemann-riak-ring +9 -0
  88. data/tools/riemann-riak/riak_status/key_count.erl +13 -0
  89. data/tools/riemann-riak/riak_status/riak_status.rb +152 -0
  90. data/tools/riemann-riak/riak_status/ringready.erl +9 -0
  91. metadata +195 -34
@@ -0,0 +1,347 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'riemann/tools'
4
+ require 'riemann/tools/utils'
5
+
6
+ module Riemann
7
+ module Tools
8
+ class Health
9
+ include Riemann::Tools
10
+ include Riemann::Tools::Utils
11
+
12
+ opt :cpu_warning, 'CPU warning threshold (fraction of total jiffies)', default: 0.9
13
+ opt :cpu_critical, 'CPU critical threshold (fraction of total jiffies)', default: 0.95
14
+ opt :disk_warning, 'Disk warning threshold (fraction of space used)', default: 0.9
15
+ opt :disk_critical, 'Disk critical threshold (fraction of space used)', default: 0.95
16
+ opt :disk_ignorefs, 'A list of filesystem types to ignore',
17
+ default: %w[anon_inodefs autofs cd9660 devfs devtmpfs fdescfs iso9660 linprocfs linsysfs nfs procfs tmpfs]
18
+ opt :load_warning, 'Load warning threshold (load average / core)', default: 3.0
19
+ opt :load_critical, 'Load critical threshold (load average / core)', default: 8.0
20
+ opt :memory_warning, 'Memory warning threshold (fraction of RAM)', default: 0.85
21
+ opt :memory_critical, 'Memory critical threshold (fraction of RAM)', default: 0.95
22
+ opt :checks, 'A list of checks to run.', type: :strings, default: %w[cpu load memory disk]
23
+
24
+ def initialize
25
+ @limits = {
26
+ cpu: { critical: opts[:cpu_critical], warning: opts[:cpu_warning] },
27
+ disk: { critical: opts[:disk_critical], warning: opts[:disk_warning] },
28
+ load: { critical: opts[:load_critical], warning: opts[:load_warning] },
29
+ memory: { critical: opts[:memory_critical], warning: opts[:memory_warning] },
30
+ }
31
+ case (@ostype = `uname -s`.chomp.downcase)
32
+ when 'darwin'
33
+ @cores = `sysctl -n hw.ncpu`.to_i
34
+ @cpu = method :darwin_cpu
35
+ @disk = method :disk
36
+ @load = method :darwin_load
37
+ @memory = method :darwin_memory
38
+ darwin_top
39
+ when 'freebsd'
40
+ @cores = `sysctl -n hw.ncpu`.to_i
41
+ @cpu = method :freebsd_cpu
42
+ @disk = method :disk
43
+ @load = method :bsd_load
44
+ @memory = method :freebsd_memory
45
+ when 'openbsd'
46
+ @cores = `sysctl -n hw.ncpu`.to_i
47
+ @cpu = method :openbsd_cpu
48
+ @disk = method :disk
49
+ @load = method :bsd_load
50
+ @memory = method :openbsd_memory
51
+ when 'sunos'
52
+ @cores = `mpstat -a 2>/dev/null`.split[33].to_i
53
+ @cpu = method :sunos_cpu
54
+ @disk = method :disk
55
+ @load = method :bsd_load
56
+ @memory = method :sunos_memory
57
+ else
58
+ @cores = `nproc`.to_i
59
+ puts "WARNING: OS '#{@ostype}' not explicitly supported. Falling back to Linux" unless @ostype == 'linux'
60
+ @cpu = method :linux_cpu
61
+ @disk = method :disk
62
+ @load = method :linux_load
63
+ @memory = method :linux_memory
64
+ @supports_exclude_type = `df --help 2>&1 | grep -e "--exclude-type"` != ''
65
+ end
66
+
67
+ opts[:checks].each do |check|
68
+ case check
69
+ when 'disk'
70
+ @disk_enabled = true
71
+ when 'load'
72
+ @load_enabled = true
73
+ when 'cpu'
74
+ @cpu_enabled = true
75
+ when 'memory'
76
+ @memory_enabled = true
77
+ end
78
+ end
79
+ end
80
+
81
+ def alert(service, state, metric, description)
82
+ report(
83
+ service: service.to_s,
84
+ state: state.to_s,
85
+ metric: metric.to_f,
86
+ description: description,
87
+ )
88
+ end
89
+
90
+ def report_pct(service, fraction, report)
91
+ return unless fraction
92
+
93
+ if fraction > @limits[service][:critical]
94
+ alert service, :critical, fraction, "#{format('%.2f', fraction * 100)}% #{report}"
95
+ elsif fraction > @limits[service][:warning]
96
+ alert service, :warning, fraction, "#{format('%.2f', fraction * 100)}% #{report}"
97
+ else
98
+ alert service, :ok, fraction, "#{format('%.2f', fraction * 100)}% #{report}"
99
+ end
100
+ end
101
+
102
+ def linux_cpu
103
+ new = File.read('/proc/stat')
104
+ unless new[/cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/]
105
+ alert 'cpu', :unknown, nil, "/proc/stat doesn't include a CPU line"
106
+ return false
107
+ end
108
+ u2, n2, s2, i2 = [Regexp.last_match(1), Regexp.last_match(2), Regexp.last_match(3),
109
+ Regexp.last_match(4),].map(&:to_i)
110
+
111
+ if @old_cpu
112
+ u1, n1, s1, i1 = @old_cpu
113
+
114
+ used = (u2 + n2 + s2) - (u1 + n1 + s1)
115
+ total = used + i2 - i1
116
+ fraction = used.to_f / total
117
+
118
+ report_pct :cpu, fraction, "user+nice+system\n\n#{reverse_numeric_sort_with_header(`ps -eo pcpu,pid,comm`)}"
119
+ end
120
+
121
+ @old_cpu = [u2, n2, s2, i2]
122
+ end
123
+
124
+ def linux_load
125
+ load = File.read('/proc/loadavg').split(/\s+/)[0].to_f / @cores
126
+ if load > @limits[:load][:critical]
127
+ alert 'load', :critical, load, "1-minute load average/core is #{load}"
128
+ elsif load > @limits[:load][:warning]
129
+ alert 'load', :warning, load, "1-minute load average/core is #{load}"
130
+ else
131
+ alert 'load', :ok, load, "1-minute load average/core is #{load}"
132
+ end
133
+ end
134
+
135
+ def linux_memory
136
+ m = File.read('/proc/meminfo').split(/\n/).each_with_object({}) do |line, info|
137
+ x = line.split(/:?\s+/)
138
+ # Assume kB...
139
+ info[x[0]] = x[1].to_i
140
+ end
141
+
142
+ free = m['MemFree'].to_i + m['Buffers'].to_i + m['Cached'].to_i
143
+ total = m['MemTotal'].to_i
144
+ fraction = 1 - (free.to_f / total)
145
+
146
+ report_pct :memory, fraction, "used\n\n#{reverse_numeric_sort_with_header(`ps -eo pmem,pid,comm`)}"
147
+ end
148
+
149
+ def freebsd_cpu
150
+ u2, n2, s2, t2, i2 = `sysctl -n kern.cp_time 2>/dev/null`.split.map(&:to_i) # FreeBSD has 5 cpu stats
151
+
152
+ if @old_cpu
153
+ u1, n1, s1, t1, i1 = @old_cpu
154
+
155
+ used = (u2 + n2 + s2 + t2) - (u1 + n1 + s1 + t1)
156
+ total = used + i2 - i1
157
+ fraction = used.to_f / total
158
+
159
+ report_pct :cpu, fraction,
160
+ "user+nice+sytem+interrupt\n\n#{reverse_numeric_sort_with_header(`ps -axo pcpu,pid,comm`)}"
161
+ end
162
+
163
+ @old_cpu = [u2, n2, s2, t2, i2]
164
+ end
165
+
166
+ def openbsd_cpu
167
+ u2, n2, s2, t2, i2 = # OpenBSD separates with ,
168
+ `sysctl -n kern.cp_time 2>/dev/null`.split(',').map(&:to_i)
169
+ if @old_cpu
170
+ u1, n1, s1, t1, i1 = @old_cpu
171
+
172
+ used = (u2 + n2 + s2 + t2) - (u1 + n1 + s1 + t1)
173
+ total = used + i2 - i1
174
+ fraction = used.to_f / total
175
+
176
+ report_pct :cpu, fraction,
177
+ "user+nice+sytem+interrupt\n\n#{reverse_numeric_sort_with_header(`ps -axo pcpu,pid,comm`)}"
178
+ end
179
+
180
+ @old_cpu = [u2, n2, s2, t2, i2]
181
+ end
182
+
183
+ def sunos_cpu
184
+ mpstats = `mpstat -a 2>/dev/null`.split
185
+ u2 = mpstats[29].to_i
186
+ s2 = mpstats[30].to_i
187
+ t2 = mpstats[31].to_i
188
+ i2 = mpstats[32].to_i
189
+
190
+ if @old_cpu
191
+ u1, s1, t1, i1 = @old_cpu
192
+
193
+ used = (u2 + s2 + t2) - (u1 + s1 + t1)
194
+ total = used + i2 - i1
195
+ fraction = if i2 == i1 && used.zero? # If the system is <1% used in both samples then total will be 0 + (99 - 99), avoid a div by 0
196
+ 0
197
+ else
198
+ used.to_f / total
199
+ end
200
+
201
+ report_pct :cpu, fraction,
202
+ "user+sytem+interrupt\n\n#{reverse_numeric_sort_with_header(`ps -ao pcpu,pid,comm`)}"
203
+ end
204
+
205
+ @old_cpu = [u2, s2, t2, i2]
206
+ end
207
+
208
+ def bsd_load
209
+ m = `uptime`.split(':')[-1].chomp.gsub(/\s+/, '').split(',')
210
+ load = m[0].to_f / @cores
211
+ if load > @limits[:load][:critical]
212
+ alert 'load', :critical, load, "1-minute load average/core is #{load}"
213
+ elsif load > @limits[:load][:warning]
214
+ alert 'load', :warning, load, "1-minute load average/core is #{load}"
215
+ else
216
+ alert 'load', :ok, load, "1-minute load average/core is #{load}"
217
+ end
218
+ end
219
+
220
+ def freebsd_memory
221
+ meminfo = `sysctl -n vm.stats.vm.v_page_count vm.stats.vm.v_wire_count vm.stats.vm.v_active_count 2>/dev/null`.chomp.split
222
+ fraction = (meminfo[1].to_f + meminfo[2].to_f) / meminfo[0].to_f
223
+
224
+ report_pct :memory, fraction, "used\n\n#{reverse_numeric_sort_with_header(`ps -axo pmem,pid,comm`)}"
225
+ end
226
+
227
+ def openbsd_memory
228
+ meminfo = `vmstat 2>/dev/null`.chomp.split
229
+ fraction = meminfo[28].to_f / meminfo[29] # The ratio of active to free memory unlike the others :(
230
+
231
+ report_pct :memory, fraction, "used\n\n#{reverse_numeric_sort_with_header(`ps -axo pmem,pid,comm`)}"
232
+ end
233
+
234
+ def sunos_memory
235
+ meminfo = `vmstat 2>/dev/null`.chomp.split
236
+ total_mem = `prtconf | grep Memory`.split[2].to_f * 1024 # reports in GB but vmstat is in MB
237
+ fraction = (total_mem - meminfo[32].to_f) / total_mem
238
+
239
+ report_pct :memory, fraction, "used\n\n#{reverse_numeric_sort_with_header(`ps -ao pmem,pid,comm`)}"
240
+ end
241
+
242
+ def darwin_top
243
+ raw = `top -l 1 | grep -i "^\\(cpu\\|physmem\\|load\\)"`.chomp
244
+ @topdata = { stamp: Time.now.to_i }
245
+ raw.each_line do |ln|
246
+ if ln.match(/Load Avg: [0-9.]+, [0-9.]+, ([0-9.])+/i)
247
+ @topdata[:load] = Regexp.last_match(1).to_f
248
+ elsif ln.match(/CPU usage: [0-9.]+% user, [0-9.]+% sys, ([0-9.]+)% idle/i)
249
+ @topdata[:cpu] = 1 - (Regexp.last_match(1).to_f / 100)
250
+ elsif (mdat = ln.match(/PhysMem: ([0-9]+)([BKMGT]) wired, ([0-9]+)([BKMGT]) active, ([0-9]+)([BKMGT]) inactive, ([0-9]+)([BKMGT]) used, ([0-9]+)([BKMGT]) free/i))
251
+ wired = mdat[1].to_i * (1024**'BKMGT'.index(mdat[2]))
252
+ active = mdat[3].to_i * (1024**'BKMGT'.index(mdat[4]))
253
+ inactive = mdat[5].to_i * (1024**'BKMGT'.index(mdat[6]))
254
+ used = mdat[7].to_i * (1024**'BKMGT'.index(mdat[8]))
255
+ free = mdat[9].to_i * (1024**'BKMGT'.index(mdat[10]))
256
+ @topdata[:memory] = (wired + active + used).to_f / (wired + active + used + inactive + free)
257
+ # This is for OSX Mavericks which
258
+ # uses a different format for top
259
+ # Example: PhysMem: 4662M used (1328M wired), 2782M unused.
260
+ elsif (mdat = ln.match(/PhysMem: ([0-9]+)([BKMGT]) used \([0-9]+[BKMGT] wired\), ([0-9]+)([BKMGT]) unused/i))
261
+ used = mdat[1].to_i * (1024**'BKMGT'.index(mdat[2]))
262
+ unused = mdat[3].to_i * (1024**'BKMGT'.index(mdat[4]))
263
+ @topdata[:memory] = used.to_f / (used + unused)
264
+ end
265
+ end
266
+ end
267
+
268
+ def darwin_cpu
269
+ darwin_top unless (Time.now.to_i - @topdata[:stamp]) < opts[:interval]
270
+ unless @topdata[:cpu]
271
+ alert 'cpu', :unknown, nil, 'unable to get CPU stats from top'
272
+ return false
273
+ end
274
+ report_pct :cpu, @topdata[:cpu], "usage\n\n#{reverse_numeric_sort_with_header(`ps -eo pcpu,pid,comm`)}"
275
+ end
276
+
277
+ def darwin_load
278
+ darwin_top unless (Time.now.to_i - @topdata[:stamp]) < opts[:interval]
279
+ unless @topdata[:load]
280
+ alert 'load', :unknown, nil, 'unable to get load ave from top'
281
+ return false
282
+ end
283
+ metric = @topdata[:load] / @cores
284
+ if metric > @limits[:load][:critical]
285
+ alert 'load', :critical, metric, "1-minute load average per core is #{metric}"
286
+ elsif metric > @limits[:load][:warning]
287
+ alert 'load', :warning, metric, "1-minute load average per core is #{metric}"
288
+ else
289
+ alert 'load', :ok, metric, "1-minute load average per core is #{metric}"
290
+ end
291
+ end
292
+
293
+ def darwin_memory
294
+ darwin_top unless (Time.now.to_i - @topdata[:stamp]) < opts[:interval]
295
+ unless @topdata[:memory]
296
+ alert 'memory', :unknown, nil, 'unable to get memory data from top'
297
+ return false
298
+ end
299
+ report_pct :memory, @topdata[:memory], "usage\n\n#{reverse_numeric_sort_with_header(`ps -eo pmem,pid,comm`)}"
300
+ end
301
+
302
+ def df
303
+ case @ostype
304
+ when 'darwin', 'freebsd', 'openbsd'
305
+ `df -P -t no#{opts[:disk_ignorefs].join(',')}`
306
+ when 'sunos'
307
+ `df -P` # Is there a good way to exlude iso9660 here?
308
+ else
309
+ if @supports_exclude_type
310
+ `df -P #{opts[:disk_ignorefs].map { |fstype| "--exclude-type=#{fstype}" }.join(' ')}`
311
+ else
312
+ `df -P`
313
+ end
314
+ end
315
+ end
316
+
317
+ def disk
318
+ df.split(/\n/).each do |r|
319
+ f = r.split(/\s+/)
320
+ next if f[0] == 'Filesystem'
321
+
322
+ # Calculate capacity
323
+ used = f[2].to_i
324
+ available = f[3].to_i
325
+ total_without_reservation = used + available
326
+
327
+ x = used.to_f / total_without_reservation
328
+
329
+ if x > @limits[:disk][:critical]
330
+ alert "disk #{f[5]}", :critical, x, "#{f[4]} used"
331
+ elsif x > @limits[:disk][:warning]
332
+ alert "disk #{f[5]}", :warning, x, "#{f[4]} used"
333
+ else
334
+ alert "disk #{f[5]}", :ok, x, "#{f[4]} used"
335
+ end
336
+ end
337
+ end
338
+
339
+ def tick
340
+ @cpu.call if @cpu_enabled
341
+ @memory.call if @memory_enabled
342
+ @disk.call if @disk_enabled
343
+ @load.call if @load_enabled
344
+ end
345
+ end
346
+ end
347
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'riemann/tools'
4
+
5
+ module Riemann
6
+ module Tools
7
+ class Net
8
+ include Riemann::Tools
9
+
10
+ opt :interfaces, 'Interfaces to monitor', type: :strings, default: nil
11
+ opt :ignore_interfaces, 'Interfaces to ignore', type: :strings, default: ['lo']
12
+
13
+ def initialize
14
+ @old_state = nil
15
+ @interfaces = if opts[:interfaces]
16
+ opts[:interfaces].reject(&:empty?).map(&:dup)
17
+ else
18
+ []
19
+ end
20
+ @ignore_interfaces = opts[:ignore_interfaces].reject(&:empty?).map(&:dup)
21
+ end
22
+
23
+ def state
24
+ f = File.read('/proc/net/dev')
25
+ state = {}
26
+ f.split("\n").each do |line|
27
+ next unless line =~ /\A\s*([[:alnum:]-]+?):\s*([\s\d]+)\s*/
28
+
29
+ iface = Regexp.last_match(1)
30
+
31
+ next unless @interfaces.empty? || @interfaces.any? { |pattern| iface.match?(pattern) }
32
+ next if @ignore_interfaces.any? { |pattern| iface.match?(pattern) }
33
+
34
+ ['rx bytes',
35
+ 'rx packets',
36
+ 'rx errs',
37
+ 'rx drop',
38
+ 'rx fifo',
39
+ 'rx frame',
40
+ 'rx compressed',
41
+ 'rx multicast',
42
+ 'tx bytes',
43
+ 'tx packets',
44
+ 'tx errs',
45
+ 'tx drops',
46
+ 'tx fifo',
47
+ 'tx colls',
48
+ 'tx carrier',
49
+ 'tx compressed',].map do |service|
50
+ "#{iface} #{service}"
51
+ end.zip( # rubocop:disable Style/MultilineBlockChain
52
+ Regexp.last_match(2).split(/\s+/).map(&:to_i),
53
+ ).each do |service, value|
54
+ state[service] = value
55
+ end
56
+ end
57
+
58
+ state
59
+ end
60
+
61
+ def tick
62
+ state = self.state
63
+
64
+ if @old_state
65
+ # Report services from `@old_state` that don't exist in `state` as expired
66
+ @old_state.reject { |k| state.key?(k) }.each do |service, _metric|
67
+ report(service: service.dup, state: 'expired')
68
+ end
69
+
70
+ # Report delta for services that have values in both `@old_state` and `state`
71
+ state.each do |service, metric|
72
+ next unless @old_state.key?(service)
73
+
74
+ delta = metric - @old_state[service]
75
+ svc_state = case service
76
+ when /drop$/
77
+ if delta.positive?
78
+ 'warning'
79
+ else
80
+ 'ok'
81
+ end
82
+ when /errs$/
83
+ if delta.positive?
84
+ 'warning'
85
+ else
86
+ 'ok'
87
+ end
88
+ else
89
+ 'ok'
90
+ end
91
+
92
+ report(
93
+ service: service.dup,
94
+ metric: (delta.to_f / opts[:interval]),
95
+ state: svc_state,
96
+ )
97
+ end
98
+ end
99
+
100
+ @old_state = state
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'riemann/tools'
4
+
5
+ module Riemann
6
+ module Tools
7
+ class Ntp
8
+ include Riemann::Tools
9
+
10
+ def initialize
11
+ @hostname = `hostname`.chomp
12
+ @ostype = `uname -s`.chomp.downcase
13
+ abort 'WARNING: macOS not explicitly supported. Exiting.' if @ostype == 'darwin'
14
+ end
15
+
16
+ def tick
17
+ stats = `ntpq -p -n`
18
+ stats.each_line do |stat|
19
+ m = stat.split
20
+ next if m.grep(/^===/).any? || m.grep(/^remote/).any?
21
+
22
+ @ntp_host = m[0].gsub('*', '').gsub('-', '').gsub('+', '')
23
+ send('delay', m[7])
24
+ send('offset', m[8])
25
+ send('jitter', m[9])
26
+ end
27
+ end
28
+
29
+ def send(type, metric)
30
+ report(
31
+ host: @hostname,
32
+ service: "ntp peer #{@ntp_host} #{type}",
33
+ metric: metric.to_f,
34
+ state: 'ok',
35
+ description: "ntp peer #{@ntp_host} #{type}",
36
+ tags: ['ntp'],
37
+ )
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Riemann
4
+ module Tools
5
+ module Utils # :nodoc:
6
+ def reverse_numeric_sort_with_header(data, header: 1, count: 10)
7
+ lines = data.chomp.split("\n")
8
+ header = lines.shift(header)
9
+
10
+ lines.sort_by!(&:to_f)
11
+ lines.reverse!
12
+
13
+ (header + lines[0, count]).join("\n")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Riemann
4
+ module Tools # :nodoc:
5
+ VERSION = '1.1.0'
6
+ end
7
+ end
data/lib/riemann/tools.rb CHANGED
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Riemann
2
4
  module Tools
3
- require 'trollop'
5
+ require 'optimist'
4
6
  require 'riemann/client'
5
7
 
6
8
  def self.included(base)
@@ -9,31 +11,36 @@ module Riemann
9
11
  new.run
10
12
  end
11
13
 
12
- def opt(*a)
13
- a.unshift :opt
14
+ def opt(*args)
15
+ args.unshift :opt
14
16
  @opts ||= []
15
- @opts << a
17
+ @opts << args
16
18
  end
17
19
 
18
20
  def options
19
- p = Trollop::Parser.new
21
+ p = Optimist::Parser.new
20
22
  @opts.each do |o|
21
- p.send *o
23
+ p.send(*o)
22
24
  end
23
- Trollop::with_standard_exception_handling(p) do
25
+ Optimist.with_standard_exception_handling(p) do
24
26
  p.parse ARGV
25
27
  end
26
28
  end
27
29
 
28
- opt :host, "Riemann host", :default => '127.0.0.1'
29
- opt :port, "Riemann port", :default => 5555
30
- opt :event_host, "Event hostname", :type => String
31
- opt :interval, "Seconds between updates", :default => 5
32
- opt :tag, "Tag to add to events", :type => String, :multi => true
33
- opt :ttl, "TTL for events", :type => Integer
34
- opt :attribute, "Attribute to add to the event", :type => String, :multi => true
35
- opt :timeout, "Timeout (in seconds) when waiting for acknowledgements", :default => 30
36
- opt :tcp, "Use TCP transport instead of UDP (improves reliability, slight overhead.", :default => true
30
+ opt :host, 'Riemann host', default: '127.0.0.1'
31
+ opt :port, 'Riemann port', default: 5555
32
+ opt :event_host, 'Event hostname', type: String
33
+ opt :interval, 'Seconds between updates', default: 5
34
+ opt :tag, 'Tag to add to events', type: String, multi: true
35
+ opt :ttl, 'TTL for events', type: Integer
36
+ opt :attribute, 'Attribute to add to the event', type: String, multi: true
37
+ opt :timeout, 'Timeout (in seconds) when waiting for acknowledgements', default: 30
38
+ opt :tcp, 'Use TCP transport instead of UDP (improves reliability, slight overhead.', default: true
39
+ opt :tls, 'Use TLS for securing traffic', default: false
40
+ opt :tls_key, 'TLS Key to use when using TLS', type: String
41
+ opt :tls_cert, 'TLS Certificate to use when using TLS', type: String
42
+ opt :tls_ca_cert, 'Trusted CA Certificate when using TLS', type: String
43
+ opt :tls_verify, 'Verify TLS peer when using TLS', default: true
37
44
  end
38
45
  end
39
46
 
@@ -41,14 +48,12 @@ module Riemann
41
48
  def options
42
49
  @options ||= self.class.options
43
50
  end
44
- alias :opts :options
51
+ alias opts options
45
52
 
46
53
  def attributes
47
54
  @attributes ||= Hash[options[:attribute].map do |attr|
48
- k,v = attr.split(/=/)
49
- if k and v
50
- [k,v]
51
- end
55
+ k, v = attr.split(/=/)
56
+ [k, v] if k && v
52
57
  end]
53
58
  end
54
59
 
@@ -60,9 +65,7 @@ module Riemann
60
65
 
61
66
  event[:ttl] ||= (options[:ttl] || (options[:interval] * 2))
62
67
 
63
- if options[:event_host]
64
- event[:host] = options[:event_host].dup
65
- end
68
+ event[:host] = options[:event_host].dup if options[:event_host]
66
69
 
67
70
  event = event.merge(attributes)
68
71
 
@@ -71,11 +74,16 @@ module Riemann
71
74
 
72
75
  def new_riemann_client
73
76
  r = Riemann::Client.new(
74
- :host => options[:host],
75
- :port => options[:port],
76
- :timeout => options[:timeout]
77
+ host: options[:host],
78
+ port: options[:port],
79
+ timeout: options[:timeout],
80
+ ssl: options[:tls],
81
+ key_file: options[:tls_key],
82
+ cert_file: options[:tls_cert],
83
+ ca_file: options[:tls_ca_cert],
84
+ ssl_verify: options[:tls_verify],
77
85
  )
78
- if options[:tcp]
86
+ if options[:tcp] || options[:tls]
79
87
  r.tcp
80
88
  else
81
89
  r
@@ -85,15 +93,15 @@ module Riemann
85
93
  def riemann
86
94
  @riemann ||= new_riemann_client
87
95
  end
88
- alias :r :riemann
96
+ alias r riemann
89
97
 
90
98
  def run
91
99
  t0 = Time.now
92
100
  loop do
93
101
  begin
94
102
  tick
95
- rescue => e
96
- $stderr.puts "#{e.class} #{e}\n#{e.backtrace.join "\n"}"
103
+ rescue StandardError => e
104
+ warn "#{e.class} #{e}\n#{e.backtrace.join "\n"}"
97
105
  end
98
106
 
99
107
  # Sleep.
@@ -101,7 +109,6 @@ module Riemann
101
109
  end
102
110
  end
103
111
 
104
- def tick
105
- end
112
+ def tick; end
106
113
  end
107
114
  end