1 |
|
-module(mongoose_instrument_prometheus). |
2 |
|
|
3 |
|
-behaviour(mongoose_instrument). |
4 |
|
|
5 |
|
-export([set_up/3, handle_event/4]). |
6 |
|
|
7 |
|
%% Define Prometheus metric-related types, because the library has no type specs |
8 |
|
-type spec() :: proplists:proplist(). |
9 |
|
-type name() :: string(). |
10 |
|
-type help() :: string(). |
11 |
|
|
12 |
|
-spec set_up(mongoose_instrument:event_name(), mongoose_instrument:labels(), |
13 |
|
mongoose_instrument:config()) -> boolean(). |
14 |
|
set_up(EventName, Labels, #{metrics := Metrics}) -> |
15 |
1446 |
maps:foreach(fun(MetricName, MetricType) -> |
16 |
2282 |
set_up_metric(EventName, Labels, MetricName, MetricType) |
17 |
|
end, Metrics), |
18 |
1446 |
true; |
19 |
|
set_up(_EventName, _Labels, #{}) -> |
20 |
:-( |
false. |
21 |
|
|
22 |
|
-spec handle_event(mongoose_instrument:event_name(), mongoose_instrument:labels(), |
23 |
|
mongoose_instrument:config(), mongoose_instrument:measurements()) -> ok. |
24 |
|
handle_event(EventName, Labels, #{metrics := Metrics}, Measurements) -> |
25 |
14871 |
LabelValues = labels_to_values(Labels), |
26 |
14871 |
maps:foreach(fun(MetricName, MetricType) -> |
27 |
32182 |
handle_metric_event(EventName, LabelValues, MetricName, MetricType, Measurements) |
28 |
|
end, Metrics). |
29 |
|
|
30 |
|
-spec set_up_metric(mongoose_instrument:event_name(), mongoose_instrument:labels(), |
31 |
|
mongoose_instrument:metric_name(), mongoose_instrument:metric_type()) -> |
32 |
|
ok. |
33 |
|
set_up_metric(EventName, Labels, MetricName, MetricType) -> |
34 |
2282 |
LabelKeys = labels_to_keys(Labels), |
35 |
2282 |
LabelValues = labels_to_values(Labels), |
36 |
2282 |
MetricSpec = metric_spec(EventName, LabelKeys, MetricName), |
37 |
2282 |
case declare_metric(MetricSpec, MetricType) of |
38 |
27 |
true -> ok; |
39 |
2255 |
false -> reset_metric(proplists:get_value(name, MetricSpec), LabelValues, MetricType) |
40 |
|
end. |
41 |
|
|
42 |
|
-spec declare_metric(proplists:proplist(), mongoose_instrument:metric_type()) -> boolean(). |
43 |
|
declare_metric(MetricSpec, spiral) -> |
44 |
1579 |
prometheus_counter:declare(MetricSpec); |
45 |
|
declare_metric(MetricSpec, histogram) -> |
46 |
703 |
prometheus_histogram:declare([{buckets, histogram_buckets()} | MetricSpec]). |
47 |
|
|
48 |
|
-spec reset_metric(name(), [mongoose_instrument:label_value()], |
49 |
|
mongoose_instrument:metric_type()) -> ok. |
50 |
|
reset_metric(Name, LabelValues, spiral) -> |
51 |
1562 |
prometheus_counter:reset(Name, LabelValues), |
52 |
1562 |
prometheus_counter:inc(Name, LabelValues, 0); |
53 |
|
reset_metric(Name, LabelValues, histogram) -> |
54 |
693 |
prometheus_histogram:reset(Name, LabelValues), |
55 |
693 |
ok. |
56 |
|
|
57 |
|
-spec metric_spec(mongoose_instrument:event_name(), [mongoose_instrument:label_key()], |
58 |
|
mongoose_instrument:metric_name()) -> spec(). |
59 |
|
metric_spec(EventName, LabelKeys, MetricName) -> |
60 |
2282 |
[{name, full_metric_name(EventName, MetricName)}, |
61 |
|
{help, metric_help(EventName, MetricName)}, |
62 |
|
{labels, LabelKeys}]. |
63 |
|
|
64 |
|
-spec histogram_buckets() -> [integer()]. |
65 |
|
histogram_buckets() -> |
66 |
703 |
histogram_buckets([], 1 bsl 30). % ~1.07 * 10^9 |
67 |
|
|
68 |
|
histogram_buckets(AccBuckets, Val) when Val > 0 -> |
69 |
21793 |
histogram_buckets([Val | AccBuckets], Val bsr 1); |
70 |
|
histogram_buckets(AccBuckets, _Val) -> |
71 |
703 |
AccBuckets. |
72 |
|
|
73 |
|
-spec handle_metric_event(mongoose_instrument:event_name(), [mongoose_instrument:label_value()], |
74 |
|
mongoose_instrument:metric_name(), mongoose_instrument:metric_type(), |
75 |
|
mongoose_instrument:measurements()) -> ok. |
76 |
|
handle_metric_event(EventName, LabelValues, MetricName, MetricType, Measurements) -> |
77 |
32182 |
case Measurements of |
78 |
|
#{MetricName := MetricValue} -> |
79 |
31198 |
FullName = full_metric_name(EventName, MetricName), |
80 |
31198 |
update_metric(FullName, LabelValues, MetricType, MetricValue); |
81 |
|
#{} -> |
82 |
984 |
ok |
83 |
|
end. |
84 |
|
|
85 |
|
-spec metric_help(mongoose_instrument:event_name(), mongoose_instrument:metric_name()) -> help(). |
86 |
|
metric_help(EventName, MetricName) -> |
87 |
2282 |
lists:flatten(io_lib:format("Event: ~p, Metric: ~p", [EventName, MetricName])). |
88 |
|
|
89 |
|
-spec full_metric_name(mongoose_instrument:event_name(), mongoose_instrument:metric_name()) -> |
90 |
|
name(). |
91 |
|
full_metric_name(EventName, MetricName) -> |
92 |
33480 |
atom_to_list(EventName) ++ "_" ++ atom_to_list(MetricName). |
93 |
|
|
94 |
|
-spec labels_to_keys(mongoose_instrument:labels()) -> [mongoose_instrument:label_key()]. |
95 |
|
labels_to_keys(Labels) -> |
96 |
2282 |
lists:sort(maps:keys(Labels)). |
97 |
|
|
98 |
|
-spec labels_to_values(mongoose_instrument:labels()) -> [mongoose_instrument:label_value()]. |
99 |
|
labels_to_values(Labels) -> |
100 |
17153 |
[V || {_K, V} <- lists:keysort(1, maps:to_list(Labels))]. |
101 |
|
|
102 |
|
-spec update_metric(name(), [mongoose_instrument:label_value()], |
103 |
|
mongoose_instrument:metric_type(), integer()) -> ok. |
104 |
|
update_metric(Name, Labels, spiral, Value) when is_integer(Value), Value >= 0 -> |
105 |
15020 |
ok = prometheus_counter:inc(Name, Labels, Value); |
106 |
|
update_metric(Name, Labels, histogram, Value) when is_integer(Value) -> |
107 |
16178 |
ok = prometheus_histogram:observe(Name, Labels, Value). |