Packages
prometheus
3.0.0-alpha10
6.1.3
6.1.2
6.1.1
6.1.0
6.0.3
6.0.2
6.0.1
6.0.0
5.1.1
5.1.0
5.0.0
4.13.0
retired
4.12.0
4.11.0
4.10.0
4.9.1
4.9.0
4.8.2
4.8.1
4.8.0
4.6.0
4.5.0
4.4.1
4.4.0
4.3.0
4.2.2
4.2.0
4.1.0
4.0.1
4.0.0
3.5.1
3.5.0
3.4.6
3.4.5
3.4.4
3.4.3
3.4.2
3.4.1
3.4.0
3.3.2
3.3.1
3.3.0
3.2.3
3.2.2
3.2.1
3.1.1
3.1.0
3.0.1
3.0.0
3.0.0-rc1
3.0.0-alpha9
3.0.0-alpha8
3.0.0-alpha7
3.0.0-alpha6
3.0.0-alpha5
3.0.0-alpha4
3.0.0-alpha3
3.0.0-alpha2
3.0.0-alpha10
3.0.0-alpha1
2.2.0
2.1.0
2.0.0
1.7.0
1.6.0
1.5.0
1.0.2
1.0.1
1.0.0
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
Prometheus.io client in Erlang
Current section
Files
Jump to
Current section
Files
src/prometheus_time.erl
%% @doc
%% Measuring time intervals with Prometheus.erl.
%% Measuring time intervals is trivial - you just have to be sure you are using
%% monotonic time source. Basically interval is a difference between
%% start time and end time.
%% Erlang has standard `erlang:monotonic_time' function that returns
%% so called native time units. Native time units are meaningless
%% and have to be converted to seconds (or other units)
%% using `erlang:convert_time_unit'.
%% However as `erlang:convert_time_unit' documentation
%% [warns](http://erlang.org/doc/man/erlang.html#convert_time_unit-3):
%%
%% ```
%% You may lose accuracy and precision when converting between time units.
%% In order to minimize such loss, collect all data at native time unit and
%% do the conversion on the end result.
%% '''
%%
%% and because Prometheus mandates support for floats,
%% `set_duration/observe_duration` functions always work with
%% native time units and conversion is delayed until scraping/retrieving value.
%% To implement this, metric needs to know desired time unit.
%% Users can specify time unit explicitly via `duration_unit'
%% or implicitly via metric name (preferred, since prometheus best practices
%% guide insists on `<name>_duration_<unit>' metric name format).
%%
%% Possible units:
%% - microseconds;
%% - milliseconds;
%% - seconds;
%% - minutes;
%% - hours;
%% - days;
%%
%% Histogram also converts buckets bounds to native units if
%% duration_unit is provided. It converts it back when scraping or
%% retrieving value.
%%
%% If values already converted to a 'real' unit, conversion can be disabled
%% by setting `duration_unit' to `false'.
%%
%% ## Examples
%%
%% Example where duration unit derived from name:
%% <pre lang="erlang">
%% prometheus_histogram:new([{name, fun_duration_seconds},
%% {buckets, [0.5, 1.1]}, %% in seconds
%% {help, ""}]),
%% prometheus_histogram:observe_duration(fun_duration_seconds,
%% fun () ->
%% timer:sleep(1000)
%% end),
%% prometheus_histogram:value(fun_duration_seconds).
%% {[0,1,0],1.001030886}
%% </pre>
%%
%% Example where duration unit set explicitly:
%% <pre lang="erlang">
%% prometheus_histogram:new([{name, fun_duration_histogram},
%% {buckets, [500, 1100]}, %% in milliseconds
%% {help, ""},
%% {duration_unit, milliseconds}]),
%%
%% prometheus_histogram:observe_duration(fun_duration_histogram,
%% fun () ->
%% timer:sleep(1000)
%% end),
%%
%% prometheus_histogram:value(fun_duration_histogram).
%% {[0,1,0],1001.885302}
%% </pre>
%%
%% Example where value is in seconds already:
%% <pre lang="erlang">
%% prometheus_histogram:new([{name, duration_seconds},
%% {buckets, [0.5, 1.1]}, %% in seconds
%% {help, ""},
%% {duration_unit, false}]),
%%
%% prometheus_histogram:dobserve(duration_seconds, 1.2),
%%
%% prometheus_histogram:value(duration_seconds).
%% {[0,0,1],1.2}
%% </pre>
%% @end
-module(prometheus_time).
-export([duration_unit_from_string/1,
validate_duration_unit/1,
maybe_convert_to_native/2,
maybe_convert_to_du/2]).
-ifdef(TEST).
-export([from_native/2,
to_native/2]).
-endif.
%%====================================================================
%% Macros
%%====================================================================
-define(DURATION_UNITS, [{"microseconds", microseconds},
{"milliseconds", milliseconds},
{"seconds", seconds},
{"minutes", minutes},
{"hours", hours},
{"days", days}]).
%%====================================================================
%% Public API
%%====================================================================
%% @private
duration_unit_from_string(Str) ->
duration_unit_from_string(Str, ?DURATION_UNITS).
%% @private
validate_duration_unit(false) ->
false;
validate_duration_unit(undefined) ->
undefined;
validate_duration_unit(SDU) ->
case lists:any(fun({_, DU}) ->
DU == SDU
end,
?DURATION_UNITS) of
true ->
SDU;
_ ->
erlang:error({invalid_value, SDU, "unknown duration unit"})
end.
%% @private
maybe_convert_to_native(_, infinity) ->
infinity;
maybe_convert_to_native(DU, Value) ->
case DU of
undefined -> Value;
_ -> to_native(Value, DU)
end.
%% @private
maybe_convert_to_du(_, infinity) ->
infinity;
maybe_convert_to_du(DU, Value) ->
case DU of
undefined -> Value;
_ -> from_native(Value, DU)
end.
%%====================================================================
%% Private Parts
%%====================================================================
duration_unit_from_string(Str, [{SDU, DU}|Rest]) ->
case string:rstr(Str, SDU) of
0 -> duration_unit_from_string(Str, Rest);
_ -> DU
end;
duration_unit_from_string(_, []) ->
undefined.
%% @private
from_native(Value) ->
erlang:convert_time_unit(trunc(Value), native, nano_seconds).
%% @private
from_native(Value, microseconds) ->
Nanoseconds = from_native(Value),
Nanoseconds / 1000;
from_native(Value, milliseconds) ->
Nanoseconds = from_native(Value),
Nanoseconds / 1000000;
from_native(Value, seconds) ->
Nanoseconds = from_native(Value),
Nanoseconds / 1000000000;
from_native(Value, minutes) ->
Nanoseconds = from_native(Value),
Nanoseconds / 60000000000;
from_native(Value, hours) ->
Nanoseconds = from_native(Value),
Nanoseconds / 3600000000000;
from_native(Value, days) ->
Nanoseconds = from_native(Value),
Nanoseconds / 86400000000000.
%% @private
to_native(Value) ->
erlang:convert_time_unit(trunc(Value), nano_seconds, native).
%% @private
to_native(Value, microseconds) ->
to_native(Value * 1000);
to_native(Value, milliseconds) ->
to_native(Value * 1000000);
to_native(Value, seconds) ->
to_native(Value * 1000000000);
to_native(Value, minutes) ->
to_native(Value * 60000000000);
to_native(Value, hours) ->
to_native(Value * 3600000000000);
to_native(Value, days) ->
to_native(Value * 86400000000000).