diff --git a/apps/emqx_management/src/emqx_mgmt_api_nodes.erl b/apps/emqx_management/src/emqx_mgmt_api_nodes.erl index 6b641c9c7..765150525 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_nodes.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_nodes.erl @@ -100,6 +100,7 @@ node_metrics_api() -> parameters => parameters(), responses => #{ <<"400">> => error_schema(<<"Node error">>, ['SOURCE_ERROR']), + %% TODO: Node Metrics Schema <<"200">> => schema(metrics, <<"Get EMQ X Node Metrics">>)}}}, {"/nodes/:node_name/metrics", Metadata, node_metrics}. @@ -110,6 +111,7 @@ node_stats_api() -> parameters => parameters(), responses => #{ <<"400">> => error_schema(<<"Node error">>, ['SOURCE_ERROR']), + %% TODO: Node Stats Schema <<"200">> => schema(stat, <<"Get EMQ X Node Stats">>)}}}, {"/nodes/:node_name/stats", Metadata, node_stats}. diff --git a/apps/emqx_management/src/emqx_mgmt_api_stats.erl b/apps/emqx_management/src/emqx_mgmt_api_stats.erl index 437d91f1b..7893f3578 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_stats.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_stats.erl @@ -17,82 +17,137 @@ -behaviour(minirest_api). --export([api_spec/0]). +-include_lib("typerefl/include/types.hrl"). + +-import( hoconsc + , [ mk/2 + , ref/1 + , ref/2 + , array/1]). + +-export([ api_spec/0 + , paths/0 + , schema/1 + , fields/1 + ]). -export([list/2]). api_spec() -> - {[stats_api()], stats_schema()}. + emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). -stats_schema() -> - Stats = #{ - type => array, - items => #{ - type => object, - properties => emqx_mgmt_util:properties([{'node', string} | properties()]) - } - }, - Stat = #{ - type => object, - properties => emqx_mgmt_util:properties(properties()) - }, - StatsInfo =#{ - oneOf => [ minirest:ref(stats) - , minirest:ref(stat) - ] - }, - [#{stats => Stats, stat => Stat, stats_info => StatsInfo}]. +paths() -> + ["/stats"]. -properties() -> - [ - {'channels.count', integer, <<"sessions.count">>}, - {'channels.max', integer, <<"session.max">>}, - {'connections.count', integer, <<"Number of current connections">>}, - {'connections.max', integer, <<"Historical maximum number of connections">>}, - {'retained.count', integer, <<"Number of currently retained messages">>}, - {'retained.max', integer, <<"Historical maximum number of retained messages">>}, - {'routes.count', integer, <<"Number of current routes">>}, - {'routes.max', integer, <<"Historical maximum number of routes">>}, - {'sessions.count', integer, <<"Number of current sessions">>}, - {'sessions.max', integer, <<"Historical maximum number of sessions">>}, - {'suboptions.count', integer, <<"subscriptions.count">>}, - {'suboptions.max', integer, <<"subscriptions.max">>}, - {'subscribers.count', integer, <<"Number of current subscribers">>}, - {'subscribers.max', integer, <<"Historical maximum number of subscribers">>}, - {'subscriptions.count', integer, <<"Number of current subscriptions, including shared subscriptions">>}, - {'subscriptions.max', integer, <<"Historical maximum number of subscriptions">>}, - {'subscriptions.shared.count', integer, <<"Number of current shared subscriptions">>}, - {'subscriptions.shared.max', integer, <<"Historical maximum number of shared subscriptions">>}, - {'topics.count', integer, <<"Number of current topics">>}, - {'topics.max', integer, <<"Historical maximum number of topics">>} - ]. +schema("/stats") -> + #{ 'operationId' => list + , get => + #{ description => <<"EMQ X stats">> + , tags => [<<"stats">>] + , parameters => [ref(aggregate)] + , responses => + #{ 200 => mk( hoconsc:union([ ref(?MODULE, base_data) + , array(ref(?MODULE, aggergate_data)) + ]) + , #{ desc => <<"List stats ok">> }) + } + } + }. + +fields(aggregate) -> + [ { aggregate + , mk( boolean() + , #{ desc => <<"Calculation aggregate for all nodes">> + , in => query + , nullable => true + , example => false})} + ]; +fields(base_data) -> + [ { 'channels.count' + , mk( integer(), #{ desc => <<"sessions.count">> + , example => 0})} + , { 'channels.max' + , mk( integer(), #{ desc => <<"session.max">> + , example => 0})} + , { 'connections.count' + , mk( integer(), #{ desc => <<"Number of current connections">> + , example => 0})} + , { 'connections.max' + , mk( integer(), #{ desc => <<"Historical maximum number of connections">> + , example => 0})} + , { 'delayed.count' + , mk( integer(), #{ desc => <<"Number of delayed messages">> + , example => 0})} + , { 'delayed.max' + , mk( integer(), #{ desc => <<"Historical maximum number of delayed messages">> + , example => 0})} + , { 'live_connections.count' + , mk( integer(), #{ desc => <<"Number of current live connections">> + , example => 0})} + , { 'live_connections.max' + , mk( integer(), #{ desc => <<"Historical maximum number of live connections">> + , example => 0})} + , { 'retained.count' + , mk( integer(), #{ desc => <<"Number of currently retained messages">> + , example => 0})} + , { 'retained.max' + , mk( integer(), #{ desc => <<"Historical maximum number of retained messages">> + , example => 0})} + , { 'routes.count' + , mk( integer(), #{ desc => <<"Number of current routes">> + , example => 0})} + , { 'routes.max' + , mk( integer(), #{ desc => <<"Historical maximum number of routes">> + , example => 0})} + , { 'sessions.count' + , mk( integer(), #{ desc => <<"Number of current sessions">> + , example => 0})} + , { 'sessions.max' + , mk( integer(), #{ desc => <<"Historical maximum number of sessions">> + , example => 0})} + , { 'suboptions.count' + , mk( integer(), #{ desc => <<"subscriptions.count">> + , example => 0})} + , { 'suboptions.max' + , mk( integer(), #{ desc => <<"subscriptions.max">> + , example => 0})} + , { 'subscribers.count' + , mk( integer(), #{ desc => <<"Number of current subscribers">> + , example => 0})} + , { 'subscribers.max' + , mk( integer(), #{ desc => <<"Historical maximum number of subscribers">> + , example => 0})} + , { 'subscriptions.count' + , mk( integer(), #{ desc => <<"Number of current subscriptions, including shared subscriptions">> + , example => 0})} + , { 'subscriptions.max' + , mk( integer(), #{ desc => <<"Historical maximum number of subscriptions">> + , example => 0})} + , { 'subscriptions.shared.count' + , mk( integer(), #{ desc => <<"Number of current shared subscriptions">> + , example => 0})} + , { 'subscriptions.shared.max' + , mk( integer(), #{ desc => <<"Historical maximum number of shared subscriptions">> + , example => 0})} + , { 'topics.count' + , mk( integer(), #{ desc => <<"Number of current topics">> + , example => 0})} + , { 'topics.max' + , mk( integer(), #{ desc => <<"Historical maximum number of topics">> + , example => 0})} + ]; +fields(aggergate_data) -> + [ { node + , mk( string(), #{ desc => <<"Node name">> + , example => <<"emqx@127.0.0.1">>})} + ] ++ fields(base_data). -stats_api() -> - Metadata = #{ - get => #{ - description => <<"EMQ X stats">>, - parameters => [#{ - name => aggregate, - in => query, - schema => #{type => boolean} - }], - responses => #{ - <<"200">> => #{ - description => <<"List stats ok">>, - content => #{ - 'application/json' => #{ - schema => minirest:ref(<<"stats_info">>) - } - } - } - }}}, - {"/stats", Metadata, list}. %%%============================================================================================== %% api apply list(get, #{query_string := Qs}) -> case maps:get(<<"aggregate">>, Qs, undefined) of - <<"true">> -> + true -> {200, emqx_mgmt:get_stats()}; _ -> Data = [maps:from_list(emqx_mgmt:get_stats(Node) ++ [{node, Node}]) || diff --git a/apps/emqx_management/src/emqx_mgmt_api_status.erl b/apps/emqx_management/src/emqx_mgmt_api_status.erl index c1f0e9139..a34c8b757 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_status.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_status.erl @@ -17,22 +17,40 @@ %% API -behaviour(minirest_api). --export([api_spec/0]). +-export([ api_spec/0 + , paths/0 + , schema/1 + ]). -export([running_status/2]). api_spec() -> - {[status_api()], []}. + emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}). -status_api() -> - Path = "/status", - Metadata = #{ - get => #{ - security => [], - responses => #{<<"200">> => #{description => <<"running">>}} - } - }, - {Path, Metadata, running_status}. +paths() -> + ["/status"]. + +schema("/status") -> + #{ 'operationId' => running_status + , get => + #{ description => <<"Node running status">> + , security => [] + , responses => + #{200 => + #{ description => <<"Node is running">> + , content => + #{ 'text/plain' => + #{ schema => #{type => string} + , example => <<"Node emqx@127.0.0.1 is started\nemqx is running">>} + } + } + } + } + }. + +%%-------------------------------------------------------------------- +%% API Handler funcs +%%-------------------------------------------------------------------- running_status(get, _Params) -> {InternalStatus, _ProvidedStatus} = init:get_status(), @@ -44,5 +62,3 @@ running_status(get, _Params) -> Status = io_lib:format("Node ~ts is ~ts~nemqx is ~ts", [node(), InternalStatus, AppStatus]), Body = list_to_binary(Status), {200, #{<<"content-type">> => <<"text/plain">>}, Body}. - - diff --git a/apps/emqx_prometheus/src/emqx_prometheus_api.erl b/apps/emqx_prometheus/src/emqx_prometheus_api.erl index 4b19c9665..0c54216c2 100644 --- a/apps/emqx_prometheus/src/emqx_prometheus_api.erl +++ b/apps/emqx_prometheus/src/emqx_prometheus_api.erl @@ -116,10 +116,8 @@ prometheus_data_schema() -> #{ description => <<"Get Prometheus Data">> , content => #{ 'application/json' => - #{ schema => #{type => object} - , description => <<"Prometheus Data in json">>} + #{schema => #{type => object}} , 'text/plain' => - #{ schema => #{type => string} - , description => <<"Prometheus Data in text/plain">>} + #{schema => #{type => string}} } }.