Packages
prometheus
4.13.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
Retired package: Breaking changes regarding automated discovery of collectors, version was promoted to 5.0.0
Current section
Files
Jump to
Current section
Files
src/prometheus_buckets.erl
-module(prometheus_buckets).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-export([new/0, new/1, position/2, default/0]).
-export([exponential/3, linear/3]).
-type bucket_bound() :: number() | infinity.
-type buckets() :: [bucket_bound(), ...].
?DOC("""
Histogram buckets configuration.
Setting the `buckets` key of a histogram to
- `default`: will use the default buckets
- `linear`: will use `Start`, `Step`, and `Count` to generate the buckets as in `linear/3`
- `exponential`: will use `Start`, `Factor`, and `Count` to generate the buckets as in `exponential/3`
You can also specify your own buckets if desired instead.
""").
-type config() ::
undefined
| default
| {linear, number(), number(), pos_integer()}
| {exponential, number(), number(), pos_integer()}
| buckets().
-export_type([bucket_bound/0, buckets/0, config/0]).
?DOC("Histogram buckets constructor, returns `default/0` plus `infinity`").
-spec new() -> buckets().
new() ->
default() ++ [infinity].
?DOC("Histogram buckets constructor").
-spec new(config()) -> buckets().
new([]) ->
erlang:error({no_buckets, []});
new(undefined) ->
erlang:error({no_buckets, undefined});
new(default) ->
default() ++ [infinity];
new({linear, Start, Step, Count}) ->
linear(Start, Step, Count) ++ [infinity];
new({exponential, Start, Factor, Count}) ->
exponential(Start, Factor, Count) ++ [infinity];
new(RawBuckets) when is_list(RawBuckets) ->
Buckets = lists:map(fun validate_bound/1, RawBuckets),
case lists:sort(Buckets) of
Buckets ->
case lists:last(Buckets) of
infinity -> Buckets;
_ -> Buckets ++ [infinity]
end;
_ ->
erlang:error({invalid_buckets, Buckets, "buckets not sorted"})
end;
new(Buckets) ->
erlang:error({invalid_buckets, Buckets, "not a list"}).
validate_bound(Bound) when is_number(Bound) ->
Bound;
validate_bound(infinity) ->
infinity;
validate_bound(Bound) ->
erlang:error({invalid_bound, Bound}).
?DOC("""
Default histogram buckets.
```erlang
1> prometheus_buckets:default().
[0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]
```
Please note these buckets are floats and represent seconds so you'll have to use
`prometheus_histogramdobserve/3` or configure `duration_unit` as `seconds`.
""").
-spec default() -> buckets().
default() -> [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10].
?DOC("""
Creates `Count` buckets, where the lowest bucket has an upper bound of `Start` and each following
bucket's upper bound is `Factor` times the previous bucket's upper bound.
The returned list is meant to be used for the `buckets` key of histogram constructors options.
```erlang
3> prometheus_buckets:exponential(100, 1.2, 3).
[100, 120, 144]
```
The function raises `{invalid_value, Value, Message}` error if `Count` isn't positive,
if `Start` isn't positive, or if `Factor` is less than or equals to 1.
""").
-spec exponential(number(), number(), pos_integer()) -> buckets().
exponential(_Start, _Factor, Count) when Count < 1 ->
erlang:error({invalid_value, Count, "Buckets count should be positive"});
exponential(Start, _Factor, _Count) when Start =< 0 ->
erlang:error({invalid_value, Start, "Buckets start should be positive"});
exponential(_Start, Factor, _Count) when Factor =< 1 ->
erlang:error({invalid_value, Factor, "Buckets factor should be greater than 1"});
exponential(Start, Factor, Count) ->
[
try_to_maintain_integer_bounds(Start * math:pow(Factor, I))
|| I <- lists:seq(0, Count - 1)
].
?DOC("""
Creates `Count` buckets, each `Width` wide, where the lowest bucket has an upper bound of `Start`.
The returned list is meant to be used for the `buckets` key of histogram constructors options.
```erlang
2> prometheus_buckets:linear(10, 5, 6).
[10, 15, 20, 25, 30, 35]
```
The function raises `{invalid_value, Value, Message}` error if `Count` is zero or negative.
""").
-spec linear(number(), number(), pos_integer()) -> buckets().
linear(_Start, _Step, Count) when Count < 1 ->
erlang:error({invalid_value, Count, "Buckets count should be positive"});
linear(Start, Step, Count) ->
linear(Start, Step, Count, []).
-spec position(buckets(), number()) -> pos_integer().
position(Buckets, Value) when is_list(Buckets), is_number(Value) ->
find_position(Buckets, Value, 0).
linear(_Current, _Step, 0, Acc) ->
lists:reverse(Acc);
linear(Current, Step, Count, Acc) ->
linear(
try_to_maintain_integer_bounds(Current + Step),
Step,
Count - 1,
[Current | Acc]
).
-spec try_to_maintain_integer_bounds
(integer()) -> integer();
(float()) -> integer() | float().
try_to_maintain_integer_bounds(Bound) when is_integer(Bound) -> Bound;
try_to_maintain_integer_bounds(Bound) when is_float(Bound) ->
TBound = trunc(Bound),
case TBound == Bound of
true -> TBound;
false -> Bound
end.
-spec find_position(buckets(), number(), non_neg_integer()) -> pos_integer().
find_position([], _Value, _Pos) ->
0;
find_position([Bound | L], Value, Pos) ->
case Value =< Bound of
true ->
Pos;
false ->
find_position(L, Value, Pos + 1)
end.