diff --git a/apps/emqx_modules/src/emqx_observer_cli.erl b/apps/emqx_modules/src/emqx_observer_cli.erl index d5a2a0bfa..d8fa1822d 100644 --- a/apps/emqx_modules/src/emqx_observer_cli.erl +++ b/apps/emqx_modules/src/emqx_observer_cli.erl @@ -35,17 +35,23 @@ disable() -> cmd(["status"]) -> observer_cli:start(); cmd(["bin_leak"]) -> - [emqx_ctl:print("~p~n", [Row]) || Row <- recon:bin_leak(100)]; + lists:foreach( + fun(Row) -> emqx_ctl:print("~p~n", [Row]) end, + recon:bin_leak(100) + ); cmd(["load", Mod]) -> Module = list_to_existing_atom(Mod), Nodes = nodes(), Res = remote_load(Nodes, Module), - emqx_ctl:print("Loaded ~p module on ~p on ~n", [Mod, Nodes, Res]); + emqx_ctl:print("Loaded ~p module on ~p: ~p~n", [Module, Nodes, Res]); cmd(_) -> emqx_ctl:usage([ - {"observer status", "observer_cli:start()"}, - {"observer bin_leak", "recon:bin_leak(100)"}, - {"observer load Mod", "recon:remote_load(Mod) to all nodes"} + {"observer status", "Start observer in the current console"}, + {"observer bin_leak", + "Force all processes to perform garbage collection " + "and prints the top-100 processes that freed the " + "biggest amount of binaries, potentially highlighting leaks."}, + {"observer load Mod", "Ensure a module is loaded in all EMQX nodes in the cluster"} ]). %% recon:remote_load/1 has a bug, when nodes() returns [], it is diff --git a/apps/emqx_modules/test/emqx_observer_cli_tests.erl b/apps/emqx_modules/test/emqx_observer_cli_tests.erl new file mode 100644 index 000000000..af1ea3f15 --- /dev/null +++ b/apps/emqx_modules/test/emqx_observer_cli_tests.erl @@ -0,0 +1,56 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2022 EMQ Technologies Co., Ltd. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +-module(emqx_observer_cli_tests). + +-include_lib("eunit/include/eunit.hrl"). + +start_observer_cli_test() -> + meck:new(observer_cli, [passthrough, no_history, no_link, no_passthrough_cover]), + meck:expect(observer_cli, start, fun() -> ok end), + try + ok = emqx_observer_cli:cmd(["status"]) + after + meck:unload(observer_cli) + end. + +bin_leak_test() -> + ok = emqx_observer_cli:cmd(["bin_leak"]). + +load_observer_cli_test() -> + ok = emqx_observer_cli:cmd(["load", "lists"]). + +unknown_command_test() -> + meck_emqx_ctl(), + try + ok = emqx_observer_cli:cmd(dummy), + receive + {usage, [_ | _]} -> ok + end + after + unmeck_emqx_ctl() + end. + +meck_emqx_ctl() -> + Pid = self(), + meck:new(emqx_ctl, [passthrough, no_history, no_link, no_passthrough_cover]), + meck:expect(emqx_ctl, usage, fun(Tuples) -> + Pid ! {usage, Tuples}, + ok + end). + +unmeck_emqx_ctl() -> + meck:unload(emqx_ctl).