metricsd 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/CHANGELOG.md +16 -0
- data/Rakefile +6 -0
- data/lib/metricsd/client.rb +91 -21
- data/lib/metricsd/version.rb +1 -1
- data/lib/metricsd.rb +38 -0
- data/metricsd.gemspec +1 -0
- data/spec/client_spec.rb +9 -1
- data/spec/metricsd_spec.rb +19 -0
- metadata +22 -7
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
## 0.2.0 (July 27, 2011)
|
|
2
|
+
|
|
3
|
+
Features:
|
|
4
|
+
|
|
5
|
+
- Added an option to enable or disable client
|
|
6
|
+
|
|
7
|
+
## 0.1.0 (July 26, 2011)
|
|
8
|
+
|
|
9
|
+
Features:
|
|
10
|
+
|
|
11
|
+
- Complete MetricsD protocol implementation
|
|
12
|
+
- Allows to send multiple metrics in a single network packet
|
|
13
|
+
- Splits metrics to several packets of 250 bytes or less
|
|
14
|
+
- Allows to specify metrics parts separator (temporary solution until all the metrics will be migrated to "." separator)
|
|
15
|
+
- Logs network problems to logger and never throws errors like this.
|
|
16
|
+
- 100% test coverage
|
data/Rakefile
CHANGED
data/lib/metricsd/client.rb
CHANGED
|
@@ -25,7 +25,7 @@ module Metricsd
|
|
|
25
25
|
# 'db.pool.pending' => db_stats[:pending],
|
|
26
26
|
# }, :group => 'doc_timestamp')
|
|
27
27
|
#
|
|
28
|
-
# You can specify message source using
|
|
28
|
+
# You can specify message source using <tt>:source => 'src'</tt> option. In this case
|
|
29
29
|
# you will be able to see summary graphs and graphs per source:
|
|
30
30
|
#
|
|
31
31
|
# # Generate graphs for all tables, and each single table.
|
|
@@ -39,7 +39,7 @@ module Metricsd
|
|
|
39
39
|
# # ... or you can pass an empty string with the same effect.
|
|
40
40
|
# Metricsd::Client.record_success("hbase.reads", :source => '')
|
|
41
41
|
#
|
|
42
|
-
# You can group your metrics using
|
|
42
|
+
# You can group your metrics using <tt>:group</tt> option. In this case metrics will be
|
|
43
43
|
# displayed together on the summary page.
|
|
44
44
|
#
|
|
45
45
|
# # Group metrics using :group option.
|
|
@@ -51,6 +51,19 @@ module Metricsd
|
|
|
51
51
|
class << self
|
|
52
52
|
# Record complete hit info. Time should be a floating point
|
|
53
53
|
# number of seconds.
|
|
54
|
+
#
|
|
55
|
+
# It creates two metrics:
|
|
56
|
+
# * +your.metric.count+ with counts of failed and succeded events
|
|
57
|
+
# * +your.metric.time+ with time statistics
|
|
58
|
+
#
|
|
59
|
+
# @param [String] metric is the metric name (like app.docs.upload)
|
|
60
|
+
# @param [Boolean] is_success indicating whether request was successful.
|
|
61
|
+
# @param [Float] time floating point number of seconds.
|
|
62
|
+
# @param [Hash] opts options.
|
|
63
|
+
# @option opts [String] :sep ("_") separator used to add suffixes +count+ and +time+.
|
|
64
|
+
# @option opts [String] :group metrics group.
|
|
65
|
+
# @option opts [String] :source metric source.
|
|
66
|
+
#
|
|
54
67
|
def record_hit(metric, is_success, time, opts = {})
|
|
55
68
|
sep = opts[:sep] || opts[:separator] || '_'
|
|
56
69
|
record_internal({
|
|
@@ -60,26 +73,51 @@ module Metricsd
|
|
|
60
73
|
)
|
|
61
74
|
end
|
|
62
75
|
|
|
63
|
-
# Record
|
|
76
|
+
# Record succeded boolean event.
|
|
77
|
+
#
|
|
78
|
+
# It creates a single metric:
|
|
79
|
+
# * +your.metric.count+ with numbers of failed and succeded events
|
|
80
|
+
#
|
|
81
|
+
# @param [String] metric is the metric name (like app.docs.upload)
|
|
82
|
+
# @param [Hash] opts options.
|
|
83
|
+
# @option opts [String] :sep ("_") separator used to add suffixes +count+ and +time+.
|
|
84
|
+
# @option opts [String] :group metrics group.
|
|
85
|
+
# @option opts [String] :source metric source.
|
|
86
|
+
#
|
|
64
87
|
def record_success(metric, opts = {})
|
|
65
88
|
sep = opts[:sep] || opts[:separator] || '_'
|
|
66
|
-
record_internal({
|
|
67
|
-
"#{metric}#{sep}count" => 1
|
|
68
|
-
}, opts
|
|
69
|
-
)
|
|
89
|
+
record_internal({"#{metric}#{sep}count" => 1}, opts)
|
|
70
90
|
end
|
|
71
91
|
|
|
72
|
-
# Record
|
|
92
|
+
# Record failed boolean event.
|
|
93
|
+
#
|
|
94
|
+
# It creates a single metric:
|
|
95
|
+
# * +your.metric.count+ with numbers of failed and succeded events
|
|
96
|
+
#
|
|
97
|
+
# @param [String] metric is the metric name (like app.docs.upload)
|
|
98
|
+
# @param [Hash] opts options.
|
|
99
|
+
# @option opts [String] :sep ("_") separator used to add suffixes +count+ and +time+.
|
|
100
|
+
# @option opts [String] :group metrics group.
|
|
101
|
+
# @option opts [String] :source metric source.
|
|
102
|
+
#
|
|
73
103
|
def record_failure(metric, opts = {})
|
|
74
104
|
sep = opts[:sep] || opts[:separator] || '_'
|
|
75
|
-
record_internal({
|
|
76
|
-
"#{metric}#{sep}count" => -1
|
|
77
|
-
}, opts
|
|
78
|
-
)
|
|
105
|
+
record_internal({"#{metric}#{sep}count" => -1}, opts)
|
|
79
106
|
end
|
|
80
107
|
|
|
81
108
|
# Record timing info. Time should be a floating point
|
|
82
109
|
# number of seconds.
|
|
110
|
+
#
|
|
111
|
+
# It creates a single metric:
|
|
112
|
+
# * +your.metric.time+ with time statistics
|
|
113
|
+
#
|
|
114
|
+
# @param [String] metric is the metric name (like app.docs.upload)
|
|
115
|
+
# @param [Float] time floating point number of seconds.
|
|
116
|
+
# @param [Hash] opts options.
|
|
117
|
+
# @option opts [String] :sep ("_") separator used to add suffixes +count+ and +time+.
|
|
118
|
+
# @option opts [String] :group metrics group.
|
|
119
|
+
# @option opts [String] :source metric source.
|
|
120
|
+
#
|
|
83
121
|
def record_time(metric, time = nil, opts = {}, &block)
|
|
84
122
|
opts, time = time, nil if Hash === time
|
|
85
123
|
sep = opts[:sep] || opts[:separator] || '_'
|
|
@@ -87,31 +125,55 @@ module Metricsd
|
|
|
87
125
|
raise ArgumentError, "You should pass a block if time is not given" unless block_given?
|
|
88
126
|
time = Benchmark.measure(&block).real
|
|
89
127
|
end
|
|
90
|
-
record_internal({
|
|
91
|
-
"#{metric}#{sep}time" => (time * 1000).round
|
|
92
|
-
}, opts
|
|
93
|
-
)
|
|
128
|
+
record_internal({"#{metric}#{sep}time" => (time * 1000).round}, opts)
|
|
94
129
|
end
|
|
95
130
|
|
|
96
131
|
# Record an integer value.
|
|
132
|
+
#
|
|
133
|
+
# It creates a single metric:
|
|
134
|
+
# * +your.metric+ with values statistics
|
|
135
|
+
#
|
|
136
|
+
# @param [String] metric is the metric name (like app.docs.upload)
|
|
137
|
+
# @param [Integer] value metric value.
|
|
138
|
+
# @param [Hash] opts options.
|
|
139
|
+
# @option opts [String] :sep ("_") separator used to add suffixes +count+ and +time+.
|
|
140
|
+
# @option opts [String] :group metrics group.
|
|
141
|
+
# @option opts [String] :source metric source.
|
|
142
|
+
#
|
|
97
143
|
def record_value(metric, value, opts = {})
|
|
98
|
-
record_internal({
|
|
99
|
-
metric => value.round
|
|
100
|
-
}, opts
|
|
101
|
-
)
|
|
144
|
+
record_internal({metric => value.round}, opts)
|
|
102
145
|
end
|
|
103
146
|
|
|
104
|
-
# Record multiple values.
|
|
147
|
+
# Record multiple integer values.
|
|
148
|
+
#
|
|
149
|
+
# It creates a metric for each entry in +metrics+ Hash:
|
|
150
|
+
# * +your.metric+ with values statistics
|
|
151
|
+
#
|
|
152
|
+
# @param [Hash] metrics a +Hash+ that maps metrics names to their values.
|
|
153
|
+
# @param [Hash] opts options.
|
|
154
|
+
# @option opts [String] :sep ("_") separator used to add suffixes +count+ and +time+.
|
|
155
|
+
# @option opts [String] :group metrics group.
|
|
156
|
+
# @option opts [String] :source metric source.
|
|
157
|
+
#
|
|
158
|
+
# @example
|
|
159
|
+
# Metricsd::Client.record_values(
|
|
160
|
+
# 'db.pool.reserved' => db_stats[:reserved],
|
|
161
|
+
# 'db.pool.available' => db_stats[:available],
|
|
162
|
+
# 'db.pool.pending' => db_stats[:pending],
|
|
163
|
+
# )
|
|
164
|
+
#
|
|
105
165
|
def record_values(metrics, opts = {})
|
|
106
166
|
record_internal(metrics, opts)
|
|
107
167
|
end
|
|
108
168
|
|
|
169
|
+
# Reset and re-establish connection.
|
|
109
170
|
def reset_connection!
|
|
110
171
|
@@socket = nil
|
|
111
172
|
end
|
|
112
173
|
|
|
113
174
|
private
|
|
114
175
|
|
|
176
|
+
# Returns a UDP socket used to send metrics to MetricsD.
|
|
115
177
|
def collector_socket
|
|
116
178
|
@@socket ||= begin
|
|
117
179
|
@@socket = UDPSocket.new
|
|
@@ -121,6 +183,8 @@ module Metricsd
|
|
|
121
183
|
|
|
122
184
|
# Send informating to the RRD collector daemon using UDP protocol.
|
|
123
185
|
def record_internal(metrics, opts = {})
|
|
186
|
+
return unless Metricsd.enabled?
|
|
187
|
+
|
|
124
188
|
opts = { :source => Metricsd.default_source }.update(opts)
|
|
125
189
|
opts[:source] = Metricsd.source if opts[:source].empty?
|
|
126
190
|
|
|
@@ -128,6 +192,8 @@ module Metricsd
|
|
|
128
192
|
send_in_packets Array(metrics).map { |arg| pack(arg[0], arg[1], opts) }.sort
|
|
129
193
|
end
|
|
130
194
|
|
|
195
|
+
# Combines string representations of metrics into packets of 250 bytes and
|
|
196
|
+
# sends them to MetricsD.
|
|
131
197
|
def send_in_packets(strings)
|
|
132
198
|
msg = ''
|
|
133
199
|
strings.each do |s|
|
|
@@ -145,6 +211,8 @@ module Metricsd
|
|
|
145
211
|
safe_send(msg) if msg.size > 0
|
|
146
212
|
end
|
|
147
213
|
|
|
214
|
+
# Sends a string to the MetricsD. Should never raise any network-specific
|
|
215
|
+
# exceptions, but log them instead, and silently return.
|
|
148
216
|
def safe_send(msg)
|
|
149
217
|
collector_socket.send(msg, 0)
|
|
150
218
|
true
|
|
@@ -154,6 +222,8 @@ module Metricsd
|
|
|
154
222
|
false
|
|
155
223
|
end
|
|
156
224
|
|
|
225
|
+
# Packs metric into a string representation according to the MetricsD
|
|
226
|
+
# protocol.
|
|
157
227
|
def pack(key, value, opts)
|
|
158
228
|
key = "#{opts[:group]}$#{key}" unless opts[:group].nil? || opts[:group].empty?
|
|
159
229
|
opts[:source].empty? ? "#{key}:#{value}" : "#{opts[:source]}@#{key}:#{value}"
|
data/lib/metricsd/version.rb
CHANGED
data/lib/metricsd.rb
CHANGED
|
@@ -2,42 +2,77 @@ require 'socket'
|
|
|
2
2
|
require 'logger'
|
|
3
3
|
require 'benchmark'
|
|
4
4
|
|
|
5
|
+
# Pure Ruby client library for MetricsD server.
|
|
5
6
|
module Metricsd
|
|
6
7
|
class << self
|
|
8
|
+
# Gets the MetricsD server host. Default is "127.0.0.1".
|
|
7
9
|
def server_host
|
|
8
10
|
@@server_host
|
|
9
11
|
end
|
|
10
12
|
|
|
13
|
+
# Sets the MetricsD server host.
|
|
11
14
|
def server_host=(host)
|
|
12
15
|
@@server_host = host
|
|
13
16
|
Client.reset_connection!
|
|
14
17
|
end
|
|
15
18
|
|
|
19
|
+
# Gets the MetricsD server port. Default is 6311.
|
|
16
20
|
def server_port
|
|
17
21
|
@@server_port
|
|
18
22
|
end
|
|
19
23
|
|
|
24
|
+
# Sets the MetricsD server port.
|
|
20
25
|
def server_port=(port)
|
|
21
26
|
@@server_port = Integer(port)
|
|
22
27
|
Client.reset_connection!
|
|
23
28
|
end
|
|
24
29
|
|
|
30
|
+
# Get the value indicating whether Metricsd is enabled.
|
|
31
|
+
def enabled?
|
|
32
|
+
!!@@enabled
|
|
33
|
+
end
|
|
34
|
+
alias :enabled :enabled?
|
|
35
|
+
|
|
36
|
+
# Sets the value indicating whether Metricsd is enabled.
|
|
37
|
+
def enabled=(enabled)
|
|
38
|
+
@@enabled = !!enabled
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Enables Metricsd client.
|
|
42
|
+
def enable!
|
|
43
|
+
@@enabled = true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Disables Metricsd client.
|
|
47
|
+
def disable!
|
|
48
|
+
@@enabled = false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Gets the source used to record host-specific metrics. Default is the
|
|
52
|
+
# first part of the hostname (e.g. "test" for "test.host.com").
|
|
25
53
|
def source
|
|
26
54
|
@@source || metricsd.default_source
|
|
27
55
|
end
|
|
28
56
|
|
|
57
|
+
# Sets the source for host-specific metrics.
|
|
29
58
|
def source=(source)
|
|
30
59
|
@@source = source
|
|
31
60
|
end
|
|
32
61
|
|
|
62
|
+
# Gets the default source for all metrics. If nil or empty string — all
|
|
63
|
+
# metrics will be host-specific (MetricsD server will generate per-host
|
|
64
|
+
# graphs in addition to summary graph for all hosts for each metric).
|
|
65
|
+
# Default is "all".
|
|
33
66
|
def default_source
|
|
34
67
|
@@default_source
|
|
35
68
|
end
|
|
36
69
|
|
|
70
|
+
# Sets the default source for all metrics.
|
|
37
71
|
def default_source=(source)
|
|
38
72
|
@@default_source = source
|
|
39
73
|
end
|
|
40
74
|
|
|
75
|
+
# Gets the logger used to output errors or warnings.
|
|
41
76
|
def logger
|
|
42
77
|
@@logger ||= if defined?(Rails)
|
|
43
78
|
Rails.logger
|
|
@@ -48,13 +83,16 @@ module Metricsd
|
|
|
48
83
|
end
|
|
49
84
|
end
|
|
50
85
|
|
|
86
|
+
# Sets the logger used to output errors or warnings.
|
|
51
87
|
def logger=(logger)
|
|
52
88
|
@@logger = logger
|
|
53
89
|
end
|
|
54
90
|
|
|
91
|
+
# Resets all values to their default state (mostly for testing purpose).
|
|
55
92
|
def reset_defaults!
|
|
56
93
|
@@server_host = '127.0.0.1'
|
|
57
94
|
@@server_port = 6311
|
|
95
|
+
@@enabled = true
|
|
58
96
|
@@source = Socket.gethostname[/^([^.]+)/, 1]
|
|
59
97
|
@@default_source = 'all'
|
|
60
98
|
@@logger = nil
|
data/metricsd.gemspec
CHANGED
|
@@ -11,6 +11,7 @@ Gem::Specification.new do |s|
|
|
|
11
11
|
s.summary = %q{Client library for MetricsD server}
|
|
12
12
|
s.description = %q{}
|
|
13
13
|
|
|
14
|
+
s.add_development_dependency 'rake'
|
|
14
15
|
s.add_development_dependency 'rspec'
|
|
15
16
|
s.add_development_dependency 'guard-rspec'
|
|
16
17
|
s.add_development_dependency 'rb-fsevent'
|
data/spec/client_spec.rb
CHANGED
|
@@ -5,7 +5,9 @@ describe Metricsd::Client do
|
|
|
5
5
|
before :each do
|
|
6
6
|
@socket = mock('Socket')
|
|
7
7
|
Metricsd::Client.stub!(:collector_socket => @socket)
|
|
8
|
-
|
|
8
|
+
# Global settings
|
|
9
|
+
Metricsd.reset_defaults!
|
|
10
|
+
Metricsd.source = 'test'
|
|
9
11
|
end
|
|
10
12
|
|
|
11
13
|
describe 'connection' do
|
|
@@ -15,6 +17,12 @@ describe Metricsd::Client do
|
|
|
15
17
|
Metricsd.logger.should_receive(:error).at_least(1) # stacktrace
|
|
16
18
|
Metricsd::Client.record_value('custom.metric', 5)
|
|
17
19
|
end
|
|
20
|
+
|
|
21
|
+
it 'should not send anything to the socket if disabled' do
|
|
22
|
+
Metricsd.disable!
|
|
23
|
+
@socket.should_not_receive(:send)
|
|
24
|
+
Metricsd::Client.record_value('custom.metric', 5)
|
|
25
|
+
end
|
|
18
26
|
end
|
|
19
27
|
|
|
20
28
|
describe '.record_hit' do
|
data/spec/metricsd_spec.rb
CHANGED
|
@@ -28,6 +28,11 @@ describe Metricsd do
|
|
|
28
28
|
it 'should create logger' do
|
|
29
29
|
Metricsd.logger.should be_a(Logger)
|
|
30
30
|
end
|
|
31
|
+
|
|
32
|
+
it 'should be enabled' do
|
|
33
|
+
Metricsd.enabled?.should be_true
|
|
34
|
+
Metricsd.enabled.should be_true
|
|
35
|
+
end
|
|
31
36
|
end
|
|
32
37
|
|
|
33
38
|
context 'setters' do
|
|
@@ -47,6 +52,20 @@ describe Metricsd do
|
|
|
47
52
|
}.to raise_error
|
|
48
53
|
end
|
|
49
54
|
|
|
55
|
+
it 'should allow to enabled and disable client' do
|
|
56
|
+
Metricsd.enabled = false
|
|
57
|
+
Metricsd.should_not be_enabled
|
|
58
|
+
|
|
59
|
+
Metricsd.enable!
|
|
60
|
+
Metricsd.should be_enabled
|
|
61
|
+
|
|
62
|
+
Metricsd.disable!
|
|
63
|
+
Metricsd.should_not be_enabled
|
|
64
|
+
|
|
65
|
+
Metricsd.enabled = true
|
|
66
|
+
Metricsd.should be_enabled
|
|
67
|
+
end
|
|
68
|
+
|
|
50
69
|
it 'should allow to change source' do
|
|
51
70
|
Metricsd.source = 'test-host'
|
|
52
71
|
Metricsd.source.should == 'test-host'
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: metricsd
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 23
|
|
5
5
|
prerelease:
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
|
-
-
|
|
8
|
+
- 2
|
|
9
9
|
- 0
|
|
10
|
-
version: 0.
|
|
10
|
+
version: 0.2.0
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
13
|
- Dmytro Shteflyuk
|
|
@@ -19,7 +19,7 @@ date: 2011-07-27 00:00:00 -04:00
|
|
|
19
19
|
default_executable:
|
|
20
20
|
dependencies:
|
|
21
21
|
- !ruby/object:Gem::Dependency
|
|
22
|
-
name:
|
|
22
|
+
name: rake
|
|
23
23
|
prerelease: false
|
|
24
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
|
25
25
|
none: false
|
|
@@ -33,7 +33,7 @@ dependencies:
|
|
|
33
33
|
type: :development
|
|
34
34
|
version_requirements: *id001
|
|
35
35
|
- !ruby/object:Gem::Dependency
|
|
36
|
-
name:
|
|
36
|
+
name: rspec
|
|
37
37
|
prerelease: false
|
|
38
38
|
requirement: &id002 !ruby/object:Gem::Requirement
|
|
39
39
|
none: false
|
|
@@ -47,7 +47,7 @@ dependencies:
|
|
|
47
47
|
type: :development
|
|
48
48
|
version_requirements: *id002
|
|
49
49
|
- !ruby/object:Gem::Dependency
|
|
50
|
-
name:
|
|
50
|
+
name: guard-rspec
|
|
51
51
|
prerelease: false
|
|
52
52
|
requirement: &id003 !ruby/object:Gem::Requirement
|
|
53
53
|
none: false
|
|
@@ -61,7 +61,7 @@ dependencies:
|
|
|
61
61
|
type: :development
|
|
62
62
|
version_requirements: *id003
|
|
63
63
|
- !ruby/object:Gem::Dependency
|
|
64
|
-
name:
|
|
64
|
+
name: rb-fsevent
|
|
65
65
|
prerelease: false
|
|
66
66
|
requirement: &id004 !ruby/object:Gem::Requirement
|
|
67
67
|
none: false
|
|
@@ -74,6 +74,20 @@ dependencies:
|
|
|
74
74
|
version: "0"
|
|
75
75
|
type: :development
|
|
76
76
|
version_requirements: *id004
|
|
77
|
+
- !ruby/object:Gem::Dependency
|
|
78
|
+
name: growl
|
|
79
|
+
prerelease: false
|
|
80
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
|
81
|
+
none: false
|
|
82
|
+
requirements:
|
|
83
|
+
- - ">="
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
hash: 3
|
|
86
|
+
segments:
|
|
87
|
+
- 0
|
|
88
|
+
version: "0"
|
|
89
|
+
type: :development
|
|
90
|
+
version_requirements: *id005
|
|
77
91
|
description: ""
|
|
78
92
|
email:
|
|
79
93
|
- kpumuk@kpumuk.info
|
|
@@ -86,6 +100,7 @@ extra_rdoc_files: []
|
|
|
86
100
|
files:
|
|
87
101
|
- .gitignore
|
|
88
102
|
- .rvmrc
|
|
103
|
+
- CHANGELOG.md
|
|
89
104
|
- Gemfile
|
|
90
105
|
- Guardfile
|
|
91
106
|
- README.md
|