mod_message_log: Run as a supervised gen_server
This commit is contained in:
parent
bdac50591a
commit
44464c0f8d
|
@ -9,12 +9,22 @@
|
|||
-author('holger@zedat.fu-berlin.de').
|
||||
|
||||
-behaviour(gen_mod).
|
||||
-behaviour(gen_server).
|
||||
|
||||
-export([start/2,
|
||||
stop/1,
|
||||
init/1,
|
||||
perform_upgrade/1]).
|
||||
%% gen_mod/supervisor callbacks.
|
||||
-export([start_link/1,
|
||||
start/2,
|
||||
stop/1]).
|
||||
|
||||
%% gen_server callbacks.
|
||||
-export([init/1,
|
||||
handle_call/3,
|
||||
handle_cast/2,
|
||||
handle_info/2,
|
||||
terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
%% ejabberd_hooks callbacks.
|
||||
-export([log_packet_send/3,
|
||||
log_packet_receive/4,
|
||||
log_packet_offline/3,
|
||||
|
@ -27,7 +37,15 @@
|
|||
-define(DEFAULT_FILENAME, <<"message.log">>).
|
||||
-define(FILE_MODES, [append, raw]).
|
||||
|
||||
-record(config, {filename = ?DEFAULT_FILENAME, iodevice}).
|
||||
-record(state, {filename = ?DEFAULT_FILENAME :: binary(),
|
||||
iodevice :: io:device()}).
|
||||
|
||||
%% -------------------------------------------------------------------
|
||||
%% gen_mod/supervisor callbacks.
|
||||
%% -------------------------------------------------------------------
|
||||
|
||||
start_link(Opts) ->
|
||||
gen_server:start_link({local, ?PROCNAME}, ?MODULE, Opts, []).
|
||||
|
||||
start(Host, Opts) ->
|
||||
ejabberd_hooks:add(user_send_packet, Host, ?MODULE,
|
||||
|
@ -36,17 +54,15 @@ start(Host, Opts) ->
|
|||
log_packet_receive, 42),
|
||||
ejabberd_hooks:add(offline_message_hook, Host, ?MODULE,
|
||||
log_packet_offline, 42),
|
||||
case whereis(?PROCNAME) of
|
||||
undefined ->
|
||||
ejabberd_hooks:add(reopen_log_hook, ?MODULE, reopen_log, 42),
|
||||
Filename = gen_mod:get_opt(filename, Opts, fun(V) -> V end,
|
||||
?DEFAULT_FILENAME),
|
||||
register(?PROCNAME, spawn(?MODULE, init,
|
||||
[#config{filename = Filename}])),
|
||||
ok;
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
Spec = {
|
||||
?PROCNAME,
|
||||
{?MODULE, start_link, [Opts]},
|
||||
permanent,
|
||||
3000,
|
||||
worker,
|
||||
[?MODULE]
|
||||
},
|
||||
supervisor:start_child(ejabberd_sup, Spec).
|
||||
|
||||
stop(Host) ->
|
||||
ejabberd_hooks:delete(user_send_packet, Host, ?MODULE,
|
||||
|
@ -55,18 +71,53 @@ stop(Host) ->
|
|||
log_packet_receive, 42),
|
||||
ejabberd_hooks:delete(offline_message_hook, Host, ?MODULE,
|
||||
log_packet_offline, 42),
|
||||
case whereis(?PROCNAME) of
|
||||
undefined ->
|
||||
ok;
|
||||
_ ->
|
||||
ejabberd_hooks:delete(reopen_log_hook, ?MODULE, reopen_log, 42),
|
||||
gen_mod:get_module_proc(Host, ?PROCNAME) ! stop,
|
||||
ok
|
||||
case supervisor:terminate_child(ejabberd_sup, ?PROCNAME) of
|
||||
ok ->
|
||||
ok = supervisor:delete_child(ejabberd_sup, ?PROCNAME);
|
||||
{error, not_found} ->
|
||||
ok % We just run one process per node.
|
||||
end.
|
||||
|
||||
init(Config) ->
|
||||
{ok, IoDevice} = file:open(Config#config.filename, ?FILE_MODES),
|
||||
loop(Config#config{iodevice = IoDevice}).
|
||||
%% -------------------------------------------------------------------
|
||||
%% gen_server callbacks.
|
||||
%% -------------------------------------------------------------------
|
||||
|
||||
init(Opts) ->
|
||||
process_flag(trap_exit, true),
|
||||
ejabberd_hooks:add(reopen_log_hook, ?MODULE, reopen_log, 42),
|
||||
Filename = gen_mod:get_opt(filename, Opts, fun(V) -> V end,
|
||||
?DEFAULT_FILENAME),
|
||||
{ok, IoDevice} = file:open(Filename, ?FILE_MODES),
|
||||
{ok, #state{filename = Filename, iodevice = IoDevice}}.
|
||||
|
||||
handle_call(_Request, _From, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
handle_cast({message, Direction, From, To, Type}, #state{iodevice = IoDevice} =
|
||||
State) ->
|
||||
write_log(IoDevice, Direction, From, To, Type),
|
||||
{noreply, State};
|
||||
handle_cast(reopen_log, #state{filename = Filename, iodevice = IoDevice} =
|
||||
State) ->
|
||||
ok = file:close(IoDevice),
|
||||
{ok, NewIoDevice} = file:open(Filename, ?FILE_MODES),
|
||||
{noreply, State#state{iodevice = NewIoDevice}};
|
||||
handle_cast(_Request, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
handle_info(_Info, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, State) ->
|
||||
ejabberd_hooks:delete(reopen_log_hook, ?MODULE, reopen_log, 42),
|
||||
ok = file:close(State#state.iodevice).
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%% -------------------------------------------------------------------
|
||||
%% ejabberd_hooks callbacks.
|
||||
%% -------------------------------------------------------------------
|
||||
|
||||
log_packet_send(From, To, Packet) ->
|
||||
log_packet(outgoing, From, To, Packet).
|
||||
|
@ -78,19 +129,22 @@ log_packet_offline(From, To, Packet) ->
|
|||
log_packet(offline, From, To, Packet).
|
||||
|
||||
reopen_log() ->
|
||||
?PROCNAME ! reopen.
|
||||
gen_server:cast(?PROCNAME, reopen_log).
|
||||
|
||||
%% -------------------------------------------------------------------
|
||||
%% Internal functions.
|
||||
%% -------------------------------------------------------------------
|
||||
|
||||
log_packet(Direction, From, To, #xmlel{name = <<"message">>} = Packet) ->
|
||||
case xml:get_subtag(Packet, <<"body">>) of
|
||||
#xmlel{children = Body} when length(Body) > 0 ->
|
||||
Type = get_message_type(Packet),
|
||||
?PROCNAME ! {message, Direction, From, To, Type};
|
||||
gen_server:cast(?PROCNAME, {message, Direction, From, To, Type});
|
||||
_ ->
|
||||
case is_carbon(Packet) of
|
||||
{true, OrigDirection} ->
|
||||
?PROCNAME ! {message, OrigDirection, From, To, carbon};
|
||||
gen_server:cast(?PROCNAME, {message, OrigDirection, From, To,
|
||||
carbon});
|
||||
false ->
|
||||
ok
|
||||
end
|
||||
|
@ -128,21 +182,6 @@ is_carbon(Packet) ->
|
|||
false
|
||||
end.
|
||||
|
||||
loop(Config) ->
|
||||
receive
|
||||
{message, Direction, From, To, Type} ->
|
||||
write_log(Config#config.iodevice, Direction, From, To, Type),
|
||||
loop(Config);
|
||||
reopen ->
|
||||
file:close(Config#config.iodevice),
|
||||
{ok, IoDevice} = file:open(Config#config.filename, ?FILE_MODES),
|
||||
loop(Config#config{iodevice = IoDevice});
|
||||
upgrade ->
|
||||
mod_message_log:perform_upgrade(Config);
|
||||
stop ->
|
||||
exit(normal)
|
||||
end.
|
||||
|
||||
write_log(IoDevice, Direction, From, To, Type) ->
|
||||
Date = format_date(calendar:local_time()),
|
||||
Record = io_lib:format("~s [~s, ~s] ~s -> ~s~n",
|
||||
|
@ -154,6 +193,3 @@ write_log(IoDevice, Direction, From, To, Type) ->
|
|||
format_date({{Year, Month, Day}, {Hour, Minute, Second}}) ->
|
||||
Format = "~B-~2..0B-~2..0B ~2..0B:~2..0B:~2..0B",
|
||||
io_lib:format(Format, [Year, Month, Day, Hour, Minute, Second]).
|
||||
|
||||
perform_upgrade(Config) ->
|
||||
loop(Config).
|
||||
|
|
Loading…
Reference in New Issue