nosey 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/nosey.rb +9 -231
- data/lib/nosey/eventmachine.rb +34 -0
- data/lib/nosey/instrumentation.rb +17 -0
- data/lib/nosey/munin.rb +146 -0
- data/lib/nosey/probe.rb +152 -0
- data/lib/nosey/report.rb +34 -0
- data/lib/nosey/version.rb +1 -1
- data/spec/lib/nosey/instrumentation_spec.rb +11 -0
- data/spec/lib/nosey/munin_spec.rb +52 -0
- data/spec/lib/nosey/probe_spec.rb +105 -0
- data/spec/lib/nosey/report_spec.rb +29 -0
- data/spec/lib/nosey_spec.rb +0 -143
- metadata +15 -2
data/lib/nosey.rb
CHANGED
@@ -1,237 +1,15 @@
|
|
1
1
|
require "nosey/version"
|
2
|
-
require 'eventmachine'
|
3
|
-
|
4
|
-
module EventMachine
|
5
|
-
module Nosey
|
6
|
-
class SocketServer < EventMachine::Connection
|
7
|
-
Host = '/tmp/nosey.socket'
|
8
|
-
Port = nil
|
9
|
-
|
10
|
-
attr_accessor :report
|
11
|
-
|
12
|
-
# Accept a collection of aggregators that we'll use to report our stats.
|
13
|
-
def initialize(report)
|
14
|
-
@report = report
|
15
|
-
end
|
16
|
-
|
17
|
-
# Dump out the stats and close down the connection
|
18
|
-
def post_init
|
19
|
-
begin
|
20
|
-
send_data report.to_s
|
21
|
-
rescue => e
|
22
|
-
send_data "Exception! #{e}\n#{e.backtrace}"
|
23
|
-
ensure
|
24
|
-
close_connection
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
# A nice short-cut for peeps who aren't familar with EM to fire up
|
29
|
-
# an Reporting server with an array of aggregators, host, and a port.
|
30
|
-
def self.start(report, host=SocketServer::Host, port=SocketServer::Port)
|
31
|
-
EventMachine::start_server(host, port, self, report)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
2
|
|
37
3
|
module Nosey
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
yield self if block_given?
|
43
|
-
self
|
44
|
-
end
|
45
|
-
|
46
|
-
def probe_sets
|
47
|
-
@probe_sets ||= Array.new
|
48
|
-
end
|
49
|
-
|
50
|
-
# Hash representation of all the probe_sets. This gives is an intermediate
|
51
|
-
# format that we can parse from other systems or code that needs reporting
|
52
|
-
# data for formatting, or whatever.
|
53
|
-
def to_hash
|
54
|
-
probe_sets.inject({}) do |report, set|
|
55
|
-
report[set.name.to_s] = set.probes.inject({}) do |memo, (_, probe)|
|
56
|
-
memo[probe.name] = probe.value
|
57
|
-
memo
|
58
|
-
end
|
59
|
-
report
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# String representation of all the probe_sets that's suitable for
|
64
|
-
# flushing out over a socket.
|
65
|
-
def to_s
|
66
|
-
to_hash.to_yaml
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
module Instrumentation
|
71
|
-
# Inject nosey instrumentation into the owning class.
|
72
|
-
def self.included(base)
|
73
|
-
base.send :include, DSL::InstanceMethods
|
74
|
-
end
|
75
|
-
|
76
|
-
module DSL
|
77
|
-
module InstanceMethods
|
78
|
-
# Setup instrumentation that we'll use to report stats for this thing
|
79
|
-
def nosey
|
80
|
-
@_nosey ||= Nosey::Probe::Set.new("#{self.class.name}##{object_id}")
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
module Probe
|
87
|
-
# Base class for containing key/value pairs in nosey. This class is responsible
|
88
|
-
# for reseting probes.
|
89
|
-
class Base
|
90
|
-
attr_reader :name
|
91
|
-
attr_accessor :value
|
92
|
-
|
93
|
-
def initialize(name=nil, value=nil)
|
94
|
-
@name, @value = name, value
|
95
|
-
end
|
96
|
-
|
97
|
-
# Set the value (don't increment or whateves)
|
98
|
-
def set(value)
|
99
|
-
@value = value
|
100
|
-
end
|
101
|
-
|
102
|
-
# Reset the value to nil
|
103
|
-
def reset
|
104
|
-
@value = nil
|
105
|
-
end
|
106
|
-
|
107
|
-
# Representation of this probe
|
108
|
-
def to_hash
|
109
|
-
{ name => value }
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
# Calulcates a min, max, and avg for a given number of samples
|
114
|
-
class Sampler < Base
|
115
|
-
attr_reader :min, :max, :sum, :count
|
116
|
-
|
117
|
-
def initialize(*args)
|
118
|
-
reset
|
119
|
-
super(*args)
|
120
|
-
end
|
4
|
+
autoload :Munin, 'nosey/munin'
|
5
|
+
autoload :Report, 'nosey/report'
|
6
|
+
autoload :Probe, 'nosey/probe'
|
7
|
+
autoload :Instrumentation, 'nosey/instrumentation'
|
121
8
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
@min = value if value < @min
|
126
|
-
@max = value if value > @max
|
127
|
-
@sum += value
|
128
|
-
@count += 1
|
129
|
-
|
130
|
-
to_hash
|
131
|
-
end
|
132
|
-
|
133
|
-
def avg
|
134
|
-
sum / count if count > 0 and sum
|
135
|
-
end
|
136
|
-
|
137
|
-
def to_hash
|
138
|
-
{
|
139
|
-
'max' => max,
|
140
|
-
'min' => min,
|
141
|
-
'sum' => sum,
|
142
|
-
'avg' => avg,
|
143
|
-
'count' => count
|
144
|
-
}
|
145
|
-
end
|
146
|
-
|
147
|
-
def value
|
148
|
-
to_hash
|
149
|
-
end
|
150
|
-
|
151
|
-
def reset
|
152
|
-
@min = @max = nil
|
153
|
-
@sum = @count = 0
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
# Count up/down values.
|
158
|
-
class Counter < Base
|
159
|
-
def increment(by=1)
|
160
|
-
change by
|
161
|
-
end
|
162
|
-
|
163
|
-
def decrement(by=1)
|
164
|
-
change -by
|
165
|
-
end
|
166
|
-
|
167
|
-
private
|
168
|
-
def change(by)
|
169
|
-
self.value ||= 0 # Init at 0 if the stat is nil
|
170
|
-
self.value += by
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
class Touch < Base
|
175
|
-
def touch
|
176
|
-
self.value = Time.now
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
# Contains a collection of probes that calculate velocities, counts, etc.
|
182
|
-
class Probe::Set
|
183
|
-
attr_reader :name
|
184
|
-
|
185
|
-
def initialize(name)
|
186
|
-
@name = name
|
187
|
-
yield self if block_given?
|
188
|
-
self
|
189
|
-
end
|
190
|
-
|
191
|
-
# Increment a counter probe
|
192
|
-
def increment(key,by=1)
|
193
|
-
ensure_probe(Probe::Counter, key).increment(by)
|
194
|
-
end
|
195
|
-
|
196
|
-
# Decrement a counter probe
|
197
|
-
def decrement(key,by=1)
|
198
|
-
ensure_probe(Probe::Counter, key).decrement(by)
|
199
|
-
end
|
200
|
-
|
201
|
-
# Sample a number and get a sum/avg/count/min/max
|
202
|
-
def sample(key,val)
|
203
|
-
ensure_probe(Probe::Sampler, key).sample(val)
|
204
|
-
end
|
205
|
-
|
206
|
-
# Touch a timestamp probe
|
207
|
-
def touch(key)
|
208
|
-
ensure_probe(Probe::Touch, key).touch
|
209
|
-
end
|
210
|
-
|
211
|
-
# List of all the probes that are active
|
212
|
-
def probes
|
213
|
-
@probes ||= Hash.new
|
214
|
-
end
|
215
|
-
|
216
|
-
# Get a probe and do all sorts of crazy stuff to it.
|
217
|
-
def probe(key)
|
218
|
-
probes[key]
|
219
|
-
end
|
220
|
-
|
221
|
-
# Generate a report with this ProbeSet
|
222
|
-
def report
|
223
|
-
Report.new do |r|
|
224
|
-
r.probe_sets << self
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
private
|
229
|
-
# This factory creates probes based on the methods called from
|
230
|
-
# the instrumentation. If a probe doesn't exist, we create an instance
|
231
|
-
# from the klass and args passed in, then set the thing up in the hash key.
|
232
|
-
def ensure_probe(klass, key, *args)
|
233
|
-
probes[key] ||= klass.new(key, *args)
|
234
|
-
end
|
9
|
+
# Load the EM reporting socket if event machine loaded
|
10
|
+
def self.load_event_machine_extensions
|
11
|
+
require 'nosey/eventmachine' # if defined? EventMachine
|
235
12
|
end
|
13
|
+
end
|
236
14
|
|
237
|
-
|
15
|
+
Nosey.load_event_machine_extensions
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
|
3
|
+
module EventMachine
|
4
|
+
module Nosey
|
5
|
+
class SocketServer < EventMachine::Connection
|
6
|
+
Host = '/tmp/nosey.socket'
|
7
|
+
Port = nil
|
8
|
+
|
9
|
+
attr_accessor :report
|
10
|
+
|
11
|
+
# Accept a collection of aggregators that we'll use to report our stats.
|
12
|
+
def initialize(report)
|
13
|
+
@report = report
|
14
|
+
end
|
15
|
+
|
16
|
+
# Dump out the stats and close down the connection
|
17
|
+
def post_init
|
18
|
+
begin
|
19
|
+
send_data report.to_s
|
20
|
+
rescue => e
|
21
|
+
send_data "Exception! #{e}\n#{e.backtrace}"
|
22
|
+
ensure
|
23
|
+
close_connection
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# A nice short-cut for peeps who aren't familar with EM to fire up
|
28
|
+
# an Reporting server with an array of aggregators, host, and a port.
|
29
|
+
def self.start(report, host=SocketServer::Host, port=SocketServer::Port)
|
30
|
+
EventMachine::start_server(host, port, self, report)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Nosey
|
2
|
+
module Instrumentation
|
3
|
+
# Inject nosey instrumentation into the owning class.
|
4
|
+
def self.included(base)
|
5
|
+
base.send :include, DSL::InstanceMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module DSL
|
9
|
+
module InstanceMethods
|
10
|
+
# Setup instrumentation that we'll use to report stats for this thing
|
11
|
+
def nosey
|
12
|
+
@_nosey ||= Nosey::Probe::Set.new("#{self.class.name}##{object_id}")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/nosey/munin.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module Nosey
|
4
|
+
module Munin
|
5
|
+
# Print the output of the munin graph to $stdout
|
6
|
+
def self.graph(args=ARGV,&block)
|
7
|
+
client = Graph::DSL.new(&block).client
|
8
|
+
|
9
|
+
# Munin passes configure into this to figure out the graph.
|
10
|
+
puts case args.first
|
11
|
+
when 'configure'
|
12
|
+
client.configure
|
13
|
+
else
|
14
|
+
client.sample
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Parse a Nosey socket for Munin
|
19
|
+
class Graph
|
20
|
+
attr_accessor :data, :title, :vertical_label, :category
|
21
|
+
attr_writer :probe_set
|
22
|
+
|
23
|
+
def initialize(data)
|
24
|
+
@data = data
|
25
|
+
@category = 'App' # Default it to app duuude
|
26
|
+
yield self if block_given?
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
# Munin calls this to setup the title and labels for the chart
|
31
|
+
# graph_title THE TITLE OF YOUR GRAPH
|
32
|
+
# graph_category THE CATEGORY / GROUP OF YOUR GRAPH
|
33
|
+
# graph_vlabel Count
|
34
|
+
# total.label Total
|
35
|
+
# other.label Other
|
36
|
+
def configure
|
37
|
+
body = StringIO.new
|
38
|
+
body.puts "graph_title #{title}"
|
39
|
+
body.puts "graph_category #{category}"
|
40
|
+
body.puts "graph_vlabel #{vertical_label}"
|
41
|
+
munin_hash.each do |field, (label, value)|
|
42
|
+
body.puts "#{field}.label #{label}"
|
43
|
+
end
|
44
|
+
body.rewind
|
45
|
+
body.read
|
46
|
+
end
|
47
|
+
|
48
|
+
# Munin calls this to set the values in the chart
|
49
|
+
# total.value 0
|
50
|
+
# other.value 2
|
51
|
+
def sample
|
52
|
+
body = StringIO.new
|
53
|
+
munin_hash.each do |field, (label, value)|
|
54
|
+
body.puts "#{field}.value #{value}"
|
55
|
+
end
|
56
|
+
body.rewind
|
57
|
+
body.read
|
58
|
+
end
|
59
|
+
|
60
|
+
def munin_hash(root_key=nil,hash=self.probe_set)
|
61
|
+
# TODO perform processing for more complicated probes, like samplers, etc
|
62
|
+
hash.reduce({}) do |memo, (name, value)|
|
63
|
+
case value
|
64
|
+
when Hash # Its nested, go deep! Oooo yeah!
|
65
|
+
munin_hash(format_field(root_key, name), value).each do |name, value|
|
66
|
+
memo[format_field(root_key, name)] = value.to_a
|
67
|
+
end
|
68
|
+
else # Its cool, return this mmmkay? Sheesh man
|
69
|
+
memo[format_field(root_key, name)] = [name, value]
|
70
|
+
end
|
71
|
+
memo
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Default to the first probeset if nothing is specified
|
76
|
+
def probe_set
|
77
|
+
report[@probe_set ||= report.keys.first]
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
def title
|
82
|
+
@title ||= probe_set
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
def process_filter(hash)
|
87
|
+
hash.select{}
|
88
|
+
end
|
89
|
+
# http://munin-monitoring.org/wiki/notes_on_datasource_names
|
90
|
+
# Notes on field names
|
91
|
+
# Each data source in a plugin must be identified by a field name. The following describes the name of the field:
|
92
|
+
|
93
|
+
# The characters must be [a-zA-Z0-9_], while the first character must be [a-zA-Z_].
|
94
|
+
# Previously we documented that there the datasource name cannot exceed 19 characters in length. This was a limit inherited by munin 1.0 from rrd. In munin 1.2 this limit has been circumvented.
|
95
|
+
|
96
|
+
# In sed and perl these RE shold be applied to all field names to make them safe:
|
97
|
+
|
98
|
+
# s/^[^A-Za-z_]/_/
|
99
|
+
# s/[^A-Za-z0-9_]/_/g
|
100
|
+
def format_field(*names)
|
101
|
+
names.compact.join("_").gsub(/[^A-Za-z0-9_]/, '_')
|
102
|
+
end
|
103
|
+
|
104
|
+
def report
|
105
|
+
@report ||= YAML.load(@data)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# A little DSL that lets us set the socket and report name we'll read
|
110
|
+
class Graph::DSL
|
111
|
+
Category = 'App'
|
112
|
+
|
113
|
+
def socket(host=EventMachine::Nosey::SocketServer::Host,port=EventMachine::Nosey::SocketServer::Port)
|
114
|
+
@host, @port = host, port
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
# Name the probset that we'll spit out for this graph
|
119
|
+
def probe_set(probe_set)
|
120
|
+
@probe_set = probe_set
|
121
|
+
self
|
122
|
+
end
|
123
|
+
|
124
|
+
# Category this thing will be in
|
125
|
+
def category(category=Category)
|
126
|
+
@category = category
|
127
|
+
self
|
128
|
+
end
|
129
|
+
|
130
|
+
# Configure an instance of a client.
|
131
|
+
def graph
|
132
|
+
Graph.new do |c|
|
133
|
+
c.data = read_socket
|
134
|
+
c.probe_set = probe_Set
|
135
|
+
c.category = category
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
# Read the report YAML data from the socket
|
141
|
+
def read_socket
|
142
|
+
UNIXSocket.new(@host).gets("\n\n")
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/lib/nosey/probe.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
module Nosey
|
2
|
+
module Probe
|
3
|
+
# Base class for containing key/value pairs in nosey. This class is responsible
|
4
|
+
# for reseting probes.
|
5
|
+
class Base
|
6
|
+
attr_reader :name
|
7
|
+
attr_accessor :value
|
8
|
+
|
9
|
+
def initialize(name=nil, value=nil)
|
10
|
+
@name, @value = name, value
|
11
|
+
end
|
12
|
+
|
13
|
+
# Set the value (don't increment or whateves)
|
14
|
+
def set(value)
|
15
|
+
@value = value
|
16
|
+
end
|
17
|
+
|
18
|
+
# Reset the value to nil
|
19
|
+
def reset
|
20
|
+
@value = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
# Representation of this probe
|
24
|
+
def to_hash
|
25
|
+
{ name => value }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Calulcates a min, max, and avg for a given number of samples
|
30
|
+
class Sampler < Base
|
31
|
+
attr_reader :min, :max, :sum, :count
|
32
|
+
|
33
|
+
def initialize(*args)
|
34
|
+
reset
|
35
|
+
super(*args)
|
36
|
+
end
|
37
|
+
|
38
|
+
def sample(value)
|
39
|
+
@min = @max = value unless @min and @max
|
40
|
+
|
41
|
+
@min = value if value < @min
|
42
|
+
@max = value if value > @max
|
43
|
+
@sum += value
|
44
|
+
@count += 1
|
45
|
+
|
46
|
+
to_hash
|
47
|
+
end
|
48
|
+
|
49
|
+
def avg
|
50
|
+
sum / count if count > 0 and sum
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_hash
|
54
|
+
{
|
55
|
+
'max' => max,
|
56
|
+
'min' => min,
|
57
|
+
'sum' => sum,
|
58
|
+
'avg' => avg,
|
59
|
+
'count' => count
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def value
|
64
|
+
to_hash
|
65
|
+
end
|
66
|
+
|
67
|
+
def reset
|
68
|
+
@min = @max = nil
|
69
|
+
@sum = @count = 0
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Count up/down values.
|
74
|
+
class Counter < Base
|
75
|
+
def increment(by=1)
|
76
|
+
change by
|
77
|
+
end
|
78
|
+
|
79
|
+
def decrement(by=1)
|
80
|
+
change -by
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
def change(by)
|
85
|
+
self.value ||= 0 # Init at 0 if the stat is nil
|
86
|
+
self.value += by
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class Touch < Base
|
91
|
+
def touch
|
92
|
+
self.value = Time.now
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Contains a collection of probes that calculate velocities, counts, etc.
|
98
|
+
class Probe::Set
|
99
|
+
attr_reader :name
|
100
|
+
|
101
|
+
def initialize(name)
|
102
|
+
@name = name
|
103
|
+
yield self if block_given?
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
107
|
+
# Increment a counter probe
|
108
|
+
def increment(key,by=1)
|
109
|
+
ensure_probe(Probe::Counter, key).increment(by)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Decrement a counter probe
|
113
|
+
def decrement(key,by=1)
|
114
|
+
ensure_probe(Probe::Counter, key).decrement(by)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Sample a number and get a sum/avg/count/min/max
|
118
|
+
def sample(key,val)
|
119
|
+
ensure_probe(Probe::Sampler, key).sample(val)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Touch a timestamp probe
|
123
|
+
def touch(key)
|
124
|
+
ensure_probe(Probe::Touch, key).touch
|
125
|
+
end
|
126
|
+
|
127
|
+
# List of all the probes that are active
|
128
|
+
def probes
|
129
|
+
@probes ||= Hash.new
|
130
|
+
end
|
131
|
+
|
132
|
+
# Get a probe and do all sorts of crazy stuff to it.
|
133
|
+
def probe(key)
|
134
|
+
probes[key]
|
135
|
+
end
|
136
|
+
|
137
|
+
# Generate a report with this ProbeSet
|
138
|
+
def report
|
139
|
+
Report.new do |r|
|
140
|
+
r.probe_sets << self
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
# This factory creates probes based on the methods called from
|
146
|
+
# the instrumentation. If a probe doesn't exist, we create an instance
|
147
|
+
# from the klass and args passed in, then set the thing up in the hash key.
|
148
|
+
def ensure_probe(klass, key, *args)
|
149
|
+
probes[key] ||= klass.new(key, *args)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
data/lib/nosey/report.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Nosey
|
2
|
+
class Report
|
3
|
+
attr_reader :probe_sets
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
yield self if block_given?
|
7
|
+
self
|
8
|
+
end
|
9
|
+
|
10
|
+
def probe_sets
|
11
|
+
@probe_sets ||= Array.new
|
12
|
+
end
|
13
|
+
|
14
|
+
# Hash representation of all the probe_sets. This gives is an intermediate
|
15
|
+
# format that we can parse from other systems or code that needs reporting
|
16
|
+
# data for formatting, or whatever.
|
17
|
+
def to_hash
|
18
|
+
# Drop the probes into the report
|
19
|
+
probe_sets.inject({}) { |report, set|
|
20
|
+
report[set.name.to_s] = set.probes.inject({}) { |memo, (_, probe)|
|
21
|
+
memo[probe.name] = probe.value
|
22
|
+
memo
|
23
|
+
}
|
24
|
+
report
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
# String representation of all the probe_sets that's suitable for
|
29
|
+
# flushing out over a socket.
|
30
|
+
def to_s
|
31
|
+
to_hash.to_yaml
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/nosey/version.rb
CHANGED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nosey::Munin::Graph do
|
4
|
+
before(:each) do
|
5
|
+
@report = Nosey::Report.new do |r|
|
6
|
+
3.times do |n|
|
7
|
+
r.probe_sets << Nosey::Probe::Set.new("Group #{n}") do |s|
|
8
|
+
s.touch 'generated-at'
|
9
|
+
s.increment 'hit'
|
10
|
+
s.sample 'chopper', 2
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
@graph = Nosey::Munin::Graph.new(@report.to_s) do |g|
|
16
|
+
g.title = "Test Graph"
|
17
|
+
g.vertical_label = "Response times"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "configuration" do
|
22
|
+
before(:each) do
|
23
|
+
@text = @graph.configure
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should have title" do
|
27
|
+
@text.scan(/graph_title Test Graph/).should have(1).item
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should have default App category" do
|
31
|
+
@text.scan(/graph_category App/).should have(1).item
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should have a vertical axis label" do
|
35
|
+
@text.scan(/graph_vlabel Response times/).should have(1).item
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should have labels" do
|
39
|
+
@text.scan(/[A-Za-z0-9_]+\.label .+\n/).should have(7).items
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "sample" do
|
44
|
+
before(:each) do
|
45
|
+
@text = @graph.sample
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should have values" do
|
49
|
+
@text.scan(/[A-Za-z0-9_]+\.value .+\n/).should have(7).items
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nosey::Probe::Set do
|
4
|
+
before(:each) do
|
5
|
+
@probes = Nosey::Probe::Set.new("My Probe Set")
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should have name" do
|
9
|
+
@probes.name.should eql("My Probe Set")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should increment" do
|
13
|
+
@probes.increment('count').should eql(1)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should decrement" do
|
17
|
+
@probes.decrement('count').should eql(-1)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should touch" do
|
21
|
+
@probes.touch('touched-at').should be_instance_of(Time)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should sample" do
|
25
|
+
@probes.sample('foobers', 1).should be_instance_of(Hash)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should get probe" do
|
29
|
+
@probes.touch('barf')
|
30
|
+
@probes.probe('barf').should be_instance_of(Nosey::Probe::Touch)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return report" do
|
34
|
+
@probes.report.probe_sets.first.should eql(@probes)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe Nosey::Probe::Counter do
|
39
|
+
before(:all) do
|
40
|
+
@counter = Nosey::Probe::Counter.new
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should init null" do
|
44
|
+
@counter.value.should be_nil
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should increment" do
|
48
|
+
@counter.increment.should eql(1)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should decrement" do
|
52
|
+
@counter.decrement(2).should eql(-1)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should set" do
|
56
|
+
@counter.set(0).should eql(0)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe Nosey::Probe::Touch do
|
61
|
+
before(:all) do
|
62
|
+
@touch = Nosey::Probe::Touch.new
|
63
|
+
end
|
64
|
+
it "should init null" do
|
65
|
+
@touch.value.should be_nil
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should touch" do
|
69
|
+
@touch.touch
|
70
|
+
@touch.value.should_not be_nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe Nosey::Probe::Sampler do
|
75
|
+
before(:each) do
|
76
|
+
@counter = Nosey::Probe::Sampler.new
|
77
|
+
@counter.sample 1
|
78
|
+
@counter.sample 2
|
79
|
+
@counter.sample 3
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should init hash" do
|
83
|
+
@counter.value.should be_instance_of(Hash)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should have avg" do
|
87
|
+
@counter.value['avg'].should eql(2)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should have sum" do
|
91
|
+
@counter.value['sum'].should eql(6)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should have min" do
|
95
|
+
@counter.value['min'].should eql(1)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should have max" do
|
99
|
+
@counter.value['max'].should eql(3)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should have count" do
|
103
|
+
@counter.value['count'].should eql(3)
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nosey::Report do
|
4
|
+
before(:each) do
|
5
|
+
@report = Nosey::Report.new do |r|
|
6
|
+
3.times do |n|
|
7
|
+
r.probe_sets << Nosey::Probe::Set.new("Group #{n}") do |set|
|
8
|
+
set.touch 'generated-at'
|
9
|
+
set.increment 'hit'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "report hash" do
|
16
|
+
it "should have groups" do
|
17
|
+
@report.to_hash.keys.should include('Group 0', 'Group 1', 'Group 2')
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should have probes" do
|
21
|
+
@report.to_hash['Group 1'].keys.should include('generated-at', 'hit')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should generate report YML for string" do
|
26
|
+
# Spot check for a probe key
|
27
|
+
YAML.load(@report.to_s)['Group 2'].keys.should include('generated-at')
|
28
|
+
end
|
29
|
+
end
|
data/spec/lib/nosey_spec.rb
CHANGED
@@ -22,147 +22,4 @@ describe EventMachine::Nosey::SocketServer do
|
|
22
22
|
}
|
23
23
|
ly{ @response }.test{|response| YAML.load(response).is_a?(Hash) }
|
24
24
|
end
|
25
|
-
end
|
26
|
-
|
27
|
-
describe Nosey::Report do
|
28
|
-
before(:each) do
|
29
|
-
@report = Nosey::Report.new do |r|
|
30
|
-
3.times do |n|
|
31
|
-
r.probe_sets << Nosey::Probe::Set.new("Group #{n}") do |set|
|
32
|
-
set.touch 'generated-at'
|
33
|
-
set.increment 'hit'
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
context "report hash" do
|
40
|
-
it "should have groups" do
|
41
|
-
@report.to_hash.keys.should include('Group 0', 'Group 1', 'Group 2')
|
42
|
-
end
|
43
|
-
|
44
|
-
it "should have probes" do
|
45
|
-
@report.to_hash['Group 1'].keys.should include('generated-at', 'hit')
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
it "should generate report YML for string" do
|
50
|
-
# Spot check for a probe key
|
51
|
-
YAML.load(@report.to_s)['Group 2'].keys.should include('generated-at')
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
describe Nosey::Probe::Set do
|
56
|
-
before(:each) do
|
57
|
-
@probes = Nosey::Probe::Set.new("My Probe Set")
|
58
|
-
end
|
59
|
-
|
60
|
-
it "should have name" do
|
61
|
-
@probes.name.should eql("My Probe Set")
|
62
|
-
end
|
63
|
-
|
64
|
-
it "should increment" do
|
65
|
-
@probes.increment('count').should eql(1)
|
66
|
-
end
|
67
|
-
|
68
|
-
it "should decrement" do
|
69
|
-
@probes.decrement('count').should eql(-1)
|
70
|
-
end
|
71
|
-
|
72
|
-
it "should touch" do
|
73
|
-
@probes.touch('touched-at').should be_instance_of(Time)
|
74
|
-
end
|
75
|
-
|
76
|
-
it "should sample" do
|
77
|
-
@probes.sample('foobers', 1).should be_instance_of(Hash)
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should get probe" do
|
81
|
-
@probes.touch('barf')
|
82
|
-
@probes.probe('barf').should be_instance_of(Nosey::Probe::Touch)
|
83
|
-
end
|
84
|
-
|
85
|
-
it "should return report" do
|
86
|
-
@probes.report.probe_sets.first.should eql(@probes)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
describe Nosey::Probe::Counter do
|
91
|
-
before(:all) do
|
92
|
-
@counter = Nosey::Probe::Counter.new
|
93
|
-
end
|
94
|
-
|
95
|
-
it "should init null" do
|
96
|
-
@counter.value.should be_nil
|
97
|
-
end
|
98
|
-
|
99
|
-
it "should increment" do
|
100
|
-
@counter.increment.should eql(1)
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should decrement" do
|
104
|
-
@counter.decrement(2).should eql(-1)
|
105
|
-
end
|
106
|
-
|
107
|
-
it "should set" do
|
108
|
-
@counter.set(0).should eql(0)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
describe Nosey::Probe::Touch do
|
113
|
-
before(:all) do
|
114
|
-
@touch = Nosey::Probe::Touch.new
|
115
|
-
end
|
116
|
-
it "should init null" do
|
117
|
-
@touch.value.should be_nil
|
118
|
-
end
|
119
|
-
|
120
|
-
it "should touch" do
|
121
|
-
@touch.touch
|
122
|
-
@touch.value.should_not be_nil
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
describe Nosey::Probe::Sampler do
|
127
|
-
before(:each) do
|
128
|
-
@counter = Nosey::Probe::Sampler.new
|
129
|
-
@counter.sample 1
|
130
|
-
@counter.sample 2
|
131
|
-
@counter.sample 3
|
132
|
-
end
|
133
|
-
|
134
|
-
it "should init hash" do
|
135
|
-
@counter.value.should be_instance_of(Hash)
|
136
|
-
end
|
137
|
-
|
138
|
-
it "should have avg" do
|
139
|
-
@counter.value['avg'].should eql(2)
|
140
|
-
end
|
141
|
-
|
142
|
-
it "should have sum" do
|
143
|
-
@counter.value['sum'].should eql(6)
|
144
|
-
end
|
145
|
-
|
146
|
-
it "should have min" do
|
147
|
-
@counter.value['min'].should eql(1)
|
148
|
-
end
|
149
|
-
|
150
|
-
it "should have max" do
|
151
|
-
@counter.value['max'].should eql(3)
|
152
|
-
end
|
153
|
-
|
154
|
-
it "should have count" do
|
155
|
-
@counter.value['count'].should eql(3)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
|
160
|
-
describe Nosey::Instrumentation do
|
161
|
-
before(:each) do
|
162
|
-
@instance = Nosey::Test::VanillaClass.new
|
163
|
-
end
|
164
|
-
|
165
|
-
it "should have nosey Probe::Set instance" do
|
166
|
-
@instance.nosey.should be_instance_of Nosey::Probe::Set
|
167
|
-
end
|
168
25
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Brad Gessler
|
@@ -129,8 +129,17 @@ files:
|
|
129
129
|
- README.md
|
130
130
|
- Rakefile
|
131
131
|
- lib/nosey.rb
|
132
|
+
- lib/nosey/eventmachine.rb
|
133
|
+
- lib/nosey/instrumentation.rb
|
134
|
+
- lib/nosey/munin.rb
|
135
|
+
- lib/nosey/probe.rb
|
136
|
+
- lib/nosey/report.rb
|
132
137
|
- lib/nosey/version.rb
|
133
138
|
- nosey.gemspec
|
139
|
+
- spec/lib/nosey/instrumentation_spec.rb
|
140
|
+
- spec/lib/nosey/munin_spec.rb
|
141
|
+
- spec/lib/nosey/probe_spec.rb
|
142
|
+
- spec/lib/nosey/report_spec.rb
|
134
143
|
- spec/lib/nosey_spec.rb
|
135
144
|
- spec/spec_helper.rb
|
136
145
|
has_rdoc: true
|
@@ -164,5 +173,9 @@ signing_key:
|
|
164
173
|
specification_version: 3
|
165
174
|
summary: Instrument Ruby EventMachine applications
|
166
175
|
test_files:
|
176
|
+
- spec/lib/nosey/instrumentation_spec.rb
|
177
|
+
- spec/lib/nosey/munin_spec.rb
|
178
|
+
- spec/lib/nosey/probe_spec.rb
|
179
|
+
- spec/lib/nosey/report_spec.rb
|
167
180
|
- spec/lib/nosey_spec.rb
|
168
181
|
- spec/spec_helper.rb
|