metriks 0.8.4 → 0.9.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/README.md CHANGED
@@ -283,6 +283,36 @@ since the process started.
283
283
 
284
284
  How to get metrics out of the process.
285
285
 
286
+ ## Graphite Reporter
287
+
288
+ Sends metrics to Graphite every 60 seconds.
289
+
290
+ ```ruby
291
+ reporter = Metriks::Reporter::Graphite.new 'localhost', 3004
292
+ reporter.start
293
+ ```
294
+
295
+
296
+ ## Logger Reporter
297
+
298
+ Send metrics to a logger every 60 seconds.
299
+
300
+ ```
301
+ reporter = Metriks::Reporter::Logger.new(:logger => Logger.new('log/metrics.log'))
302
+ reporter.start
303
+ ```
304
+
305
+
306
+ ## Librato Metrics Reporter
307
+
308
+ Send metrics to Librato Metrics every 60 seconds.
309
+
310
+ ```
311
+ reporter = Metriks::Reporter::LibratoMetrics.new('email', 'token')
312
+ reporter.start
313
+ ```
314
+
315
+
286
316
  ## Proc Title Reporter
287
317
 
288
318
  Provides a simple way to get up-to-date statistics from a process by
@@ -290,11 +320,9 @@ updating the proctitle every 5 seconds (default).
290
320
 
291
321
  ```ruby
292
322
  reporter = Metriks::Reporter::ProcTitle.new :interval => 5
293
-
294
323
  reporter.add 'reqs', 'sec' do
295
324
  Metriks.meter('rack.requests').one_minute_rate
296
325
  end
297
-
298
326
  reporter.start
299
327
  ```
300
328
 
@@ -312,9 +340,7 @@ An incomplete list of things I would like to see added:
312
340
  * Rack middleware to measure utilization, throughput and worker time
313
341
  * Basic reporters:
314
342
  * Rack endpoint returning JSON
