ruby-metrics 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ coverage
2
+ *.gem
3
+ pkg/*
4
+ .DS_Store
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm ruby-1.9.2@metrics
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ # Specify your gem's dependencies in ruby-metrics.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,32 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ruby-metrics (0.5.0)
5
+ json
6
+ ruby-units
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ diff-lcs (1.1.2)
12
+ json (1.5.1)
13
+ rspec (2.5.0)
14
+ rspec-core (~> 2.5.0)
15
+ rspec-expectations (~> 2.5.0)
16
+ rspec-mocks (~> 2.5.0)
17
+ rspec-core (2.5.1)
18
+ rspec-expectations (2.5.0)
19
+ diff-lcs (~> 1.1.2)
20
+ rspec-mocks (2.5.0)
21
+ ruby-units (1.2.0)
22
+ simplecov (0.4.0)
23
+ simplecov-html (~> 0.4.0)
24
+ simplecov-html (0.4.3)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ rspec
31
+ ruby-metrics!
32
+ simplecov (>= 0.3.8)
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2011 John Ewart
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/README.md ADDED
@@ -0,0 +1,44 @@
1
+
2
+ ## What is this?
3
+
4
+ This is a Ruby version of performance metrics inspired by [metrics][metrics] developed by Coda Hale at Yammer. Currently this is under *heavy* development -- it needs Gem packaging, more features, validation of metrics, more functional testing, and a little better test coverage. Pull requests happily accepted, please include docs and tests where possible!
5
+
6
+ ## What needs to be done?
7
+
8
+ Among other important things, this needs to be made more thread-safe. I'm currently looking at Mr. Nutter's ruby-atomic gem for making this less tedious but any suggestions are welcome!
9
+
10
+ ## What's in this?
11
+
12
+ Right now, I have:
13
+
14
+ * Counters
15
+ * Meters
16
+ * Gauges
17
+ * Histograms w/ uniform sampling
18
+
19
+ Upcoming:
20
+
21
+ * Histograms w/ exponentially decaying sampling
22
+ * Timers
23
+
24
+ ## Getting Started
25
+
26
+ The goal of ruby-metrics is to get up and running quickly. You start an agent, register some instruments, and they're exported over HTTP via JSON. For example, getting started with a counter would look like this:
27
+
28
+ @metrics = Metrics::Agent.new
29
+ @metrics.start
30
+
31
+ counter = @metrics.counter :my_counter
32
+ counter.incr
33
+ counter.incr
34
+
35
+ Then, hitting localhost:8081/status would yield:
36
+
37
+ {"my_counter":"2"}
38
+
39
+
40
+ [metrics]: https://github.com/codahale/metrics
41
+
42
+ ## License
43
+
44
+ Copyright 2011 John Ewart <john@johnewart.net>. Released under the MIT license. See the file LICENSE for further details.
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require "rubygems"
2
+ require "bundler"
3
+ require "rspec/core/rake_task"
4
+ Bundler::GemHelper.install_tasks
5
+
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
12
+ end
13
+
14
+ RSpec::Core::RakeTask.new do |t|
15
+ t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
16
+ t.pattern = 'spec/**/*_spec.rb'
17
+ end
18
+
19
+ task :default => :spec
@@ -0,0 +1,3 @@
1
+ Autotest.add_discovery do
2
+ "rspec2"
3
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require '../lib/ruby-metrics'
3
+
4
+ @metrics = Metrics::Agent.new
5
+ @metrics.start
6
+
7
+ counter = @metrics.counter :my_counter
8
+ counter.incr
9
+ counter.incr
10
+
11
+ puts "Counter: #{counter.to_i}"
data/examples/gauge.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ require '../lib/ruby-metrics'
3
+
4
+ @metrics = Metrics::Agent.new
5
+ @metrics.start
6
+
7
+ hit_count = 42
8
+ http_requests = 53
9
+
10
+ gauge = @metrics.gauge :my_gauge do
11
+ {
12
+ :hit_count => hit_count,
13
+ :http_requests => http_requests
14
+ }
15
+ end
16
+
17
+ puts "Gauge: #{gauge.to_s}"
18
+
19
+ hit_count = 65
20
+ http_requests = 99
21
+
22
+ puts "Gauge: #{gauge.to_s}"
23
+
24
+ result = gauge.get
25
+
26
+ puts "Result: #{result}"
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require '../lib/ruby-metrics'
3
+
4
+ @metrics = Metrics::Agent.new
5
+ @metrics.start
6
+
7
+ histogram = @metrics.histogram :my_histogram
8
+ data = %w(3.600 1.800 3.333 2.283 4.533 2.883 4.700 3.600 1.950 4.350 1.833 3.917 4.200 1.750 4.700 2.167 1.750 4.800 1.600 4.250 1.800 1.750 3.450 3.067 4.533 3.600 1.967 4.083 3.850 4.433 4.300 4.467 3.367 4.033 3.833 2.017 1.867 4.833 1.833 4.783 4.350 1.883 4.567 1.750 4.533 3.317 3.833 2.100 4.633 2.000 4.800 4.716 1.833 4.833 1.733 4.883 3.717 1.667 4.567 4.317 2.233 4.500 1.750 4.800 1.817 4.400 4.167 4.700 2.067 4.700 4.033 1.967 4.500 4.000 1.983 5.067 2.017 4.567 3.883 3.600 4.133 4.333 4.100 2.633 4.067 4.933 3.950 4.517 2.167 4.000 2.200 4.333 1.867 4.817 1.833 4.300 4.667 3.750 1.867 4.900 2.483 4.367 2.100 4.500 4.050 1.867 4.700 1.783 4.850 3.683 4.733 2.300 4.900 4.417 1.700 4.633 2.317 4.600 1.817 4.417 2.617 4.067 4.250 1.967 4.600 3.767 1.917 4.500 2.267 4.650 1.867 4.167 2.800 4.333 1.833 4.383 1.883 4.933 2.033 3.733 4.233 2.233 4.533 4.817 4.333 1.983 4.633 2.017 5.100 1.800 5.033 4.000 2.400 4.600 3.567 4.000 4.500 4.083 1.800 3.967 2.200 4.150 2.000 3.833 3.500 4.583 2.367 5.000 1.933 4.617 1.917 2.083 4.583 3.333 4.167 4.333 4.500 2.417 4.000 4.167 1.883 4.583 4.250 3.767 2.033 4.433 4.083 1.833 4.417 2.183 4.800 1.833 4.800 4.100 3.966 4.233 3.500 4.366 2.250 4.667 2.100 4.350 4.133 1.867 4.600 1.783 4.367 3.850 1.933 4.500 2.383 4.700 1.867 3.833 3.417 4.233 2.400 4.800 2.000 4.150 1.867 4.267 1.750 4.483 4.000 4.117 4.083 4.267 3.917 4.550 4.083 2.417 4.183 2.217 4.450 1.883 1.850 4.283 3.950 2.333 4.150 2.350 4.933 2.900 4.583 3.833 2.083 4.367 2.133 4.350 2.200 4.450 3.567 4.500 4.150 3.817 3.917 4.450 2.000 4.283 4.767 4.533 1.850 4.250 1.983 2.250 4.750 4.117 2.150 4.417 1.817 4.467)
9
+ data.each do |point|
10
+ histogram.update(point.to_f)
11
+ end
12
+
13
+ step = 0
14
+
15
+ # This is here so that we will run indefinitely so you can hit the
16
+ # status page on localhost:8001/status
17
+ loop do
18
+ sleep 1
19
+
20
+ modifier = rand(500).to_i / 100
21
+ step += 1
22
+
23
+ if (step % 2)
24
+ modifier *= -1
25
+ end
26
+
27
+ histogram.update((2 + modifier).to_f)
28
+ end
data/examples/meter.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require '../lib/ruby-metrics'
3
+
4
+ @metrics = Metrics::Agent.new
5
+ @metrics.start
6
+
7
+ timer = @metrics.meter :my_meter
8
+ timer.mark(500)
9
+
10
+ step = 0
11
+
12
+ # This is here so that we will run indefinitely so you can hit the
13
+ # status page on localhost:8001/status
14
+ loop do
15
+ sleep 1
16
+
17
+ modifier = rand(200).to_i
18
+ step += 1
19
+
20
+ if (step % 2)
21
+ modifier *= -1
22
+ end
23
+
24
+ timer.mark(500 + modifier)
25
+ end
@@ -0,0 +1,15 @@
1
+ # == Metrics Initialization
2
+ #
3
+
4
+ module Metrics
5
+
6
+ class << self
7
+ attr_writer :logger
8
+ def logger
9
+ @logger ||= Logger.new(STDOUT)
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+ require File.join(File.dirname(__FILE__), 'ruby-metrics', 'agent')
@@ -0,0 +1,55 @@
1
+ require File.join(File.dirname(__FILE__), 'logging')
2
+ require File.join(File.dirname(__FILE__), 'instruments')
3
+ require 'webrick'
4
+
5
+ class Status < WEBrick::HTTPServlet::AbstractServlet
6
+
7
+ def initialize(server, instruments)
8
+ @instruments = instruments
9
+ end
10
+
11
+ def do_GET(request, response)
12
+ status, content_type, body = do_stuff_with(request)
13
+
14
+ response.status = status
15
+ response['Content-Type'] = content_type
16
+ response.body = body
17
+ end
18
+
19
+ def do_stuff_with(request)
20
+ return 200, "text/plain", @instruments.to_json
21
+ end
22
+
23
+ end
24
+
25
+ module Metrics
26
+ class Agent
27
+ include Logging
28
+ include Instruments::TypeMethods
29
+
30
+ attr_reader :instruments
31
+
32
+ def initialize
33
+ logger.debug "Initializing Metrics..."
34
+ @instruments = Metrics::Instruments
35
+ end
36
+
37
+ def start
38
+ start_daemon_thread
39
+ end
40
+
41
+ protected
42
+ def start_daemon_thread(connection_options = {})
43
+ logger.debug "Creating Metrics daemon thread."
44
+ @daemon_thread = Thread.new do
45
+ begin
46
+ server = WEBrick::HTTPServer.new ({:Port => 8001})
47
+ server.mount "/status", Status, @instruments
48
+ server.start
49
+ rescue Exception => e
50
+ logger.error "Error in worker thread: #{e.class.name}: #{e}\n #{e.backtrace.join("\n ")}"
51
+ end # begin
52
+ end # thread new
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,64 @@
1
+ require File.join(File.dirname(__FILE__), 'statistics', 'sample')
2
+ require File.join(File.dirname(__FILE__), 'statistics', 'uniform_sample')
3
+
4
+ require File.join(File.dirname(__FILE__), 'instruments', 'base')
5
+ require File.join(File.dirname(__FILE__), 'instruments', 'counter')
6
+ require File.join(File.dirname(__FILE__), 'instruments', 'meter')
7
+ require File.join(File.dirname(__FILE__), 'instruments', 'gauge')
8
+ require File.join(File.dirname(__FILE__), 'instruments', 'histogram')
9
+
10
+
11
+ require 'json'
12
+
13
+ module Metrics
14
+ module Instruments
15
+ @instruments = {}
16
+
17
+ @types = {
18
+ :counter => Counter,
19
+ :meter => Meter,
20
+ :gauge => Gauge,
21
+ :histogram => Histogram
22
+ }
23
+
24
+ def self.register(type, name, &block)
25
+ @instruments[name] = @types[type].new(&block)
26
+ end
27
+
28
+ def self.unregister_all
29
+ @instruments = {}
30
+ end
31
+
32
+ def self.registered
33
+ @instruments
34
+ end
35
+
36
+ def self.to_json
37
+ @instruments.to_json
38
+ end
39
+
40
+ module TypeMethods
41
+
42
+ def register(type, name, &block)
43
+ Metrics::Instruments.register(type, name, &block)
44
+ end
45
+
46
+ def counter(name)
47
+ register(:counter, name)
48
+ end
49
+
50
+ def meter(name)
51
+ register(:meter, name)
52
+ end
53
+
54
+ def gauge(name, &block)
55
+ register(:gauge, name, &block)
56
+ end
57
+
58
+ def histogram(name)
59
+ register(:histogram, name)
60
+ end
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,19 @@
1
+ module Metrics
2
+ module Instruments
3
+ class Base
4
+
5
+ def to_i
6
+ raise NotImplementedError
7
+ end
8
+
9
+ def to_s
10
+ raise NotImplementedError
11
+ end
12
+
13
+ def to_f
14
+ raise NotImplementedError
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,33 @@
1
+ module Metrics
2
+ module Instruments
3
+ class Counter < Base
4
+
5
+ def initialize
6
+ @value = 0
7
+ end
8
+
9
+ def inc(value = 1)
10
+ @value += value
11
+ end
12
+ alias_method :incr, :inc
13
+
14
+ def dec(value = 1)
15
+ @value -= value
16
+ end
17
+ alias_method :decr, :dec
18
+
19
+ def clear
20
+ @value = 0
21
+ end
22
+
23
+ def to_i
24
+ @value.to_i
25
+ end
26
+
27
+ def to_s
28
+ @value.to_s
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ module Metrics
2
+ module Instruments
3
+ class Gauge < Base
4
+
5
+ def initialize(&block)
6
+ raise ArgumentError, "a block is required" unless block_given?
7
+ @block = block
8
+ end
9
+
10
+ def get
11
+ instance_exec(&@block)
12
+ end
13
+
14
+ def to_s
15
+ get.to_json
16
+ end
17
+
18
+ end
19
+ end
20
+ end