Packages
prometheus
3.0.0-alpha9
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/metrics/prometheus_counter.erl
%% @doc
%% Counter is a Metric that represents a single numerical value that only ever
%% goes up. That implies that it cannot be used to count items whose number can
%% also go down, e.g. the number of currently running processes. Those
%% "counters" are represented by {@link prometheus_gauge}.
%%
%% A Counter is typically used to count requests served, tasks completed, errors
%% occurred, etc.
%%
%% Examople use cases for Counters:
%% <ul>
%% <li>Number of requests processed</li>
%% <li>Number of items that were inserted into a queue</li>
%% <li>Total amount of data a system has processed</li>
%% </ul>
%%
%% Use the
%% <a href="https://prometheus.io/docs/querying/functions/#rate()">rate()</a>/<a
%% href="https://prometheus.io/docs/querying/functions/#irate()">irate()</a>
%% functions in Prometheus to calculate the rate of increase of a Counter.
%% By convention, the names of Counters are suffixed by `_total'.
%%
%% @end
-module(prometheus_counter).
%%% metric
-export([new/1,
new/2,
declare/1,
declare/2,
inc/1,
inc/2,
inc/3,
inc/4,
dinc/1,
dinc/2,
dinc/3,
dinc/4,
remove/1,
remove/2,
remove/3,
reset/1,
reset/2,
reset/3,
value/1,
value/2,
value/3]).
%%% collector
-export([deregister_cleanup/1,
collect_mf/2,
collect_metrics/2]).
%%% gen_server
-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3,
start_link/0]).
-import(prometheus_model_helpers, [create_mf/5,
gauge_metrics/1,
gauge_metric/1,
gauge_metric/2,
counter_metric/1,
counter_metric/2]).
-include("prometheus.hrl").
-behaviour(prometheus_metric).
-behaviour(prometheus_collector).
-behaviour(gen_server).
%%====================================================================
%% Macros
%%====================================================================
-define(TABLE, ?PROMETHEUS_COUNTER_TABLE).
-define(SUM_POS, 2).
%%====================================================================
%% Metric API
%%====================================================================
new(Spec) ->
prometheus_metric:insert_new_mf(?TABLE, ?MODULE, Spec).
%% @deprecated Please use {@link new/1} with registry
%% key instead.
new(Spec, Registry) ->
?DEPRECATED("prometheus_counter:new/2", "prometheus_counter:new/1"
" with registry key"),
new([{registry, Registry} | Spec]).
declare(Spec) ->
prometheus_metric:insert_mf(?TABLE, ?MODULE, Spec).
%% @deprecated Please use {@link declare/1} with registry
%% key instead.
declare(Spec, Registry) ->
?DEPRECATED("prometheus_counter:declare/2", "prometheus_counter:declare/1"
" with registry key"),
declare([{registry, Registry} | Spec]).
%% @equiv inc(default, Name, [], 1)
inc(Name) ->
inc(default, Name, [], 1).
inc(Name, LabelValues) when is_list(LabelValues)->
inc(default, Name, LabelValues, 1);
inc(Name, Value) ->
inc(default, Name, [], Value).
%% @equiv inc(default, Name, LabelValues, Value)
inc(Name, LabelValues, Value) ->
inc(default, Name, LabelValues, Value).
inc(_Registry, _Name, _LabelValues, Value) when Value < 0 ->
erlang:error({invalid_value, Value,
"inc accepts only non-negative integers"});
inc(Registry, Name, LabelValues, Value) when is_integer(Value) ->
try
ets:update_counter(?TABLE, {Registry, Name, LabelValues}, {?SUM_POS, Value})
catch error:badarg ->
insert_metric(Registry, Name, LabelValues, Value, fun inc/4)
end,
ok;
inc(_Registry, _Name, _LabelValues, Value) ->
erlang:error({invalid_value, Value,
"inc accepts only non-negative integers"}).
%% @equiv dinc(default, Name, [], 1)
dinc(Name) ->
dinc(default, Name, [], 1).
dinc(Name, LabelValues) when is_list(LabelValues)->
dinc(default, Name, LabelValues, 1);
dinc(Name, Value) when is_number(Value) ->
dinc(default, Name, [], Value).
%% @equiv dinc(default, Name, LabelValues, Value)
dinc(Name, LabelValues, Value) ->
dinc(default, Name, LabelValues, Value).
dinc(_Registry, _Name, _LabelValues, Value) when Value < 0 ->
erlang:error({invalid_value, Value,
"dinc accepts only non-negative numbers"});
dinc(Registry, Name, LabelValues, Value) when is_number(Value) ->
MF = prometheus_metric:check_mf_exists(?TABLE, Registry, Name, LabelValues),
CallTimeout = prometheus_metric:mf_call_timeout(MF),
case CallTimeout of
false ->
gen_server:cast(?MODULE,
{inc, {Registry, Name, LabelValues, Value}});
_ -> gen_server:call(?MODULE,
{inc, {Registry, Name, LabelValues, Value}},
CallTimeout)
end,
ok;
dinc(_Registry, _Name, _LabelValues, Value) ->
erlang:error({invalid_value, Value,
"dinc accepts only non-negative numbers"}).
%% @equiv remove(default, Name, [])
remove(Name) ->
remove(default, Name, []).
%% @equiv remove(default, Name, LabelValues)
remove(Name, LabelValues) ->
remove(default, Name, LabelValues).
remove(Registry, Name, LabelValues) ->
prometheus_metric:remove_labels(?TABLE, Registry, Name, LabelValues).
%% @equiv reset(default, Name, [])
reset(Name) ->
reset(default, Name, []).
%% @equiv reset(default, Name, LabelValues)
reset(Name, LabelValues) ->
reset(default, Name, LabelValues).
reset(Registry, Name, LabelValues) ->
prometheus_metric:check_mf_exists(?TABLE, Registry, Name, LabelValues),
ets:update_element(?TABLE, {Registry, Name, LabelValues}, {?SUM_POS, 0}).
%% @equiv value(default, Name, [])
value(Name) ->
value(default, Name, []).
%% @equiv value(default, Name, LabelValues)
value(Name, LabelValues) ->
value(default, Name, LabelValues).
value(Registry, Name, LabelValues) ->
prometheus_metric:check_mf_exists(?TABLE, Registry, Name, LabelValues),
case ets:lookup(?TABLE, {Registry, Name, LabelValues}) of
[{_Key, Value}] -> Value;
[] -> undefined
end.
%%====================================================================
%% Collector API
%%====================================================================
%% @private
deregister_cleanup(Registry) ->
prometheus_metric:deregister_mf(?TABLE, Registry),
true = ets:match_delete(?TABLE, {{Registry, '_', '_'}, '_'}),
ok.
%% @private
collect_mf(Registry, Callback) ->
[Callback(create_counter(Name, Help, {Labels, Registry})) ||
[Name, {Labels, Help}, _, _, _] <- prometheus_metric:metrics(?TABLE,
Registry)],
ok.
%% @private
collect_metrics(Name, {Labels, Registry}) ->
[counter_metric(lists:zip(Labels, LabelValues), Value) ||
[LabelValues, Value] <- ets:match(?TABLE, {{Registry, Name, '$1'}, '$2'})].
%%====================================================================
%% Gen_server API
%%====================================================================
%% @private
init(_Args) ->
{ok, []}.
%% @private
handle_call({inc, {Registry, Name, LabelValues, Value}}, _From, State) ->
dinc_impl(Registry, Name, LabelValues, Value),
{reply, ok, State}.
%% @private
handle_cast({inc, {Registry, Name, LabelValues, Value}}, State) ->
dinc_impl(Registry, Name, LabelValues, Value),
{noreply, State}.
%% @private
handle_info(_Info, State) ->
{noreply, State}.
%% @private
terminate(_Reason, _State) ->
ok.
%% @private
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%% @private
start_link() ->
gen_server:start_link({local, prometheus_counter},
prometheus_counter, [], []).
%%====================================================================
%% Private Parts
%%====================================================================
dinc_impl(Registry, Name, LabelValues, Value) ->
case ets:lookup(?TABLE, {Registry, Name, LabelValues}) of
[{_Key, OldValue}] ->
ets:update_element(?TABLE, {Registry, Name, LabelValues},
{?SUM_POS, Value + OldValue});
[] ->
insert_metric(Registry, Name, LabelValues, Value, fun dinc_impl/4)
end.
insert_metric(Registry, Name, LabelValues, Value, ConflictCB) ->
prometheus_metric:check_mf_exists(?TABLE, Registry, Name, LabelValues),
case ets:insert_new(?TABLE, {{Registry, Name, LabelValues}, Value}) of
false -> %% some sneaky process already inserted
ConflictCB(Registry, Name, LabelValues, Value);
true ->
ok
end.
create_counter(Name, Help, Data) ->
create_mf(Name, Help, counter, ?MODULE, Data).