riemann-docker 0.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 (5) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +10 -0
  4. data/bin/riemann-docker +205 -0
  5. metadata +74 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 18789e6607828d9b9942daa049e237d4db277d00
4
+ data.tar.gz: 88c3041ff216855fcdda256ade673ccbbab14540
5
+ SHA512:
6
+ metadata.gz: afb2483d328a5c8fe160244acecb4ad0041a933b7b77283a5fda376f3ccfeaf5ec0dc6763004f03e0c95e3b888e741690bedee9a0da31eb52e9df02827296dd1
7
+ data.tar.gz: 1e82590ded355a73df4ff5354d63a5d2f5a36926157a730482ecf2d1d89cd53e92f7f58e004316d72e14cd577731e04b4abc1bb3087b3b7d091553215864ad20
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.md ADDED
@@ -0,0 +1,10 @@
1
+ # Riemann Docker
2
+
3
+ Gathers Docker container metrics and sends them to Riemann.
4
+
5
+ # Getting started
6
+
7
+ ```
8
+ gem install riemann-docker
9
+ riemann-docker --help
10
+ ```
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Reports current CPU, disk, load average, and memory use to riemann.
4
+
5
+ require 'riemann/tools'
6
+
7
+ class Riemann::Tools::DockerHealth
8
+ require 'docker'
9
+ require 'socket'
10
+ include Riemann::Tools
11
+ include Docker
12
+
13
+ opt :docker_host, "Docker Container Host (see https://github.com/swipely/docker-api#host)", :default => nil
14
+ opt :cpu_warning, "CPU warning threshold (fraction of total jiffies)", :default => 0.9
15
+ opt :cpu_critical, "CPU critical threshold (fraction of total jiffies)", :default => 0.95
16
+ opt :disk_warning, "Disk warning threshold (fraction of space used)", :default => 0.9
17
+ opt :disk_critical, "Disk critical threshold (fraction of space used)", :default => 0.95
18
+ opt :memory_warning, "Memory warning threshold (fraction of RAM)", :default => 0.85
19
+ opt :memory_critical, "Memory critical threshold (fraction of RAM)", :default => 0.95
20
+ opt :host_hostname, "Suffix of host", :type => String, :default => nil
21
+ opt :checks, "A list of checks to run.", :type => :strings, :default => ['cpu', 'memory', 'disk', 'basic']
22
+
23
+ def get_containers
24
+ Docker::Container.all
25
+ end
26
+
27
+ def get_container_name(container)
28
+ container.json['Name'][1..-1]
29
+ end
30
+
31
+ def initialize
32
+
33
+ if (opts[:docker_host] != nil)
34
+ Docker.url = opts[:docker_host]
35
+ end
36
+
37
+ @hostname = opts[:host_hostname]
38
+ if (@hostname.nil? || !(@hostname.is_a? String) || @hostname.empty?)
39
+ @hostname = Socket.gethostname
40
+ end
41
+
42
+ @cpu_coefficient = 1000 * 1000 * 1000
43
+
44
+ @limits = {
45
+ :cpu => {:critical => opts[:cpu_critical], :warning => opts[:cpu_warning]},
46
+ :disk => {:critical => opts[:disk_critical], :warning => opts[:disk_warning]},
47
+ :memory => {:critical => opts[:memory_critical], :warning => opts[:memory_warning]}
48
+ }
49
+
50
+ @last_cpu_reads = Hash.new
51
+ @last_uptime_reads = Hash.new
52
+
53
+ opts[:checks].each do |check|
54
+ case check
55
+ when 'disk'
56
+ @disk_enabled = true
57
+ when 'cpu'
58
+ @cpu_enabled = true
59
+ when 'memory'
60
+ @memory_enabled = true
61
+ when 'basic'
62
+ @basic_inspection_enabled = true
63
+ end
64
+ end
65
+ end
66
+
67
+ def alert(container, service, state, metric, description)
68
+
69
+ opts = { :service => service.to_s,
70
+ :state => state.to_s,
71
+ :metric => metric.to_f,
72
+ :description => description }
73
+
74
+ if (container != nil)
75
+ opts[:host] = "#{@hostname}-#{container}"
76
+ else
77
+ opts[:host] = @hostname
78
+ end
79
+
80
+ report(opts)
81
+ end
82
+
83
+ def report_pct(container, service, fraction, report = '', name = nil)
84
+ if fraction
85
+
86
+ if (name == nil)
87
+ name = service
88
+ end
89
+
90
+ if fraction > @limits[service][:critical]
91
+ alert container, name, :critical, fraction, "#{sprintf("%.2f", fraction * 100)}% #{report}"
92
+ elsif fraction > @limits[service][:warning]
93
+ alert container, name, :warning, fraction, "#{sprintf("%.2f", fraction * 100)}% #{report}"
94
+ else
95
+ alert container, name, :ok, fraction, "#{sprintf("%.2f", fraction * 100)}% #{report}"
96
+ end
97
+ end
98
+ end
99
+
100
+
101
+ def cpu(id, name, stats)
102
+
103
+ current = stats['precpu_stats']['cpu_usage']['total_usage'] / stats['precpu_stats']['cpu_usage']['percpu_usage'].count
104
+
105
+ unless current
106
+ alert name, :cpu, :unknown, nil, 'no total usage found in docker remote api stats'
107
+ return false
108
+ end
109
+
110
+ current_time = Time.parse(stats['read']);
111
+ if (@last_cpu_reads[id] != nil)
112
+ last = @last_cpu_reads[id]
113
+ used = (current - last[:v]) / (current_time - last[:t]) / @cpu_coefficient
114
+
115
+ report_pct name, :cpu, used
116
+ end
117
+
118
+ @last_cpu_reads[id] = { v: current, t: current_time }
119
+ end
120
+
121
+ def memory(id, name, stats)
122
+ memory_stats = stats['memory_stats']
123
+ usage = memory_stats['usage'].to_f
124
+ total = memory_stats['limit'].to_f
125
+ fraction = (usage / total)
126
+
127
+ report_pct name, :memory, fraction, "#{usage} / #{total}"
128
+ end
129
+
130
+ def disk
131
+ `df -P`.split(/\n/).each do |r|
132
+ f = r.split(/\s+/)
133
+ next if f[0] == 'Filesystem'
134
+ next unless f[0] =~ /\// # Needs at least one slash in the mount path
135
+
136
+ # Calculate capacity
137
+ x = f[4].to_f/100
138
+ report_pct(nil, :disk, x, "#{f[3].to_i / 1024} mb left", "disk #{f[5]}")
139
+ end
140
+ end
141
+
142
+ def basic_inspection(id, name, inspection)
143
+
144
+ state = inspection['State']
145
+ json_state = JSON.generate(state)
146
+
147
+ running = state['Running']
148
+
149
+ alert(name, "status",
150
+ running ? "ok" : "critical",
151
+ running ? 1 : 0,
152
+ json_state)
153
+
154
+ if (running)
155
+ start_time = DateTime.rfc3339(state['StartedAt']).to_time.utc.to_i
156
+ now = DateTime.now.to_time.utc.to_i
157
+ uptime = now - start_time
158
+
159
+ if (@last_uptime_reads[id] != nil)
160
+ last = @last_uptime_reads[id]
161
+ restarted = start_time != last
162
+ alert(name, "uptime",
163
+ restarted ? "critical" : "ok",
164
+ uptime,
165
+ "last 'StartedAt' measure was #{last} (#{Time.at(last).utc.to_s}), " +
166
+ "now it's #{start_time} (#{Time.at(start_time).utc.to_s})")
167
+ end
168
+
169
+ @last_uptime_reads[id] = start_time
170
+ end
171
+ end
172
+
173
+ def tick
174
+
175
+ # Disk is the same in every container
176
+ if @disk_enabled
177
+ disk()
178
+ end
179
+
180
+ # Get CPU, Memory and Load of each container
181
+ containers = get_containers()
182
+ containers.each do |container|
183
+
184
+ id = container.id
185
+ name = get_container_name(container)
186
+
187
+ stats = Docker::Util.parse_json(container.connection.get("/containers/#{id}/stats", {stream:false}))
188
+
189
+ if @basic_inspection_enabled
190
+ inspection = Docker::Util.parse_json(container.connection.get("/containers/#{id}/json"))
191
+ basic_inspection(id, name, inspection)
192
+ end
193
+ if @cpu_enabled
194
+ cpu(id, name, stats)
195
+ end
196
+ if @memory_enabled
197
+ memory(id, name, stats)
198
+ end
199
+ end
200
+
201
+ end
202
+ end
203
+
204
+ Riemann::Tools::DockerHealth.run
205
+
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: riemann-docker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Shani Elharrar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: riemann-tools
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.2.7
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.2.7
27
+ - !ruby/object:Gem::Dependency
28
+ name: docker-api
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.22.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.22.0
41
+ description:
42
+ email: ''
43
+ executables:
44
+ - riemann-docker
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - LICENSE
49
+ - README.md
50
+ - bin/riemann-docker
51
+ homepage: https://github.com/riemann/riemann-docker
52
+ licenses: []
53
+ metadata: {}
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 1.8.7
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project: riemann-docker
70
+ rubygems_version: 2.4.5
71
+ signing_key:
72
+ specification_version: 4
73
+ summary: Submits Docker container stats to riemann.
74
+ test_files: []