smith-datadog 0.7.1

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 (3) hide show
  1. checksums.yaml +7 -0
  2. data/bin/smith-datadog +155 -0
  3. metadata +179 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cd9057a6a6acefdea335d979828646067a44e353
4
+ data.tar.gz: 47ea2a06c836ad9c7e824989a992faa46aa7bdfb
5
+ SHA512:
6
+ metadata.gz: 4bfd71b8a6955411a9c4291083487d174fffe5b8ad93d2c401c3e5f6f4bf2f62e3ff3b74d95e8b68686881351ea01d2d0c9a73e3c70228a7373510bcccfa6413
7
+ data.tar.gz: c086efc6de1645a97b4a0ab367558c71c62b29025a5ca7430d6e8059ac1a940a7ff08b8bb796114ecf8d04bc5dc78299fd4941b57803465825a22417bb7be4d1
data/bin/smith-datadog ADDED
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pp'
4
+ require 'dogapi'
5
+ require 'sys/proctable'
6
+
7
+ require 'smith'
8
+ require 'smith/commands/common'
9
+
10
+ class Smith::Datadog
11
+
12
+ include Smith::Commands::Common
13
+ include Smith::Logger
14
+
15
+ SERVICE_NAME = "Smith"
16
+ API_KEY = ENV.fetch('DATADOG_API_KEY')
17
+
18
+ def initialize
19
+ @datadog = Dogapi::Client.new(API_KEY)
20
+ end
21
+
22
+ def run
23
+ Smith::Messaging::Sender.new(Smith::QueueDefinitions::Agency_control.call) do |queue|
24
+ on_check do |check|
25
+ @datadog.emit_event(Dogapi::Event.new(check[:description], check))
26
+ end
27
+
28
+ queue.on_error do |channel, channel_close|
29
+ logger.fatal { "Channel error: #{channel_close.reply_code}: #{channel_close.reply_text}." }
30
+ Smith.stop
31
+ end
32
+
33
+ EM.add_periodic_timer(options[:interval]) { run_check(queue) }
34
+ end
35
+ end
36
+
37
+ def run_check(queue)
38
+ @on_check.call(alert(:heartbeat, :running, "smith-datadog heatbeat"))
39
+
40
+ queue.on_timeout(options[:timeout]) do |message_id|
41
+ @on_check.call(alert(:agency, :timeout, "Agency timeout."))
42
+ end
43
+
44
+ queue.on_reply(:auto_ack => true, :reply_queue_name => "datadog.#{Digest::SHA1.hexdigest($$.to_s)}") do |reply_payload, r|
45
+ check(reply_payload.response).each do |agent|
46
+ @on_check.call(agent)
47
+ end
48
+ end
49
+
50
+ queue.consumer_count do |count|
51
+ if count > 0
52
+ queue.publish(Smith::ACL::AgencyCommand.new(:command => 'list', :args => ['-a', '-l']))
53
+ else
54
+ @on_check.call(alert(:agency, :critical, "Agency not running."))
55
+ end
56
+ end
57
+ end
58
+
59
+ def on_check(&blk)
60
+ @on_check = blk
61
+ end
62
+
63
+ # Checks that the list of agents return from the list command matches
64
+ # the list of know agents and composes an appropriate alert.
65
+ def check(response)
66
+ options[:group].map do |group|
67
+ begin
68
+ group_agents = options[:agents] + agent_group(group)
69
+ running_agents = parse_response(response)
70
+
71
+ group_agents.map do |agent_name|
72
+ if running_agents.has_key?(agent_name) && running_agents[agent_name].any? { |a| a[:state] == "running" && running?(a[:pid]) }
73
+ alert(agent_name, :running, "Agent running")
74
+ else
75
+ alert(agent_name, :critical, "Agent not running")
76
+ end
77
+ end
78
+ rescue RuntimeError => e
79
+ alert("Group #{group}: #{e.message}", :critical, e.message)
80
+ end
81
+ end.flatten
82
+ end
83
+
84
+ # Returns a Nested hash representing the running agents.
85
+ def parse_response(response)
86
+ split_response = response.split(/\n/).map(&:strip)
87
+ ((/^total/.match(split_response.first)) ? split_response[1..-1] : []).each_with_object(Hash.new { |h,k| h[k] = []}) do |e, acc|
88
+ fields = e.split(/\s +/)
89
+ acc[fields.last] << { :state => fields[0], :uuid => fields[1], :pid => fields[2], :description => fields.last }
90
+ end
91
+ end
92
+
93
+ # Construct an alert messages
94
+ def alert(service, state, description, extra={})
95
+ {:source_type_name => 'name', :description => description, :alert_type => 'info', :source_type_name => SERVICE_NAME, :msg_title => "#{service} #{description}", :aggregation_key => service(service)}.merge(extra).tap { |a| logger.info { "#{a[:service]}: #{state(state)}" } }
96
+ end
97
+
98
+ # Return true if the given pid exists in the process table.
99
+ def running?(pid)
100
+ !(pid.nil? || Sys::ProcTable.ps(pid.to_i).nil?)
101
+ end
102
+
103
+ # Return the service name
104
+ def service(name)
105
+ "#{SERVICE_NAME} #{name}"
106
+ end
107
+
108
+ def state(state)
109
+ {:timeout => "warning", :running => "info", :critical => "error"}[state]
110
+ end
111
+
112
+ def options
113
+ @options ||= begin
114
+ OptionParser.accept(Pathname) {|p,| Pathname.new(p) if p}
115
+
116
+ defaults = {:interval => 30, :timeout => 11, :agents => [], :group => [], :tags => [], :host => 'localhost', :port => 5555, :agency_timeout => 60}
117
+ defaults.tap do |options|
118
+ parser = OptionParser.new do |opts|
119
+ opts.separator "\n"
120
+ opts.set_summary_indent " "
121
+
122
+ opts.banner = "\nUsage: #{opts.program_name} OPTIONS"
123
+ opts.on_head "\n Periodically lists the running agents and sends the result to datadog."
124
+
125
+ opts.on("--interval <i>", Integer, "Polling interval in seconds (default #{options[:interval]})") { |t| options[:interval] = t }
126
+ opts.on("--timeout <i>", Integer, "Agency timeout (default #{options[:timeout]})") { |t| options[:interval] = t }
127
+ opts.on("--host <s>", String, "Riemann host (default #{options[:host]})") { |v| options[:host] = v }
128
+ opts.on("--port <i>", Integer, "Riemann port (default #{options[:port]})") { |v| options[:port] = v }
129
+ opts.on("--tags <tag1,tag1,...>", Array, "Tags to add to the alert") { |t| options[:tags] = t }
130
+
131
+ opts.on("--agents <agent1,agent2,...>", Array, "Agents to monitor") { |v| options[:agents] + v }
132
+ opts.on("--agent-group <group name>>", Array, "The name of an 'agent group' to monitor") { |g| options[:group] += g }
133
+
134
+ opts.separator "\n"
135
+ end
136
+
137
+ parser.parse!
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ checker = Smith::Datadog.new
144
+
145
+ begin
146
+ include Smith::Logger
147
+
148
+ Smith.compile_acls
149
+ Smith.start do
150
+ checker.run
151
+ end
152
+ rescue => e
153
+ logger.fatal(e.message)
154
+ logger.fatal("Exiting")
155
+ end
metadata ADDED
@@ -0,0 +1,179 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smith-datadog
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.1
5
+ platform: ruby
6
+ authors:
7
+ - Richard Heycock
8
+ - Rob Sharp
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-10-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: smith
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '0.8'
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.8.3
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - "~>"
29
+ - !ruby/object:Gem::Version
30
+ version: '0.8'
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.8.3
34
+ - !ruby/object:Gem::Dependency
35
+ name: dogapi
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ type: :runtime
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ - !ruby/object:Gem::Dependency
49
+ name: sys-proctable
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.9'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.9'
62
+ - !ruby/object:Gem::Dependency
63
+ name: activesupport
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.0'
69
+ type: :runtime
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.0'
76
+ - !ruby/object:Gem::Dependency
77
+ name: yard
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.8.7
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.8.7
90
+ - !ruby/object:Gem::Dependency
91
+ name: bundler
92
+ requirement: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1'
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1'
104
+ - !ruby/object:Gem::Dependency
105
+ name: rake
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '10'
111
+ type: :development
112
+ prerelease: false
113
+ version_requirements: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '10'
118
+ - !ruby/object:Gem::Dependency
119
+ name: git-version-bump
120
+ requirement: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ type: :development
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ - !ruby/object:Gem::Dependency
133
+ name: rspec
134
+ requirement: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ type: :development
140
+ prerelease: false
141
+ version_requirements: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ description: Integrate smith agent monitoring with Datadog
147
+ email: rob.sharp@digivizer.com
148
+ executables:
149
+ - smith-datadog
150
+ extensions: []
151
+ extra_rdoc_files: []
152
+ files:
153
+ - bin/smith-datadog
154
+ homepage: https://github.com/dgvz/smith-datadog
155
+ licenses:
156
+ - GPL-3.0
157
+ metadata: {}
158
+ post_install_message:
159
+ rdoc_options: []
160
+ require_paths:
161
+ - lib
162
+ required_ruby_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ required_rubygems_version: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ requirements: []
173
+ rubyforge_project:
174
+ rubygems_version: 2.5.1
175
+ signing_key:
176
+ specification_version: 4
177
+ summary: Monitor smith agents, reporting to Datadog
178
+ test_files: []
179
+ has_rdoc: