Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions lib/metriks/reporter/counter_derivative.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
module Metriks
module Reporter
class CounterDerivative
def initialize(reporter)
@reporter = reporter
@last = Hash.new
end

def each(&block)
@registry.each do |name, metric|
case metric
when Metriks::Meter
if @last["#{name}.count"]
count = metric.count
block.call("#{name}.count", count - @last["#{name}.count"])
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we only report like this, it means we won't actually report the marks that happened before the reporter was run for the first time.

Because we know these things are in-process, I think it would actually make more sense to initialize @last with a default of 0 for the hash values:

  @last = Hash.new do |h,k|
    h[k] = 0
  end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

@last["#{name}.count"] = count
end
when Metriks::Counter
block.call("#{name}.count", metric.count)
when Metriks::Gauge
block.call("#{name}.value", metric.value)
when Metriks::UtilizationTimer
if @last["#{name}.count"]
count = metric.count
block.call("#{name}.count", count - @last["#{name}.count"])
@last["#{name}.count"] = count
end

block.call("#{name}.min", metric.min)
block.call("#{name}.max", metric.max)
block.call("#{name}.median", metric.median)
block.call("#{name}.stddev", metric.stddev)

block.call("#{name}.one_minute_utilization", metric.one_minute_utilization)
block.call("#{name}.five_minute_utilization", metric.five_minute_utilization)
block.call("#{name}.fifteen_minute_utilization", metric.fifteen_minute_utilization)

snapshot = metric.snapshot

block.call("#{name}.median", snapshot.median)
block.call("#{name}.75th_percentile", snapshot.get_75th_percentile)
block.call("#{name}.95th_percentile", snapshot.get_95th_percentile)
block.call("#{name}.98th_percentile", snapshot.get_98th_percentile)
block.call("#{name}.99th_percentile", snapshot.get_99th_percentile)
block.call("#{name}.999th_percentile", snapshot.get_999th_percentile)
when Metriks::Timer
if @last["#{name}.count"]
count = metric.count
block.call("#{name}.count", count - @last["#{name}.count"])
@last["#{name}.count"] = count
end

block.call("#{name}.min", metric.min)
block.call("#{name}.max", metric.max)
block.call("#{name}.median", metric.median)
block.call("#{name}.stddev", metric.stddev)

snapshot = metric.snapshot

block.call("#{name}.median", snapshot.median)
block.call("#{name}.75th_percentile", snapshot.get_75th_percentile)
block.call("#{name}.95th_percentile", snapshot.get_95th_percentile)
block.call("#{name}.98th_percentile", snapshot.get_98th_percentile)
block.call("#{name}.99th_percentile", snapshot.get_99th_percentile)
block.call("#{name}.999th_percentile", snapshot.get_999th_percentile)
when Metriks::Histogram
block.call("#{name}.count", metric.count)
block.call("#{name}.min", metric.min)
block.call("#{name}.max", metric.max)
block.call("#{name}.median", metric.median)
block.call("#{name}.stddev", metric.stddev)

snapshot = metric.snapshot

block.call("#{name}.median", snapshot.median)
block.call("#{name}.75th_percentile", snapshot.get_75th_percentile)
block.call("#{name}.95th_percentile", snapshot.get_95th_percentile)
block.call("#{name}.98th_percentile", snapshot.get_98th_percentile)
block.call("#{name}.99th_percentile", snapshot.get_99th_percentile)
block.call("#{name}.999th_percentile", snapshot.get_999th_percentile)
end
end
end
end
end
end
105 changes: 105 additions & 0 deletions lib/metriks/reporter/flattening_registry_enumerator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
module Metriks
module Reporter
class FlatteningRegistryEnumerator
def initialize(registry, options = {})
@registry = registry
if options[:counter_derivitive]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be :counter_derivative.

@last = Hash.new { |h,k| h[k] = 0 }
end
end

def each(&block)
@registry.each do |name, metric|
case metric
when Metriks::Meter
if @last
count = metric.count
block.call("#{name}.count", count - @last["#{name}.count"])
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to append .count here? Calling it the name of the metric seems like it would be good enough.

@last["#{name}.count"] = count
else
block.call("#{name}.count", metric.count)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if it ever makes sense to actually send count... in the cases that I can think of, I don't believe it does.

block.call("#{name}.one_minute_rate", metric.one_minute_rate)
block.call("#{name}.five_minute_rate", metric.five_minute_rate)
block.call("#{name}.fifteen_minute_rate", metric.fifteen_minute_rate)
block.call("#{name}.mean_rate", metric.mean_rate)
end

when Metriks::Counter
block.call("#{name}.count", metric.count)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason to append .count to the end of the metric name? Maybe we should just call it the metric name and be done with it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .count makes sense for systems like Graphite. Not sure about others.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you know that a value is a count when it does not say .count?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That brings up a good philosophical point:

Do we want the metric names to contain "schema" information that can be used to help format them properly? Is it useful to do that?

I sort of lean toward the side of not caring about that schema information being included in the metric name, but I could see the value of it depending on what sort of backend you were using.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With schema information you mean "meter", "timer", ...? That seems pretty verbose to me. ("foo.bar.baz.meter.one_minute_rate") If a reporter wants to get rid of that it has to do some string wrangling.

Another option is to pass the metric class to the block.

block.call("#{name}.one_minute_rate", metric.one_minute_rate, metric.class)

That way the reporter can just ignore the class name but can access it if it needs to take a decision based on the metric type.

And then one could ask: why compute the name string in the first place?

block.call(name, "one_minute_rate", metric.one_minute_rate, metric.class)

Which makes the reporter to do more work again.

I like the simplicity of the current enumeration approach.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, and we can always create new registry presentation classes for the reporters later. ;)

