collectd 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,146 @@
1
+ ruby-collectd
2
+ =============
3
+
4
+ `ruby-collectd` lets you send statistics to `collectd` from Ruby.
5
+
6
+ This can be useful if you want to **instrument data** from within daemons
7
+ or servers written in Ruby.
8
+
9
+ `ruby-collectd` works by talking the `collectd` network protocol, and
10
+ sending stats periodicially to a network-aware instance of `collectd`.
11
+
12
+ Setup
13
+ -----
14
+
15
+ You need to have `collectd` load the network plugin, and listen on UDP
16
+ port `25826` (so it's acting as a server):
17
+
18
+ ::
19
+
20
+ # /etc/collectd.conf
21
+
22
+ LoadPlugin network
23
+
24
+ <Plugin "network">
25
+ Listen "ff18::efc0:4a42"
26
+ </Plugin>
27
+
28
+
29
+ To install the gem, make sure GitHub's RubyGems server is known to your local
30
+ RubyGems, then install it:
31
+
32
+ ::
33
+
34
+ gem sources -a http://gems.github.com
35
+ sudo gem install astro-collectd
36
+
37
+
38
+ Usage
39
+ -----
40
+
41
+ ::
42
+
43
+ require 'rubygems'
44
+ require 'collectd'
45
+
46
+ First of all, specify a server to send data to:
47
+
48
+ ::
49
+
50
+ Collectd.add_server(interval=10, addr='ff18::efc0:4a42', port=25826)
51
+
52
+ Each server you add will receive all the data you push later.
53
+ An interval of 10 is quite reasonable. Because of UDP and `collectd`'s
54
+ network buffering, you can set the interval to less than 10, but you
55
+ won't see much benefit.
56
+
57
+ `ruby-collectd` gives you a free data collector out of the box, and it's
58
+ a nice gentle introduction to instrumenting your app.
59
+
60
+ To collect memory and CPU statistics of your Ruby process, do:
61
+
62
+ ::
63
+
64
+ Stats = Collectd.my_process(:woo_data)
65
+ Stats.with_full_proc_stats
66
+
67
+ In the first line, we set up a new plugin. ``my_process`` is the plugin
68
+ name (magically handled by method_missing), and ``:woo_data`` is the
69
+ plugin instance.
70
+
71
+ A **plugin name** is generally an application's name, and a **plugin instance**
72
+ is a unique identifier of an instance of an application (i.e. you have
73
+ multiple daemons or scripts running at the same time).
74
+
75
+ In the second line, ``with_full_proc_stats`` is a method provided by
76
+ `ruby-collectd` that collects stats about the current running process.
77
+ It makes use of polled gauges, which we talk about later.
78
+
79
+ Behind the scenes, ``with_full_proc_stats`` is using a **simple interface**
80
+ you can use to instrument your own data.
81
+
82
+ Back in the first line we set up a plugin which we wanted to record some
83
+ data on. ``with_full_proc_stats`` sets up **types**, which are a kind of data
84
+ you are measuring (in this case CPU and memory usage).
85
+
86
+ You can do this yourself like this:
87
+
88
+ ::
89
+
90
+ Stats = Collectd.my_daemon(:backend)
91
+
92
+ # Set counter absolutely
93
+ Stats.my_counter(:my_sleep).counter = 0
94
+ Stats.my_gauge(:my_gauge).gauge = 23
95
+
96
+ loop do
97
+ # Increment counter relatively
98
+ Stats.my_counter(:my_sleep).count! 5
99
+ # Set gauge absolutely
100
+ Stats.my_gauge(:my_stack).gauge = rand(40)
101
+ sleep 5
102
+ end
103
+
104
+
105
+ (Don't worry if this doesn't make sense - gauges and counters are explained
106
+ below)
107
+
108
+ You can also **poll** for your data, if you feel comfortable with that:
109
+
110
+ ::
111
+
112
+ Stats.counter(:seconds_elapsed).polled_counter do
113
+ Time.now.to_i
114
+ end
115
+
116
+
117
+ Glossary / collectd's data model
118
+ --------------------------------
119
+
120
+ `collectd` groups data by **six categories:**
121
+
122
+ * *hostname* is grabbed from ``hostname -f``
123
+ * *plugin* is the application's name
124
+ * *plugin-instance* is passed from the programs' side with the
125
+ programs instance identifier, useful if you're running the same
126
+ script twice (PIDs are quite too random)
127
+ * *type* is the kind of data you are measuring and must be defined in
128
+ types.db_ for collectd to understand
129
+ * *type-instance* provides further distinction and have no relation to
130
+ other type-instances. Multiple type-instances are only rendered into
131
+ one graph by collection3 if defined with module GenericStacked.
132
+ * *values* are one or more field names and types belonging
133
+ together. The exact amount of fields and their corresponding names
134
+ (useful to collection3) are specified in collectd's types.db_.
135
+
136
+ A value can be either of **two types:**
137
+
138
+ * *COUNTER* is for increasing counters where you want to plot the
139
+ delta. Network interface traffic counters are a good example.
140
+ * *GAUGE* is values that go up and down to be plotted as-is, like a
141
+ temperature graph.
142
+
143
+
144
+ .. _types.db: http://collectd.org/documentation/manpages/types.db.5.shtml
145
+
146
+
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'jeweler'
3
+ rescue LoadError
4
+ raise "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
5
+ end
6
+
7
+ Jeweler::Tasks.new do |s|
8
+ s.name = "collectd"
9
+ s.summary = "Send collectd statistics from Ruby"
10
+ s.email = "astro@spaceboyz.net"
11
+ s.homepage = "http://github.com/astro/ruby-collectd"
12
+ s.authors = ["Stephan Maka"]
13
+ s.files = FileList["[A-Z]*", "{lib,spec,examples}/**/*"]
14
+ #s.add_dependency 'eventmachine'
15
+ end
16
+
17
+ begin
18
+ require 'spec/rake/spectask'
19
+ desc "Run all Spec"
20
+ Spec::Rake::SpecTask.new('spec') do |spec|
21
+ spec.spec_files = FileList['spec/*.rb']
22
+ spec.verbose = true
23
+ spec.warning = true
24
+ spec.rcov = true
25
+ spec.rcov_opts = []
26
+ spec.rcov_opts = ['--exclude', 'spec']
27
+ end
28
+ rescue LoadError
29
+ task :spec do
30
+ abort "Rspec is not available. In order to run rspec, you must: sudo gem install rspec"
31
+ end
32
+ end
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 12
3
+ :major: 0
4
+ :minor: 0
@@ -0,0 +1,19 @@
1
+ require 'eventmachine'
2
+ require 'collectd'
3
+
4
+ EM.run do
5
+ Collectd::use_eventmachine = true
6
+ Collectd::add_server 1
7
+ Stats = Collectd.ruby_collectd(:test)
8
+ Stats.with_full_proc_stats
9
+
10
+ c = 0
11
+ EM.add_periodic_timer(0.01) do
12
+ Stats.ping(:fun).gauge = 42 + Math.sin(Time.now.to_f / 600) * 23.5
13
+ Stats.cpu(:time).counter = c
14
+
15
+ c += 1
16
+ print '.'
17
+ STDOUT.flush
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ require 'collectd'
2
+
3
+ Collectd::add_server 1
4
+ Stats = Collectd::ruby_collectd(:test)
5
+ Stats.with_full_proc_stats
6
+
7
+ c = 0
8
+ loop do
9
+ Stats.ping(:fun).gauge = 42 + Math.sin(Time.now.to_f / 600) * 23.5
10
+ Stats.cpu(:time).counter = c
11
+ c += 1
12
+ Thread.pass
13
+ sleep 0.01
14
+ print '.'
15
+ STDOUT.flush
16
+ end
@@ -0,0 +1,10 @@
1
+ require 'collectd/proc_stats'
2
+ require 'collectd/interface'
3
+ require 'collectd/server'
4
+ begin
5
+ require 'collectd/em_server'
6
+ rescue LoadError
7
+ # EM is optional
8
+ end
9
+
10
+
@@ -0,0 +1,24 @@
1
+ require 'eventmachine'
2
+
3
+ module Collectd
4
+ class EmServer < Values
5
+
6
+ def initialize(interval, host, port)
7
+ super(interval)
8
+ @sock = UDPSocket.new(host.index(':') ? Socket::AF_INET6 : Socket::AF_INET)
9
+ @sock.connect(host, port)
10
+
11
+ EM.add_periodic_timer(interval) do
12
+ Collectd.run_pollables_for self
13
+ Thread.critical = true
14
+ pkt = make_pkt
15
+ Thread.critical = false
16
+ begin
17
+ @sock.send(pkt, 0)
18
+ rescue SystemCallError
19
+ end
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ module Collectd
2
+ # EventMachine support stuff. Included in Collectd::Plugin.
3
+ module EmPlugin
4
+ ##
5
+ # Attaches additional callback and errback to deferrable to track
6
+ # a common set of success/error rate/latency
7
+ def track_deferrable(name, deferrable)
8
+ attach_time = Time.now
9
+ deferrable.callback do |*a|
10
+ push_deferrable_values("#{name}_success", attach_time)
11
+ end
12
+ deferrable.errback do |*a|
13
+ push_deferrable_values("#{name}_error", attach_time)
14
+ end
15
+ end
16
+ def push_deferrable_values(name, attach_time)
17
+ latency(name).gauge = Time.now - attach_time
18
+ counter(name).count! 1
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,211 @@
1
+ require 'collectd/pkt'
2
+ require 'collectd/em_support'
3
+
4
+
5
+ module Collectd
6
+ class << self
7
+
8
+ def hostname
9
+ @@hostname ||= `hostname -f`.strip
10
+ @@hostname
11
+ end
12
+ def hostname=(h)
13
+ @@hostname = h
14
+ end
15
+
16
+ @@servers = []
17
+
18
+ def add_server(interval, addr='ff18::efc0:4a42', port=25826)
19
+ if defined?(EM) && EM.reactor_running?
20
+ @@servers << EmServer.new(interval, addr, port)
21
+ else
22
+ @@servers << Server.new(interval, addr, port)
23
+ end
24
+ end
25
+
26
+ def <<(server)
27
+ @@servers << server
28
+ end
29
+
30
+ def reset!
31
+ @@servers.each do |server|
32
+ server.close if server.respond_to?(:close)
33
+ end
34
+ @@servers = []
35
+ @@pollables = []
36
+ end
37
+
38
+ def each_server(&block)
39
+ @@servers.each(&block)
40
+ end
41
+
42
+ def add_pollable(&block)
43
+ @@pollables ||= []
44
+ @@pollables << block
45
+ end
46
+ def run_pollables_for(server)
47
+ @@pollables ||= []
48
+ @@pollables.each do |block|
49
+ block.call(server)
50
+ end
51
+ end
52
+
53
+ def method_missing(plugin, plugin_instance)
54
+ Plugin.new(plugin, plugin_instance)
55
+ end
56
+
57
+ end
58
+
59
+ ##
60
+ # Interface helper
61
+ class Plugin
62
+ include ProcStats
63
+ include EmPlugin
64
+ def initialize(plugin, plugin_instance)
65
+ @plugin, @plugin_instance = plugin, plugin_instance
66
+ end
67
+ def method_missing(type, type_instance)
68
+ Type.new(@plugin, @plugin_instance, type, type_instance)
69
+ end
70
+ end
71
+
72
+ ##
73
+ # Interface helper
74
+ class Type
75
+ def initialize(plugin, plugin_instance, type, type_instance)
76
+ @plugin, @plugin_instance = plugin, plugin_instance
77
+ @type, @type_instance = type, type_instance
78
+ end
79
+ ##
80
+ # GAUGE
81
+ def gauge=(values)
82
+ values = [values] unless values.kind_of? Array
83
+ Collectd.each_server do |server|
84
+ server.set_gauge(plugin_type, values)
85
+ end
86
+ end
87
+ ##
88
+ # COUNTER
89
+ def counter=(values)
90
+ values = [values] unless values.kind_of? Array
91
+ Collectd.each_server do |server|
92
+ server.set_counter(plugin_type, values)
93
+ end
94
+ end
95
+ def count!(*values)
96
+ Collectd.each_server do |server|
97
+ server.inc_counter(plugin_type, values)
98
+ end
99
+ end
100
+ def polled_gauge(&block)
101
+ Collectd.add_pollable do |server|
102
+ values = block.call
103
+ if values
104
+ values = [values] unless values.kind_of? Array
105
+ server.set_gauge(plugin_type, values)
106
+ end
107
+ end
108
+ end
109
+ def polled_count(&block)
110
+ Collectd.add_pollable do |server|
111
+ values = block.call
112
+ if values
113
+ values = [values] unless values.kind_of? Array
114
+ server.inc_counter(plugin_type, values)
115
+ end
116
+ end
117
+ end
118
+ def polled_counter(&block)
119
+ Collectd.add_pollable do |server|
120
+ values = block.call
121
+ if values
122
+ values = [values] unless values.kind_of? Array
123
+ server.set_counter(plugin_type, values)
124
+ end
125
+ end
126
+ end
127
+ private
128
+ ##
129
+ # [plugin, plugin_instance, type, type_instance]
130
+ def plugin_type
131
+ [@plugin, @plugin_instance, @type, @type_instance]
132
+ end
133
+ end
134
+
135
+ ##
136
+ # Value-holder, baseclass for servers
137
+ class Values
138
+ attr_reader :interval
139
+ def initialize(interval)
140
+ @interval = interval
141
+ @counters = {}
142
+ @gauges = {}
143
+ end
144
+ def set_counter(plugin_type, values)
145
+ @counters[plugin_type] = values
146
+ end
147
+ def inc_counter(plugin_type, values)
148
+ old_values = @counters[plugin_type] || []
149
+ values.map! { |value|
150
+ value + (old_values.shift || 0)
151
+ }
152
+ @counters[plugin_type] = values
153
+ end
154
+ def set_gauge(plugin_type, values)
155
+ # Use count & sums for average
156
+ if @gauges.has_key?(plugin_type)
157
+ old_values = @gauges[plugin_type]
158
+ count = old_values.shift || 0
159
+ values.map! { |value| value + (old_values.shift || value) }
160
+ @gauges[plugin_type] = [count + 1] + values
161
+ else
162
+ @gauges[plugin_type] = [1] + values
163
+ end
164
+ end
165
+
166
+ def make_pkt
167
+ plugin_type_values = {}
168
+ @counters.each do |plugin_types,values|
169
+ plugin, plugin_instance, type, type_instance = plugin_types
170
+ plugin_type_values[plugin] ||= {}
171
+ plugin_type_values[plugin][plugin_instance] ||= {}
172
+ plugin_type_values[plugin][plugin_instance][type] ||= {}
173
+ plugin_type_values[plugin][plugin_instance][type][type_instance] =
174
+ Packet::Values.new(values.map { |value| Packet::Values::Counter.new(value) })
175
+ end
176
+ @gauges.each do |plugin_types,values|
177
+ plugin, plugin_instance, type, type_instance = plugin_types
178
+ plugin_type_values[plugin] ||= {}
179
+ plugin_type_values[plugin][plugin_instance] ||= {}
180
+ plugin_type_values[plugin][plugin_instance][type] ||= {}
181
+ count = values.shift || next
182
+ values.map! { |value| value.to_f / count }
183
+ plugin_type_values[plugin][plugin_instance][type][type_instance] =
184
+ Packet::Values.new(values.map { |value| Packet::Values::Gauge.new(value) })
185
+ end
186
+ pkt = [Packet::Host.new(Collectd.hostname),
187
+ Packet::Time.new(Time.now.to_i),
188
+ Packet::Interval.new(10)]
189
+ plugin_type_values.each do |plugin,plugin_instances|
190
+ pkt << Packet::Plugin.new(plugin)
191
+ plugin_instances.each do |plugin_instance,types|
192
+ pkt << Packet::PluginInstance.new(plugin_instance)
193
+ types.each do |type,type_instances|
194
+ pkt << Packet::Type.new(type)
195
+ type_instances.each do |type_instance,values|
196
+ pkt << Packet::TypeInstance.new(type_instance)
197
+ pkt << values
198
+ end
199
+ end
200
+ end
201
+ end
202
+
203
+ # Reset only gauges. Counters are persistent for incrementing.
204
+ @gauges = {}
205
+
206
+ # And return serialized packet of parts
207
+ pkt.to_s
208
+ end
209
+ end
210
+
211
+ end
@@ -0,0 +1,111 @@
1
+ module Collectd
2
+ module Packet
3
+
4
+ class Part
5
+ def to_s(content)
6
+ [type, content.length + 4].pack("nn") + content
7
+ end
8
+
9
+ ##
10
+ # Makes subclasses more declarative
11
+ def self.type(number=nil)
12
+ number ? @type = number : @type
13
+ end
14
+
15
+ def type
16
+ self.class.type
17
+ end
18
+ end
19
+
20
+ class String < Part
21
+ def initialize(s)
22
+ @s = s
23
+ end
24
+ def to_s
25
+ super "#{@s}\000"
26
+ end
27
+ end
28
+
29
+ class Number < Part
30
+ def initialize(n)
31
+ @n = n
32
+ end
33
+ def to_s
34
+ super [@n >> 32, @n & 0xffffffff].pack("NN")
35
+ end
36
+ end
37
+
38
+ class Host < String
39
+ type 0
40
+ end
41
+
42
+ class Time < Number
43
+ type 1
44
+ end
45
+
46
+ class Plugin < String
47
+ type 2
48
+ end
49
+
50
+ class PluginInstance < String
51
+ type 3
52
+ end
53
+
54
+ class Type < String
55
+ type 4
56
+ end
57
+
58
+ class TypeInstance < String
59
+ type 5
60
+ end
61
+
62
+ class Values < Part
63
+ type 6
64
+ def initialize(v)
65
+ @v = v
66
+ end
67
+ def to_s
68
+ types, values = [], []
69
+ @v.each { |v1|
70
+ types << [v1.type].pack("C")
71
+ values << v1.to_s
72
+ }
73
+ super [@v.length].pack("n") + types.join + values.join
74
+ end
75
+
76
+ class Counter < Part
77
+ type 0
78
+ def initialize(c)
79
+ @c = c
80
+ end
81
+ def to_s
82
+ [@c >> 32, @c & 0xffffffff].pack("NN")
83
+ end
84
+ end
85
+
86
+ class Gauge < Part
87
+ type 1
88
+ def initialize(f)
89
+ @f = f
90
+ end
91
+ def to_s
92
+ [@f].pack("d")
93
+ end
94
+ end
95
+ end
96
+
97
+ class Interval < Number
98
+ type 7
99
+ end
100
+
101
+
102
+ class Message < String
103
+ type 0x100
104
+ end
105
+
106
+ class Severity < Number
107
+ type 0x101
108
+ end
109
+
110
+ end
111
+ end
@@ -0,0 +1,46 @@
1
+ module Collectd
2
+ ##
3
+ # Included by Interface
4
+ module ProcStats
5
+ def process_status(field)
6
+ fields = {}
7
+ begin
8
+ IO.readlines("/proc/#{$$}/status").each { |line|
9
+ line.strip!
10
+ if line =~ /^(.+?):\s+(.+)$/
11
+ fields[$1] = $2
12
+ end
13
+ }
14
+ rescue Errno::ENOENT
15
+ nil
16
+ else
17
+ fields[field]
18
+ end
19
+ end
20
+
21
+ def with_polled_memory
22
+ memory('VmRSS').polled_gauge do
23
+ (v = process_status('VmRSS')) ? v.to_i * 1024 : nil
24
+ end
25
+ memory('VmSize').polled_gauge do
26
+ (v = process_status('VmSize')) ? v.to_i * 1024 : nil
27
+ end
28
+
29
+ self
30
+ end
31
+
32
+ def with_polled_cpu
33
+ cpu('user').polled_counter do
34
+ (Process::times.utime * 100).to_i
35
+ end
36
+ cpu('system').polled_counter do
37
+ (Process::times.stime * 100).to_i
38
+ end
39
+ end
40
+
41
+ def with_full_proc_stats
42
+ with_polled_memory
43
+ with_polled_cpu
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,29 @@
1
+ require 'socket'
2
+ require 'thread'
3
+
4
+ module Collectd
5
+ class Server < Values
6
+
7
+ def initialize(interval, host, port)
8
+ super(interval)
9
+ @sock = UDPSocket.new(host.index(':') ? Socket::AF_INET6 : Socket::AF_INET)
10
+ @sock.connect(host, port)
11
+
12
+ Thread.new do
13
+ loop do
14
+ sleep interval
15
+
16
+ Collectd.run_pollables_for self
17
+ Thread.critical = true
18
+ pkt = make_pkt
19
+ Thread.critical = false
20
+ begin
21
+ @sock.send(pkt, 0)
22
+ rescue SystemCallError
23
+ end
24
+ end
25
+ end.abort_on_exception = true
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,197 @@
1
+ $: << File.dirname(__FILE__) + '/../lib'
2
+ require 'collectd'
3
+
4
+ describe Collectd do
5
+ before(:each) do
6
+ @server = mock('Server')
7
+ Collectd << @server
8
+ end
9
+ after(:each) do
10
+ Collectd.reset!
11
+ end
12
+
13
+ it 'should set_counter' do
14
+ @server.should_receive(:set_counter).
15
+ with([:plugin1, :plugin_instance1,
16
+ :type1, :type_instance1], [23])
17
+ Collectd.plugin1(:plugin_instance1).type1(:type_instance1).counter = 23
18
+ end
19
+ it 'should inc_counter' do
20
+ @server.should_receive(:inc_counter).
21
+ with([:plugin1, :plugin_instance1,
22
+ :type1, :type_instance1], [23, 42])
23
+ Collectd.plugin1(:plugin_instance1).type1(:type_instance1).count! 23, 42
24
+ end
25
+ it 'should set_gauge' do
26
+ @server.should_receive(:set_gauge).
27
+ with([:plugin1, :plugin_instance1,
28
+ :type1, :type_instance1], [23, 42, 5])
29
+ Collectd.plugin1(:plugin_instance1).type1(:type_instance1).gauge = [23, 42, 5]
30
+ end
31
+
32
+ it 'should poll a pollable' do
33
+ pollable = mock('Pollable')
34
+ Collectd.add_pollable { |*a|
35
+ pollable.call *a
36
+ }
37
+ pollable.should_receive(:call).with(@server).and_return(nil)
38
+ Collectd.run_pollables_for @server
39
+ end
40
+ it 'should poll a polled_count' do
41
+ Collectd.plugin1(:plugin_instance1).type1(:type_instance1).polled_count do
42
+ [23, 42, 5, 7]
43
+ end
44
+ @server.should_receive(:inc_counter).
45
+ with([:plugin1, :plugin_instance1,
46
+ :type1, :type_instance1], [23, 42, 5, 7])
47
+ Collectd.run_pollables_for @server
48
+ end
49
+ it 'should poll a polled_counter' do
50
+ Collectd.plugin1(:plugin_instance1).type1(:type_instance1).polled_counter do
51
+ [23, 42, 5, 7]
52
+ end
53
+ @server.should_receive(:set_counter).
54
+ with([:plugin1, :plugin_instance1,
55
+ :type1, :type_instance1], [23, 42, 5, 7])
56
+ Collectd.run_pollables_for @server
57
+ end
58
+ it 'should poll a polled_gauge' do
59
+ Collectd.plugin1(:plugin_instance1).type1(:type_instance1).polled_gauge do
60
+ [23, 42, 5, 7]
61
+ end
62
+ @server.should_receive(:set_gauge).
63
+ with([:plugin1, :plugin_instance1,
64
+ :type1, :type_instance1], [23, 42, 5, 7])
65
+ Collectd.run_pollables_for @server
66
+ end
67
+ end
68
+
69
+ class StubServer < Collectd::Values
70
+ attr_reader :counters
71
+ attr_reader :gauges
72
+ def initialize
73
+ super(1000)
74
+ end
75
+ end
76
+
77
+ describe Collectd::ProcStats do
78
+ before(:each) do
79
+ @server = StubServer.new
80
+ Collectd << @server
81
+ Collectd.plugin1(:plugin_instance1).with_full_proc_stats
82
+ Collectd.run_pollables_for @server
83
+ end
84
+ after(:each) do
85
+ Collectd.reset!
86
+ end
87
+
88
+ context 'when polling memory' do
89
+ it 'should report VmRSS' do
90
+ g = @server.gauges[[:plugin1, :plugin_instance1, :memory, "VmRSS"]]
91
+ g[0].should be_kind_of(Fixnum)
92
+ end
93
+ it 'should report VmSize' do
94
+ g = @server.gauges[[:plugin1, :plugin_instance1, :memory, "VmSize"]]
95
+ g[0].should be_kind_of(Fixnum)
96
+ end
97
+ end
98
+ context 'when polling cpu' do
99
+ it 'should report user time' do
100
+ c = @server.counters[[:plugin1, :plugin_instance1, :cpu, "user"]]
101
+ c[0].should be_kind_of(Fixnum)
102
+ end
103
+ it 'should report system time' do
104
+ c = @server.counters[[:plugin1, :plugin_instance1, :cpu, "system"]]
105
+ c[0].should be_kind_of(Fixnum)
106
+ end
107
+ end
108
+ end
109
+
110
+ describe Collectd::EmPlugin do
111
+ before(:each) do
112
+ @server = StubServer.new
113
+ Collectd << @server
114
+ @df = EM::DefaultDeferrable.new
115
+ Collectd.plugin1(:plugin_instance1).track_deferrable('df', @df)
116
+ end
117
+ after(:each) do
118
+ Collectd.reset!
119
+ end
120
+
121
+ context 'when succeeding' do
122
+ it 'should callback' do
123
+ @df.succeed
124
+ end
125
+ it 'should report latency' do
126
+ @df.succeed
127
+ g = @server.gauges[[:plugin1, :plugin_instance1, :latency, 'df_success']]
128
+ g[0].should be_kind_of(Numeric)
129
+ end
130
+ it 'should increase a counter' do
131
+ @df.succeed
132
+ c = @server.counters[[:plugin1, :plugin_instance1, :counter, 'df_success']]
133
+ c[0].should be_kind_of(Numeric)
134
+ end
135
+ end
136
+ context 'when failing' do
137
+ it 'should callback' do
138
+ @df.fail
139
+ end
140
+ it 'should report latency' do
141
+ @df.fail
142
+ g = @server.gauges[[:plugin1, :plugin_instance1, :latency, 'df_error']]
143
+ g[0].should be_kind_of(Numeric)
144
+ end
145
+ it 'should increase a counter' do
146
+ @df.fail
147
+ c = @server.counters[[:plugin1, :plugin_instance1, :counter, 'df_error']]
148
+ c[0].should be_kind_of(Numeric)
149
+ end
150
+ end
151
+ end
152
+
153
+ describe Collectd::Server do
154
+ before :all do
155
+ Collectd.add_server(0.1)
156
+ end
157
+ after :all do
158
+ Collectd.reset!
159
+ end
160
+
161
+ it "should spawn a Collectd::Server" do
162
+ servers = []
163
+ Collectd.each_server { |s| servers << s }
164
+ servers.length.should == 1
165
+ servers[0].should be_kind_of(Collectd::Server)
166
+ end
167
+
168
+ it "should run for 2 seconds" do
169
+ sleep 2
170
+ end
171
+ end
172
+
173
+ describe Collectd::EmServer do
174
+ it "should spawn a Collectd::Server" do
175
+ EM.run {
176
+ Collectd.add_server 0.1
177
+ EM.next_tick {
178
+ EM.stop
179
+ servers = []
180
+ Collectd.each_server { |s| servers << s }
181
+ servers.length.should == 1
182
+ servers[0].should be_kind_of(Collectd::EmServer)
183
+ Collectd.reset!
184
+ }
185
+ }
186
+ end
187
+
188
+ it "should run for 2 seconds" do
189
+ EM.run {
190
+ Collectd.add_server 0.1
191
+ EM::Timer.new(2) {
192
+ EM.stop
193
+ Collectd.reset!
194
+ }
195
+ }
196
+ end
197
+ end if defined?(EM)
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: collectd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.12
5
+ platform: ruby
6
+ authors:
7
+ - Stephan Maka
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-12 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: astro@spaceboyz.net
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rst
24
+ files:
25
+ - README.rst
26
+ - Rakefile
27
+ - VERSION.yml
28
+ - examples/em_sender.rb
29
+ - examples/sender.rb
30
+ - lib/collectd.rb
31
+ - lib/collectd/em_server.rb
32
+ - lib/collectd/em_support.rb
33
+ - lib/collectd/interface.rb
34
+ - lib/collectd/pkt.rb
35
+ - lib/collectd/proc_stats.rb
36
+ - lib/collectd/server.rb
37
+ - spec/interface_spec.rb
38
+ has_rdoc: true
39
+ homepage: http://github.com/astro/ruby-collectd
40
+ licenses: []
41
+
42
+ post_install_message:
43
+ rdoc_options:
44
+ - --charset=UTF-8
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.3.5
63
+ signing_key:
64
+ specification_version: 3
65
+ summary: Send collectd statistics from Ruby
66
+ test_files:
67
+ - spec/interface_spec.rb
68
+ - examples/sender.rb
69
+ - examples/em_sender.rb