Skip to content

Commit

Permalink
extract formatting into own module
Browse files Browse the repository at this point in the history
  • Loading branch information
Sascha Kattelmann committed Jun 29, 2017
1 parent 3015cd8 commit 9eb0481
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 76 deletions.
103 changes: 103 additions & 0 deletions src/exometer_prometheus_fmt.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
-module(exometer_prometheus_fmt).

-export([
name/1,
type/1,
metrics/1
]).

-type prom_name() :: iolist().
-type prom_type() :: iolist().
-type prom_help() :: iolist().
-type prom_text() :: binary().
-type metric_info() :: {exometer:name(),
exometer:value(),
prom_name(),
prom_type(),
prom_help()}.


%% -------------------------------------------------------
%% Public API
%% -------------------------------------------------------

-spec name(exometer:name()) -> binary().
name(MetricId) ->
NameList = lists:join($_, lists:map(fun ioize/1, MetricId)),
NameBin = iolist_to_binary(NameList),
re:replace(NameBin, "-|\\.", "_", [global, {return,binary}]).

-spec type(atom()) -> binary().
type(undefined) -> <<"untyped">>;
type(counter) -> <<"gauge">>;
type(gauge) -> <<"gauge">>;
type(spiral) -> <<"gauge">>;
type(histogram) -> <<"summary">>;
type(function) -> <<"gauge">>;
type(Tuple) when is_tuple(Tuple) ->
case element(1, Tuple) of
function -> <<"gauge">>;
_Else -> <<"untyped">>
end.

-spec metrics([metric_info()]) -> prom_text().
metrics(Metrics) ->
Formatted = metrics(Metrics, []),
iolist_to_binary(Formatted).


%% -------------------------------------------------------
%% Internal
%% -------------------------------------------------------

metrics([], Akk) ->
Akk;
metrics([{Metric, DataPoints, Name, Type, Help} | Metrics], Akk) ->
Payload = [[<<"# HELP ">>, Name, <<" ">>, Help, <<"\n">>,
<<"# TYPE ">>, Name, <<" ">>, Type, <<"\n">>] |
[[Name, map_datapoint(DPName), <<" ">>, ioize(Value), <<"\n">>]
|| {DPName, Value} <- DataPoints, is_valid_datapoint(DPName)]],
Payload1 = maybe_add_sum(Payload, Name, Metric, Type),
metrics(Metrics, [Payload1, <<"\n">> | Akk]).

ioize(Atom) when is_atom(Atom) ->
atom_to_binary(Atom, utf8);
ioize(Number) when is_float(Number) ->
float_to_binary(Number, [{decimals, 4}]);
ioize(Number) when is_integer(Number) ->
integer_to_binary(Number);
ioize(Something) ->
Something.

maybe_add_sum(Payload, MetricName, Metric, <<"summary">>) ->
{ok, [{mean, Mean}, {n, N}]} = exometer:get_value(Metric, [mean, n]),
[Payload | [MetricName, <<"_sum ">>, ioize(Mean * N), <<"\n">>]];
maybe_add_sum(Payload, _MetricName, _Metric, _Else) ->
Payload.

map_datapoint(value) -> <<"">>;
map_datapoint(one) -> <<"">>;
map_datapoint(n) -> <<"_count">>;
map_datapoint(50) -> <<"{quantile=\"0.5\"}">>;
map_datapoint(90) -> <<"{quantile=\"0.9\"}">>;
map_datapoint(Integer) when is_integer(Integer) ->
Bin = ioize(Integer),
<<"{quantile=\"0.", Bin/binary, "\"}">>;
map_datapoint(Something) ->
%% this is for functions with alternative datapoints
Bin = ioize(Something),
<<"{datapoint=\"", Bin/binary, "\"}">>.

is_valid_datapoint(value) -> true;
is_valid_datapoint(one) -> true;
is_valid_datapoint(n) -> true;
is_valid_datapoint(Number) when is_number(Number) -> true;
is_valid_datapoint(count) -> false;
is_valid_datapoint(mean) -> false;
is_valid_datapoint(min) -> false;
is_valid_datapoint(max) -> false;
is_valid_datapoint(median) -> false;
is_valid_datapoint(ms_since_reset) -> false;
%% this is for functions with alternative datapoints
is_valid_datapoint(_Else) -> true.

81 changes: 5 additions & 76 deletions src/exometer_report_prometheus.erl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
%% Public API
%% -------------------------------------------------------

-spec fetch() -> exometer_prometheus_fmt:prom_text().
fetch() ->
exometer_report:call_reporter(exometer_report_prometheus, {request, fetch}).

