collectd 0.0.12

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.
@@ -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