315
- * Logger reporter to output metrics on a time interval
316
343
  * [Statsd](https://github.com/etsy/statsd) reporter
317
- * [Librato Metrics](http://metrics.librato.com) reporter
318
344
  * Metaprogramming instrumentation hooks like [Shopify's statsd-instrument](https://github.com/Shopify/statsd-instrument)
319
345
 
320
346
 
@@ -72,10 +72,9 @@ module Metriks
72
72
  @mutex.synchronize do
73
73
  old_start_time = @start_time
74
74
  @start_time = Time.now
75
- keys = @values.keys
76
- keys.each do |key|
75
+ @values.keys.each do |key|
77
76
  value = @values.delete(key)
78
- @values[key* Math.exp(-@alpha * (@start_time - old_start_time))] = value
77
+ @values[key * Math.exp(-@alpha * (@start_time - old_start_time))] = value
79
78
  end
80
79
  end
81
80
  end
@@ -0,0 +1,97 @@
1
+
2
+ module Metriks::Reporter
3
+ class Graphite
4
+ def initialize(host, port, options = {})
5
+ @host = host
6
+ @port = port
7
+ @prefix = options[:prefix]
8
+ @registry = options[:registry] || Metriks::Registry.default
9
+ @interval = options[:interval] || 60
10
+ @on_errror = options[:on_error] || proc { |ex| }
11
+ end
12
+
13
+ def socket
14
+ @socket = nil if @socket.closed?
15
+ @socket ||= TCPSocket.new(host, port)
16
+ end
17
+
18
+ def start
19
+ @thread ||= Thread.new do
20
+ loop do
21
+ sleep @interval
22
+
23
+ Thread.new do
24
+ begin
25
+ write
26
+ rescue Exception => ex
27
+ @on_error[ex] rescue nil
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def stop
35
+ @thread.kill if @thread
36
+ @thread = nil
37
+ end
38
+
39
+ def write
40
+ @registry.each do |name, metric|
41
+ case metric
42
+ when Metriks::Meter
43
+ write_metric name, metric, [
44
+ :count, :one_minute_rate, :five_minute_rate,
45
+ :fifteen_minute_rate, :mean_rate
46
+ ]
47
+ when Metriks::Counter
48
+ write_metric name, metric, [
49
+ :count
50
+ ]
51
+ when Metriks::UtilizationTimer
52
+ write_metric name, metric, [
53
+ :count, :one_minute_rate, :five_minute_rate,
54
+ :fifteen_minute_rate, :mean_rate,
55
+ :min, :max, :mean, :stddev,
56
+ :one_minute_utilization, :five_minute_utilization,
57
+ :fifteen_minute_utilization, :mean_utilization,
58
+ ], [
59
+ :median, :get_95th_percentile
60
+ ]
61
+ when Metriks::Timer
62
+ write_metric name, metric, [
63
+ :count, :one_minute_rate, :five_minute_rate,
64
+ :fifteen_minute_rate, :mean_rate,
65
+ :min, :max, :mean, :stddev
66
+ ], [
67
+ :median, :get_95th_percentile
68
+ ]
69
+ end
70
+ end
71
+ end
72
+
73
+ def write_metric(base_name, metric, keys, snapshot_keys = [])
74
+ time = Time.now.to_i
75
+
76
+ base_name = base_name.to_s.gsub(/ +/, '_')
77
+ if @prefix
78
+ base_name = "#{@prefix}.#{base_name}"
79
+ end
80
+
81
+ keys.flatten.each do |key|
82
+ name = key.to_s.gsub(/^get_/, '')
83
+ value = metric.send(key)
84
+ socket.write("#{base_name}.#{name} #{value} #{time}\n")
85
+ end
86
+
87
+ unless snapshot_keys.empty?
88
+ snapshot = metric.snapshot
89
+ snapshot_keys.flatten.each do |key|
90
+ name = key.to_s.gsub(/^get_/, '')
91
+ value = snapshot.send(key)
92
+ socket.write("#{base_name}.#{name} #{value} #{time}\n")
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,140 @@
1
+ require 'faraday'
2
+ require 'faraday_middleware'
3
+ require 'yajl'
4
+ require 'yajl/json_gem'
5
+
6
+ module Metriks::Reporter
7
+ class LibratoMetrics
8
+ def self.connection
9
+ @connection ||= Faraday::Connection.new('https://metrics-api.librato.com') do |b|
10
+ b.use FaradayMiddleware::EncodeJson
11
+ b.adapter Faraday.default_adapter
12
+ b.use Faraday::Response::RaiseError
13
+ b.use FaradayMiddleware::ParseJson, :content_type => /\bjson$/
14
+ end.tap do |c|
15
+ c.headers[:content_type] = 'application/json'
16
+ c.headers[:user_agent] = "Metriks/#{Metriks::VERSION} Faraday/#{Faraday::VERSION}"
17
+ end
18
+ end
19
+
20
+
21
+ def initialize(email, token, options = {})
22
+ @email = email
23
+ @token = token
24
+ @prefix = options[:prefix]
25
+ @registry = options[:registry] || Metriks::Registry.default
26
+ @interval = options[:interval] || 60
27
+ @on_errror = options[:on_error] || proc { |ex| }
28
+ @source = options[:source]
29
+ end
30
+
31
+ def start
32
+ @thread ||= Thread.new do
33
+ loop do
34
+ sleep @interval
35
+
36
+ Thread.new do
37
+ begin
38
+ write
39
+ rescue Exception => ex
40
+ @on_error[ex] rescue nil
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ def stop
48
+ @thread.kill if @thread
49
+ @thread = nil
50
+ end
51
+
52
+ def write
53
+ gauges = []
54
+ @registry.each do |name, metric|
55
+ gauges << case metric
56
+ when Metriks::Meter
57
+ prepare_metric name, metric, [
58
+ :count, :one_minute_rate, :five_minute_rate,
59
+ :fifteen_minute_rate, :mean_rate
60
+ ]
61
+ when Metriks::Counter
62
+ prepare_metric name, metric, [
63
+ :count
64
+ ]
65
+ when Metriks::UtilizationTimer
66
+ prepare_metric name, metric, [
67
+ :count, :one_minute_rate, :five_minute_rate,
68
+ :fifteen_minute_rate, :mean_rate,
69
+ :min, :max, :mean, :stddev,
70
+ :one_minute_utilization, :five_minute_utilization,
71
+ :fifteen_minute_utilization, :mean_utilization,
72
+ ], [
73
+ :median, :get_95th_percentile
74
+ ]
75
+ when Metriks::Timer
76
+ prepare_metric name, metric, [
77
+ :count, :one_minute_rate, :five_minute_rate,
78
+ :fifteen_minute_rate, :mean_rate,
79
+ :min, :max, :mean, :stddev
80
+ ], [
81
+ :median, :get_95th_percentile
82
+ ]
83
+ end
84
+ end
85
+
86
+ submit(:gauges => gauges.flatten)
87
+ end
88
+
89
+ def connection
90
+ @connection ||= self.class.connection.dup.tap do |c|
91
+ c.basic_auth @email, @token
92
+ end
93
+ end
94
+
95
+ def submit(body)
96
+ connection.post '/v1/metrics' do |req|
97
+ req.body = body
98
+ end
99
+ end
100
+
101
+ def prepare_metric(base_name, metric, keys, snapshot_keys = [])
102
+ results = []
103
+ time = Time.now.to_i
104
+
105
+ base_name = base_name.to_s.gsub(/ +/, '_')
106
+ if @prefix
107
+ base_name = "#{@prefix}.#{base_name}"
108
+ end
109
+
110
+ keys.flatten.each do |key|
111
+ name = key.to_s.gsub(/^get_/, '')
112
+ value = metric.send(key)
113
+
114
+ results << {
115
+ :name => "#{base_name}.#{name}",
116
+ :source => @source,
117
+ :time => time,
118
+ :value => value
119
+ }
120
+ end
121
+
122
+ unless snapshot_keys.empty?
123
+ snapshot = metric.snapshot
124
+ snapshot_keys.flatten.each do |key|
125
+ name = key.to_s.gsub(/^get_/, '')
126
+ value = snapshot.send(key)
127
+
128
+ results << {
129
+ :name => "#{base_name}.#{name}",
130
+ :source => @source,
131
+ :time => time,
132
+ :value => value
133
+ }
134
+ end
135
+ end
136
+
137
+ results
138
+ end
139
+ end
140
+ end
data/lib/metriks.rb CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Metriks
3
- VERSION = '0.8.4'
3
+ VERSION = '0.9.0'
4
4
 
5
5
  def self.get(name)
6
6
  Metriks::Registry.default.get(name)
data/metriks.gemspec CHANGED
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
13
13
  ## If your rubyforge_project name is different, then edit it and comment out
14
14
  ## the sub! line in the Rakefile
15
15
  s.name = 'metriks'
16
- s.version = '0.8.4'
17
- s.date = '2012-02-27'
16
+ s.version = '0.9.0'
17
+ s.date = '2012-03-03'
18
18
 
19
19
  ## Make sure your summary is short. The description may be as long
20
20
  ## as you like.
@@ -26,15 +26,12 @@ Gem::Specification.new do |s|
26
26
  ## a custom homepage, consider using your GitHub URL or the like.
27
27
  s.authors = ["Eric Lindvall"]
28
28
  s.email = 'eric@sevenscale.com'
29
- s.homepage = 'https://github.com/eric/metriks_client'
29
+ s.homepage = 'https://github.com/eric/metriks'
30
30
 
31
31
  ## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
32
32
  ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
33
33
  s.require_paths = %w[lib]
34
34
 
35
- ## If your gem includes any executables, list them here.
36
- # s.executables = ["name"]
37
-
38
35
  ## Specify any RDoc options here. You'll want to add your README and
39
36
  ## LICENSE files to the extra_rdoc_files list.
40
37
  s.rdoc_options = ["--charset=UTF-8"]
@@ -45,10 +42,14 @@ Gem::Specification.new do |s|
45
42
  s.add_dependency('atomic', ["~> 1.0"])
46
43
  s.add_dependency('hitimes', [ "~> 1.1"])
47
44
  s.add_dependency('rbtree', [ "~> 0.3" ])
45
+ s.add_dependency('faraday', ['~> 0.7.0'])
46
+ s.add_dependency('faraday_middleware', ['~> 0.8.4'])
47
+ s.add_dependency('yajl-ruby')
48
48
 
49
49
  ## List your development dependencies here. Development dependencies are
50
50
  ## those that are only needed during development
51
51
  s.add_development_dependency('tomdoc', ["~> 0.2"])
52
+ s.add_development_dependency('mocha', ['~> 0.10'])
52
53
 
53
54
  ## Leave this section as-is. It will be automatically generated from the
54
55
  ## contents of your Git repository via the gemspec task. DO NOT REMOVE
@@ -67,6 +68,8 @@ Gem::Specification.new do |s|
67
68
  lib/metriks/histogram.rb
68
69
  lib/metriks/meter.rb
69
70
  lib/metriks/registry.rb
71
+ lib/metriks/reporter/graphite.rb
72
+ lib/metriks/reporter/librato_metrics.rb
70
73
  lib/metriks/reporter/logger.rb
71
74
  lib/metriks/reporter/proc_title.rb
72
75
  lib/metriks/simple_moving_average.rb
@@ -76,7 +79,9 @@ Gem::Specification.new do |s|
76
79
  lib/metriks/utilization_timer.rb
77
80
  metriks.gemspec
78
81
  test/counter_test.rb
82
+ test/graphite_reporter_test.rb
79
83
  test/histogram_test.rb
84
+ test/librato_metrics_reporter_test.rb
80
85
  test/logger_reporter_test.rb
81
86
  test/meter_test.rb
82
87
  test/metriks_test.rb
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+
3
+ require 'metriks/reporter/graphite'
4
+
5
+ class GraphiteReporterTest < Test::Unit::TestCase
6
+ def setup
7
+ @registry = Metriks::Registry.new
8
+ @reporter = Metriks::Reporter::Graphite.new('localhost', 3333, :registry => @registry)
9
+ @stringio = StringIO.new
10
+
11
+ @reporter.stubs(:socket).returns(@stringio)
12
+ end
13
+
14
+ def teardown
15
+ @reporter.stop
16
+ @registry.stop
17
+ end
18
+
19
+ def test_write
20
+ @registry.meter('meter.testing').mark
21
+ @registry.counter('counter.testing').increment
22
+ @registry.timer('timer.testing').update(1.5)
23
+ @registry.utilization_timer('utilization_timer.testing').update(1.5)
24
+
25
+ @reporter.write
26
+
27
+ assert_match /timer.testing.median \d/, @stringio.string
28
+ end
29
+ end
@@ -0,0 +1,32 @@
1
+ require 'test_helper'
2
+
3
+ require 'metriks/reporter/librato_metrics'
4
+
5
+ class LibratoMetricsReporterTest < Test::Unit::TestCase
6
+ def setup
7
+ @registry = Metriks::Registry.new
8
+ @reporter = Metriks::Reporter::LibratoMetrics.new('user', 'password', :registry => @registry)
9
+
10
+ @reporter.connection.builder.tap do |c|
11
+ c.swap 1, Faraday::Adapter::Test do |stub|
12
+ stub.post '/v1/metrics' do |env|
13
+ [ 200, {}, '' ]
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ def teardown
20
+ @reporter.stop
21
+ @registry.stop
22
+ end
23
+
24
+ def test_write
25
+ @registry.meter('meter.testing').mark
26
+ @registry.counter('counter.testing').increment
27
+ @registry.timer('timer.testing').update(1.5)
28
+ @registry.utilization_timer('utilization_timer.testing').update(1.5)
29
+
30
+ @reporter.write
31
+ end
32
+ end
data/test/test_helper.rb CHANGED
@@ -2,6 +2,7 @@ require 'test/unit'
2
2
  require 'pp'
3
3
 
4
4
  require 'turn'
5
+ require 'mocha'
5
6
 
6
7
  require 'metriks'
7
8
 
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 8
8
- - 4
9
- version: 0.8.4
7
+ - 9
8
+ - 0
9
+ version: 0.9.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Eric Lindvall
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2012-02-27 00:00:00 -08:00
17
+ date: 2012-03-03 00:00:00 -08:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -57,9 +57,49 @@ dependencies:
57
57
  type: :runtime
58
58
  version_requirements: *id003
59
59
  - !ruby/object:Gem::Dependency
60
- name: tomdoc
60
+ name: faraday
61
61
  prerelease: false
62
62
  requirement: &id004 !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ~>
65
+ - !ruby/object:Gem::Version
66
+ segments:
67
+ - 0
68
+ - 7
69
+ - 0
70
+ version: 0.7.0
71
+ type: :runtime
72
+ version_requirements: *id004
73
+ - !ruby/object:Gem::Dependency
74
+ name: faraday_middleware
75
+ prerelease: false
76
+ requirement: &id005 !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ~>
79
+ - !ruby/object:Gem::Version
80
+ segments:
81
+ - 0
82
+ - 8
83
+ - 4
84
+ version: 0.8.4
85
+ type: :runtime
86
+ version_requirements: *id005
87
+ - !ruby/object:Gem::Dependency
88
+ name: yajl-ruby
89
+ prerelease: false
90
+ requirement: &id006 !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ segments:
95
+ - 0
96
+ version: "0"
97
+ type: :runtime
98
+ version_requirements: *id006
99
+ - !ruby/object:Gem::Dependency
100
+ name: tomdoc
101
+ prerelease: false
102
+ requirement: &id007 !ruby/object:Gem::Requirement
63
103
  requirements:
64
104
  - - ~>
65
105
  - !ruby/object:Gem::Version
@@ -68,7 +108,20 @@ dependencies:
68
108
  - 2
69
109
  version: "0.2"
70
110
  type: :development
71
- version_requirements: *id004
111
+ version_requirements: *id007
112
+ - !ruby/object:Gem::Dependency
113
+ name: mocha
114
+ prerelease: false
115
+ requirement: &id008 !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ~>
118
+ - !ruby/object:Gem::Version
119
+ segments:
120
+ - 0
121
+ - 10
122
+ version: "0.10"
123
+ type: :development
124
+ version_requirements: *id008
72
125
  description: An experimental metrics client.
73
126
  email: eric@sevenscale.com
74
127
  executables: []
@@ -91,6 +144,8 @@ files:
91
144
  - lib/metriks/histogram.rb
92
145
  - lib/metriks/meter.rb
93
146
  - lib/metriks/registry.rb
147
+ - lib/metriks/reporter/graphite.rb
148
+ - lib/metriks/reporter/librato_metrics.rb
94
149
  - lib/metriks/reporter/logger.rb
95
150
  - lib/metriks/reporter/proc_title.rb
96
151
  - lib/metriks/simple_moving_average.rb
@@ -100,7 +155,9 @@ files:
100
155
  - lib/metriks/utilization_timer.rb
101
156
  - metriks.gemspec
102
157
  - test/counter_test.rb
158
+ - test/graphite_reporter_test.rb
103
159
  - test/histogram_test.rb
160
+ - test/librato_metrics_reporter_test.rb
104
161
  - test/logger_reporter_test.rb
105
162
  - test/meter_test.rb
106
163
  - test/metriks_test.rb
@@ -110,7 +167,7 @@ files:
110
167
  - test/timer_test.rb
111
168
  - test/utilization_timer_test.rb
112
169
  has_rdoc: true
113
- homepage: https://github.com/eric/metriks_client
170
+ homepage: https://github.com/eric/metriks
114
171
  licenses: []
115
172
 
116
173
  post_install_message:
@@ -141,7 +198,9 @@ specification_version: 2
141
198
  summary: An experimental metrics client
142
199
  test_files:
143
200
  - test/counter_test.rb
201
+ - test/graphite_reporter_test.rb
144
202
  - test/histogram_test.rb
203
+ - test/librato_metrics_reporter_test.rb
145
204
  - test/logger_reporter_test.rb
146
205
  - test/meter_test.rb
147
206
  - test/metriks_test.rb