when Metriks::Gauge
block.call("#{name}.value", metric.value)
when Metriks::UtilizationTimer
if @last
count = metric.count
block.call("#{name}.count", count - @last["#{name}.count"])
@last["#{name}.count"] = count
else
block.call("#{name}.one_minute_rate", metric.one_minute_rate)
block.call("#{name}.five_minute_rate", metric.five_minute_rate)
block.call("#{name}.fifteen_minute_rate", metric.fifteen_minute_rate)
end

block.call("#{name}.min", metric.min)
block.call("#{name}.max", metric.max)
block.call("#{name}.median", metric.median)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The #median method only exists on the snapshot object. This doesn't work. (and #median is already called on the snapshot below)

Same for Timer and Histogram.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

block.call("#{name}.stddev", metric.stddev)

block.call("#{name}.one_minute_utilization", metric.one_minute_utilization)
block.call("#{name}.five_minute_utilization", metric.five_minute_utilization)
block.call("#{name}.fifteen_minute_utilization", metric.fifteen_minute_utilization)

snapshot = metric.snapshot

block.call("#{name}.median", snapshot.median)
block.call("#{name}.75th_percentile", snapshot.get_75th_percentile)
block.call("#{name}.95th_percentile", snapshot.get_95th_percentile)
block.call("#{name}.98th_percentile", snapshot.get_98th_percentile)
block.call("#{name}.99th_percentile", snapshot.get_99th_percentile)
block.call("#{name}.999th_percentile", snapshot.get_999th_percentile)
when Metriks::Timer
if @last
count = metric.count
block.call("#{name}.count", count - @last["#{name}.count"])
@last["#{name}.count"] = count
else
block.call("#{name}.count", metric.count)
block.call("#{name}.one_minute_rate", metric.one_minute_rate)
block.call("#{name}.five_minute_rate", metric.five_minute_rate)
block.call("#{name}.fifteen_minute_rate", metric.fifteen_minute_rate)
block.call("#{name}.mean_rate", metric.mean_rate)
end

block.call("#{name}.min", metric.min)
block.call("#{name}.max", metric.max)
block.call("#{name}.median", metric.median)
block.call("#{name}.stddev", metric.stddev)

snapshot = metric.snapshot

block.call("#{name}.median", snapshot.median)
block.call("#{name}.75th_percentile", snapshot.get_75th_percentile)
block.call("#{name}.95th_percentile", snapshot.get_95th_percentile)
block.call("#{name}.98th_percentile", snapshot.get_98th_percentile)
block.call("#{name}.99th_percentile", snapshot.get_99th_percentile)
block.call("#{name}.999th_percentile", snapshot.get_999th_percentile)
when Metriks::Histogram
block.call("#{name}.count", metric.count)
block.call("#{name}.min", metric.min)
block.call("#{name}.max", metric.max)
block.call("#{name}.median", metric.median)
block.call("#{name}.stddev", metric.stddev)

snapshot = metric.snapshot

block.call("#{name}.median", snapshot.median)
block.call("#{name}.75th_percentile", snapshot.get_75th_percentile)
block.call("#{name}.95th_percentile", snapshot.get_95th_percentile)
block.call("#{name}.98th_percentile", snapshot.get_98th_percentile)
block.call("#{name}.99th_percentile", snapshot.get_99th_percentile)
block.call("#{name}.999th_percentile", snapshot.get_999th_percentile)
end
end
end
end
end
end
63 changes: 6 additions & 57 deletions lib/metriks/reporter/graphite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,71 +47,20 @@ def restart
end

def write
@registry.each do |name, metric|
case metric
when Metriks::Meter
write_metric name, metric, [
:count, :one_minute_rate, :five_minute_rate,
:fifteen_minute_rate, :mean_rate
]
when Metriks::Counter
write_metric name, metric, [
:count
]
when Metriks::Gauge
write_metric name, metric, [
:value
]
when Metriks::UtilizationTimer
write_metric name, metric, [
:count, :one_minute_rate, :five_minute_rate,
:fifteen_minute_rate, :mean_rate,
:min, :max, :mean, :stddev,
:one_minute_utilization, :five_minute_utilization,
:fifteen_minute_utilization, :mean_utilization,
], [
:median, :get_95th_percentile
]
when Metriks::Timer
write_metric name, metric, [
:count, :one_minute_rate, :five_minute_rate,
:fifteen_minute_rate, :mean_rate,
:min, :max, :mean, :stddev
], [
:median, :get_95th_percentile
]
when Metriks::Histogram
write_metric name, metric, [
:count, :min, :max, :mean, :stddev
], [
:median, :get_95th_percentile
]
end
Metriks::Reporter::FlatteningRegistryEnumerator.new(@registry).each do |name, value|
write_metric(name, value)
end
end

def write_metric(base_name, metric, keys, snapshot_keys = [])
def write_metric(name, value)
time = Time.now.to_i

base_name = base_name.to_s.gsub(/ +/, '_')
if @prefix
base_name = "#{@prefix}.#{base_name}"
end

keys.flatten.each do |key|
name = key.to_s.gsub(/^get_/, '')
value = metric.send(key)
socket.write("#{base_name}.#{name} #{value} #{time}\n")
name = "#{@prefix}.#{name}"
end

unless snapshot_keys.empty?
snapshot = metric.snapshot
snapshot_keys.flatten.each do |key|
name = key.to_s.gsub(/^get_/, '')
value = snapshot.send(key)
socket.write("#{base_name}.#{name} #{value} #{time}\n")
end
end
name = name.to_s.gsub(/ +/, '_')
socket.write("#{name} #{value} #{time}\n")
rescue Errno::EPIPE
socket.close
end
Expand Down
Loading