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