Skip to content

Commit

Permalink
Add support for custom DISTRIBUTION metric
Browse files Browse the repository at this point in the history
Example of usage follows:

    iex> MyApp.Statix.distribution("rendering", 12, [])
    :ok

From the Datadog documentation:

> 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, and aggregations occur server-side.
Because the underlying data structure represents raw, unaggregated data,
distributions provide two major features:
>
>  - Calculation of percentile aggregations
>  - Customization of tagging

https://docs.datadoghq.com/developers/metrics/types/?tab=distribution#definition

Closes lexmag#46
  • Loading branch information
dnlserrano authored and dustinfarris committed Apr 25, 2024
1 parent 18fdfb7 commit 2f02341
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 8 deletions.
25 changes: 24 additions & 1 deletion lib/statix.ex
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,24 @@ defmodule Statix do
"""
@callback timing(key, value :: String.Chars.t(), options) :: on_send

@doc """
Same as `distribution(key, value, [])`.
"""
@callback distribution(key, value :: String.Chars.t()) :: on_send

@doc """
Writes the given `value` to the StatsD distribution identified by `key`.
`value` is expected in milliseconds.
## Examples
iex> MyApp.Statix.distribution("rendering", 12, [])
:ok
"""
@callback distribution(key, value :: String.Chars.t(), options) :: on_send

@doc """
Writes the given `value` to the StatsD set identified by `key`.
Expand Down Expand Up @@ -330,6 +348,10 @@ defmodule Statix do
Statix.transmit(current_statix(), :timing, key, val, options)
end

def distribution(key, val, options \\ []) do
Statix.transmit(current_statix(), :distribution, key, val, options)
end

def measure(key, options \\ [], fun) when is_function(fun, 0) do
{elapsed, result} = :timer.tc(fun)

Expand All @@ -349,7 +371,8 @@ defmodule Statix do
histogram: 3,
timing: 3,
measure: 3,
set: 3
set: 3,
distribution: 3
)
end
end
Expand Down
3 changes: 2 additions & 1 deletion lib/statix/packet.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ defmodule Statix.Packet do
gauge: "g",
histogram: "h",
timing: "ms",
set: "s"
set: "s",
distribution: "d"
}

for {name, type} <- metrics do
Expand Down
9 changes: 9 additions & 0 deletions test/statix/overriding_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ defmodule Statix.OverridingTest do
super([key, "-overridden"], value, options)
end

def distribution(key, value, options) do
super([key, "-overridden"], value, options)
end

setup do
connect()
end
Expand Down Expand Up @@ -64,6 +68,11 @@ defmodule Statix.OverridingTest do
assert_receive {:test_server, _, "sample-overridden:3|ms|#foo"}
end

test "distribution/3" do
distribution("sample", 3, tags: ["foo"])
assert_receive {:test_server, _, "sample-overridden:3|d|#foo"}
end

test "measure/3" do
measure("sample", [tags: ["foo"]], fn ->
:timer.sleep(100)
Expand Down
3 changes: 2 additions & 1 deletion test/statix/pool_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ defmodule Statix.PoolingTest do
{:histogram, [3]},
{:timing, [3]},
{:measure, [fn -> nil end]},
{:set, [3]}
{:set, [3]},
{:distribution, [3]}
]
|> Enum.map(fn {function, arguments} ->
apply(__MODULE__, function, ["sample" | arguments])
Expand Down
32 changes: 27 additions & 5 deletions test/statix_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -155,27 +155,49 @@ defmodule StatixTest do
refute_received _any
end

test "distribution/2,3" do
__MODULE__.distribution(["sample"], 2)
assert_receive {:test_server, _, "sample:2|d"}

distribution("sample", 2.1)
assert_receive {:test_server, _, "sample:2.1|d"}

distribution("sample", 3, tags: ["foo:bar", "baz"])
assert_receive {:test_server, _, "sample:3|d|#foo:bar,baz"}

distribution("sample", 3, sample_rate: 1.0, tags: ["foo", "bar"])
assert_receive {:test_server, _, "sample:3|d|@1.0|#foo,bar"}

distribution("sample", 3, sample_rate: 0.0)

refute_received _any
end

test "port closed" do
close_port()

assert capture_log(fn ->
assert {:error, :port_closed} == increment("sample")
end) =~ "counter metric \"sample\" lost value 1 error=:port_closed\n\e[0m"
end) =~ "counter metric \"sample\" lost value 1 error=:port_closed"

assert capture_log(fn ->
assert {:error, :port_closed} == decrement("sample")
end) =~ "counter metric \"sample\" lost value -1 error=:port_closed\n\e[0m"
end) =~ "counter metric \"sample\" lost value -1 error=:port_closed"

assert capture_log(fn ->
assert {:error, :port_closed} == gauge("sample", 2)
end) =~ "gauge metric \"sample\" lost value 2 error=:port_closed\n\e[0m"
end) =~ "gauge metric \"sample\" lost value 2 error=:port_closed"

assert capture_log(fn ->
assert {:error, :port_closed} == histogram("sample", 3)
end) =~ "histogram metric \"sample\" lost value 3 error=:port_closed\n\e[0m"
end) =~ "histogram metric \"sample\" lost value 3 error=:port_closed"

assert capture_log(fn ->
assert {:error, :port_closed} == timing("sample", 2.5)
end) =~ "timing metric \"sample\" lost value 2.5 error=:port_closed\n\e[0m"
end) =~ "timing metric \"sample\" lost value 2.5 error=:port_closed"

assert capture_log(fn ->
assert {:error, :port_closed} == distribution("sample", 2.5)
end) =~ "distribution metric \"sample\" lost value 2.5 error=:port_closed"
end
end

0 comments on commit 2f02341

Please sign in to comment.