solanum 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,44 @@
1
+ require 'solanum/source'
2
+ require 'solanum/util'
3
+
4
+ class Solanum::Source::Load < Solanum::Source
5
+ attr_reader :load_states
6
+
7
+ STAT_FILE = '/proc/loadavg'
8
+
9
+
10
+ def initialize(opts)
11
+ super(opts)
12
+ @load_states = opts['load_states'] || {}
13
+ end
14
+
15
+
16
+ def collect!
17
+ events = []
18
+
19
+ loadavg = File.read(STAT_FILE).chomp.split(' ')
20
+
21
+ load1m = loadavg[0].to_f
22
+
23
+ events << {
24
+ service: 'process load',
25
+ metric: load1m,
26
+ state: state_over(@load_states, load1m),
27
+ }
28
+
29
+ running, count = *loadavg[3].split('/')
30
+
31
+ events << {
32
+ service: 'process running',
33
+ metric: running.to_i,
34
+ }
35
+
36
+ events << {
37
+ service: 'process count',
38
+ metric: count.to_i,
39
+ }
40
+
41
+ events
42
+ end
43
+
44
+ end
@@ -0,0 +1,70 @@
1
+ require 'solanum/source'
2
+ require 'solanum/util'
3
+
4
+ class Solanum::Source::Memory < Solanum::Source
5
+ attr_reader :thresholds, :swap_thresholds
6
+
7
+
8
+ def initialize(opts)
9
+ super(opts)
10
+ @thresholds = opts['thresholds'] || {}
11
+ @swap_thresholds = opts['swap_thresholds'] || {}
12
+ end
13
+
14
+
15
+ def collect!
16
+ events = []
17
+
18
+ meminfo = Hash.new(0)
19
+ File.readlines('/proc/meminfo').each do |line|
20
+ measure, quantity = *line.chomp.split(/: +/)
21
+ value, unit = *quantity.split(' ')
22
+ meminfo[measure] = value.to_i
23
+ end
24
+
25
+ mem_total = meminfo['MemTotal'].to_f
26
+ record_usage = lambda do |type|
27
+ if meminfo[type]
28
+ usage_pct = meminfo[type]/mem_total.to_f
29
+ events << {
30
+ service: "memory #{type.downcase}",
31
+ metric: usage_pct,
32
+ }
33
+ end
34
+ end
35
+
36
+ total_used = mem_total - meminfo['MemFree']
37
+ mem_used = total_used - meminfo['Buffers'] - meminfo['Cached']
38
+ usage = mem_used/mem_total
39
+ events << {
40
+ service: 'memory usage',
41
+ metric: usage,
42
+ state: state_over(@thresholds, usage),
43
+ }
44
+
45
+ events << {
46
+ service: 'memory buffers',
47
+ metric: meminfo['Buffers']/mem_total
48
+ }
49
+
50
+ cached = meminfo['Cached'] + meminfo['SReclaimable'] - meminfo['Shmem']
51
+ events << {
52
+ service: 'memory cached',
53
+ metric: cached/mem_total
54
+ }
55
+
56
+ if meminfo['SwapTotal'] && meminfo['SwapTotal'] > 0
57
+ swap_total = meminfo['SwapTotal']
58
+ swap_free = meminfo['SwapFree']
59
+ usage = 1.0 - swap_free/swap_total.to_f
60
+ events << {
61
+ service: 'swap usage',
62
+ metric: usage,
63
+ state: state_over(@swap_thresholds, usage),
64
+ }
65
+ end
66
+
67
+ events
68
+ end
69
+
70
+ end
@@ -0,0 +1,65 @@
1
+ require 'solanum/source'
2
+
3
+ # bytes - The total number of bytes of data transmitted or received by the interface.
4
+ # packets - The total number of packets of data transmitted or received by the interface.
5
+ # errs - The total number of transmit or receive errors detected by the device driver.
6
+ # drop - The total number of packets dropped by the device driver.
7
+ # fifo - The number of FIFO buffer errors.
8
+ # frame - The number of packet framing errors.
9
+ # colls - The number of collisions detected on the interface.
10
+ # compressed - The number of compressed packets transmitted or received by the device driver. (This appears to be unused in the 2.2.15 kernel.)
11
+ # carrier - The number of carrier losses detected by the device driver.
12
+ # multicast - The number of multicast frames transmitted or received by the device driver.
13
+ class Solanum::Source::Network < Solanum::Source
14
+ attr_reader :interfaces, :detailed
15
+
16
+ STAT_FILE = '/proc/net/dev'
17
+
18
+ FIELDS = %w{
19
+ rx_bytes rx_packets rx_errs rx_drop rx_fifo rx_frame rx_compressed rx_multicast
20
+ tx_bytes tx_packets tx_errs tx_drop tx_fifo tx_colls tx_carrier tx_compressed
21
+ }
22
+
23
+ SIMPLE_FIELDS = %w{rx_bytes rx_packets tx_bytes tx_packets}
24
+
25
+
26
+ def initialize(opts)
27
+ super(opts)
28
+ @interfaces = opts['interfaces'] || []
29
+ @detailed = opts['detailed'] || false
30
+ @last = {}
31
+ end
32
+
33
+
34
+ def parse_stats(line)
35
+ columns = line.strip.split(/\s+/)
36
+ iface = columns.shift.chomp(':')
37
+ return iface, Hash[FIELDS.zip(columns.map(&:to_i))]
38
+ end
39
+
40
+
41
+ def collect!
42
+ events = []
43
+
44
+ File.readlines(STAT_FILE).drop(2).each do |line|
45
+ iface, stats = parse_stats(line)
46
+
47
+ if @interfaces.empty? || @interfaces.include?(iface)
48
+ if @last[iface]
49
+ FIELDS.each do |field|
50
+ next unless @detailed || SIMPLE_FIELDS.include?(field)
51
+ diff = stats[field] - @last[iface][field]
52
+ events << {
53
+ service: "net #{iface} #{field.gsub('_', ' ')}",
54
+ metric: diff,
55
+ }
56
+ end
57
+ end
58
+ @last[iface] = stats
59
+ end
60
+ end
61
+
62
+ events
63
+ end
64
+
65
+ end
@@ -0,0 +1,28 @@
1
+ require 'solanum/source'
2
+ require 'solanum/util'
3
+
4
+ class Solanum::Source::Uptime < Solanum::Source
5
+
6
+ STAT_FILE = '/proc/uptime'
7
+
8
+
9
+ def initialize(opts)
10
+ super(opts)
11
+ end
12
+
13
+
14
+ def collect!
15
+ events = []
16
+
17
+ uptime = File.read(STAT_FILE).split(' ').first.to_f
18
+
19
+ events << {
20
+ service: 'uptime',
21
+ metric: uptime,
22
+ description: "Up for #{duration_str(uptime)}",
23
+ }
24
+
25
+ events
26
+ end
27
+
28
+ end
@@ -0,0 +1,40 @@
1
+ # Return a human-friendly duration string for the given duration in seconds.
2
+ def duration_str(duration)
3
+ days = (duration/86400).to_i
4
+ hours = ((duration % 86400)/3600).to_i
5
+ minutes = ((duration % 3600)/60).to_i
6
+ seconds = (duration % 60).to_i
7
+ hms = "%02d:%02d:%02d" % [hours, minutes, seconds]
8
+
9
+ if 0 < days
10
+ "#{days} days, #{hms}"
11
+ else
12
+ hms
13
+ end
14
+ end
15
+
16
+
17
+ # Calculate the state of a metric by comparing it to the given thresholds. The
18
+ # metric is compared to each threshold in turn, largest to smallest. The first
19
+ # threshold the metric is larger than is returned, or the 'min_sate' is
20
+ # returned.
21
+ def state_over(thresholds, metric, min_state='ok')
22
+ thresholds.sort_by {|e| -e[1] }.each do |threshold_entry|
23
+ key, threshold = *threshold_entry
24
+ return key if threshold <= metric
25
+ end
26
+ return min_state
27
+ end
28
+
29
+
30
+ # Calculate the state of a metric by comparing it to the given thresholds. The
31
+ # metric is compared to each threshold in turn, smallest to largest. The first
32
+ # threshold the metric is smaller than is returned, or the 'max_state' is
33
+ # returned.
34
+ def state_under(thresholds, metric, max_state='ok')
35
+ thresholds.sort_by {|e| e[1] }.each do |threshold_entry|
36
+ key, threshold = *threshold_entry
37
+ return key if threshold > metric
38
+ end
39
+ return max_state
40
+ end
metadata CHANGED
@@ -1,64 +1,79 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solanum
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.0
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Greg Look
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2015-07-28 00:00:00.000000000 Z
12
+ date: 2017-12-23 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: riemann-client
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - '>='
19
+ - - ! '>='
18
20
  - !ruby/object:Gem::Version
