diff --git a/apps/emqx_dashboard/include/emqx_dashboard.hrl b/apps/emqx_dashboard/include/emqx_dashboard.hrl index 61e513a5f..c2d3479cf 100644 --- a/apps/emqx_dashboard/include/emqx_dashboard.hrl +++ b/apps/emqx_dashboard/include/emqx_dashboard.hrl @@ -72,6 +72,7 @@ ]). -define(GAUGE_SAMPLER_LIST, [ + disconnected_durable_sessions, durable_subscriptions, subscriptions, topics, diff --git a/apps/emqx_dashboard/src/emqx_dashboard_monitor.erl b/apps/emqx_dashboard/src/emqx_dashboard_monitor.erl index f2ebe3831..d3b533ebf 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_monitor.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_monitor.erl @@ -262,6 +262,8 @@ merge_cluster_rate(Node, Cluster) -> Fun = fun %% cluster-synced values + (disconnected_durable_sessions, V, NCluster) -> + NCluster#{disconnected_durable_sessions => V}; (durable_subscriptions, V, NCluster) -> NCluster#{durable_subscriptions => V}; (topics, V, NCluster) -> @@ -417,22 +419,40 @@ getstats(Key) -> _:_ -> 0 end. -stats(connections) -> emqx_stats:getstat('connections.count'); -stats(durable_subscriptions) -> emqx_stats:getstat('durable_subscriptions.count'); -stats(live_connections) -> emqx_stats:getstat('live_connections.count'); -stats(cluster_sessions) -> emqx_stats:getstat('cluster_sessions.count'); -stats(topics) -> emqx_stats:getstat('topics.count'); -stats(subscriptions) -> emqx_stats:getstat('subscriptions.count'); -stats(shared_subscriptions) -> emqx_stats:getstat('subscriptions.shared.count'); -stats(retained_msg_count) -> emqx_stats:getstat('retained.count'); -stats(received) -> emqx_metrics:val('messages.received'); -stats(received_bytes) -> emqx_metrics:val('bytes.received'); -stats(sent) -> emqx_metrics:val('messages.sent'); -stats(sent_bytes) -> emqx_metrics:val('bytes.sent'); -stats(validation_succeeded) -> emqx_metrics:val('messages.validation_succeeded'); -stats(validation_failed) -> emqx_metrics:val('messages.validation_failed'); -stats(dropped) -> emqx_metrics:val('messages.dropped'); -stats(persisted) -> emqx_metrics:val('messages.persisted'). +stats(connections) -> + emqx_stats:getstat('connections.count'); +stats(disconnected_durable_sessions) -> + emqx_persistent_session_bookkeeper:get_disconnected_session_count(); +stats(durable_subscriptions) -> + emqx_stats:getstat('durable_subscriptions.count'); +stats(live_connections) -> + emqx_stats:getstat('live_connections.count'); +stats(cluster_sessions) -> + emqx_stats:getstat('cluster_sessions.count'); +stats(topics) -> + emqx_stats:getstat('topics.count'); +stats(subscriptions) -> + emqx_stats:getstat('subscriptions.count'); +stats(shared_subscriptions) -> + emqx_stats:getstat('subscriptions.shared.count'); +stats(retained_msg_count) -> + emqx_stats:getstat('retained.count'); +stats(received) -> + emqx_metrics:val('messages.received'); +stats(received_bytes) -> + emqx_metrics:val('bytes.received'); +stats(sent) -> + emqx_metrics:val('messages.sent'); +stats(sent_bytes) -> + emqx_metrics:val('bytes.sent'); +stats(validation_succeeded) -> + emqx_metrics:val('messages.validation_succeeded'); +stats(validation_failed) -> + emqx_metrics:val('messages.validation_failed'); +stats(dropped) -> + emqx_metrics:val('messages.dropped'); +stats(persisted) -> + emqx_metrics:val('messages.persisted'). %% ------------------------------------------------------------------------------------------------- %% Retained && License Quota diff --git a/apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl b/apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl index 1dca9d341..c8bb9c8be 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl @@ -194,6 +194,8 @@ swagger_desc(validation_failed) -> swagger_desc_format("Schema validations failed "); swagger_desc(persisted) -> swagger_desc_format("Messages saved to the durable storage "); +swagger_desc(disconnected_durable_sessions) -> + <<"Disconnected durable sessions at the time of sampling.", ?APPROXIMATE_DESC>>; swagger_desc(durable_subscriptions) -> <<"Subscriptions from durable sessions at the time of sampling.", ?APPROXIMATE_DESC>>; swagger_desc(subscriptions) -> diff --git a/apps/emqx_dashboard/test/emqx_dashboard_monitor_SUITE.erl b/apps/emqx_dashboard/test/emqx_dashboard_monitor_SUITE.erl index f174e03be..59951faa9 100644 --- a/apps/emqx_dashboard/test/emqx_dashboard_monitor_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_dashboard_monitor_SUITE.erl @@ -341,6 +341,8 @@ t_persistent_session_stats(_Config) -> ?retry(1_000, 10, begin ?assertMatch( {ok, #{ + <<"connections">> := 2, + <<"disconnected_durable_sessions">> := 0, %% N.B.: we currently don't perform any deduplication between persistent %% and non-persistent routes, so we count `commont/topic' twice and get 8 %% instead of 6 here. @@ -356,6 +358,29 @@ t_persistent_session_stats(_Config) -> ?assert(PSRouteCount > 0, #{ps_route_count => PSRouteCount}), PSSubCount = emqx_persistent_session_bookkeeper:get_subscription_count(), ?assert(PSSubCount > 0, #{ps_sub_count => PSSubCount}), + + %% Now with disconnected but alive persistent sessions + {ok, {ok, _}} = + ?wait_async_action( + emqtt:disconnect(PSClient), + #{?snk_kind := dashboard_monitor_flushed} + ), + ?retry(1_000, 10, begin + ?assertMatch( + {ok, #{ + <<"connections">> := 1, + <<"disconnected_durable_sessions">> := 1, + %% N.B.: we currently don't perform any deduplication between persistent + %% and non-persistent routes, so we count `commont/topic' twice and get 8 + %% instead of 6 here. + <<"topics">> := 8, + <<"durable_subscriptions">> := 4, + <<"subscriptions">> := 4 + }}, + request(["monitor_current"]) + ) + end), + ok. request(Path) ->