ruby-metrics 0.8.6 → 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.
Files changed (41) hide show
  1. data/.bundle/config +1 -2
  2. data/.gitignore +2 -0
  3. data/.rvmrc +1 -1
  4. data/.travis.yml +5 -0
  5. data/CHANGELOG.md +48 -0
  6. data/Gemfile +8 -2
  7. data/README.md +2 -1
  8. data/Rakefile +20 -7
  9. data/examples/gmontest.rb +17 -0
  10. data/examples/opentsdb_reporter.rb +77 -0
  11. data/lib/ruby-metrics.rb +3 -4
  12. data/lib/ruby-metrics/agent.rb +72 -16
  13. data/lib/ruby-metrics/instruments/counter.rb +19 -12
  14. data/lib/ruby-metrics/instruments/gauge.rb +13 -9
  15. data/lib/ruby-metrics/instruments/histogram.rb +46 -45
  16. data/lib/ruby-metrics/instruments/meter.rb +29 -26
  17. data/lib/ruby-metrics/instruments/timer.rb +38 -37
  18. data/lib/ruby-metrics/integration.rb +3 -4
  19. data/lib/ruby-metrics/logging.rb +0 -2
  20. data/lib/ruby-metrics/reporter.rb +28 -0
  21. data/lib/ruby-metrics/statistics/exponential_sample.rb +4 -5
  22. data/lib/ruby-metrics/statistics/uniform_sample.rb +1 -2
  23. data/lib/ruby-metrics/time_units.rb +13 -11
  24. data/lib/ruby-metrics/version.rb +1 -1
  25. data/ruby-metrics-ganglia.gemspec +21 -0
  26. data/ruby-metrics-librato.gemspec +20 -0
  27. data/ruby-metrics-opentsdb.gemspec +21 -0
  28. data/ruby-metrics.gemspec +18 -15
  29. data/spec/agent_spec.rb +13 -4
  30. data/spec/instruments/meter_spec.rb +40 -3
  31. data/spec/instruments/timer_spec.rb +1 -1
  32. data/spec/spec_helper.rb +1 -1
  33. metadata +106 -105
  34. data/Gemfile.lock +0 -34
  35. data/lib/ruby-metrics/instruments.rb +0 -89
  36. data/lib/ruby-metrics/instruments/base.rb +0 -23
  37. data/lib/ruby-metrics/statistics/sample.rb +0 -21
  38. data/spec/instruments/base_spec.rb +0 -16
  39. data/spec/instruments_spec.rb +0 -76
  40. data/spec/integration/webrick_spec.rb +0 -18
  41. data/spec/statistics/sample_spec.rb +0 -22
@@ -1,2 +1 @@
1
- ---
2
- BUNDLE_DISABLE_SHARED_GEMS: "1"
1
+ --- {}
data/.gitignore CHANGED
@@ -2,3 +2,5 @@ coverage
2
2
  *.gem