19
- version: 0.2.2
21
+ version: 0.2.6
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
- - - '>='
27
+ - - ! '>='
25
28
  - !ruby/object:Gem::Version
26
- version: 0.2.2
29
+ version: 0.2.6
27
30
  description:
28
- email: greg@greg-look.net
31
+ email: greg@greglook.net
29
32
  executables:
30
33
  - solanum
31
34
  extensions: []
32
35
  extra_rdoc_files: []
33
36
  files:
34
- - lib/solanum/config.rb
35
- - lib/solanum/matcher.rb
36
37
  - lib/solanum/source.rb
38
+ - lib/solanum/schedule.rb
39
+ - lib/solanum/config.rb
40
+ - lib/solanum/source/cpu.rb
41
+ - lib/solanum/source/memory.rb
42
+ - lib/solanum/source/diskstats.rb
43
+ - lib/solanum/source/uptime.rb
44
+ - lib/solanum/source/network.rb
45
+ - lib/solanum/source/load.rb
46
+ - lib/solanum/source/certificate.rb
47
+ - lib/solanum/output/print.rb
48
+ - lib/solanum/output/riemann.rb
49
+ - lib/solanum/util.rb
37
50
  - lib/solanum.rb
38
51
  - bin/solanum
39
52
  - README.md
40
53
  homepage: https://github.com/greglook/solanum
