nosey 0.0.1 → 0.0.2
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.
- 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
|