Skip to content

Commit

Permalink
Add distribution metric type for Datadog compatibility
Browse files Browse the repository at this point in the history
Signed-off-by: Marc Jeffrey <[email protected]>
  • Loading branch information
mjeffrey18 authored and miketheman committed Apr 24, 2022
1 parent 3dfce79 commit f3a461e
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 7 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
This project aims to adhere to [Semantic Versioning](http://semver.org/).

## 0.4.0 / 2022-04-24

- Added `Statsd::Client.distribution(metric_name, value, tags)` for Datadog compatibility

## 0.3.0 / 2021-04-11

- Crystal 0.35.1 removed Errno, so was removed in code as well #15
Expand Down
1 change: 1 addition & 0 deletions examples/benchmark.cr
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ Benchmark.ips do |x|
x.report("gauges w/tags") { statsd.gauge("users.current", 5, tags: ["foo:bar"]) }
x.report("timing") { statsd.timing("db.query", 100) }
x.report("time") { statsd.time("timed.block") { true } }
x.report("distribution") { statsd.distribution("request.latency", 5) }
end
2 changes: 1 addition & 1 deletion shard.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: statsd
version: 0.3.0
version: 0.4.0

authors:
- Mike Fiedler <[email protected]>
Expand Down
24 changes: 24 additions & 0 deletions spec/statsd/methods_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,28 @@ describe Statsd::Methods do
end
end
end

describe "#distribution" do
it "should format the message according to the statsd spec" do
with_server do |server, statsd|
statsd.distribution("foobar", 50)
expected_message = "foobar:50|d"
server.gets(expected_message.bytesize).should eq expected_message
end
end

it "should raise an exception for negative values" do
with_server do |server, statsd|
expect_raises(Exception) { statsd.distribution("foobar", -50) }
end
end

it "should format the message according to the extended statsd spec" do
with_server do |server, statsd|
statsd.distribution("foobar", 50, tags: ["foo:bar"])
expected_message = "foobar:50|d|#foo:bar"
server.gets(expected_message.bytesize).should eq expected_message
end
end
end
end
5 changes: 5 additions & 0 deletions spec/statsd/metric_message_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ describe Statsd::MetricMessage do
message.should eq("users.current:20|g")
end

it "supports #distribution" do
message = Statsd::MetricMessage.serialize_metric("request.latency", 20.0442, "d")
message.should eq("request.latency:20.0442|d")
end

it "supports #counter (Int32)" do
message = Statsd::MetricMessage.serialize_metric("page.views", 1, "c")
message.should eq("page.views:1|c")
Expand Down
44 changes: 38 additions & 6 deletions src/statsd/methods.cr
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
module Statsd
module Methods
COUNTER_TYPE = "c"
GAUGE_TYPE = "g"
HISTOGRAM_TYPE = "h"
DISTRIBUTION_TYPE = "d"
TIMING_TYPE = "ms"
SET_TYPE = "s"

# Gauge
#
# A gauge is an instantaneous measurement of a value, like the gas gauge in a car.
# It differs from a counter by being calculated at the client rather than the server.
# Valid gauge values are in the range [0, 2^64^)
def gauge(metric_name, value, tags = nil)
raise "Gauges may only receive positive values" unless positive? value
send_metric(metric_name, value, "g", tags: tags)
send_metric(metric_name, value, GAUGE_TYPE, tags: tags)
end

# Counters
Expand All @@ -24,11 +31,11 @@ module Statsd
# ```

def increment(metric_name, sample_rate = nil, tags = nil)
send_metric(metric_name, 1, "c", sample_rate, tags: tags)
send_metric(metric_name, 1, COUNTER_TYPE, sample_rate, tags: tags)
end

def decrement(metric_name, sample_rate = nil, tags = nil)
send_metric(metric_name, -1, "c", sample_rate, tags: tags)
send_metric(metric_name, -1, COUNTER_TYPE, sample_rate, tags: tags)
end

# Timers
Expand All @@ -51,7 +58,7 @@ module Statsd
# ```
def timing(metric_name, ms, tags = nil)
raise "Timers may only receive positive values" unless positive? ms
send_metric(metric_name, ms, "ms", tags: tags)
send_metric(metric_name, ms, TIMING_TYPE, tags: tags)
end

# Measure execution time of a given block, using {#timing}.
Expand All @@ -72,7 +79,7 @@ module Statsd
# <metric name>:<value>|s
# ```
def set(metric_name, value, tags = nil)
send_metric(metric_name, value, "s", tags: tags)
send_metric(metric_name, value, SET_TYPE, tags: tags)
end

# Histograms
Expand All @@ -87,7 +94,32 @@ module Statsd
# ```
def histogram(metric_name, value, tags = nil)
raise "Histograms may only receive positive values" unless positive? value
send_metric(metric_name, value, "h", tags: tags)
send_metric(metric_name, value, HISTOGRAM_TYPE, tags: tags)
end

# Distributions
#
# The DISTRIBUTION metric type is specific to DataDog (DogStatsD).
#
# The DISTRIBUTION metric submission type represents the global statistical distribution of a set of values calculated across your entire distributed infrastructure in one time interval.
# A DISTRIBUTION can be used to instrument logical objects, like services, independently from the underlying hosts.
#
# Unlike the HISTOGRAM metric type, which aggregates on the Agent during a given time interval, a DISTRIBUTION metric sends all the raw data during a time interval to Datadog.
# Aggregations occur on the server-side. Because the underlying data structure represents raw, un-aggregated data, distributions provide two major features:
#
# - Calculation of percentile aggregations
# - Customization of tagging
#
# Like other metric types, such as GAUGE or HISTOGRAM, the DISTRIBUTION metric type has the following aggregations available:
# count, min, max, sum, and avg
#
# Example:
# ```
# <metric name>:<value>|d
# ```
def distribution(metric_name, value, tags = nil)
raise "distribution may only receive positive values" unless positive? value
send_metric(metric_name, value, DISTRIBUTION_TYPE, tags: tags)
end

# Helpers
Expand Down

0 comments on commit f3a461e

Please sign in to comment.