./ct_report/coverage/mongoose_admin_api_metrics.COVER.html

1 -module(mongoose_admin_api_metrics).
2
3 -behaviour(mongoose_admin_api).
4 -export([routes/1]).
5
6 -behaviour(cowboy_rest).
7 -export([init/2,
8 is_authorized/2,
9 content_types_provided/2,
10 allowed_methods/2,
11 to_json/2]).
12
13 -ignore_xref([to_json/2, from_json/2]).
14
15 -import(mongoose_admin_api, [parse_body/1, try_handle_request/3, throw_error/2, resource_created/4]).
16
17 -type req() :: cowboy_req:req().
18 -type state() :: mongoose_admin_api:state().
19
20 -include("mongoose.hrl").
21
22 -spec routes(state()) -> mongoose_http_handler:routes().
23 routes(State) ->
24 4 [{"/metrics/", ?MODULE, State},
25 {"/metrics/all/[:metric]", ?MODULE, State#{suffix => all}},
26 {"/metrics/global/[:metric]", ?MODULE, State#{suffix => global}},
27 {"/metrics/host_type/:host_type/[:metric]", ?MODULE, State}].
28
29 -spec init(req(), state()) -> {cowboy_rest, req(), state()}.
30 init(Req, State) ->
31
:-(
mongoose_admin_api:init(Req, State).
32
33 -spec is_authorized(req(), state()) -> {true | {false, iodata()}, req(), state()}.
34 is_authorized(Req, State) ->
35
:-(
mongoose_admin_api:is_authorized(Req, State).
36
37 -spec content_types_provided(req(), state()) ->
38 {[{{binary(), binary(), '*'}, atom()}], req(), state()}.
39 content_types_provided(Req, State) ->
40
:-(
{[
41 {{<<"application">>, <<"json">>, '*'}, to_json}
42 ], Req, State}.
43
44 -spec allowed_methods(req(), state()) -> {[binary()], req(), state()}.
45 allowed_methods(Req, State) ->
46
:-(
{[<<"OPTIONS">>, <<"HEAD">>, <<"GET">>], Req, State}.
47
48 %% @doc Called for a method of type "GET"
49 -spec to_json(req(), state()) -> {iodata() | stop, req(), state()}.
50 to_json(Req, State) ->
51
:-(
try_handle_request(Req, State, fun handle_get/2).
52
53 %% Internal functions
54
55 handle_get(Req, State = #{suffix := all}) ->
56
:-(
Bindings = cowboy_req:bindings(Req),
57
:-(
case get_metric_name(Bindings) of
58 {metric, Metric} ->
59
:-(
case mongoose_metrics:get_aggregated_values(Metric) of
60 [] ->
61
:-(
throw_error(not_found, <<"Metric not found">>);
62 Value ->
63
:-(
{jiffy:encode(#{metric => prepare_value(Value)}), Req, State}
64 end;
65 all_metrics ->
66
:-(
Values = get_sum_metrics(),
67
:-(
{jiffy:encode(#{metrics => Values}), Req, State}
68 end;
69 handle_get(Req, State = #{suffix := global}) ->
70
:-(
Bindings = cowboy_req:bindings(Req),
71
:-(
handle_get_values(Req, State, Bindings, global);
72 handle_get(Req, State) ->
73
:-(
Bindings = cowboy_req:bindings(Req),
74
:-(
case Bindings of
75 #{host_type := HostType} ->
76
:-(
handle_get_values(Req, State, Bindings, HostType);
77 #{} ->
78
:-(
{HostTypes, Metrics} = get_available_host_type_metrics(),
79
:-(
Global = get_available_global_metrics(),
80
:-(
Reply = #{host_types => HostTypes, metrics => Metrics, global => Global},
81
:-(
{jiffy:encode(Reply), Req, State}
82 end.
83
84 handle_get_values(Req, State, Bindings, HostType) ->
85
:-(
case get_metric_name(Bindings) of
86 {metric, Metric} ->
87
:-(
case mongoose_metrics:get_metric_value(HostType, Metric) of
88 {ok, Value} ->
89
:-(
{jiffy:encode(#{metric => prepare_value(Value)}), Req, State};
90 _Other ->
91
:-(
throw_error(not_found, <<"Metric not found">>)
92 end;
93 all_metrics ->
94
:-(
case mongoose_metrics:get_metric_values(HostType) of
95 [] ->
96
:-(
throw_error(not_found, <<"No metrics found">>);
97 Metrics ->
98
:-(
Values = prepare_metrics(Metrics),
99
:-(
{jiffy:encode(#{metrics => Values}), Req, State}
100 end
101 end.
102
103 -spec get_sum_metrics() -> map().
104 get_sum_metrics() ->
105
:-(
{_HostTypes, Metrics} = get_available_host_type_metrics(),
106
:-(
maps:from_list([{Metric, get_sum_metric(Metric)} || Metric <- Metrics]).
107
108 -spec get_sum_metric(atom()) -> map().
109 get_sum_metric(Metric) ->
110
:-(
maps:from_list(mongoose_metrics:get_aggregated_values(Metric)).
111
112 -spec get_available_metrics(HostType :: mongooseim:host_type()) -> [any()].
113 get_available_metrics(HostType) ->
114
:-(
mongoose_metrics:get_host_type_metric_names(HostType).
115
116 -spec get_available_host_type_metrics() -> {[any(), ...], [any()]}.
117 get_available_host_type_metrics() ->
118
:-(
HostTypes = get_available_host_types(),
119
:-(
Metrics = [Metric || [Metric] <- get_available_metrics(hd(HostTypes))],
120
:-(
{HostTypes, Metrics}.
121
122 get_available_global_metrics() ->
123
:-(
[Metric || [Metric] <- mongoose_metrics:get_global_metric_names()].
124
125 -spec get_available_host_types() -> [mongooseim:host_type()].
126 get_available_host_types() ->
127
:-(
?ALL_HOST_TYPES.
128
129 prepare_metrics(Metrics) ->
130
:-(
maps:from_list([{prepare_name(NameParts, FullName), prepare_value(Value)}
131
:-(
|| {FullName = [_HostType | NameParts], Value} <- Metrics]).
132
133 prepare_name(NameParts, FullName) ->
134
:-(
try
135
:-(
ToStrings = [atom_to_list(NamePart) || NamePart <- NameParts],
136
:-(
list_to_binary(string:join(ToStrings, "."))
137 catch Class:Reason:Stacktrace ->
138
:-(
erlang:raise(Class, {failed_to_prepare_name, FullName, Reason}, Stacktrace)
139 end.
140
141 prepare_value(KVs) ->
142
:-(
maps:from_list([{prepare_key(K), V} || {K, V} <- KVs]).
143
144
:-(
prepare_key(K) when is_integer(K) -> integer_to_binary(K);
145
:-(
prepare_key(K) when is_atom(K) -> atom_to_binary(K).
146
147 get_metric_name(#{metric := MetricBin}) ->
148
:-(
try {metric, binary_to_existing_atom(MetricBin)}
149
:-(
catch _:_ -> throw_error(not_found, <<"Metric not found">>)
150 end;
151 get_metric_name(#{}) ->
152
:-(
all_metrics.
Line Hits Source