metricsd 0.1.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 +4 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/README.md +66 -0
- data/Rakefile +1 -0
- data/lib/metricsd/client.rb +163 -0
- data/lib/metricsd/version.rb +3 -0
- data/lib/metricsd.rb +68 -0
- data/metricsd.gemspec +23 -0
- data/spec/client_spec.rb +214 -0
- data/spec/metricsd_spec.rb +65 -0
- metadata +135 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ree-1.8.7-2011.03@metricsd --create
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Metricsd
|
2
|
+
|
3
|
+
Metricsd is a pure Ruby client library for the [MetricsD](https://github.com/kpumuk/metricsd) server.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add the "metricsd" gem to your `Gemfile`.
|
8
|
+
|
9
|
+
gem 'metricsd'
|
10
|
+
|
11
|
+
And run `bundle install` command.
|
12
|
+
|
13
|
+
## Getting started
|
14
|
+
|
15
|
+
You can configure Metricsd connection parameters by accessing attributes of `Metricsd` module:
|
16
|
+
|
17
|
+
Metricsd.server_host = 'metrics.local'
|
18
|
+
Metricsd.server_port = 6311
|
19
|
+
|
20
|
+
There are few more setting, please check project documentation.
|
21
|
+
|
22
|
+
Now you should be able to record you metrics:
|
23
|
+
|
24
|
+
# Record success hit
|
25
|
+
Metricsd::Client.record_success("api.docs.upload")
|
26
|
+
# Record failure hit
|
27
|
+
Metricsd::Client.record_failure("api.docs.upload")
|
28
|
+
# Record timing info
|
29
|
+
Metricsd::Client.record_time("api.docs.upload", 0.14)
|
30
|
+
# Record complete success hit info (count + timing)
|
31
|
+
Metricsd::Client.record_hit("api.docs.upload", true, 0.14)
|
32
|
+
# Record an integer value
|
33
|
+
Metricsd::Client.record_value("user.password.size", 15)
|
34
|
+
Metricsd::Client.record_value("user.age", 26)
|
35
|
+
|
36
|
+
You can combine you metrics to send them in a single network packet for performance reason:
|
37
|
+
|
38
|
+
# Send all database pool stats
|
39
|
+
Metricsd::Client.record_values({
|
40
|
+
'db.pool.reserved' => db_stats[:reserved],
|
41
|
+
'db.pool.available' => db_stats[:available],
|
42
|
+
'db.pool.pending' => db_stats[:pending],
|
43
|
+
}, :group => 'doc_timestamp')
|
44
|
+
|
45
|
+
You can specify message source using :source => 'src' option. In this case you will be able to see summary graphs and graphs per source:
|
46
|
+
|
47
|
+
# Generate graphs for all tables, and each single table.
|
48
|
+
Metricsd::Client.record_success("hbase.reads", :source => @hbase_table)
|
49
|
+
|
50
|
+
By default only summary statistics is calculated. You can enable per-host graphs by specifying the appropriate source:
|
51
|
+
|
52
|
+
# Generate summary graph for all hosts, and graphs for each single host.
|
53
|
+
Metricsd::Client.record_success("hbase.reads", :source => Metricsd::Client.source)
|
54
|
+
# ... or you can pass an empty string with the same effect.
|
55
|
+
Metricsd::Client.record_success("hbase.reads", :source => '')
|
56
|
+
|
57
|
+
You can group your metrics using :group option. In this case metrics will be displayed together on the summary page.
|
58
|
+
|
59
|
+
# Group metrics using :group option.
|
60
|
+
Metricsd::Client.record_success("reads", :source => @hbase_table, :group => 'hbase')
|
61
|
+
# Group metrics using special syntax "group$metric".
|
62
|
+
Metricsd::Client.record_success("hbase$reads", :source => @hbase_table)
|
63
|
+
|
64
|
+
## More info
|
65
|
+
|
66
|
+
Check the [Project Documentation](http://rubydoc.info/gems/metricsd/) or check the tests to find out how to use this client.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
@@ -0,0 +1,163 @@
|
|
1
|
+
module Metricsd
|
2
|
+
# Client class implements MetricsD protocol, allowing to send various metrics
|
3
|
+
# to the MetricsD server for collecting, analyzing, and graphing them.
|
4
|
+
#
|
5
|
+
# Class allows to record count and timing stats to the database:
|
6
|
+
#
|
7
|
+
# # Record success hit
|
8
|
+
# Metricsd::Client.record_success("api.docs.upload")
|
9
|
+
# # Record failure hit
|
10
|
+
# Metricsd::Client.record_failure("api.docs.upload")
|
11
|
+
# # Record timing info
|
12
|
+
# Metricsd::Client.record_time("api.docs.upload", 0.14)
|
13
|
+
# # Record complete success hit info (count + timing)
|
14
|
+
# Metricsd::Client.record_hit("api.docs.upload", true, 0.14)
|
15
|
+
# # Record an integer value
|
16
|
+
# Metricsd::Client.record_value("user.password.size", 15)
|
17
|
+
# Metricsd::Client.record_value("user.age", 26)
|
18
|
+
#
|
19
|
+
# To send several metrics in a single network packet, you can use record_values:
|
20
|
+
#
|
21
|
+
# # Send all database pool stats
|
22
|
+
# Metricsd::Client.record_values({
|
23
|
+
# 'db.pool.reserved' => db_stats[:reserved],
|
24
|
+
# 'db.pool.available' => db_stats[:available],
|
25
|
+
# 'db.pool.pending' => db_stats[:pending],
|
26
|
+
# }, :group => 'doc_timestamp')
|
27
|
+
#
|
28
|
+
# You can specify message source using :source => 'src' option. In this case
|
29
|
+
# you will be able to see summary graphs and graphs per source:
|
30
|
+
#
|
31
|
+
# # Generate graphs for all tables, and each single table.
|
32
|
+
# Metricsd::Client.record_success("hbase.reads", :source => @hbase_table)
|
33
|
+
#
|
34
|
+
# By default only summary statistics is calculated. You can enable per-host graphs
|
35
|
+
# by specifying the appropriate source:
|
36
|
+
#
|
37
|
+
# # Generate summary graph for all hosts, and graphs for each single host.
|
38
|
+
# Metricsd::Client.record_success("hbase.reads", :source => Metricsd::Client.source)
|
39
|
+
# # ... or you can pass an empty string with the same effect.
|
40
|
+
# Metricsd::Client.record_success("hbase.reads", :source => '')
|
41
|
+
#
|
42
|
+
# You can group your metrics using :group option. In this case metrics will be
|
43
|
+
# displayed together on the summary page.
|
44
|
+
#
|
45
|
+
# # Group metrics using :group option.
|
46
|
+
# Metricsd::Client.record_success("reads", :source => @hbase_table, :group => 'hbase')
|
47
|
+
# # Group metrics using special syntax "group$metric".
|
48
|
+
# Metricsd::Client.record_success("hbase$reads", :source => @hbase_table)
|
49
|
+
#
|
50
|
+
class Client
|
51
|
+
class << self
|
52
|
+
# Record complete hit info. Time should be a floating point
|
53
|
+
# number of seconds.
|
54
|
+
def record_hit(metric, is_success, time, opts = {})
|
55
|
+
sep = opts[:sep] || opts[:separator] || '_'
|
56
|
+
record_internal({
|
57
|
+
"#{metric}#{sep}count" => is_success ? 1 : -1,
|
58
|
+
"#{metric}#{sep}time" => (time * 1000).round
|
59
|
+
}, opts
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Record success hit.
|
64
|
+
def record_success(metric, opts = {})
|
65
|
+
sep = opts[:sep] || opts[:separator] || '_'
|
66
|
+
record_internal({
|
67
|
+
"#{metric}#{sep}count" => 1
|
68
|
+
}, opts
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Record success failure.
|
73
|
+
def record_failure(metric, opts = {})
|
74
|
+
sep = opts[:sep] || opts[:separator] || '_'
|
75
|
+
record_internal({
|
76
|
+
"#{metric}#{sep}count" => -1
|
77
|
+
}, opts
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Record timing info. Time should be a floating point
|
82
|
+
# number of seconds.
|
83
|
+
def record_time(metric, time = nil, opts = {}, &block)
|
84
|
+
opts, time = time, nil if Hash === time
|
85
|
+
sep = opts[:sep] || opts[:separator] || '_'
|
86
|
+
if time.nil?
|
87
|
+
raise ArgumentError, "You should pass a block if time is not given" unless block_given?
|
88
|
+
time = Benchmark.measure(&block).real
|
89
|
+
end
|
90
|
+
record_internal({
|
91
|
+
"#{metric}#{sep}time" => (time * 1000).round
|
92
|
+
}, opts
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Record an integer value.
|
97
|
+
def record_value(metric, value, opts = {})
|
98
|
+
record_internal({
|
99
|
+
metric => value.round
|
100
|
+
}, opts
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Record multiple values.
|
105
|
+
def record_values(metrics, opts = {})
|
106
|
+
record_internal(metrics, opts)
|
107
|
+
end
|
108
|
+
|
109
|
+
def reset_connection!
|
110
|
+
@@socket = nil
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def collector_socket
|
116
|
+
@@socket ||= begin
|
117
|
+
@@socket = UDPSocket.new
|
118
|
+
@@socket.connect(Metricsd.server_host, Metricsd.server_port)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Send informating to the RRD collector daemon using UDP protocol.
|
123
|
+
def record_internal(metrics, opts = {})
|
124
|
+
opts = { :source => Metricsd.default_source }.update(opts)
|
125
|
+
opts[:source] = Metricsd.source if opts[:source].empty?
|
126
|
+
|
127
|
+
# Build the message for
|
128
|
+
send_in_packets Array(metrics).map { |arg| pack(arg[0], arg[1], opts) }.sort
|
129
|
+
end
|
130
|
+
|
131
|
+
def send_in_packets(strings)
|
132
|
+
msg = ''
|
133
|
+
strings.each do |s|
|
134
|
+
if s.size > 250
|
135
|
+
Metricsd.logger.warn("Message is larger than 250 bytes, so it was ignored: #{s}")
|
136
|
+
next
|
137
|
+
end
|
138
|
+
|
139
|
+
if msg.size + s.size + (msg.size > 0 ? 1 : 0) > 250
|
140
|
+
safe_send(msg)
|
141
|
+
msg = ''
|
142
|
+
end
|
143
|
+
msg << (msg.size > 0 ? ';' : '') << s
|
144
|
+
end
|
145
|
+
safe_send(msg) if msg.size > 0
|
146
|
+
end
|
147
|
+
|
148
|
+
def safe_send(msg)
|
149
|
+
collector_socket.send(msg, 0)
|
150
|
+
true
|
151
|
+
rescue Errno::ECONNREFUSED => e
|
152
|
+
Metricsd.logger.error("Exception occurred while trying to send data to metricsd: #{e.inspect}")
|
153
|
+
e.backtrace.each { |line| Metricsd.logger.error(line) }
|
154
|
+
false
|
155
|
+
end
|
156
|
+
|
157
|
+
def pack(key, value, opts)
|
158
|
+
key = "#{opts[:group]}$#{key}" unless opts[:group].nil? || opts[:group].empty?
|
159
|
+
opts[:source].empty? ? "#{key}:#{value}" : "#{opts[:source]}@#{key}:#{value}"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
data/lib/metricsd.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'logger'
|
3
|
+
require 'benchmark'
|
4
|
+
|
5
|
+
module Metricsd
|
6
|
+
class << self
|
7
|
+
def server_host
|
8
|
+
@@server_host
|
9
|
+
end
|
10
|
+
|
11
|
+
def server_host=(host)
|
12
|
+
@@server_host = host
|
13
|
+
Client.reset_connection!
|
14
|
+
end
|
15
|
+
|
16
|
+
def server_port
|
17
|
+
@@server_port
|
18
|
+
end
|
19
|
+
|
20
|
+
def server_port=(port)
|
21
|
+
@@server_port = Integer(port)
|
22
|
+
Client.reset_connection!
|
23
|
+
end
|
24
|
+
|
25
|
+
def source
|
26
|
+
@@source || metricsd.default_source
|
27
|
+
end
|
28
|
+
|
29
|
+
def source=(source)
|
30
|
+
@@source = source
|
31
|
+
end
|
32
|
+
|
33
|
+
def default_source
|
34
|
+
@@default_source
|
35
|
+
end
|
36
|
+
|
37
|
+
def default_source=(source)
|
38
|
+
@@default_source = source
|
39
|
+
end
|
40
|
+
|
41
|
+
def logger
|
42
|
+
@@logger ||= if defined?(Rails)
|
43
|
+
Rails.logger
|
44
|
+
elsif defined?(Loops)
|
45
|
+
Loops.logger
|
46
|
+
else
|
47
|
+
Logger.new(STDOUT)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def logger=(logger)
|
52
|
+
@@logger = logger
|
53
|
+
end
|
54
|
+
|
55
|
+
def reset_defaults!
|
56
|
+
@@server_host = '127.0.0.1'
|
57
|
+
@@server_port = 6311
|
58
|
+
@@source = Socket.gethostname[/^([^.]+)/, 1]
|
59
|
+
@@default_source = 'all'
|
60
|
+
@@logger = nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
reset_defaults!
|
65
|
+
end
|
66
|
+
|
67
|
+
require 'metricsd/client'
|
68
|
+
require "metricsd/version"
|
data/metricsd.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "metricsd/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "metricsd"
|
7
|
+
s.version = Metricsd::VERSION
|
8
|
+
s.authors = ["Dmytro Shteflyuk"]
|
9
|
+
s.email = ["kpumuk@kpumuk.info"]
|
10
|
+
s.homepage = "https://github.com/kpumuk/metricsd-ruby"
|
11
|
+
s.summary = %q{Client library for MetricsD server}
|
12
|
+
s.description = %q{}
|
13
|
+
|
14
|
+
s.add_development_dependency 'rspec'
|
15
|
+
s.add_development_dependency 'guard-rspec'
|
16
|
+
s.add_development_dependency 'rb-fsevent'
|
17
|
+
s.add_development_dependency 'growl'
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'metricsd'
|
3
|
+
|
4
|
+
describe Metricsd::Client do
|
5
|
+
before :each do
|
6
|
+
@socket = mock('Socket')
|
7
|
+
Metricsd::Client.stub!(:collector_socket => @socket)
|
8
|
+
Metricsd.stub!(:source => 'test')
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'connection' do
|
12
|
+
it 'should not throw, but log exceptions on failure' do
|
13
|
+
@socket.should_receive(:send).and_raise(Errno::ECONNREFUSED.new('exception from test'))
|
14
|
+
Metricsd.logger.should_receive(:error).once.with(match(/exception from test/))
|
15
|
+
Metricsd.logger.should_receive(:error).at_least(1) # stacktrace
|
16
|
+
Metricsd::Client.record_value('custom.metric', 5)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '.record_hit' do
|
21
|
+
it 'should send two metrics in a single packet' do
|
22
|
+
@socket.should_receive(:send).with('all@custom.metric_count:1;all@custom.metric_time:450', 0)
|
23
|
+
Metricsd::Client.record_hit('custom.metric', true, 0.45)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should handle is_success=false' do
|
27
|
+
@socket.should_receive(:send).with('all@custom.metric_count:-1;all@custom.metric_time:450', 0)
|
28
|
+
Metricsd::Client.record_hit('custom.metric', false, 0.45)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should change separator if :sep option is specified' do
|
32
|
+
@socket.should_receive(:send).with('all@custom.metric!count:1;all@custom.metric!time:450', 0)
|
33
|
+
Metricsd::Client.record_hit('custom.metric', true, 0.45, :sep => '!')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should apply group to both the metrics' do
|
37
|
+
@socket.should_receive(:send).with('all@test$custom.metric_count:1;all@test$custom.metric_time:450', 0)
|
38
|
+
Metricsd::Client.record_hit('custom.metric', true, 0.45, :group => 'test')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should apply source if empty string passed' do
|
42
|
+
@socket.should_receive(:send).with('test@custom.metric_count:1;test@custom.metric_time:450', 0)
|
43
|
+
Metricsd::Client.record_hit('custom.metric', true, 0.45, :source => '')
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should apply source if specified' do
|
47
|
+
@socket.should_receive(:send).with('test2@custom.metric_count:1;test2@custom.metric_time:450', 0)
|
48
|
+
Metricsd::Client.record_hit('custom.metric', true, 0.45, :source => 'test2')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '.record_success' do
|
53
|
+
it 'should record successes' do
|
54
|
+
@socket.should_receive(:send).with('all@custom.metric_count:1', 0)
|
55
|
+
Metricsd::Client.record_success('custom.metric')
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should change separator if :sep option is specified' do
|
59
|
+
@socket.should_receive(:send).with('all@custom.metric!count:1', 0)
|
60
|
+
Metricsd::Client.record_success('custom.metric', :sep => '!')
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should apply group if specified' do
|
64
|
+
@socket.should_receive(:send).with('all@test$custom.metric_count:1', 0)
|
65
|
+
Metricsd::Client.record_success('custom.metric', :group => 'test')
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should apply source if empty string passed' do
|
69
|
+
@socket.should_receive(:send).with('test@custom.metric_count:1', 0)
|
70
|
+
Metricsd::Client.record_success('custom.metric', :source => '')
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should apply source specified' do
|
74
|
+
@socket.should_receive(:send).with('test2@custom.metric_count:1', 0)
|
75
|
+
Metricsd::Client.record_success('custom.metric', :source => 'test2')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '.record_failure' do
|
80
|
+
it 'should record failures' do
|
81
|
+
@socket.should_receive(:send).with('all@custom.metric_count:-1', 0)
|
82
|
+
Metricsd::Client.record_failure('custom.metric')
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should change separator if :sep option is specified' do
|
86
|
+
@socket.should_receive(:send).with('all@custom.metric!count:-1', 0)
|
87
|
+
Metricsd::Client.record_failure('custom.metric', :sep => '!')
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should apply group if specified' do
|
91
|
+
@socket.should_receive(:send).with('all@test$custom.metric_count:-1', 0)
|
92
|
+
Metricsd::Client.record_failure('custom.metric', :group => 'test')
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should apply source if empty string passed' do
|
96
|
+
@socket.should_receive(:send).with('test@custom.metric_count:-1', 0)
|
97
|
+
Metricsd::Client.record_failure('custom.metric', :source => '')
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should apply source specified' do
|
101
|
+
@socket.should_receive(:send).with('test2@custom.metric_count:-1', 0)
|
102
|
+
Metricsd::Client.record_failure('custom.metric', :source => 'test2')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '.record_time' do
|
107
|
+
it 'should record time if specified' do
|
108
|
+
@socket.should_receive(:send).with('all@custom.metric_time:450', 0)
|
109
|
+
Metricsd::Client.record_time('custom.metric', 0.45)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should yield a block if time is not specified' do
|
113
|
+
@socket.should_receive(:send).with(match(/all@custom.metric_time:1\d{2}/), 0)
|
114
|
+
yielded = false
|
115
|
+
Metricsd::Client.record_time('custom.metric') do
|
116
|
+
yielded = true
|
117
|
+
sleep 0.1
|
118
|
+
end
|
119
|
+
yielded.should be_true
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should use options if time is not specified' do
|
123
|
+
@socket.should_receive(:send).with(match(/all@custom.metric_time:\d+/), 0)
|
124
|
+
yielded = false
|
125
|
+
Metricsd::Client.record_time('custom.metric', {}) do
|
126
|
+
yielded = true
|
127
|
+
end
|
128
|
+
yielded.should be_true
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'should change separator if :sep option is specified' do
|
132
|
+
@socket.should_receive(:send).with('all@custom.metric!time:450', 0)
|
133
|
+
Metricsd::Client.record_time('custom.metric', 0.45, :sep => '!')
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'should apply group if specified' do
|
137
|
+
@socket.should_receive(:send).with('all@test$custom.metric_time:450', 0)
|
138
|
+
Metricsd::Client.record_time('custom.metric', 0.45, :group => 'test')
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should apply source if empty string passed' do
|
142
|
+
@socket.should_receive(:send).with('test@custom.metric_time:450', 0)
|
143
|
+
Metricsd::Client.record_time('custom.metric', 0.45, :source => '')
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'should apply source specified' do
|
147
|
+
@socket.should_receive(:send).with('test2@custom.metric_time:450', 0)
|
148
|
+
Metricsd::Client.record_time('custom.metric', 0.45, :source => 'test2')
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe '.record_value' do
|
153
|
+
it 'should record value' do
|
154
|
+
@socket.should_receive(:send).with('all@custom.metric:23', 0)
|
155
|
+
Metricsd::Client.record_value('custom.metric', 23)
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'should apply group if specified' do
|
159
|
+
@socket.should_receive(:send).with('all@test$custom.metric:23', 0)
|
160
|
+
Metricsd::Client.record_value('custom.metric', 23, :group => 'test')
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'should apply source if empty string passed' do
|
164
|
+
@socket.should_receive(:send).with('test@custom.metric:23', 0)
|
165
|
+
Metricsd::Client.record_value('custom.metric', 23, :source => '')
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'should apply source specified' do
|
169
|
+
@socket.should_receive(:send).with('test2@custom.metric:23', 0)
|
170
|
+
Metricsd::Client.record_value('custom.metric', 23, :source => 'test2')
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe '.record_values' do
|
175
|
+
it 'should record all the values specified' do
|
176
|
+
@socket.should_receive(:send).with('all@another.metric:47;all@custom.metric:23', 0)
|
177
|
+
Metricsd::Client.record_values({'custom.metric' => 23, 'another.metric' => 47})
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should apply group if specified' do
|
181
|
+
@socket.should_receive(:send).with('all@test$another.metric:47;all@test$custom.metric:23', 0)
|
182
|
+
Metricsd::Client.record_values({'custom.metric' => 23, 'another.metric' => 47}, :group => 'test')
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'should apply source if empty string passed' do
|
186
|
+
@socket.should_receive(:send).with('test@another.metric:47;test@custom.metric:23', 0)
|
187
|
+
Metricsd::Client.record_values({'custom.metric' => 23, 'another.metric' => 47}, :source => '')
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'should apply source specified' do
|
191
|
+
@socket.should_receive(:send).with('test2@another.metric:47;test2@custom.metric:23', 0)
|
192
|
+
Metricsd::Client.record_values({'custom.metric' => 23, 'another.metric' => 47}, :source => 'test2')
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'should split packets in 250 bytes' do
|
196
|
+
packets, metrics = Array.new(2) { '' }, {}
|
197
|
+
1.upto(8) do |metric|
|
198
|
+
packet, name, value = (metric - 1) / 4, "my.super.long.custom.metric#{metric}", 10000000 + metric
|
199
|
+
metrics[name] = value
|
200
|
+
packets[packet] << "my.super.long.host.name@#{name}:#{value}" << (metric % 4 > 0 ? ';' : '')
|
201
|
+
end
|
202
|
+
|
203
|
+
@socket.should_receive(:send).once.with(packets[0], 0)
|
204
|
+
@socket.should_receive(:send).once.with(packets[1], 0)
|
205
|
+
Metricsd::Client.record_values(metrics, :source => 'my.super.long.host.name')
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'should not allow packets larger than 250 bytes' do
|
209
|
+
@socket.should_not_receive(:send)
|
210
|
+
Metricsd.logger.should_receive(:warn).with(match(/Message is larger than 250 bytes/))
|
211
|
+
Metricsd::Client.record_values({'a' * 300 => 5}, :source => 'my.super.long.host.name')
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'metricsd'
|
3
|
+
|
4
|
+
describe Metricsd do
|
5
|
+
after :each do
|
6
|
+
Metricsd.reset_defaults!
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'with defaults' do
|
10
|
+
source = Socket.gethostname.split('.').first
|
11
|
+
|
12
|
+
it 'should have server_host = 127.0.0.1' do
|
13
|
+
Metricsd.server_host.should == '127.0.0.1'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should have server_port = 6311' do
|
17
|
+
Metricsd.server_port.should == 6311
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should have source = #{source}" do
|
21
|
+
Metricsd.source.should == source
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should have default_source = all' do
|
25
|
+
Metricsd.default_source.should == 'all'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should create logger' do
|
29
|
+
Metricsd.logger.should be_a(Logger)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'setters' do
|
34
|
+
it 'should allow to change server_host' do
|
35
|
+
Metricsd.server_host = 'metrics.local'
|
36
|
+
Metricsd.server_host.should == 'metrics.local'
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should allow to change server_port' do
|
40
|
+
Metricsd.server_port = '8000'
|
41
|
+
Metricsd.server_port.should == 8000
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should not allow invalid server_port' do
|
45
|
+
expect {
|
46
|
+
Metricsd.server_port = 'aaa'
|
47
|
+
}.to raise_error
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should allow to change source' do
|
51
|
+
Metricsd.source = 'test-host'
|
52
|
+
Metricsd.source.should == 'test-host'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should allow to change default_source' do
|
56
|
+
Metricsd.default_source = 'nothing'
|
57
|
+
Metricsd.default_source.should == 'nothing'
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should allow to change logger' do
|
61
|
+
mock = Metricsd.logger = mock('Logger')
|
62
|
+
Metricsd.logger.should be(mock)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: metricsd
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Dmytro Shteflyuk
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-07-27 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: guard-rspec
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rb-fsevent
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: growl
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :development
|
76
|
+
version_requirements: *id004
|
77
|
+
description: ""
|
78
|
+
email:
|
79
|
+
- kpumuk@kpumuk.info
|
80
|
+
executables: []
|
81
|
+
|
82
|
+
extensions: []
|
83
|
+
|
84
|
+
extra_rdoc_files: []
|
85
|
+
|
86
|
+
files:
|
87
|
+
- .gitignore
|
88
|
+
- .rvmrc
|
89
|
+
- Gemfile
|
90
|
+
- Guardfile
|
91
|
+
- README.md
|
92
|
+
- Rakefile
|
93
|
+
- lib/metricsd.rb
|
94
|
+
- lib/metricsd/client.rb
|
95
|
+
- lib/metricsd/version.rb
|
96
|
+
- metricsd.gemspec
|
97
|
+
- spec/client_spec.rb
|
98
|
+
- spec/metricsd_spec.rb
|
99
|
+
has_rdoc: true
|
100
|
+
homepage: https://github.com/kpumuk/metricsd-ruby
|
101
|
+
licenses: []
|
102
|
+
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
hash: 3
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
version: "0"
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
hash: 3
|
123
|
+
segments:
|
124
|
+
- 0
|
125
|
+
version: "0"
|
126
|
+
requirements: []
|
127
|
+
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 1.6.2
|
130
|
+
signing_key:
|
131
|
+
specification_version: 3
|
132
|
+
summary: Client library for MetricsD server
|
133
|
+
test_files:
|
134
|
+
- spec/client_spec.rb
|
135
|
+
- spec/metricsd_spec.rb
|