Packages
prometheus
5.1.0
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
-module(prometheus_boolean).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC("""
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:
```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.
```
""").
%%% metric
-export([
new/1,
declare/1,
deregister/1,
deregister/2,
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,
values/2
]).
%%% collector
-export([
deregister_cleanup/1,
collect_mf/2,
collect_metrics/2
]).
-include("prometheus.hrl").
-behaviour(prometheus_metric).
-behaviour(prometheus_collector).
-define(TABLE, ?PROMETHEUS_BOOLEAN_TABLE).
-define(BOOLEAN_POS, 2).
?DOC("""
Creates a boolean using `Spec`.
Raises:
* `{missing_metric_spec_key, Key, Spec}` error if required `Spec` key is missing.
* `{invalid_metric_name, Name, Message}` error if metric `Name` is invalid.
* `{invalid_metric_help, Help, Message}` error if metric `Help` is invalid.
* `{invalid_metric_labels, Labels, Message}` error if `Labels` isn't a list.
* `{invalid_label_name, Name, Message}` error if `Name` isn't a valid label name.
* `{mf_already_exists, {Registry, Name}, Message}` error if a boolean with the same `Spec` already exists.
""").
-spec new(prometheus_metric:spec()) -> ok.
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 `Spec` key is missing.
* `{invalid_metric_name, Name, Message}` error if metric `Name` is invalid.
* `{invalid_metric_help, Help, Message}` error if metric `Help` is invalid.
* `{invalid_metric_labels, Labels, Message}` error if `Labels` isn't a list.
* `{invalid_label_name, Name, Message}` error if `Name` isn't a valid label name.
""").
-spec declare(prometheus_metric:spec()) -> boolean().
declare(Spec) ->
prometheus_metric:insert_mf(?TABLE, ?MODULE, Spec).
?DOC(#{equiv => deregister(default, Name)}).
-spec deregister(prometheus_metric:name()) -> {boolean(), boolean()}.
deregister(Name) ->
deregister(default, Name).
?DOC("""
Removes all boolean series with name `Name` and removes Metric Family from `Registry`.
After this call new/1 for `Name` and `Registry` will succeed.
Returns `{true, _}` if `Name` was a registered boolean. Otherwise returns `{true, _}`.
""").
-spec deregister(prometheus_registry:registry(), prometheus_metric:name()) ->
{boolean(), boolean()}.
deregister(Registry, Name) ->
MFR = prometheus_metric:deregister_mf(?TABLE, Registry, Name),
NumDeleted = ets:select_delete(?TABLE, deregister_select(Registry, Name)),
{MFR, NumDeleted > 0}.
?DOC(false).
-spec set_default(prometheus_registry:registry(), prometheus_metric:name()) -> ok.
set_default(Registry, Name) ->
set(Registry, Name, [], undefined).
?DOC(#{equiv => set(default, Name, [], Value)}).
-spec set(prometheus_metric:name(), prometheus:prometheus_boolean()) -> ok.
set(Name, Value) ->
set(default, Name, [], Value).
?DOC(#{equiv => set(default, Name, LabelValues, Value)}).
-spec set(Name, LabelValues, Value) -> ok when
Name :: prometheus_metric:name(),
LabelValues :: prometheus_metric:label_values(),
Value :: prometheus:prometheus_boolean().
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`.
* `{unknown_metric, Registry, Name}` error if boolean with named `Name` can't be found in `Registry`.
* `{invalid_metric_arity, Present, Expected}` error if labels count mismatch.
""").
-spec set(Registry, Name, LabelValues, Value) -> ok when
Registry :: prometheus_registry:registry(),
Name :: prometheus_metric:name(),
LabelValues :: prometheus_metric:label_values(),
Value :: prometheus:prometheus_boolean().
set(Registry, Name, LabelValues, Value) ->
Value1 = prometheus_model_helpers:boolean_value(Value),
set_1(Registry, Name, LabelValues, Value1).
?DOC(#{equiv => toggle(default, Name, [])}).
-spec toggle(prometheus_metric:name()) -> ok.
toggle(Name) ->
toggle(default, Name, []).
?DOC(#{equiv => toggle(default, Name, LabelValues)}).
-spec toggle(prometheus_metric:name(), prometheus_metric:label_values()) -> ok.
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.
* `{unknown_metric, Registry, Name}` error if boolean with named `Name` can't be found in `Registry`.
* `{invalid_metric_arity, Present, Expected}` error if labels count mismatch.
""").
-spec toggle(Registry, Name, LabelValues) -> ok when
Registry :: prometheus_registry:registry(),
Name :: prometheus_metric:name(),
LabelValues :: prometheus_metric:label_values().
toggle(Registry, Name, LabelValues) ->
Key = {Registry, Name, LabelValues},
Spec = {?BOOLEAN_POS, 1, 1, 0},
try
ets:update_counter(?TABLE, Key, Spec)
catch
error:badarg ->
save_toggle(Registry, Name, LabelValues)
end,
ok.
?DOC(#{equiv => remove(default, Name, [])}).
-spec remove(prometheus_metric:name()) -> boolean().
remove(Name) ->
remove(default, Name, []).
?DOC(#{equiv => remove(default, Name, LabelValues)}).
-spec remove(prometheus_metric:name(), prometheus_metric:label_values()) -> boolean().
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`.
* `{invalid_metric_arity, Present, Expected}` error if labels count mismatch.
""").
-spec remove(Registry, Name, LabelValues) -> boolean() when
Registry :: prometheus_registry:registry(),
Name :: prometheus_metric:name(),
LabelValues :: prometheus_metric:label_values().
remove(Registry, Name, LabelValues) ->
prometheus_metric:remove_labels(?TABLE, Registry, Name, LabelValues).
?DOC(#{equiv => reset(default, Name, [])}).
-spec reset(prometheus_metric:name()) -> boolean().
reset(Name) ->
reset(default, Name, []).
?DOC(#{equiv => reset(default, Name, LabelValues)}).
-spec reset(prometheus_metric:name(), prometheus_metric:label_values()) -> boolean().
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`.
* `{invalid_metric_arity, Present, Expected}` error if labels count mismatch.
""").
-spec reset(Registry, Name, LabelValues) -> boolean() when
Registry :: prometheus_registry:registry(),
Name :: prometheus_metric:name(),
LabelValues :: prometheus_metric:label_values().
reset(Registry, Name, LabelValues) ->
prometheus_metric:check_mf_exists(?TABLE, Registry, Name, LabelValues),
ets:update_element(?TABLE, {Registry, Name, LabelValues}, {?BOOLEAN_POS, 0}).
?DOC(#{equiv => value(default, Name, [])}).
-spec value(prometheus_metric:name()) -> boolean() | undefined.
value(Name) ->
value(default, Name, []).
?DOC(#{equiv => value(default, Name, LabelValues)}).
-spec value(prometheus_metric:name(), prometheus_metric:label_values()) -> boolean() | undefined.
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`.
Raises:
* `{unknown_metric, Registry, Name}` error if boolean named `Name` can't be found in `Registry`.
* `{invalid_metric_arity, Present, Expected}` error if labels count mismatch.
""").
-spec value(Registry, Name, LabelValues) -> boolean() | undefined when
Registry :: prometheus_registry:registry(),
Name :: prometheus_metric:name(),
LabelValues :: prometheus_metric:label_values().
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.
-spec values(prometheus_registry:registry(), prometheus_metric:name()) -> [{list(), boolean()}].
values(Registry, Name) ->
case prometheus_metric:check_mf_exists(?TABLE, Registry, Name) of
false ->
[];
MF ->
Labels = prometheus_metric:mf_labels(MF),
[
{lists:zip(Labels, LabelValues), Value =:= 1}
|| [LabelValues, Value] <- load_all_values(Registry, Name)
]
end.
%%====================================================================
%% Collector API
%%====================================================================
?DOC(false).
-spec deregister_cleanup(prometheus_registry:registry()) -> ok.
deregister_cleanup(Registry) ->
prometheus_metric:deregister_mf(?TABLE, Registry),
true = ets:match_delete(?TABLE, {{Registry, '_', '_'}, '_'}),
ok.
?DOC(false).
-spec collect_mf(prometheus_registry:registry(), prometheus_collector:collect_mf_callback()) -> ok.
collect_mf(Registry, Callback) ->
[
Callback(create_boolean(Name, Help, {CLabels, Labels, Registry}))
|| [Name, {Labels, Help}, CLabels, _, _] <- prometheus_metric:metrics(?TABLE, Registry)
],
ok.
?DOC(false).
-spec collect_metrics(prometheus_metric:name(), tuple()) -> [prometheus_model:'Metric'()].
collect_metrics(Name, {CLabels, Labels, Registry}) ->
[
prometheus_model_helpers:boolean_metric(
CLabels ++ lists:zip(Labels, LabelValues), Value
)
|| [LabelValues, Value] <- load_all_values(Registry, Name)
].
%%====================================================================
%% Private Parts
%%====================================================================
deregister_select(Registry, Name) ->
[{{{Registry, Name, '_'}, '_'}, [], [true]}].
set_1(Registry, Name, LabelValues, Value) ->
Key = {Registry, Name, LabelValues},
Spec = {?BOOLEAN_POS, Value},
case ets:update_element(?TABLE, Key, Spec) of
false ->
insert_metric(Registry, Name, LabelValues, Value, fun set_1/4);
true ->
ok
end.
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
%% some sneaky process already inserted
false ->
ConflictCB(Registry, Name, LabelValues, Value);
true ->
ok
end.
load_all_values(Registry, Name) ->
ets:match(?TABLE, {{Registry, Name, '$1'}, '$2'}).
create_boolean(Name, Help, Data) ->
prometheus_model_helpers:create_mf(Name, Help, boolean, ?MODULE, Data).