Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

add support for derivative metrics #22

Open
wants to merge 3 commits into from

2 participants

@hollow

A derivative metric is like a meter but accepts an absolute counter as
input. This is useful for metrics like bytes sent over the network or
cpu cycles which are generally monotonically increasing counters and
therefore need to be derived from the previous sample to get a useful
rate/s value.

hollow added some commits
@hollow hollow add support for derivative metrics
A derivative metric is like a meter but accepts an absolute counter as
input. This is useful for metrics like bytes sent over the network or
cpu cycles which are generally monotonically increasing counters and
therefore need to be derived from the previous sample to get a useful
rate/s value.
f426d16
@hollow hollow update require statement d2baf70
@hollow hollow add unit test for derive 4a9a9e4
@eric eric commented on the diff
lib/metriks/derive.rb
@@ -0,0 +1,13 @@
+require 'atomic'
+
+require 'metriks/meter'
+
+module Metriks
+ class Derive < Metriks::Meter
+ def mark(val = 1)
+ @last ||= Atomic.new(val)
@eric Owner
eric added a note

This needs to be initialized in the constructor to be threadsafe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@eric eric commented on the diff
lib/metriks/derive.rb
@@ -0,0 +1,13 @@
+require 'atomic'
+
+require 'metriks/meter'
+
+module Metriks
+ class Derive < Metriks::Meter
+ def mark(val = 1)
+ @last ||= Atomic.new(val)
+ last = @last.swap(val)
+ super(last > val ? val : val - last)
@eric Owner
eric added a note

One problem with doing this simplistically is that the rate calculations, etc. are all updated every 5 seconds. If a counter is polled (and mark() is called) less frequently than 5 seconds, the rates will be recorded as all happening right when mark() was called instead of something more reasonable (like linearly from the last time it was polled and now).

I'll have to dig into the underlying classes more to see if there's a reasonable way to do this sort of thing, but it may be that a meter isn't the right thing to be using as an underlying implementation for a derived counter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@eric
Owner

I think we should make a derivative metric not inherit from Meter.

The things to consider are:

  1. How often is the derived metric going to be updated?
  2. How often is the reporter going to report on the metric?
  3. What should happen if the derived metric hasn't been updated since the last report?
  4. What should happen if the derived metric has been updated more than once since the last report?

With the Meter we have, we expect that we will be incrementing it as things happen, but with this derived metric, we are (I would guess) expecting to update it on a regular interval, so it has a lot of different implications.

@hollow

In my case:

  1. every second
  2. just like for any other metric?

since i collect these metrics every second, i don't really care about the other two, but i would suggest something like:

  1. & 4. nothing or something invalid (like -∞)

probably do it similar to RRDtool, people are already familiar how DERIVE works with RRAs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 12, 2012
  1. @hollow

    add support for derivative metrics

    hollow authored
    A derivative metric is like a meter but accepts an absolute counter as
    input. This is useful for metrics like bytes sent over the network or
    cpu cycles which are generally monotonically increasing counters and
    therefore need to be derived from the previous sample to get a useful
    rate/s value.
  2. @hollow

    update require statement

    hollow authored
  3. @hollow

    add unit test for derive

    hollow authored
This page is out of date. Refresh to see the latest.
View
5 lib/metriks.rb
@@ -1,4 +1,3 @@
-
module Metriks
VERSION = '0.9.9.1'
@@ -22,6 +21,10 @@ def self.meter(name)
Metriks::Registry.default.meter(name)
end
+ def self.derive(name)
+ Metriks::Registry.default.derive(name)
+ end
+
def self.histogram(name)
Metriks::Registry.default.histogram(name)
end
View
13 lib/metriks/derive.rb
@@ -0,0 +1,13 @@
+require 'atomic'
+
+require 'metriks/meter'
+
+module Metriks
+ class Derive < Metriks::Meter
+ def mark(val = 1)
+ @last ||= Atomic.new(val)
@eric Owner
eric added a note

This needs to be initialized in the constructor to be threadsafe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ last = @last.swap(val)
+ super(last > val ? val : val - last)
@eric Owner
eric added a note

One problem with doing this simplistically is that the rate calculations, etc. are all updated every 5 seconds. If a counter is polled (and mark() is called) less frequently than 5 seconds, the rates will be recorded as all happening right when mark() was called instead of something more reasonable (like linearly from the last time it was polled and now).

I'll have to dig into the underlying classes more to see if there's a reasonable way to do this sort of thing, but it may be that a meter isn't the right thing to be using as an underlying implementation for a derived counter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ end
+ end
+end
View
18 lib/metriks/registry.rb
@@ -2,6 +2,7 @@
require 'metriks/timer'
require 'metriks/utilization_timer'
require 'metriks/meter'
+require 'metriks/derive'
module Metriks
# Public: A collection of metrics
@@ -86,6 +87,21 @@ def meter(name)
add_or_get(name, Metriks::Meter)
end
+ # Public: Fetch or create a new derivative metric. Derivatives are a meter
+ # that tracks throughput by calculating the derivative to the previous
+ # value.
+ #
+ # name - The String name of the metric to define or fetch
+ #
+ # Examples
+ #
+ # registry.derive('network.bytes')
+ #
+ # Returns the Metricks::Derive identified by the name.
+ def derive(name)
+ add_or_get(name, Metriks::Derive)
+ end
+
# Public: Fetch or create a new timer metric. Timers provide the means to
# time the execution of a method including statistics on the number of
# invocations, average length of time, throughput.
@@ -188,4 +204,4 @@ def add_or_get(name, klass, &create_metric)
end
end
end
-end
+end
View
32 test/derive_test.rb
@@ -0,0 +1,32 @@
+require 'test_helper'
+
+require 'metriks/derive'
+
+class DeriveTest < Test::Unit::TestCase
+ include ThreadHelper
+
+ def setup
+ @meter = Metriks::Derive.new
+ end
+
+ def teardown
+ @meter.stop
+ end
+
+ def test_meter
+ @meter.mark(100)
+ @meter.mark(150)
+
+ assert_equal 50, @meter.count
+ end
+
+ def test_one_minute_rate
+ @meter.mark(1000)
+ @meter.mark(2000)
+
+ # Pretend it's been 5 seconds
+ @meter.tick
+
+ assert_equal 200, @meter.one_minute_rate
+ end
+end
Something went wrong with that request. Please try again.