41
54
  licenses:
42
55
  - Public Domain
43
- metadata: {}
44
56
  post_install_message:
45
57
  rdoc_options: []
46
58
  require_paths:
47
59
  - lib
48
60
  required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
49
62
  requirements:
50
- - - '>='
63
+ - - ! '>='
51
64
  - !ruby/object:Gem::Version
52
- version: 1.9.1
65
+ version: 1.9.3
53
66
  required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
54
68
  requirements:
55
- - - '>='
69
+ - - ! '>='
56
70
  - !ruby/object:Gem::Version
57
71
  version: '0'
58
72
  requirements: []
59
73
  rubyforge_project:
60
- rubygems_version: 2.0.14
74
+ rubygems_version: 1.8.23
61
75
  signing_key:
62
- specification_version: 4
63
- summary: DSL for custom monitoring configuration
76
+ specification_version: 3
77
+ summary: Extensible monitoring daemon
64
78
  test_files: []
79
+ has_rdoc:
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: e9ebaaa5f2e140d9a0b2d821bc685a363f103ea1
4
- data.tar.gz: 4fc6fbb8e60b919d8a9d1d8c8d36d557a80269ca
5
- SHA512:
6
- metadata.gz: 30e99d6aa3fba2cf78f4ba69bde44e799212ca457a7de325ee40585e111c237188b3b1d0770c642a86641da5c253eab09a64310ae4a39fc2f7be6cee19a7d4f6
7
- data.tar.gz: 254e37a291a4e3925e3a0e38cb7fde12f4a177508ba0354ed6ba035d2844fd086411ed040eedb63d421f51f2841f4d9277d9b8b32a26f232497f547a2a7e0160
@@ -1,70 +0,0 @@
1
- require 'json'
2
-
3
- # A matcher takes in an input string and returns a hash of measurement names to
4
- # numeric values.
5
- #
6
- # Author:: Greg Look
7
- class Solanum::Matcher
8
- attr_reader :fn
9
-
10
- # Creates a new Matcher which will run the given function on input.
11
- def initialize(fn)
12
- raise "function must be provided" if fn.nil?
13
- @fn = fn
14
- end
15
-
16
- # Attempts to match the given input, returning a hash of metrics.
17
- def call(input)
18
- {}
19
- end
20
-
21
-
22
- ### MATCHER TYPES ###
23
-
24
- public
25
-
26
- # LinePattern matchers define a regular expression which is tested against
27
- # each line of input. The given function is called for **each** matched line,
28
- # and the resulting measurements are merged together.
29
- class LinePattern < Solanum::Matcher
30
- def initialize(fn, pattern)
31
- super fn
32
- raise "pattern must be provided" if pattern.nil?
33
- @pattern = pattern
34
- end
35
-
36
- def call(input)
37
- raise "No input provided!" if input.nil?
38
- lines = input.split("\n")
39
- metrics = {}
40
-
41
- lines.each do |line|
42
- begin
43
- if @pattern === line
44
- measurements = @fn.call($~)
45
- metrics.merge!(measurements) if measurements
46
- end
47
- rescue => e
48
- STDERR.puts("Error calculating metrics from line match: #{e.inspect}")
49
- end
50
- end
51
-
52
- metrics
53
- end
54
- end
55
-
56
-
57
- # JsonReader matches a JSON-formatted input string and passes the parsed
58
- # object to the block body.
59
- class JSONReader < Solanum::Matcher
60
- def call(input)
61
- begin
62
- json = JSON.parse(input)
63
- @fn.call(json)
64
- rescue => e
65
- STDERR.puts("Error matching JSON input: #{e.inspect}")
66
- {}
67
- end
68
- end
69
- end
70
- end