Packages
prometheus
3.3.2
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_boolean.erl
%% @doc
%% Boolean metric, to report booleans and flags.
%%
%% Boolean is a non-standard metric that uses untyped metric underneath.
%%
%% A Boolean is typically used as a flag i.e. enabled/disabled, online/offline.
%%
%% Example:
%% <pre lang="erlang">
%% -module(my_fuse_instrumenter).
%%
%% -export([setup/0,
%% fuse_event/2]).
%%
%% setup() ->
%% prometheus_boolean:declare([{name, app_fuse_state},
%% {labels, [name]}, %% fuse name
%% {help, "State of various app fuses."}]),
%%
%% fuse_event(Fuse, Event) ->
%% case Event of
%% ok -> prometheus_boolean:set(app_fuse_state, [Fuse], true);
%% blown -> prometheus_boolean:set(app_fuse_state, [Fuse], false);
%% _ -> ok
%% end.
%% </pre>
%% @end
-module(prometheus_boolean).
%%% metric
-export([new/1,
declare/1,
set_default/2,
set/2,
set/3,
set/4,
toggle/1,
toggle/2,
toggle/3,
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]).
-import(prometheus_model_helpers, [create_mf/5,
boolean_metric/2]).
-include("prometheus.hrl").
-behaviour(prometheus_metric).
-behaviour(prometheus_collector).
%%====================================================================
%% Macros
%%====================================================================
-define(TABLE, ?PROMETHEUS_BOOLEAN_TABLE).
-define(BOOLEAN_POS, 2).
%%====================================================================
%% Metric API
%%====================================================================
%% @doc Creates a boolean using `Spec'.
%%
%% Raises `{missing_metric_spec_key, Key, Spec}' error if required `Soec' key
%% is missing.<br/>
%% Raises `{invalid_metric_name, Name, Message}' error if metric `Name'
%% is invalid.<br/>
%% Raises `{invalid_metric_help, Help, Message}' error if metric `Help'
%% is invalid.<br/>
%% Raises `{invalid_metric_labels, Labels, Message}' error if `Labels'
%% isn't a list.<br/>
%% Raises `{invalid_label_name, Name, Message}' error if `Name' isn't a valid
%% label name.<br/>
%% Raises `{invalid_value_error, Value, Message}' error if `duration_unit' is
%% unknown or doesn't match metric name.<br/>
%% Raises `{mf_already_exists, {Registry, Name}, Message}' error if a boolean
%% with the same `Spec' already exists.
%% @end
new(Spec) ->
prometheus_metric:insert_new_mf(?TABLE, ?MODULE, Spec).
%% @doc Creates a boolean using `Spec'.
%% If a boolean with the same `Spec' exists returns `false'.
%%
%% Raises `{missing_metric_spec_key, Key, Spec}' error if required `Soec' key
%% is missing.<br/>
%% Raises `{invalid_metric_name, Name, Message}' error if metric `Name'
%% is invalid.<br/>
%% Raises `{invalid_metric_help, Help, Message}' error if metric `Help'
%% is invalid.<br/>
%% Raises `{invalid_metric_labels, Labels, Message}' error if `Labels'
%% isn't a list.<br/>
%% Raises `{invalid_label_name, Name, Message}' error if `Name' isn't a valid
%% label name.<br/>
%% Raises `{invalid_value_error, Value, MessagE}' error if `duration_unit' is
%% unknown or doesn't match metric name.<br/>
%% @end
declare(Spec) ->
prometheus_metric:insert_mf(?TABLE, ?MODULE, Spec).
%% @private
set_default(Registry, Name) ->
set(Registry, Name, [], undefined).
%% @equiv set(default, Name, [], Value)
set(Name, Value) ->
set(default, Name, [], Value).
%% @equiv set(default, Name, LabelValues, Value)
set(Name, LabelValues, Value) ->
set(default, Name, LabelValues, Value).
%% @doc Sets the boolean identified by `Registry', `Name'
%% and `LabelValues' to `Value'.
%%
%% Valid "truthy" values:
%% - `true`;
%% - `false`;
%% - `0` -> false;
%% - `number > 0` -> true;
%% - `[]` -> false
%% - `non-empty list` -> true;
%% - `undefined` -> undefined
%%
%% Other values will generate `invalid_value` error.
%%
%% Raises `{invalid_value, Value, Message}' if `Value'
%% isn't a boolean or `undefined'.<br/>
%% Raises `{unknown_metric, Registry, Name}' error if boolean with named `Name'
%% can't be found in `Registry'.<br/>
%% Raises `{invalid_metric_arity, Present, Expected}' error if labels count
%% mismatch.
%% @end
set(Registry, Name, LabelValues, Value0) ->
Value = prometheus_model_helpers:boolean_value(Value0),
set_(Registry, Name, LabelValues, Value).
%% @equiv toggle(default, Name, [])
toggle(Name) ->
toggle(default, Name, []).
%% @equiv toggle(default, Name, LabelValues, Value)
toggle(Name, LabelValues) ->
toggle(default, Name, LabelValues).
%% @doc Toggles the boolean identified by `Registry', `Name'
%% and `LabelValues'.
%%
%% If boolean set to undefined, it can't be toggled.
%%
%% Raises `{invalid_value, undefined, Message}' if boolean is undefined.<br/>
%% Raises `{unknown_metric, Registry, Name}' error if boolean with named `Name'
%% can't be found in `Registry'.<br/>
%% Raises `{invalid_metric_arity, Present, Expected}' error if labels count
%% mismatch.
%% @end
toggle(Registry, Name, LabelValues) ->
try
ets:update_counter(?TABLE, {Registry, Name, LabelValues},
{?BOOLEAN_POS, 1, 1, 0})
catch error:badarg ->
save_toggle(Registry, Name, LabelValues)
end,
ok.
%% @equiv remove(default, Name, [])
remove(Name) ->
remove(default, Name, []).
%% @equiv remove(default, Name, LabelValues)
remove(Name, LabelValues) ->
remove(default, Name, LabelValues).
%% @doc Removes boolean series identified by `Registry', `Name'
%% and `LabelValues'.
%%
%% Raises `{unknown_metric, Registry, Name}' error if boolean with name `Name'
%% can't be found in `Registry'.<br/>
%% Raises `{invalid_metric_arity, Present, Expected}' error if labels count
%% mismatch.
%% @end
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).
%% @doc Resets the value of the boolean identified by `Registry', `Name'
%% and `LabelValues'.
%%
%% Raises `{unknown_metric, Registry, Name}' error if boolean with name `Name'
%% can't be found in `Registry'.<br/>
%% Raises `{invalid_metric_arity, Present, Expected}' error if labels count
%% mismatch.
%% @end
reset(Registry, Name, LabelValues) ->
prometheus_metric:check_mf_exists(?TABLE, Registry, Name, LabelValues),
ets:update_element(?TABLE, {Registry, Name, LabelValues}, {?BOOLEAN_POS, 0}).
%% @equiv value(default, Name, [])
value(Name) ->
value(default, Name, []).
%% @equiv value(default, Name, LabelValues)
value(Name, LabelValues) ->
value(default, Name, LabelValues).
%% @doc Returns the value of the boolean identified by `Registry', `Name'
%% and `LabelValues'. If there is no boolean for `LabelValues',
%% returns `undefined'.
%%
%% If duration unit set, value will be converted to the duration unit.
%% {@link prometheus_time. Read more here.}
%%
%% Raises `{unknown_metric, Registry, Name}' error if boolean named `Name'
%% can't be found in `Registry'.<br/>
%% Raises `{invalid_metric_arity, Present, Expected}' error if labels count
%% mismatch.
%% @end
value(Registry, Name, LabelValues) ->
case ets:lookup(?TABLE, {Registry, Name, LabelValues}) of
[{_Key, 0}] ->
false;
[{_Key, 1}] ->
true;
[{_Key, undefined}] ->
undefined;
[] ->
prometheus_metric:check_mf_exists(?TABLE, Registry, Name, LabelValues),
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_boolean(Name, Help, {Labels, Registry, DU})) ||
[Name, {Labels, Help}, _, DU, _] <- prometheus_metric:metrics(?TABLE,
Registry)],
ok.
%% @private
collect_metrics(Name, {Labels, Registry, DU}) ->
[boolean_metric(lists:zip(Labels, LabelValues),
prometheus_time:maybe_convert_to_du(DU, Value)) ||
[LabelValues, Value] <- ets:match(?TABLE, {{Registry, Name, '$1'}, '$2'})].
%%====================================================================
%% Private Parts
%%====================================================================
set_(Registry, Name, LabelValues, Value) ->
case ets:update_element(?TABLE, {Registry, Name, LabelValues},
{?BOOLEAN_POS, Value}) of
false ->
insert_metric(Registry, Name, LabelValues, Value, fun set_/4);
true ->
ok
end,
ok.
save_toggle(Registry, Name, LabelValues) ->
case ets:lookup(?TABLE, {Registry, Name, LabelValues}) of
[{_Key, undefined}] ->
erlang:error({invalid_value, undefined,
"can't toggle undefined boolean"});
[] ->
insert_metric(Registry, Name, LabelValues, 0, fun toggle/3)
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_boolean(Name, Help, Data) ->
create_mf(Name, Help, boolean, ?MODULE, Data).