186 lines
5.8 KiB
Erlang
186 lines
5.8 KiB
Erlang
%%--------------------------------------------------------------------
|
|
%% Copyright (c) 2019-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
|
|
%%--------------------------------------------------------------------
|
|
|
|
-module(emqx_dashboard_monitor_api).
|
|
|
|
-include("emqx_dashboard.hrl").
|
|
-include_lib("typerefl/include/types.hrl").
|
|
|
|
-behaviour(minirest_api).
|
|
|
|
-export([api_spec/0]).
|
|
|
|
-export([
|
|
paths/0,
|
|
schema/1,
|
|
fields/1
|
|
]).
|
|
|
|
-export([
|
|
monitor/2,
|
|
monitor_current/2
|
|
]).
|
|
|
|
api_spec() ->
|
|
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
|
|
|
|
paths() ->
|
|
[
|
|
"/monitor",
|
|
"/monitor/nodes/:node",
|
|
"/monitor_current",
|
|
"/monitor_current/nodes/:node"
|
|
].
|
|
|
|
schema("/monitor") ->
|
|
#{
|
|
'operationId' => monitor,
|
|
get => #{
|
|
tags => [<<"Metrics">>],
|
|
desc => <<"List monitor data.">>,
|
|
parameters => [parameter_latest()],
|
|
responses => #{
|
|
200 => hoconsc:mk(hoconsc:array(hoconsc:ref(sampler)), #{}),
|
|
400 => emqx_dashboard_swagger:error_codes(['BAD_RPC'], <<"Bad RPC">>)
|
|
}
|
|
}
|
|
};
|
|
schema("/monitor/nodes/:node") ->
|
|
#{
|
|
'operationId' => monitor,
|
|
get => #{
|
|
tags => [<<"Metrics">>],
|
|
desc => <<"List the monitor data on the node.">>,
|
|
parameters => [parameter_node(), parameter_latest()],
|
|
responses => #{
|
|
200 => hoconsc:mk(hoconsc:array(hoconsc:ref(sampler)), #{}),
|
|
400 => emqx_dashboard_swagger:error_codes(['BAD_RPC'], <<"Bad RPC">>)
|
|
}
|
|
}
|
|
};
|
|
schema("/monitor_current") ->
|
|
#{
|
|
'operationId' => monitor_current,
|
|
get => #{
|
|
tags => [<<"Metrics">>],
|
|
desc => <<"Current status. Gauge and rate.">>,
|
|
responses => #{
|
|
200 => hoconsc:mk(hoconsc:ref(sampler_current), #{})
|
|
}
|
|
}
|
|
};
|
|
schema("/monitor_current/nodes/:node") ->
|
|
#{
|
|
'operationId' => monitor_current,
|
|
get => #{
|
|
tags => [<<"Metrics">>],
|
|
desc => <<"Node current status. Gauge and rate.">>,
|
|
parameters => [parameter_node()],
|
|
responses => #{
|
|
200 => hoconsc:mk(hoconsc:ref(sampler_current), #{}),
|
|
400 => emqx_dashboard_swagger:error_codes(['BAD_RPC'], <<"Bad RPC">>)
|
|
}
|
|
}
|
|
}.
|
|
|
|
parameter_latest() ->
|
|
Info = #{
|
|
in => query,
|
|
required => false,
|
|
example => 5 * 60,
|
|
desc => <<"The latest N seconds data. Like 300 for 5 min.">>
|
|
},
|
|
{latest, hoconsc:mk(range(1, inf), Info)}.
|
|
|
|
parameter_node() ->
|
|
Info = #{
|
|
in => path,
|
|
required => true,
|
|
example => node(),
|
|
desc => <<"EMQX node name.">>
|
|
},
|
|
{node, hoconsc:mk(binary(), Info)}.
|
|
|
|
fields(sampler) ->
|
|
Samplers =
|
|
[
|
|
{SamplerName, hoconsc:mk(integer(), #{desc => swagger_desc(SamplerName)})}
|
|
|| SamplerName <- ?SAMPLER_LIST
|
|
],
|
|
[{time_stamp, hoconsc:mk(non_neg_integer(), #{desc => <<"Timestamp">>})} | Samplers];
|
|
fields(sampler_current) ->
|
|
Names = maps:values(?DELTA_SAMPLER_RATE_MAP) ++ ?GAUGE_SAMPLER_LIST,
|
|
[
|
|
{SamplerName, hoconsc:mk(integer(), #{desc => swagger_desc(SamplerName)})}
|
|
|| SamplerName <- Names
|
|
].
|
|
|
|
%% -------------------------------------------------------------------------------------------------
|
|
%% API
|
|
|
|
monitor(get, #{query_string := QS, bindings := Bindings}) ->
|
|
Latest = maps:get(<<"latest">>, QS, infinity),
|
|
Node = binary_to_atom(maps:get(node, Bindings, <<"all">>)),
|
|
case emqx_dashboard_monitor:samplers(Node, Latest) of
|
|
{badrpc, {Node, Reason}} ->
|
|
Message = list_to_binary(io_lib:format("Bad node ~p, rpc failed ~p", [Node, Reason])),
|
|
{400, 'BAD_RPC', Message};
|
|
Samplers ->
|
|
{200, Samplers}
|
|
end.
|
|
|
|
monitor_current(get, #{bindings := Bindings}) ->
|
|
NodeOrCluster = binary_to_atom(maps:get(node, Bindings, <<"all">>), utf8),
|
|
case emqx_dashboard_monitor:current_rate(NodeOrCluster) of
|
|
{ok, CurrentRate} ->
|
|
{200, CurrentRate};
|
|
{badrpc, {Node, Reason}} ->
|
|
Message = list_to_binary(io_lib:format("Bad node ~p, rpc failed ~p", [Node, Reason])),
|
|
{400, 'BAD_RPC', Message}
|
|
end.
|
|
|
|
%% -------------------------------------------------------------------------------------------------
|
|
%% Internal
|
|
|
|
swagger_desc(received) ->
|
|
swagger_desc_format("Received messages ");
|
|
swagger_desc(received_bytes) ->
|
|
swagger_desc_format("Received bytes ");
|
|
swagger_desc(sent) ->
|
|
swagger_desc_format("Sent messages ");
|
|
swagger_desc(sent_bytes) ->
|
|
swagger_desc_format("Sent bytes ");
|
|
swagger_desc(dropped) ->
|
|
swagger_desc_format("Dropped messages ");
|
|
swagger_desc(subscriptions) ->
|
|
<<
|
|
"Subscriptions at the time of sampling."
|
|
" Can only represent the approximate state"
|
|
>>;
|
|
swagger_desc(topics) ->
|
|
<<
|
|
"Count topics at the time of sampling."
|
|
" Can only represent the approximate state"
|
|
>>;
|
|
swagger_desc(connections) ->
|
|
<<
|
|
"Connections at the time of sampling."
|
|
" Can only represent the approximate state"
|
|
>>;
|
|
swagger_desc(received_msg_rate) ->
|
|
swagger_desc_format("Dropped messages ", per);
|
|
%swagger_desc(received_bytes_rate) -> swagger_desc_format("Received bytes ", per);
|
|
swagger_desc(sent_msg_rate) ->
|
|
swagger_desc_format("Sent messages ", per);
|
|
%swagger_desc(sent_bytes_rate) -> swagger_desc_format("Sent bytes ", per);
|
|
swagger_desc(dropped_msg_rate) ->
|
|
swagger_desc_format("Dropped messages ", per).
|
|
|
|
swagger_desc_format(Format) ->
|
|
swagger_desc_format(Format, last).
|
|
|
|
swagger_desc_format(Format, Type) ->
|
|
Interval = emqx_conf:get([dashboard, monitor, interval], ?DEFAULT_SAMPLE_INTERVAL),
|
|
list_to_binary(io_lib:format(Format ++ "~p ~p seconds", [Type, Interval])).
|