Expand All @@ -40,11 +41,11 @@ exometer_init(Opts) ->
{ok, #state{}}.

exometer_subscribe(Metric, DataPoints, _Interval, Opts, State = #state{entries=Entries}) ->
Name = make_metric_name(Metric),
Name = exometer_prometheus_fmt:name(Metric),
Help = proplists:get_value(help, Opts, <<"undefined">>),
Type = case proplists:get_value(type, Opts, undefined) of
undefined -> map_type(exometer:info(Metric, type));
SomeType -> ioize(SomeType)
undefined -> exometer_prometheus_fmt:type(exometer:info(Metric, type));
SomeType -> atom_to_binary(SomeType, latin1)
end,
Entry = {Metric, DataPoints, Name, Type, Help},
{ok, State#state{entries = Entries ++ [Entry]}}.
Expand All @@ -71,7 +72,7 @@ exometer_terminate(_Reason, _) -> ignore.

fetch_and_format_metrics(Entries) ->
Metrics = fetch_metrics(Entries),
format_metrics(Metrics).
exometer_prometheus_fmt:metrics(Metrics).

fetch_metrics(Entries) ->
fetch_metrics(Entries, []).
Expand All @@ -86,75 +87,3 @@ fetch_metrics([{Metric, DataPoints, Name, Type, Help} | Entries], Akk) ->
fetch_metrics(Entries, Akk)
end.

format_metrics(Metrics) ->
Formatted = format_metrics(Metrics, []),
iolist_to_binary(Formatted).

format_metrics([], Akk) ->
Akk;
format_metrics([{Metric, DataPoints, Name, Type, Help} | Metrics], Akk) ->
Payload = [[<<"# HELP ">>, Name, <<" ">>, Help, <<"\n">>,
<<"# TYPE ">>, Name, <<" ">>, Type, <<"\n">>] |
[[Name, map_datapoint(DPName), <<" ">>, ioize(Value), <<"\n">>]
|| {DPName, Value} <- DataPoints, is_valid_datapoint(DPName)]],
Payload1 = maybe_add_sum(Payload, Name, Metric, Type),
format_metrics(Metrics, [Payload1, <<"\n">> | Akk]).

make_metric_name(Metric) ->
NameList = lists:join($_, lists:map(fun ioize/1, Metric)),
NameBin = iolist_to_binary(NameList),
re:replace(NameBin, "-|\\.", "_", [global, {return,binary}]).

ioize(Atom) when is_atom(Atom) ->
atom_to_binary(Atom, utf8);
ioize(Number) when is_float(Number) ->
float_to_binary(Number, [{decimals, 4}]);
ioize(Number) when is_integer(Number) ->
integer_to_binary(Number);
ioize(Something) ->
Something.

maybe_add_sum(Payload, MetricName, Metric, <<"summary">>) ->
{ok, [{mean, Mean}, {n, N}]} = exometer:get_value(Metric, [mean, n]),
[Payload | [MetricName, <<"_sum ">>, ioize(Mean * N), <<"\n">>]];
maybe_add_sum(Payload, _MetricName, _Metric, _Else) ->
Payload.

map_type(undefined) -> <<"untyped">>;
map_type(counter) -> <<"gauge">>;
map_type(gauge) -> <<"gauge">>;
map_type(spiral) -> <<"gauge">>;
map_type(histogram) -> <<"summary">>;
map_type(function) -> <<"gauge">>;
map_type(Tuple) when is_tuple(Tuple) ->
case element(1, Tuple) of
function -> <<"gauge">>;
_Else -> <<"untyped">>
end.

map_datapoint(value) -> <<"">>;
map_datapoint(one) -> <<"">>;
map_datapoint(n) -> <<"_count">>;
map_datapoint(50) -> <<"{quantile=\"0.5\"}">>;
map_datapoint(90) -> <<"{quantile=\"0.9\"}">>;
map_datapoint(Integer) when is_integer(Integer) ->
Bin = ioize(Integer),
<<"{quantile=\"0.", Bin/binary, "\"}">>;
map_datapoint(Something) ->
%% this is for functions with alternative datapoints
Bin = ioize(Something),
<<"{datapoint=\"", Bin/binary, "\"}">>.

is_valid_datapoint(value) -> true;
is_valid_datapoint(one) -> true;
is_valid_datapoint(n) -> true;
is_valid_datapoint(Number) when is_number(Number) -> true;
is_valid_datapoint(count) -> false;
is_valid_datapoint(mean) -> false;
is_valid_datapoint(min) -> false;
is_valid_datapoint(max) -> false;
is_valid_datapoint(median) -> false;
is_valid_datapoint(ms_since_reset) -> false;
%% this is for functions with alternative datapoints
is_valid_datapoint(_Else) -> true.

0 comments on commit 9eb0481

Please sign in to comment.