3
3
  pkg/*
4
4
  .DS_Store
5
+ doc
6
+ .yardoc
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm ruby-1.9.2@metrics
1
+ rvm ruby-1.9.3@metrics
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0
5
+ - 2.1
@@ -0,0 +1,48 @@
1
+ v0.8.6 -- June 2, 2011
2
+ ======================
3
+
4
+ * Updated tests for JSON serialization of instruments
5
+ * Fixed JSON serialization of some instruments
6
+
7
+ v0.8.5 -- May 11, 2011
8
+ ======================
9
+
10
+ * Removed dependency on quantity gem -- conflicted with ActiveSupport
11
+ * Updated code to compute some unit conversions manually instead of depending on quantity
12
+
13
+
14
+ v0.8.0 -- April 26, 2011
15
+ ========================
16
+
17
+ * Added timer example
18
+ * Changes to timer initialization
19
+ * Added register_with_options to support timers with different units or options
20
+ * Integrated Matt's changes for integration to modularize webrick and rack export options
21
+
22
+ v0.7.0 -- April 18, 2011
23
+ ========================
24
+
25
+ * Replaced ruby-units with quantity
26
+ * Added time unit conversion internally
27
+ * Initial implementation of Timer instrument
28
+ * More spec tests to increase coverage
29
+
30
+
31
+ v0.6.0 -- April 15, 2011
32
+ ========================
33
+
34
+ * Exponentially decaying samples for histograms
35
+ * Updates to Meter to use exponentially decaying samples
36
+ * Ability to override WEBrick port in constructor
37
+ * Updates to README
38
+
39
+ v0.5.0 -- April 13, 2011
40
+ ========================
41
+
42
+ * Initial gem packaging (courtesy of @richardiux)
43
+ * Histograms
44
+ * Sampling classes for histograms
45
+ * Updates to weighted average calculations
46
+ * Tests, tests, tests!
47
+ * Mumblety-peg....
48
+
data/Gemfile CHANGED
@@ -1,4 +1,10 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in ruby-metrics.gemspec
4
- gemspec
4
+ gemspec :name => 'ruby-metrics'
5
+ gemspec :name => 'ruby-metrics-opentsdb'
6
+
7
+ group :test do
8
+ gem 'rake'
9
+ gem 'timecop'
10
+ end
data/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ [![Build Status](https://travis-ci.org/johnewart/ruby-metrics.svg?branch=master)](https://travis-ci.org/johnewart/ruby-metrics)
1
2
 
2
3
  ## What is this?
3
4
 
@@ -83,4 +84,4 @@ mount Metrics::Integration::Rack::Endpoint.new(:agent => @agent)
83
84
 
84
85
  ## License
85
86
 
86
- Copyright 2011 John Ewart <john@johnewart.net>. Released under the MIT license. See the file LICENSE for further details.
87
+ Copyright 2011-2014 John Ewart <john@johnewart.net>. Released under the MIT license. See the file LICENSE for further details.
data/Rakefile CHANGED
@@ -1,14 +1,27 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/lib')
1
2
  require "rubygems"
2
3
  require "bundler"
3
4
  require "rspec/core/rake_task"
4
- Bundler::GemHelper.install_tasks
5
+ require 'ruby-metrics/version'
5
6
 
6
- begin
7
- Bundler.setup(:default, :development)
8
- rescue Bundler::BundlerError => e
9
- $stderr.puts e.message
10
- $stderr.puts "Run `bundle install` to install missing gems"
11
- exit e.status_code
7
+ desc 'Build gem into the pkg directory'
8
+ task :build do
9
+ FileUtils.rm_rf('pkg')
10
+ Dir['*.gemspec'].each do |gemspec|
11
+ puts "Building #{gemspec}"
12
+ system "gem build #{gemspec}"
13
+ end
14
+ FileUtils.mkdir_p('pkg')
15
+ FileUtils.mv(Dir['*.gem'], 'pkg')
16
+ end
17
+
18
+ desc 'Tags version, pushes to remote, and pushes gem'
19
+ task :release => :build do
20
+ puts "Releasing v#{Metrics::VERSION}"
21
+ sh 'git', 'tag', '-m', "Version #{Metrics::VERSION}", "v#{Metrics::VERSION}"
22
+ sh "git push origin master"
23
+ sh "git push origin v#{Metrics::VERSION}"
24
+ #sh "ls pkg/*.gem | xargs -n 1 gem push"
12
25
  end
13
26
 
14
27
  RSpec::Core::RakeTask.new do |t|
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ gem 'gmetric'
3
+ require 'gmetric'
4
+
5
+ result = Ganglia::GMetric.send("172.16.32.130", 8670, {
6
+ :hostname => 'ook.unixninjas.org',
7
+ :spoof => 0,
8
+ :name => 'narf',
9
+ :units => 'reqs/sec',
10
+ :type => 'uint8',
11
+ :value => 7000,
12
+ :tmax => 60,
13
+ :dmax => 300,
14
+ })
15
+
16
+ puts "Result: #{result.inspect}"
17
+
@@ -0,0 +1,77 @@
1
+
2
+ require 'rubygems'
3
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
4
+
5
+ require 'ruby-metrics'
6
+ require 'ruby-metrics/reporters/opentsdb'
7
+
8
+ @metrics = Metrics::Agent.new
9
+ @hit_counter = 42
10
+ @http_counter = 53
11
+
12
+ def hit_count
13
+ return 42 + rand(40)
14
+ end
15
+
16
+ def http_requests
17
+ return 64 + rand(50)
18
+ end
19
+
20
+ gauge = @metrics.gauge :my_gauge do
21
+ {
22
+ :hit_count => hit_count,
23
+ :http_requests => http_requests
24
+ }
25
+ end
26
+
27
+ step = 0
28
+ meter = @metrics.meter :faults, 'faults'
29
+
30
+ puts "Gauge: #{gauge.to_s}"
31
+
32
+ result = gauge.get
33
+ counter = @metrics.counter :my_counter
34
+ counter.incr
35
+ counter.incr(50)
36
+
37
+ counter_two = @metrics.counter :counter_two
38
+ counter_two.incr(0)
39
+
40
+ timer = @metrics.timer :request_timer, 'requests'
41
+ puts "Result: #{result}"
42
+
43
+ Thread.new {
44
+ begin
45
+ modifier = rand(200).to_i
46
+ step += 1
47
+
48
+ if (step % 2)
49
+ modifier *= -1
50
+ end
51
+
52
+ meter.mark(500 + modifier)
53
+ puts "Sleeping for 0.53s --> #{meter.count}"
54
+ sleep 0.53
55
+ end while(true)
56
+ }
57
+
58
+ Thread.new {
59
+ while(true)
60
+ begin
61
+ puts "TIMER1: #{timer.inspect}"
62
+ timer.time do
63
+ sleeptime = rand(10) + 2
64
+ puts "Sleeping for #{sleeptime}"
65
+ sleep sleeptime
66
+ true
67
+ end
68
+ puts "TIMER2: #{timer.inspect}"
69
+ rescue => e
70
+ puts "Error: #{e.inspect}"
71
+ end
72
+ end
73
+ }
74
+
75
+ opentsdb = Metrics::Reporters::OpenTSDBReporter.new({:hostname => 'localhost', :port => 4242, :agent => @metrics })
76
+ @metrics.report_to('opentsdb', opentsdb)
77
+ @metrics.report_periodically(3.26)
@@ -1,16 +1,15 @@
1
1
  # == Metrics Initialization
2
2
  #
3
3
 
4
+ require 'logger'
5
+
4
6
  module Metrics
5
-
6
7
  class << self
7
8
  attr_writer :logger
8
9
  def logger
9
10
  @logger ||= Logger.new(STDOUT)
10
11
  end
11
12
  end
12
-
13
13
  end
14
14
 
15
-
16
- require File.join(File.dirname(__FILE__), 'ruby-metrics', 'agent')
15
+ require 'ruby-metrics/agent'
@@ -1,22 +1,78 @@
1
- require File.join(File.dirname(__FILE__), 'logging')
2
- require File.join(File.dirname(__FILE__), 'instruments')
3
- require File.join(File.dirname(__FILE__), 'integration')
1
+ require 'ruby-metrics/logging'
2
+
3
+ require 'ruby-metrics/time_units'
4
+
5
+ require 'ruby-metrics/instruments/counter'
6
+ require 'ruby-metrics/instruments/meter'
7
+ require 'ruby-metrics/instruments/gauge'
8
+ require 'ruby-metrics/instruments/histogram'
9
+ require 'ruby-metrics/instruments/timer'
10
+
11
+ require 'ruby-metrics/integration'
12
+ require 'ruby-metrics/reporter'
13
+
14
+ require 'json'
4
15
 
5
16
  module Metrics
6
17
  class Agent
7
18
  include Logging
8
- include Instruments::TypeMethods
9
-
10
- attr_reader :instruments
11
-
12
- def initialize
13
- logger.debug "Initializing Metrics..."
14
- @instruments = Metrics::Instruments
15
- end
16
-
17
- def to_json
18
- @instruments.to_json
19
- end
20
-
19
+
20
+ attr_reader :instruments, :reporters, :reporter
21
+
22
+ def initialize(options = {})
23
+ @instruments = {}
24
+ @reporters = {}
25
+ end
26
+
27
+ alias_method :registered, :instruments
28
+
29
+ def counter(name, units = '')
30
+ @instruments[name] ||= Instruments::Counter.new(:units => units)
31
+ end
32
+
33
+ def meter(name, units = '')
34
+ @instruments[name] ||= Instruments::Meter.new(:units => units)
35
+ end
36
+
37
+ def gauge(name, units = '', &block)
38
+ @instruments[name] ||= Instruments::Gauge.new(:units => units, &block)
39
+ end
40
+
41
+ def timer(name, units = '', options = {})
42
+ @instruments[name] ||= Instruments::Timer.new(options.merge(:units => units))
43
+ end
44
+
45
+ def uniform_histogram(name)
46
+ @instruments[name] ||= Instruments::UniformHistogram.new
47
+ end
48
+
49
+ # For backwards compatibility
50
+ alias_method :histogram, :uniform_histogram
51
+
52
+ def exponential_histogram(name)
53
+ @instruments[name] ||= Instruments::ExponentialHistogram.new
54
+ end
55
+
56
+ def report_to(name, service)
57
+ @reporters[name] ||= service
58
+ end
59
+
60
+ def send_metrics!
61
+ @reporters.each do |name, service|
62
+ service.report(self)
63
+ end
64
+ end
65
+
66
+ def report_periodically(delay = nil)
67
+ @reporter = Reporter.new({:agent => self, :delay => delay})
68
+ end
69
+
70
+ def as_json(*_)
71
+ @instruments
72
+ end
73
+
74
+ def to_json(*_)
75
+ as_json.to_json
76
+ end
21
77
  end
22
78
  end
@@ -1,35 +1,42 @@
1
1
  module Metrics
2
2
  module Instruments
3
- class Counter < Base
4
-
5
- def initialize
3
+ class Counter
4
+
5
+ attr_reader :units
6
+
7
+ def initialize(options = {})
6
8
  @value = 0
7
9
  end
8
-
10
+
9
11
  def inc(value = 1)
10
12
  @value += value
11
13
  end
12
14
  alias_method :incr, :inc
13
-
15
+
14
16
  def dec(value = 1)
15
17
  @value -= value
16
18
  end
17
19
  alias_method :decr, :dec
18
-
20
+
19
21
  def clear
20
22
  @value = 0
21
23
  end
22
-
24
+
23
25
  def to_i
24
26
  @value.to_i
25
27
  end
26
-
27
- def to_json(*_)
28
+
29
+ def to_s
28
30
  @value.to_s
29
31
  end
30
-
31
- end
32
32
 
33
- register_instrument(:counter, Counter)
33
+ def as_json(*_)
34
+ @value
35
+ end
36
+
37
+ def to_json(*_)
38
+ as_json.to_json
39
+ end
40
+ end
34
41
  end
35
42
  end
@@ -1,22 +1,26 @@
1
1
  module Metrics
2
2
  module Instruments
3
- class Gauge < Base
4
-
5
- def initialize(&block)
3
+ class Gauge
4
+ attr_reader :units
5
+
6
+ def initialize(options = {}, &block)
6
7
  raise ArgumentError, "a block is required" unless block_given?
7
8
  @block = block
9
+ @units = options[:units]
8
10
  end
9
-
11
+
10
12
  def get
11
13
  instance_exec(&@block)
12
14
  end
13
-
15
+
16
+ def as_json(*_)
17
+ value = get
18
+ value.respond_to?(:as_json) ? value.as_json : value
19
+ end
20
+
14
21
  def to_json(*_)
15
- get.to_json
22
+ as_json.to_json
16
23
  end
17
-
18
24
  end
19
-
20
- register_instrument(:gauge, Gauge)
21
25
  end
22
26
  end
@@ -1,7 +1,10 @@
1
+ require 'ruby-metrics/statistics/uniform_sample'
2
+ require 'ruby-metrics/statistics/exponential_sample'
3
+
1
4
  module Metrics
2
5
  module Instruments
3
- class Histogram < Base
4
-
6
+ class Histogram
7
+
5
8
  def initialize(type = :uniform)
6
9
  @count = 0
7
10
  case type
@@ -16,7 +19,7 @@ module Metrics
16
19
  @variance_s = 0
17
20
  @variance_m = -1
18
21
  end
19
-
22
+
20
23
  def update(value)
21
24
  @count += 1
22
25
  @sum += value
@@ -25,8 +28,8 @@ module Metrics
25
28
  update_min(value)
26
29
  update_variance(value);
27
30
  end
28
-
29
- def clear
31
+
32
+ def clear
30
33
  @sample.clear
31
34
  @min = nil
32
35
  @max = nil
@@ -35,20 +38,20 @@ module Metrics
35
38
  @variance_m = -1
36
39
  @variance_s = 0
37
40
  end
38
-
41
+
39
42
  def quantiles(percentiles)
40
43
  # Calculated using the same logic as R and Ecxel use
41
44
  # as outlined by the NIST here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc252.htm
42
45
  count = @count
43
46
  scores = {}
44
47
  values = @sample.values[0..count-1]
45
-
48
+
46
49
  percentiles.each do |pct|
47
50
  scores[pct] = 0.0
48
51
  end
49
-
52
+
50
53
  if count > 0
51
- values.sort!
54
+ values.sort!
52
55
  percentiles.each do |pct|
53
56
  idx = pct * (values.length - 1) + 1.0
54
57
  if idx <= 1
@@ -62,49 +65,49 @@ module Metrics
62
65
  end
63
66
  end
64
67
  end
65
-
68
+
66
69
  return scores
67
70
  end
68
-
71
+
69
72
  def update_min(value)
70
73
  if (@min == nil || value < @min)
71
- @min = value
74
+ @min = value
72
75
  end
73
76
  end
74
-
77
+
75
78
  def update_max(value)
76
79
  if (@max == nil || value > @max)
77
- @max = value
78
- end
80
+ @max = value
81
+ end
79
82
  end
80
-
83
+
81
84
  def update_variance(value)
82
85
  count = @count
83
86
  old_m = @variance_m
84
87
  new_m = @variance_m + ((value - old_m) / count)
85
88
  new_s = @variance_s + ((value - old_m) * (value - new_m))
86
-
89
+
87
90
  @variance_m = new_m
88
91
  @variance_s = new_s
89
92
  end
90
-
93
+
91
94
  def variance
92
95
  count = @count
93
- variance_s = @variance_s
94
-
95
- if count <= 1
96
+ variance_s = @variance_s
97
+
98
+ if count <= 1
96
99
  return 0.0
97
100
  else
98
101
  return variance_s.to_f / (count - 1).to_i
99
102
  end
100
103
  end
101
-
104
+
102
105
  def count
103
106
  count = @count
104
107
  return count
105
108
  end
106
-
107
-
109
+
110
+
108
111
  def max
109
112
  max = @max
110
113
  if max != nil
@@ -113,7 +116,7 @@ module Metrics
113
116
  return 0.0
114
117
  end
115
118
  end
116
-
119
+
117
120
  def min
118
121
  min = @min
119
122
  if min != nil
@@ -122,60 +125,58 @@ module Metrics
122
125
  return 0.0
123
126
  end
124
127
  end
125
-
128
+
126
129
  def mean
127
130
  count = @count
128
131
  sum = @sum
129
-
132
+
130
133
  if count > 0
131
134
  return sum / count
132
135
  else
133
136
  return 0.0
134
137
  end
135
138
  end
136
-
137
- def std_dev
139
+
140
+ def std_dev
138
141
  count = @count
139
142
  variance = self.variance()
140
-
143
+
141
144
  if count > 0
142
145
  return Math.sqrt(variance)
143
- else
146
+ else
144
147
  return 0.0
145
148
  end
146
149
  end
147
-
150
+
148
151
  def values
149
152
  @sample.values
150
153
  end
151
-
152
- def to_json(*_)
154
+
155
+ def as_json(*_)
153
156
  {
154
- :min => self.min,
157
+ :min => self.min,
155
158
  :max => self.max,
156
- :mean => self.mean,
157
- :variance => self.variance,
159
+ :mean => self.mean,
160
+ :variance => self.variance,
158
161
  :percentiles => self.quantiles([0.25, 0.50, 0.75, 0.95, 0.97, 0.98, 0.99])
159
- }.to_json
162
+ }
163
+ end
164
+
165
+ def to_json(*_)
166
+ as_json.to_json
160
167
  end
161
-
162
168
  end
163
-
169
+
164
170
  class ExponentialHistogram < Histogram
165
171
  def initialize
166
172
  super(:exponential)
167
173
  end
168
174
  end
169
175
 
170
- register_instrument(:exponential_histogram, ExponentialHistogram)
171
-
172
176
  class UniformHistogram < Histogram
173
177
  def initialize
174
178
  super(:uniform)
175
179
  end
176
180
  end
177
-
178
- register_instrument(:uniform_histogram, UniformHistogram)
179
181
  end
180
-
181
182
  end