cli
This commit is contained in:
parent
470d5644ef
commit
e09148b040
|
@ -24,6 +24,7 @@
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
%%%-----------------------------------------------------------------------------
|
%%%-----------------------------------------------------------------------------
|
||||||
|
|
||||||
-module(emqttd_app).
|
-module(emqttd_app).
|
||||||
|
|
||||||
-author("Feng Lee <feng@emqtt.io>").
|
-author("Feng Lee <feng@emqtt.io>").
|
||||||
|
@ -49,6 +50,7 @@
|
||||||
start(_StartType, _StartArgs) ->
|
start(_StartType, _StartArgs) ->
|
||||||
print_banner(),
|
print_banner(),
|
||||||
emqttd_mnesia:start(),
|
emqttd_mnesia:start(),
|
||||||
|
emqttd_ctl:init(),
|
||||||
{ok, Sup} = emqttd_sup:start_link(),
|
{ok, Sup} = emqttd_sup:start_link(),
|
||||||
start_servers(Sup),
|
start_servers(Sup),
|
||||||
emqttd:load_all_mods(),
|
emqttd:load_all_mods(),
|
||||||
|
|
|
@ -29,6 +29,10 @@
|
||||||
-author('feng@emqtt.io').
|
-author('feng@emqtt.io').
|
||||||
|
|
||||||
-include("emqttd.hrl").
|
-include("emqttd.hrl").
|
||||||
|
-include("emqttd_cli.hrl").
|
||||||
|
|
||||||
|
%% CLI callbacks
|
||||||
|
-export([cli_useradd/1, cli_userdel/1]).
|
||||||
|
|
||||||
-behaviour(emqttd_auth_mod).
|
-behaviour(emqttd_auth_mod).
|
||||||
|
|
||||||
|
@ -42,6 +46,22 @@
|
||||||
|
|
||||||
-record(?AUTH_USERNAME_TAB, {username, password}).
|
-record(?AUTH_USERNAME_TAB, {username, password}).
|
||||||
|
|
||||||
|
%%%=============================================================================
|
||||||
|
%%% CLI
|
||||||
|
%%%=============================================================================
|
||||||
|
|
||||||
|
cli_useradd([Username, Password]) ->
|
||||||
|
?PRINT("~p~n", [add_user(list_to_binary(Username), list_to_binary(Password))]);
|
||||||
|
|
||||||
|
cli_useradd(_) ->
|
||||||
|
?PRINT_CMD("useradd <Username> <Password>", "#add user").
|
||||||
|
|
||||||
|
cli_userdel([Username]) ->
|
||||||
|
?PRINT("~p~n", [remove_user(list_to_binary(Username))]);
|
||||||
|
|
||||||
|
cli_userdel(_) ->
|
||||||
|
?PRINT_CMD("userdel <Username>", "#delete user").
|
||||||
|
|
||||||
%%%=============================================================================
|
%%%=============================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%=============================================================================
|
%%%=============================================================================
|
||||||
|
@ -67,6 +87,8 @@ init(Opts) ->
|
||||||
{disc_copies, [node()]},
|
{disc_copies, [node()]},
|
||||||
{attributes, record_info(fields, ?AUTH_USERNAME_TAB)}]),
|
{attributes, record_info(fields, ?AUTH_USERNAME_TAB)}]),
|
||||||
mnesia:add_table_copy(?AUTH_USERNAME_TAB, node(), ram_copies),
|
mnesia:add_table_copy(?AUTH_USERNAME_TAB, node(), ram_copies),
|
||||||
|
emqttd_ctl:register_cmd(useradd, {?MODULE, cli_useradd}, []),
|
||||||
|
emqttd_ctl:register_cmd(userdel, {?MODULE, cli_userdel}, []),
|
||||||
{ok, Opts}.
|
{ok, Opts}.
|
||||||
|
|
||||||
check(#mqtt_client{username = undefined}, _Password, _Opts) ->
|
check(#mqtt_client{username = undefined}, _Password, _Opts) ->
|
||||||
|
|
|
@ -28,7 +28,10 @@
|
||||||
|
|
||||||
-author("Feng Lee <feng@emqtt.io>").
|
-author("Feng Lee <feng@emqtt.io>").
|
||||||
|
|
||||||
-include_lib("emqttd.hrl").
|
-include("emqttd.hrl").
|
||||||
|
-include("emqttd_cli.hrl").
|
||||||
|
|
||||||
|
-export([cli/1]).
|
||||||
|
|
||||||
%% API Function Exports
|
%% API Function Exports
|
||||||
-export([start_link/0]).
|
-export([start_link/0]).
|
||||||
|
@ -68,6 +71,16 @@
|
||||||
sysdescr % Broker description
|
sysdescr % Broker description
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
%%%=============================================================================
|
||||||
|
%%% CLI callback
|
||||||
|
%%%=============================================================================
|
||||||
|
cli([]) ->
|
||||||
|
Funs = [sysdescr, version, uptime, datetime],
|
||||||
|
[?PRINT("~-20s~s~n", [Fun, ?MODULE:Fun()]) || Fun <- Funs];
|
||||||
|
|
||||||
|
cli(_) ->
|
||||||
|
?PRINT_CMD("broker", "#query broker version, uptime and description").
|
||||||
|
|
||||||
%%%=============================================================================
|
%%%=============================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%=============================================================================
|
%%%=============================================================================
|
||||||
|
@ -223,6 +236,8 @@ init([]) ->
|
||||||
% Create $SYS Topics
|
% Create $SYS Topics
|
||||||
emqttd_pubsub:create(<<"$SYS/brokers">>),
|
emqttd_pubsub:create(<<"$SYS/brokers">>),
|
||||||
[ok = create_topic(Topic) || Topic <- ?SYSTOP_BROKERS],
|
[ok = create_topic(Topic) || Topic <- ?SYSTOP_BROKERS],
|
||||||
|
%% CLI
|
||||||
|
emqttd_ctl:register_cmd(broker, {?MODULE, cli}, []),
|
||||||
% Tick
|
% Tick
|
||||||
{ok, #state{started_at = os:timestamp(),
|
{ok, #state{started_at = os:timestamp(),
|
||||||
heartbeat = start_tick(1000, heartbeat),
|
heartbeat = start_tick(1000, heartbeat),
|
||||||
|
@ -279,7 +294,9 @@ handle_info(_Info, State) ->
|
||||||
|
|
||||||
terminate(_Reason, #state{heartbeat = Hb, tick_tref = TRef}) ->
|
terminate(_Reason, #state{heartbeat = Hb, tick_tref = TRef}) ->
|
||||||
stop_tick(Hb),
|
stop_tick(Hb),
|
||||||
stop_tick(TRef).
|
stop_tick(TRef),
|
||||||
|
emqttd_ctl:unregister_cmd(broker),
|
||||||
|
ok.
|
||||||
|
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
|
@ -24,32 +24,86 @@
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
%%%-----------------------------------------------------------------------------
|
%%%-----------------------------------------------------------------------------
|
||||||
|
|
||||||
-module(emqttd_ctl).
|
-module(emqttd_ctl).
|
||||||
|
|
||||||
-author("Feng Lee <feng@emqtt.io>").
|
-author("Feng Lee <feng@emqtt.io>").
|
||||||
|
|
||||||
-include("emqttd.hrl").
|
-include("emqttd.hrl").
|
||||||
|
|
||||||
-define(PRINT_MSG(Msg),
|
-include("emqttd_cli.hrl").
|
||||||
io:format(Msg)).
|
|
||||||
|
|
||||||
-define(PRINT(Format, Args),
|
-export([init/0,
|
||||||
io:format(Format, Args)).
|
register_cmd/3,
|
||||||
|
unregister_cmd/1,
|
||||||
|
run/1]).
|
||||||
|
|
||||||
-export([status/1,
|
-export([status/1,
|
||||||
vm/1,
|
vm/1,
|
||||||
broker/1,
|
|
||||||
stats/1,
|
stats/1,
|
||||||
metrics/1,
|
metrics/1,
|
||||||
cluster/1,
|
cluster/1,
|
||||||
clients/1,
|
clients/1,
|
||||||
sessions/1,
|
sessions/1,
|
||||||
listeners/1,
|
listeners/1,
|
||||||
bridges/1,
|
bridges/1]).
|
||||||
plugins/1,
|
|
||||||
trace/1,
|
-define(CMD_TAB, mqttd_ctl_cmd).
|
||||||
useradd/1,
|
|
||||||
userdel/1]).
|
%%%=============================================================================
|
||||||
|
%%% API
|
||||||
|
%%%=============================================================================
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% @doc Init cmd table.
|
||||||
|
%% @end
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
init() ->
|
||||||
|
ets:new(?CMD_TAB, [ordered_set, named_table, public]),
|
||||||
|
register_cmd(status, {?MODULE, status}, []),
|
||||||
|
register_cmd(vm, {?MODULE, vm}, []),
|
||||||
|
register_cmd(cluster, {?MODULE, cluster}, []).
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% @doc Register a command
|
||||||
|
%% @end
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
-spec register_cmd(atom(), {module(), atom()}, list()) -> true.
|
||||||
|
register_cmd(Cmd, MF, Opts) ->
|
||||||
|
ets:insert(?CMD_TAB, {Cmd, MF, Opts}).
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% @doc Unregister a command
|
||||||
|
%% @end
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
-spec unregister_cmd(atom()) -> true.
|
||||||
|
unregister_cmd(Cmd) ->
|
||||||
|
ets:delete(?CMD_TAB, Cmd).
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% @doc Run a command
|
||||||
|
%% @end
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
run([]) -> usage();
|
||||||
|
|
||||||
|
run([CmdS|Args]) ->
|
||||||
|
case ets:lookup(?CMD_TAB, list_to_atom(CmdS)) of
|
||||||
|
[{_, {Mod, Fun}, _}] -> Mod:Fun(Args);
|
||||||
|
[] -> usage()
|
||||||
|
end.
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% @doc Usage
|
||||||
|
%% @end
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
usage() ->
|
||||||
|
?PRINT("Usage: ~s~n", [?MODULE]),
|
||||||
|
[Mod:Cmd(["help"]) || {_, {Mod, Cmd}, _} <- ets:tab2list(?CMD_TAB)].
|
||||||
|
|
||||||
|
%%%=============================================================================
|
||||||
|
%%% Commands
|
||||||
|
%%%=============================================================================
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% @doc Query node status
|
%% @doc Query node status
|
||||||
|
@ -63,7 +117,36 @@ status([]) ->
|
||||||
?PRINT_MSG("emqttd is not running~n");
|
?PRINT_MSG("emqttd is not running~n");
|
||||||
{value,_Version} ->
|
{value,_Version} ->
|
||||||
?PRINT_MSG("emqttd is running~n")
|
?PRINT_MSG("emqttd is running~n")
|
||||||
end.
|
end;
|
||||||
|
status(_) ->
|
||||||
|
?PRINT_CMD("status", "#query broker status").
|
||||||
|
|
||||||
|
vm([]) ->
|
||||||
|
vm(["all"]);
|
||||||
|
|
||||||
|
vm(["all"]) ->
|
||||||
|
[begin vm([Name]), ?PRINT_MSG("~n") end || Name <- ["load", "memory", "process", "io"]];
|
||||||
|
|
||||||
|
vm(["load"]) ->
|
||||||
|
[?PRINT("cpu/~-20s~s~n", [L, V]) || {L, V} <- emqttd_vm:loads()];
|
||||||
|
|
||||||
|
vm(["memory"]) ->
|
||||||
|
[?PRINT("memory/~-17s~w~n", [Cat, Val]) || {Cat, Val} <- erlang:memory()];
|
||||||
|
|
||||||
|
vm(["process"]) ->
|
||||||
|
lists:foreach(fun({Name, Key}) ->
|
||||||
|
?PRINT("process/~-16s~w~n", [Name, erlang:system_info(Key)])
|
||||||
|
end, [{limit, process_limit}, {count, process_count}]);
|
||||||
|
|
||||||
|
vm(["io"]) ->
|
||||||
|
?PRINT("io/~-21s~w~n", [max_fds, proplists:get_value(max_fds, erlang:system_info(check_io))]);
|
||||||
|
|
||||||
|
vm(_) ->
|
||||||
|
?PRINT_CMD("vm all", "#query info of erlang vm"),
|
||||||
|
?PRINT_CMD("vm load", "#query load of erlang vm"),
|
||||||
|
?PRINT_CMD("vm memory", "#query memory of erlang vm"),
|
||||||
|
?PRINT_CMD("vm process", "#query process of erlang vm"),
|
||||||
|
?PRINT_CMD("vm io", "#queue io of erlang vm").
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% @doc Cluster with other node
|
%% @doc Cluster with other node
|
||||||
|
@ -93,45 +176,11 @@ cluster([SNode]) ->
|
||||||
end;
|
end;
|
||||||
pang ->
|
pang ->
|
||||||
?PRINT("failed to connect to ~p~n", [Node])
|
?PRINT("failed to connect to ~p~n", [Node])
|
||||||
end.
|
end;
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
cluster(_) ->
|
||||||
%% @doc Add user
|
?PRINT_CMD("cluster [<Node>]", "#cluster with node, query cluster info ").
|
||||||
%% @end
|
|
||||||
%%------------------------------------------------------------------------------
|
|
||||||
useradd([Username, Password]) ->
|
|
||||||
?PRINT("~p~n", [emqttd_auth_username:add_user(bin(Username), bin(Password))]).
|
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
|
||||||
%% @doc Delete user
|
|
||||||
%% @end
|
|
||||||
%%------------------------------------------------------------------------------
|
|
||||||
userdel([Username]) ->
|
|
||||||
?PRINT("~p~n", [emqttd_auth_username:remove_user(bin(Username))]).
|
|
||||||
|
|
||||||
vm([]) ->
|
|
||||||
[vm([Name]) || Name <- ["load", "memory", "process", "io"]];
|
|
||||||
|
|
||||||
vm(["load"]) ->
|
|
||||||
?PRINT_MSG("Load: ~n"),
|
|
||||||
[?PRINT(" ~s:~s~n", [L, V]) || {L, V} <- emqttd_vm:loads()];
|
|
||||||
|
|
||||||
vm(["memory"]) ->
|
|
||||||
?PRINT_MSG("Memory: ~n"),
|
|
||||||
[?PRINT(" ~s:~p~n", [Cat, Val]) || {Cat, Val} <- erlang:memory()];
|
|
||||||
|
|
||||||
vm(["process"]) ->
|
|
||||||
?PRINT_MSG("Process: ~n"),
|
|
||||||
?PRINT(" process_limit:~p~n", [erlang:system_info(process_limit)]),
|
|
||||||
?PRINT(" process_count:~p~n", [erlang:system_info(process_count)]);
|
|
||||||
|
|
||||||
vm(["io"]) ->
|
|
||||||
?PRINT_MSG("IO: ~n"),
|
|
||||||
?PRINT(" max_fds:~p~n", [proplists:get_value(max_fds, erlang:system_info(check_io))]).
|
|
||||||
|
|
||||||
broker([]) ->
|
|
||||||
Funs = [sysdescr, version, uptime, datetime],
|
|
||||||
[?PRINT("~s: ~s~n", [Fun, emqttd_broker:Fun()]) || Fun <- Funs].
|
|
||||||
|
|
||||||
stats([]) ->
|
stats([]) ->
|
||||||
[?PRINT("~s: ~p~n", [Stat, Val]) || {Stat, Val} <- emqttd_stats:getstats()].
|
[?PRINT("~s: ~p~n", [Stat, Val]) || {Stat, Val} <- emqttd_stats:getstats()].
|
||||||
|
@ -216,50 +265,6 @@ bridges(["stop", SNode, Topic]) ->
|
||||||
{error, Error} -> ?PRINT("error: ~p~n", [Error])
|
{error, Error} -> ?PRINT("error: ~p~n", [Error])
|
||||||
end.
|
end.
|
||||||
|
|
||||||
plugins(["list"]) ->
|
|
||||||
lists:foreach(fun(Plugin) -> print(plugin, Plugin) end, emqttd_plugins:list());
|
|
||||||
|
|
||||||
plugins(["load", Name]) ->
|
|
||||||
case emqttd_plugins:load(list_to_atom(Name)) of
|
|
||||||
{ok, StartedApps} -> ?PRINT("Start apps: ~p~nPlugin ~s loaded successfully.~n", [StartedApps, Name]);
|
|
||||||
{error, Reason} -> ?PRINT("load plugin error: ~p~n", [Reason])
|
|
||||||
end;
|
|
||||||
|
|
||||||
plugins(["unload", Name]) ->
|
|
||||||
case emqttd_plugins:unload(list_to_atom(Name)) of
|
|
||||||
ok -> ?PRINT("Plugin ~s unloaded successfully.~n", [Name]);
|
|
||||||
{error, Reason} -> ?PRINT("unload plugin error: ~p~n", [Reason])
|
|
||||||
end.
|
|
||||||
|
|
||||||
trace(["list"]) ->
|
|
||||||
lists:foreach(fun({{Who, Name}, LogFile}) ->
|
|
||||||
?PRINT("trace ~s ~s -> ~s~n", [Who, Name, LogFile])
|
|
||||||
end, emqttd_trace:all_traces());
|
|
||||||
|
|
||||||
trace(["client", ClientId, "off"]) ->
|
|
||||||
stop_trace(client, ClientId);
|
|
||||||
trace(["client", ClientId, LogFile]) ->
|
|
||||||
start_trace(client, ClientId, LogFile);
|
|
||||||
trace(["topic", Topic, "off"]) ->
|
|
||||||
stop_trace(topic, Topic);
|
|
||||||
trace(["topic", Topic, LogFile]) ->
|
|
||||||
start_trace(topic, Topic, LogFile).
|
|
||||||
|
|
||||||
start_trace(Who, Name, LogFile) ->
|
|
||||||
case emqttd_trace:start_trace({Who, bin(Name)}, LogFile) of
|
|
||||||
ok ->
|
|
||||||
?PRINT("trace ~s ~s successfully.~n", [Who, Name]);
|
|
||||||
{error, Error} ->
|
|
||||||
?PRINT("trace ~s ~s error: ~p~n", [Who, Name, Error])
|
|
||||||
end.
|
|
||||||
stop_trace(Who, Name) ->
|
|
||||||
case emqttd_trace:stop_trace({Who, bin(Name)}) of
|
|
||||||
ok ->
|
|
||||||
?PRINT("stop to trace ~s ~s successfully.~n", [Who, Name]);
|
|
||||||
{error, Error} ->
|
|
||||||
?PRINT("stop to trace ~s ~s error: ~p.~n", [Who, Name, Error])
|
|
||||||
end.
|
|
||||||
|
|
||||||
|
|
||||||
node_name(SNode) ->
|
node_name(SNode) ->
|
||||||
SNode1 =
|
SNode1 =
|
||||||
|
@ -333,11 +338,8 @@ print(session, {{ClientId, _ClientPid}, SessInfo}) ->
|
||||||
"message_queue=~w, message_dropped=~w, "
|
"message_queue=~w, message_dropped=~w, "
|
||||||
"awaiting_rel=~w, awaiting_ack=~w, awaiting_comp=~w, "
|
"awaiting_rel=~w, awaiting_ack=~w, awaiting_comp=~w, "
|
||||||
"created_at=~w, subscriptions=~s)~n",
|
"created_at=~w, subscriptions=~s)~n",
|
||||||
[ClientId | [format(Key, proplists:get_value(Key, SessInfo)) || Key <- InfoKeys]]);
|
[ClientId | [format(Key, proplists:get_value(Key, SessInfo)) || Key <- InfoKeys]]).
|
||||||
|
|
||||||
print(plugin, #mqtt_plugin{name = Name, version = Ver, descr = Descr, active = Active}) ->
|
|
||||||
?PRINT("Plugin(~s, version=~s, description=~s, active=~s)~n",
|
|
||||||
[Name, Ver, Descr, Active]).
|
|
||||||
|
|
||||||
format(created_at, Val) ->
|
format(created_at, Val) ->
|
||||||
emqttd_util:now_to_secs(Val);
|
emqttd_util:now_to_secs(Val);
|
||||||
|
|
|
@ -24,18 +24,21 @@
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
%%%-----------------------------------------------------------------------------
|
%%%-----------------------------------------------------------------------------
|
||||||
|
|
||||||
-module(emqttd_metrics).
|
-module(emqttd_metrics).
|
||||||
|
|
||||||
-author("Feng Lee <feng@emqtt.io>").
|
-author("Feng Lee <feng@emqtt.io>").
|
||||||
|
|
||||||
-include("emqttd.hrl").
|
-include("emqttd.hrl").
|
||||||
|
|
||||||
|
-include("emqttd_cli.hrl").
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
-define(SERVER, ?MODULE).
|
-define(SERVER, ?MODULE).
|
||||||
|
|
||||||
%% API Function Exports
|
%% API Function Exports
|
||||||
-export([start_link/0]).
|
-export([start_link/0, cli/1]).
|
||||||
|
|
||||||
-export([all/0, value/1,
|
-export([all/0, value/1,
|
||||||
inc/1, inc/2, inc/3,
|
inc/1, inc/2, inc/3,
|
||||||
|
@ -93,6 +96,17 @@
|
||||||
start_link() ->
|
start_link() ->
|
||||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% @doc CLI command callback
|
||||||
|
%% @end
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
cli([]) ->
|
||||||
|
[?PRINT("~-32s ~w~n", [Metric, Val]) || {Metric, Val} <- lists:sort(emqttd_metrics:all())];
|
||||||
|
|
||||||
|
cli(_) ->
|
||||||
|
?PRINT_CMD("metrics", "#query broker metrics").
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% @doc Get all metrics
|
%% @doc Get all metrics
|
||||||
%% @end
|
%% @end
|
||||||
|
@ -193,6 +207,8 @@ init([]) ->
|
||||||
[create_metric(Metric) || Metric <- Metrics],
|
[create_metric(Metric) || Metric <- Metrics],
|
||||||
% $SYS Topics for metrics
|
% $SYS Topics for metrics
|
||||||
[ok = emqttd_pubsub:create(metric_topic(Topic)) || {_, Topic} <- Metrics],
|
[ok = emqttd_pubsub:create(metric_topic(Topic)) || {_, Topic} <- Metrics],
|
||||||
|
%% Register CLI commands
|
||||||
|
emqttd_ctl:register_cmd(metrics, {?MODULE, cli}, []),
|
||||||
% Tick to publish metrics
|
% Tick to publish metrics
|
||||||
{ok, #state{tick_tref = emqttd_broker:start_tick(tick)}, hibernate}.
|
{ok, #state{tick_tref = emqttd_broker:start_tick(tick)}, hibernate}.
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,9 @@
|
||||||
-author("Feng Lee <feng@emqtt.io>").
|
-author("Feng Lee <feng@emqtt.io>").
|
||||||
|
|
||||||
-include("emqttd.hrl").
|
-include("emqttd.hrl").
|
||||||
|
-include("emqttd_cli.hrl").
|
||||||
|
|
||||||
|
-export([cli/1]).
|
||||||
|
|
||||||
-export([load/0, unload/0]).
|
-export([load/0, unload/0]).
|
||||||
|
|
||||||
|
@ -37,6 +40,36 @@
|
||||||
|
|
||||||
-export([list/0]).
|
-export([list/0]).
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% CLI callback
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
cli(["list"]) ->
|
||||||
|
lists:foreach(fun(Plugin) -> print(Plugin) end, list());
|
||||||
|
|
||||||
|
cli(["load", Name]) ->
|
||||||
|
case load(list_to_atom(Name)) of
|
||||||
|
{ok, StartedApps} -> ?PRINT("Start apps: ~p~nPlugin ~s loaded successfully.~n", [StartedApps, Name]);
|
||||||
|
{error, Reason} -> ?PRINT("load plugin error: ~p~n", [Reason])
|
||||||
|
end;
|
||||||
|
|
||||||
|
cli(["unload", Name]) ->
|
||||||
|
case emqttd_plugins:unload(list_to_atom(Name)) of
|
||||||
|
ok ->
|
||||||
|
?PRINT("Plugin ~s unloaded successfully.~n", [Name]);
|
||||||
|
{error, Reason} ->
|
||||||
|
?PRINT("unload plugin error: ~p~n", [Reason])
|
||||||
|
end;
|
||||||
|
|
||||||
|
cli(_) ->
|
||||||
|
?PRINT_CMD("plugins list", "#query loaded plugins"),
|
||||||
|
?PRINT_CMD("plugins load <Plugin>", "#load plugin"),
|
||||||
|
?PRINT_CMD("plugins unload <Plugin>", "#unload plugin").
|
||||||
|
|
||||||
|
print(#mqtt_plugin{name = Name, version = Ver, descr = Descr, active = Active}) ->
|
||||||
|
?PRINT("Plugin(~s, version=~s, description=~s, active=~s)~n",
|
||||||
|
[Name, Ver, Descr, Active]).
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% @doc Load all plugins when the broker started.
|
%% @doc Load all plugins when the broker started.
|
||||||
%% @end
|
%% @end
|
||||||
|
@ -44,6 +77,7 @@
|
||||||
|
|
||||||
-spec load() -> list() | {error, any()}.
|
-spec load() -> list() | {error, any()}.
|
||||||
load() ->
|
load() ->
|
||||||
|
emqttd_ctl:register_cmd(plugins, {?MODULE, cli}, []),
|
||||||
case env(loaded_file) of
|
case env(loaded_file) of
|
||||||
{ok, File} ->
|
{ok, File} ->
|
||||||
with_loaded_file(File, fun(Names) -> load_plugins(Names, false) end);
|
with_loaded_file(File, fun(Names) -> load_plugins(Names, false) end);
|
||||||
|
|
|
@ -24,17 +24,23 @@
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
%%%-----------------------------------------------------------------------------
|
%%%-----------------------------------------------------------------------------
|
||||||
|
|
||||||
-module(emqttd_trace).
|
-module(emqttd_trace).
|
||||||
|
|
||||||
-author("Feng Lee <feng@emqtt.io>").
|
-author("Feng Lee <feng@emqtt.io>").
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-include("emqttd_cli.hrl").
|
||||||
|
|
||||||
|
%% CLI
|
||||||
|
-export([cli/1]).
|
||||||
|
|
||||||
%% API Function Exports
|
%% API Function Exports
|
||||||
-export([start_link/0]).
|
-export([start_link/0]).
|
||||||
|
|
||||||
-export([start_trace/2, stop_trace/1, all_traces/0]).
|
-export([start_trace/2, stop_trace/1, all_traces/0]).
|
||||||
|
|
||||||
|
-behaviour(gen_server).
|
||||||
|
|
||||||
%% gen_server Function Exports
|
%% gen_server Function Exports
|
||||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||||
terminate/2, code_change/3]).
|
terminate/2, code_change/3]).
|
||||||
|
@ -45,6 +51,48 @@
|
||||||
|
|
||||||
-define(TRACE_OPTIONS, [{formatter_config, [time, " [",severity,"] ", message, "\n"]}]).
|
-define(TRACE_OPTIONS, [{formatter_config, [time, " [",severity,"] ", message, "\n"]}]).
|
||||||
|
|
||||||
|
|
||||||
|
%%%=============================================================================
|
||||||
|
%%% CLI
|
||||||
|
%%%=============================================================================
|
||||||
|
|
||||||
|
cli(["list"]) ->
|
||||||
|
lists:foreach(fun({{Who, Name}, LogFile}) ->
|
||||||
|
?PRINT("trace ~s ~s -> ~s~n", [Who, Name, LogFile])
|
||||||
|
end, all_traces());
|
||||||
|
|
||||||
|
cli(["client", ClientId, "off"]) ->
|
||||||
|
cli(trace_off, client, ClientId);
|
||||||
|
cli(["client", ClientId, LogFile]) ->
|
||||||
|
cli(trace_on, client, ClientId, LogFile);
|
||||||
|
cli(["topic", Topic, "off"]) ->
|
||||||
|
cli(trace_off, topic, Topic);
|
||||||
|
cli(["topic", Topic, LogFile]) ->
|
||||||
|
cli(trace_on, topic, Topic, LogFile);
|
||||||
|
|
||||||
|
cli(_) ->
|
||||||
|
?PRINT_CMD("trace list", "#query all traces"),
|
||||||
|
?PRINT_CMD("trace client <ClientId> <LogFile>","#trace client with ClientId"),
|
||||||
|
?PRINT_CMD("trace client <ClientId> off", "#stop to trace client"),
|
||||||
|
?PRINT_CMD("trace topic <Topic> <LogFile>", "#trace topic with Topic"),
|
||||||
|
?PRINT_CMD("trace topic <Topic> off", "#stop to trace Topic").
|
||||||
|
|
||||||
|
cli(trace_on, Who, Name, LogFile) ->
|
||||||
|
case start_trace({Who, list_to_binary(Name)}, LogFile) of
|
||||||
|
ok ->
|
||||||
|
?PRINT("trace ~s ~s successfully.~n", [Who, Name]);
|
||||||
|
{error, Error} ->
|
||||||
|
?PRINT("trace ~s ~s error: ~p~n", [Who, Name, Error])
|
||||||
|
end.
|
||||||
|
|
||||||
|
cli(trace_off, Who, Name) ->
|
||||||
|
case stop_trace({Who, list_to_binary(Name)}) of
|
||||||
|
ok ->
|
||||||
|
?PRINT("stop to trace ~s ~s successfully.~n", [Who, Name]);
|
||||||
|
{error, Error} ->
|
||||||
|
?PRINT("stop to trace ~s ~s error: ~p.~n", [Who, Name, Error])
|
||||||
|
end.
|
||||||
|
|
||||||
%%%=============================================================================
|
%%%=============================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%=============================================================================
|
%%%=============================================================================
|
||||||
|
@ -85,6 +133,7 @@ all_traces() ->
|
||||||
gen_server:call(?MODULE, all_traces).
|
gen_server:call(?MODULE, all_traces).
|
||||||
|
|
||||||
init([]) ->
|
init([]) ->
|
||||||
|
emqttd_ctl:register_cmd(trace, {?MODULE, cli}, []),
|
||||||
{ok, #state{level = info, trace_map = #{}}}.
|
{ok, #state{level = info, trace_map = #{}}}.
|
||||||
|
|
||||||
handle_call({start_trace, Who, LogFile}, _From, State = #state{level = Level, trace_map = TraceMap}) ->
|
handle_call({start_trace, Who, LogFile}, _From, State = #state{level = Level, trace_map = TraceMap}) ->
|
||||||
|
@ -122,6 +171,7 @@ handle_info(_Info, State) ->
|
||||||
{noreply, State}.
|
{noreply, State}.
|
||||||
|
|
||||||
terminate(_Reason, _State) ->
|
terminate(_Reason, _State) ->
|
||||||
|
emqttd_ctl:unregister_cmd(trace),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
|
|
Loading…
Reference in New Issue