./ct_report/coverage/mongoose_metrics_api.COVER.html

1 -module(mongoose_metrics_api).
2 -export([get_metrics/1,
3 get_metrics_as_dicts/2,
4 get_cluster_metrics_as_dicts/3]).
5
6 -include("mongoose_logger.hrl").
7
8 -type name() :: [atom() | integer()].
9 -type key() :: atom().
10 -type metric_result() ::
11 {ok, #{binary() => binary() | non_neg_integer()}}.
12 -type dict_result() :: #{binary() => binary() | non_neg_integer()}.
13 -type metric_dict_result() ::
14 {ok, #{binary() => binary() | [dict_result()]}}.
15 -type metric_node_dict_result() ::
16 {ok, #{binary() => binary() | [metric_dict_result()]}}
17 | {error, binary()}.
18
19 -spec get_metrics(Name :: name()) -> {ok, [metric_result()]}.
20 get_metrics(Name) ->
21 6 Values = exometer:get_values(Name),
22 6 {ok, lists:map(fun make_metric_result/1, Values)}.
23
24 -spec get_metrics_as_dicts(Name :: name(), Keys :: [key()]) ->
25 {ok, [metric_dict_result()]}.
26 get_metrics_as_dicts(Name, Keys) ->
27 3 Values = exometer:get_values(Name),
28 3 {ok, [make_metric_dict_result(V, Keys) || V <- Values]}.
29
30 -spec get_cluster_metrics_as_dicts(Name :: name(), Keys :: [key()],
31 Nodes :: [node()]) ->
32 {ok, [metric_node_dict_result()]}.
33 get_cluster_metrics_as_dicts(Name, Keys, Nodes) ->
34 3 Nodes2 = existing_nodes(Nodes),
35 3 F = fun(Node) -> rpc:call(Node, exometer, get_values, [Name]) end,
36 3 Results = mongoose_lib:pmap(F, Nodes2),
37 3 {ok, [make_node_result(Node, Result, Keys)
38 3 || {Node, Result} <- lists:zip(Nodes2, Results)]}.
39
40 make_node_result(Node, {ok, Values}, Keys) ->
41 7 {ok, #{<<"node">> => Node,
42 1070 <<"result">> => [make_metric_dict_result(V, Keys) || V <- Values]}};
43 make_node_result(Node, Other, _Keys) ->
44
:-(
?LOG_ERROR(#{what => metric_get_failed,
45
:-(
remote_node => Node, reason => Other}),
46
:-(
{error, <<"Failed to get metrics">>}.
47
48 filter_keys(Dict, []) ->
49 1692 Dict;
50 filter_keys(Dict, Keys) ->
51 616 [KV || KV = {Key, _} <- Dict, lists:member(Key, Keys)].
52
53 existing_nodes(Nodes) ->
54 3 AllNodes = [node()|nodes()],
55 3 filter_nodes(AllNodes, Nodes).
56
57 filter_nodes(AllNodes, []) ->
58 2 AllNodes;
59 filter_nodes(AllNodes, AllowedNodes) ->
60 1 [Node || Node <- AllNodes, lists:member(Node, AllowedNodes)].
61
62 make_metric_result({Name, Dict}) ->
63 1382 PreparedName = format_name(Name),
64 1382 Map = format_dict(Dict),
65 1382 {ok, Map#{<<"name">> => PreparedName}}.
66
67 make_metric_dict_result({Name, Dict}, Keys) ->
68 2308 PreparedName = format_name(Name),
69 2308 {ok, #{<<"name">> => PreparedName, <<"dict">> => format_dict_entries(Dict, Keys)}}.
70
71 format_dict_entries(Dict, Keys) ->
72 2308 [{ok, #{<<"key">> => Key, <<"value">> => Value}}
73 2308 || {Key, Value} <- filter_keys(Dict, Keys)].
74
75 format_name(Name) ->
76 3690 lists:map(fun format_name_segment/1, Name).
77
78 format_name_segment(Segment) when is_atom(Segment) ->
79 8162 {ok, atom_to_binary(Segment)};
80 format_name_segment(Segment) when is_binary(Segment) ->
81 2559 {ok, Segment}.
82
83 format_dict(Dict) ->
84 1382 format_dict2(maps:from_list(Dict)).
85
86 format_dict2(#{one := _} = Dict) ->
87 1017 format_spiral(Dict);
88 format_dict2(#{ms_since_reset := _} = Dict) ->
89 31 format_counter(Dict);
90 format_dict2(#{value := _} = Dict) ->
91 24 format_gauge(Dict);
92 format_dict2(#{median := _} = Dict) ->
93 294 format_histogram(Dict);
94 format_dict2(#{connections := _, recv_cnt := _} = Dict) ->
95 4 format_merged_inet_stats(Dict);
96 format_dict2(#{processes_used := _} = Dict) ->
97 4 format_vm_stats_memory(Dict);
98 format_dict2(#{port_count := _} = Dict) ->
99 4 format_vm_system_info(Dict);
100 format_dict2(#{fsm := _, regular := _} = Dict) ->
101 4 format_probe_queues(Dict);
102 format_dict2(#{recv_cnt := _, workers := _} = Dict) ->
103
:-(
format_rdbms_stats(Dict).
104
105 format_spiral(#{one := One, count := Count}) ->
106 1017 #{<<"type">> => <<"spiral">>, <<"one">> => One, <<"count">> => Count}.
107
108 format_counter(#{value := Value, ms_since_reset := MS}) ->
109 31 #{<<"type">> => <<"counter">>, <<"value">> => Value, <<"ms_since_reset">> => MS}.
110
111 format_gauge(#{value := Value}) ->
112 24 #{<<"type">> => <<"gauge">>, <<"value">> => Value}.
113
114 format_histogram(#{n := N, mean := Mean, min := Min, max := Max, median := Median,
115 50 := P50, 75 := P75, 90 := P90, 95 := P95,
116 99 := P99, 999 := P999}) ->
117 294 #{<<"type">> => <<"histogram">>, <<"n">> => N, <<"mean">> => Mean,
118 <<"min">> => Min, <<"max">> => Max, <<"median">> => Median,
119 <<"p50">> => P50, <<"p75">> => P75, <<"p90">> => P90, <<"p95">> => P95,
120 <<"p99">> => P99, <<"p999">> => P999}.
121
122 format_merged_inet_stats(#{connections := Cons,
123 recv_cnt := RCnt, recv_max := RMax, recv_oct := ROct,
124 send_cnt := SCnt, send_max := SMax, send_oct := SOct,
125 send_pend := SPend}) ->
126 %% Metrics from a pool of connections
127 4 #{<<"type">> => <<"merged_inet_stats">>, <<"connections">> => Cons,
128 <<"recv_cnt">> => RCnt, <<"recv_max">> => RMax, <<"recv_oct">> => ROct,
129 <<"send_cnt">> => SCnt, <<"send_max">> => SMax, <<"send_oct">> => SOct,
130 <<"send_pend">> => SPend}.
131
132 format_rdbms_stats(#{recv_cnt := RCnt, recv_max := RMax, recv_oct := ROct,
133 send_cnt := SCnt, send_max := SMax, send_oct := SOct,
134 send_pend := SPend, workers := Workers}) ->
135
:-(
#{<<"type">> => <<"rdbms_stats">>, <<"workers">> => Workers,
136 <<"recv_cnt">> => RCnt, <<"recv_max">> => RMax, <<"recv_oct">> => ROct,
137 <<"send_cnt">> => SCnt, <<"send_max">> => SMax, <<"send_oct">> => SOct,
138 <<"send_pend">> => SPend}.
139
140 format_vm_stats_memory(#{total := Total, processes_used := P,
141 atom_used := A, binary := B, ets := E, system := S}) ->
142 4 #{<<"type">> => <<"vm_stats_memory">>,
143 <<"total">> => Total, <<"processes_used">> => P, <<"atom_used">> => A,
144 <<"binary">> => B, <<"ets">> => E, <<"system">> => S}.
145
146 format_vm_system_info(#{port_count := PortCount, port_limit := PortLimit,
147 process_count := ProcessCount, process_limit := ProcessLimit,
148 ets_limit := EtsLimit}) ->
149 4 #{<<"type">> => <<"vm_system_info">>,
150 <<"port_count">> => PortCount, <<"port_limit">> => PortLimit,
151 <<"process_count">> => ProcessCount, <<"process_limit">> => ProcessLimit,
152 <<"ets_limit">> => EtsLimit}.
153
154 format_probe_queues(#{fsm := FSM, regular := Regular, total := Total}) ->
155 4 #{<<"type">> => <<"probe_queues">>,
156 <<"fsm">> => FSM, <<"regular">> => Regular, <<"total">> => Total}.
Line Hits Source