ruby-metrics 0.8.6 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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