Current section

Files

Jump to
dogstatsde src dogstatsd.erl
Raw

src/dogstatsd.erl

-module(dogstatsd).
-type metric_name() :: iodata().
-type metric_value() :: number().
-type metric_type() :: counter | gauge | histogram | timer | set.
-type metric_sample_rate() :: number().
-type metric_tags() :: map().
-type metric_data() :: {metric_name(), metric_value()}
| {metric_name(), metric_value(), metric_sample_rate()|metric_tags()}
| {metric_name(), metric_value(), metric_sample_rate(), metric_tags()}.
-type event_title() :: iodata().
-type event_text() :: iodata().
-type event_type() :: info | error | warning | success.
-type event_priority() :: normal | low.
-type event_tags() :: map().
-export_type([
metric_name/0
,metric_value/0
,metric_type/0
,metric_sample_rate/0
,metric_tags/0
,metric_data/0
]).
-export([
gauge/1, gauge/2, gauge/3, gauge/4
,counter/1 ,counter/2, counter/3, counter/4
,increment/1, increment/2, increment/3, increment/4
,histogram/1, histogram/2, histogram/3, histogram/4
,timer/1, timer/2, timer/3, timer/4
,timing/1, timing/2, timing/3, timing/4
,set/1, set/2, set/3, set/4
,event/1, event/2, event/3, event/4, event/5
]).
-spec send_metric(metric_type(), [metric_data()]) -> ok.
send_metric(_Type, []) ->
ok;
send_metric(Type, MetricDataList) ->
NormalizedMetricDataList = [normalize_metric_data(MetricData) || MetricData <- MetricDataList],
send({metric, {Type, NormalizedMetricDataList}}).
-spec send_event(event_title(), event_text(), event_type(), event_priority(), event_tags()) -> ok.
send_event(Title, Text, Type, Priority, Tags) ->
send({event, {Title, Text, Type, Priority, Tags}}).
-spec send({atom(), tuple()}) -> ok.
send(Data) ->
wpool:cast(dogstatsd_worker, Data).
-define(SPEC_TYPE_1(Type), -spec Type(metric_data() | [metric_data()]) -> ok).
-define(MK_TYPE_1(Type),
Type(MetricDataList) when is_list(MetricDataList) ->
send_metric(Type, MetricDataList);
Type(MetricData) when is_tuple(MetricData) ->
send_metric(Type, [MetricData])
).
-define(SPEC_TYPE_2(Type), -spec Type(metric_name(), metric_value()) -> ok).
-define(MK_TYPE_2(Type),
Type(Name, Value) when is_number(Value) ->
send_metric(Type, [{Name, Value}])
).
-define(SPEC_TYPE_3(Type), -spec Type(metric_name(), metric_value(), metric_sample_rate()|metric_tags()) -> ok).
-define(MK_TYPE_3(Type),
Type(Name, Value, SampleRateOrTags) when is_number(Value) andalso (is_number(SampleRateOrTags) orelse is_map(SampleRateOrTags)) ->
send_metric(Type, [{Name, Value, SampleRateOrTags}])
).
-define(SPEC_TYPE_4(Type), -spec Type(metric_name(), metric_value(), metric_sample_rate(), metric_tags()) -> ok).
-define(MK_TYPE_4(Type),
Type(Name, Value, SampleRate, Tags) when is_number(SampleRate), is_map(Tags) ->
send_metric(Type, [{Name, Value, SampleRate, Tags}])
).
-define(ALIAS_TYPE_1(Alias, Real), Alias(A) -> Real(A)).
-define(ALIAS_TYPE_2(Alias, Real), Alias(A, B) -> Real(A, B)).
-define(ALIAS_TYPE_3(Alias, Real), Alias(A, B, C) -> Real(A, B, C)).
-define(ALIAS_TYPE_4(Alias, Real), Alias(A, B, C, D) -> Real(A, B, C, D)).
?SPEC_TYPE_1(gauge).
?SPEC_TYPE_2(gauge).
?SPEC_TYPE_3(gauge).
?SPEC_TYPE_4(gauge).
?MK_TYPE_1(gauge).
?MK_TYPE_2(gauge).
?MK_TYPE_3(gauge).
?MK_TYPE_4(gauge).
?SPEC_TYPE_1(counter).
?SPEC_TYPE_2(counter).
?SPEC_TYPE_3(counter).
?SPEC_TYPE_4(counter).
?MK_TYPE_1(counter).
?MK_TYPE_2(counter).
?MK_TYPE_3(counter).
?MK_TYPE_4(counter).
?ALIAS_TYPE_1(increment, counter).
?ALIAS_TYPE_2(increment, counter).
?ALIAS_TYPE_3(increment, counter).
?ALIAS_TYPE_4(increment, counter).
?SPEC_TYPE_1(histogram).
?SPEC_TYPE_2(histogram).
?SPEC_TYPE_3(histogram).
?SPEC_TYPE_4(histogram).
?MK_TYPE_1(histogram).
?MK_TYPE_2(histogram).
?MK_TYPE_3(histogram).
?MK_TYPE_4(histogram).
?SPEC_TYPE_1(timer).
?SPEC_TYPE_2(timer).
?SPEC_TYPE_3(timer).
?SPEC_TYPE_4(timer).
?MK_TYPE_1(timer).
?MK_TYPE_2(timer).
?MK_TYPE_3(timer).
?MK_TYPE_4(timer).
?ALIAS_TYPE_1(timing, timer).
?ALIAS_TYPE_2(timing, timer).
?ALIAS_TYPE_3(timing, timer).
?ALIAS_TYPE_4(timing, timer).
?SPEC_TYPE_1(set).
?SPEC_TYPE_2(set).
?SPEC_TYPE_3(set).
?SPEC_TYPE_4(set).
?MK_TYPE_1(set).
?MK_TYPE_2(set).
?MK_TYPE_3(set).
?MK_TYPE_4(set).
-spec event(event_title()) -> ok.
event(Title) -> event(Title, "").
-spec event(event_title(), event_text()) -> ok.
event(Title, Text) -> event(Title, Text, info).
-spec event(event_title(), event_text(), event_type()) -> ok.
event(Title, Text, Type) -> event(Title, Text, Type, normal).
-spec event(event_title(), event_text(), event_type(), event_priority()) -> ok.
event(Title, Text, Type, Priority) -> event(Title, Text, Type, Priority, #{}).
-spec event(event_title(), event_text(), event_type(), event_priority(), event_tags()) -> ok.
event(Title, Text, Type, Priority, Tags) ->
send_event(Title, Text, Type, Priority, Tags).
%%%===================================================================
%%% Internal functions
%%%===================================================================
normalize_metric_data({Name, Value}) ->
{Name, Value, 1.0, #{}};
normalize_metric_data({Name, Value, SampleRate}) when is_number(SampleRate) ->
{Name, Value, SampleRate, #{}};
normalize_metric_data({Name, Value, Tags}) when is_map(Tags) ->
{Name, Value, 1.0, Tags};
normalize_metric_data({_Name, _Value, _SampleRate, _Tags} = AlreadyNormalized) ->
AlreadyNormalized.
%%% Tests
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
test_setup() ->
meck:new(wpool),
meck:expect(wpool, 'cast', fun (dogstatsd_worker, _Data) -> ok end).
test_teardown(_) ->
meck:unload(wpool).
gauge_test_() ->
{setup,
fun test_setup/0,
fun test_teardown/1,
[
?_assertEqual(ok, dogstatsd:gauge("foo.bar", 1))
,?_assertEqual(ok, dogstatsd:gauge("foo.bar", 1, 0.5))
,?_assertEqual(ok, dogstatsd:gauge("foo.bar", 1, #{baz => qux}))
,?_assertEqual(ok, dogstatsd:gauge("foo.bar", 1, 0.25, #{baz => qux}))
,?_assertError(function_clause, dogstatsd:gauge("foo.bar", #{baz => qux}))
,?_assertError(function_clause, dogstatsd:gauge("foo.bar", #{baz => qux}, 0.5))
,?_assertError(function_clause, dogstatsd:gauge("foo.bar", 1, "hello"))
,?_assertEqual(ok, dogstatsd:gauge([{"foo.bar", 1, 0.5, #{foo => bar}},
{"foo.bar", 1, 0.5, #{foo => bar}}]))
,?_assertError(function_clause, dogstatsd:gauge([{"foo.bar", 1, 0.5, #{foo => bar}},
{"foo.bar", 1, "hello"}]))
]}.
normalize_metric_data_test_() ->
[
?_assertEqual({"key", "value", 1.0, #{}}, normalize_metric_data({"key", "value"}))
,?_assertEqual({"key", "value", 12, #{}}, normalize_metric_data({"key", "value", 12}))
,?_assertEqual({"key", "value", 1.0, #{foo => bar}},
normalize_metric_data({"key", "value", #{foo => bar}}))
,?_assertEqual({"key", "value", 12, #{foo => bar}},
normalize_metric_data({"key", "value", 12, #{foo => bar}}))
].
-endif.