Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
38 changes: 24 additions & 14 deletions lib/statsd/instrument.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,21 @@ def self.generate_metric_name(metric_name, callee, *args)
metric_name.respond_to?(:call) ? metric_name.call(callee, args).gsub('::', '.') : metric_name.gsub('::', '.')
end

def self.duration
start = current_timestamp
yield
current_timestamp - start
end

if Process.respond_to?(:clock_gettime)
# @private
def self.duration
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
yield
Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
def self.current_timestamp
Process.clock_gettime(Process::CLOCK_MONOTONIC)
end
else
# @private
def self.duration
start = Time.now
yield
Time.now - start
def self.current_timestamp
Time.now
end
end

Expand Down Expand Up @@ -277,17 +279,25 @@ def backend
# http_response = StatsD.measure('HTTP.call.duration') do
# HTTP.get(url)
# end
def measure(key, value = nil, *metric_options, &block)
def measure(key, value = nil, *metric_options)
if value.is_a?(Hash) && metric_options.empty?
metric_options = [value]
value = value.fetch(:value, nil)
end

result = nil
value = 1000 * StatsD::Instrument.duration { result = block.call } if block_given?
metric = collect_metric(hash_argument(metric_options).merge(type: :ms, name: key, value: value))
result = metric unless block_given?
result
if block_given?
result = nil
start = StatsD::Instrument.current_timestamp
begin
result = yield
ensure
value = 1000 * (StatsD::Instrument.current_timestamp - start)
collect_metric(hash_argument(metric_options).merge(type: :ms, name: key, value: value))
result
end
else
collect_metric(hash_argument(metric_options).merge(type: :ms, name: key, value: value))
end
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can still use the old duration method.

value = 1000 * StatsD::Instrument.duration do
  begin
    result = yield
  ensure
    ...
  end
end

Copy link
Author

Choose a reason for hiding this comment

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

The problem is that we need to have the duration by the time we reach the ensure block in order to deliver the metric with the actual length of the call. I dont think this would work :(

end

# Emits a counter metric.
Expand Down
2 changes: 1 addition & 1 deletion lib/statsd/instrument/metric_expectation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@ def to_s
def inspect
"#<StatsD::Instrument::MetricExpectation #{self.to_s}>"
end
end
end
16 changes: 16 additions & 0 deletions test/statsd_instrumentation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ def ssl_post(arg)
{:success => arg}
end

def boom
raise "boom!"
end

def purchase(arg)
ssl_post(arg)
end
Expand Down Expand Up @@ -198,6 +202,18 @@ def test_statsd_measure
ActiveMerchant::UniqueGateway.statsd_remove_measure :ssl_post, 'ActiveMerchant.Gateway.ssl_post'
end

def test_statsd_measure_when_exception_is_raised
ActiveMerchant::UniqueGateway.statsd_measure :boom, 'ActiveMerchant.Gateway.boom', sample_rate: 0.3

assert_statsd_measure('ActiveMerchant.Gateway.boom', sample_rate: 0.3) do
assert_raises("boom!") do
ActiveMerchant::UniqueGateway.new.boom
end
end
ensure
ActiveMerchant::UniqueGateway.statsd_remove_measure :boom, 'ActiveMerchant.Gateway.boom'
end

def test_statsd_measure_uses_normalized_metric_name
ActiveMerchant::UniqueGateway.statsd_measure :ssl_post, 'ActiveMerchant::Gateway.ssl_post'

Expand Down
13 changes: 12 additions & 1 deletion test/statsd_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,24 @@ def test_statsd_measure_with_explicit_value_and_sample_rate
end

def test_statsd_measure_with_benchmarked_block_duration
StatsD::Instrument.stubs(:duration).returns(1.12)
StatsD::Instrument.stubs(:current_timestamp).returns(0, 1.12)
metric = capture_statsd_call do
StatsD.measure('values.foobar') { 'foo' }
end
assert_equal 1120.0, metric.value
end

def test_statsd_measure_with_benchmarked_block_duration_even_when_it_raises
StatsD::Instrument.stubs(:current_timestamp).returns(0, 1.12)
metric = capture_statsd_call do
exception = "boom!"
assert_raises(exception) do
StatsD.measure('values.foobar') { raise exception }
end
end
assert_equal 1120.0, metric.value
end

def test_statsd_measure_returns_return_value_of_block
return_value = StatsD.measure('values.foobar') { 'sarah' }
assert_equal 'sarah', return_value
Expand Down