From 006a2412938b29e5541e9d294f32cc3ee2c8e6c0 Mon Sep 17 00:00:00 2001 From: Fabio Salvini Date: Sun, 2 Jul 2017 10:42:13 +0200 Subject: [PATCH] Comments skeleton --- TODO.md | 2 +- apps/log_monitor/src/config.erl | 174 +++++++++++++++++++---- apps/log_monitor/src/gatherer.erl | 118 +++++++++++++-- apps/log_monitor/src/log_monitor_app.erl | 6 +- apps/log_monitor/src/log_monitor_sup.erl | 5 +- apps/log_monitor/src/log_sup.erl | 46 ++++++ apps/log_monitor/src/logfiles_sup.erl | 81 +++++++++-- apps/log_monitor/src/mailer.erl | 117 +++++++++++++-- apps/log_monitor/src/mnesia_tables.hrl | 8 ++ apps/log_monitor/src/utils.erl | 23 +++ apps/log_monitor/src/watcher.erl | 117 +++++++++++++-- 11 files changed, 621 insertions(+), 76 deletions(-) diff --git a/TODO.md b/TODO.md index 7b8c65c..17a7346 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,5 @@ TODO ===== - + - Fix gatherer state. - Limit number of emails that can be sent in a period of time. - gen_fsm for gatherer? diff --git a/apps/log_monitor/src/config.erl b/apps/log_monitor/src/config.erl index 22dba0a..ddc3f71 100644 --- a/apps/log_monitor/src/config.erl +++ b/apps/log_monitor/src/config.erl @@ -1,45 +1,98 @@ +%%%------------------------------------------------------------------- +%%% @author Fabio Salvini +%%% @copyright (C) 2017, Fabio Salvini +%%% @doc +%%% +%%% @end +%%% Created : 2 Jul 2017 by Fabio Salvini +%%%------------------------------------------------------------------- -module(config). + -behaviour(gen_server). -include_lib("mnesia_tables.hrl"). --export([status/0]). --export([reload/0]). --export([start_link/0, init/1, terminate/2]). --export([handle_info/2, handle_cast/2, handle_call/3]). --export([code_change/3]). +%% API +-export([start_link/0]). +-export([status/0, reload/0]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-define(SERVER, ?MODULE). -record(state, {statuses}). +%%%=================================================================== +%%% API +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @doc +%% Starts the server +%% +%% @spec start_link() -> {ok, Pid} | ignore | {error, Error} +%% @end +%%-------------------------------------------------------------------- start_link() -> gen_server:start_link(?MODULE, [], []). +%%-------------------------------------------------------------------- +%% @doc +%% Get the status of the log files +%% +%% @spec status() -> [{Logfile, Status}] +%% @end +%%-------------------------------------------------------------------- +status() -> + gen_server:call(config, {get_statuses}). + +%%-------------------------------------------------------------------- +%% @doc +%% Reload the configuration +%% +%% @spec reload() -> ok +%% @end +%%-------------------------------------------------------------------- +reload() -> + gen_server:call(config, {reload}). + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Initializes the server +%% +%% @spec init(Args) -> {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% @end +%%-------------------------------------------------------------------- init([]) -> register(config, self()), Statuses = ets:new(log_statuses, []), timer:apply_after(1000, ?MODULE, reload, []), {ok, #state{statuses = Statuses}}. -handle_info({watcher_init, File}, State = #state{statuses = Statuses}) -> - case ets:lookup(Statuses, File) of - %% If the File has been removed, do nothing - [] -> ok; - _ -> ets:insert(Statuses, {File, active}) - end, - {noreply, State}; -handle_info({watcher_terminate, File}, State = #state{statuses = Statuses}) -> - case ets:lookup(Statuses, File) of - %% If the File has been removed, do nothing - [] -> ok; - _ -> ets:insert(Statuses, {File, inactive}) - end, - {noreply, State}; -handle_info(_Msg, State) -> - {noreply, State}. - -handle_cast(_Msg, State) -> - {noreply, State}. - +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Handling call messages +%% +%% @spec handle_call(Request, From, State) -> +%% {reply, Reply, State} | +%% {reply, Reply, State, Timeout} | +%% {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, Reply, State} | +%% {stop, Reason, State} +%% @end +%%-------------------------------------------------------------------- handle_call({reload}, _From, State = #state{statuses = Statuses}) -> {ok, File} = application:get_env(log_monitor, logfiles_config), {ok, Terms} = file:consult(File), @@ -56,21 +109,80 @@ handle_call({reload}, _From, State = #state{statuses = Statuses}) -> manage_existing_logfiles(proplists:get_value(existing, LogfilesPartitions), Statuses), manage_new_logfiles(proplists:get_value(new, LogfilesPartitions), Statuses), {reply, ok, State}; + handle_call({get_statuses}, _From, State = #state{statuses = Statuses}) -> {reply, ets:tab2list(Statuses), State}. +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Handling cast messages +%% +%% @spec handle_cast(Msg, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% @end +%%-------------------------------------------------------------------- +handle_cast(_Msg, State) -> + {noreply, State}. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Handling all non call/cast messages +%% +%% @spec handle_info(Info, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% @end +%%-------------------------------------------------------------------- +handle_info({watcher_init, File}, State = #state{statuses = Statuses}) -> + case ets:lookup(Statuses, File) of + %% If the File has been removed, do nothing + [] -> ok; + _ -> ets:insert(Statuses, {File, active}) + end, + {noreply, State}; + +handle_info({watcher_terminate, File}, State = #state{statuses = Statuses}) -> + case ets:lookup(Statuses, File) of + %% If the File has been removed, do nothing + [] -> ok; + _ -> ets:insert(Statuses, {File, inactive}) + end, + {noreply, State}; + +handle_info(_Msg, State) -> + {noreply, State}. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any +%% necessary cleaning up. When it returns, the gen_server terminates +%% with Reason. The return value is ignored. +%% +%% @spec terminate(Reason, State) -> void() +%% @end +%%-------------------------------------------------------------------- terminate(_Reason, _State) -> shutdown. +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Convert process state when code is changed +%% +%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState} +%% @end +%%-------------------------------------------------------------------- code_change(_OldVsn, State, _Extra) -> {ok, State}. -status() -> - gen_server:call(config, {get_statuses}). - -reload() -> - gen_server:call(config, {reload}). - +%%%=================================================================== +%%% Internal functions +%%%=================================================================== compare_groups(Groups) -> Old = list_groups(), Deleted = lists:filter(fun(Name) -> not lists:any(fun(#log_monitor_group{name = N, email_receivers = _}) -> N == Name end, Groups) end, Old), diff --git a/apps/log_monitor/src/gatherer.erl b/apps/log_monitor/src/gatherer.erl index 795f4de..501435a 100644 --- a/apps/log_monitor/src/gatherer.erl +++ b/apps/log_monitor/src/gatherer.erl @@ -1,18 +1,102 @@ +%%%------------------------------------------------------------------- +%%% @author Fabio Salvini +%%% @copyright (C) 2017, Fabio Salvini +%%% @doc +%%% +%%% @end +%%% Created : 2 Jul 2017 by Fabio Salvini +%%%------------------------------------------------------------------- -module(gatherer). + -behaviour(gen_server). --export([start_link/2, init/1, terminate/2]). --export([handle_info/2, handle_cast/2, handle_call/3]). --export([code_change/3]). +%% API +-export([start_link/2]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-define(SERVER, ?MODULE). -record(log, {file, error_regex}). +%% -record(state, {}). +%%%=================================================================== +%%% API +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @doc +%% Starts the server +%% +%% @spec start_link(File, ErrorRegex) -> {ok, Pid} | +%% ignore | +%% {error, Error} +%% @end +%%-------------------------------------------------------------------- start_link(File, ErrorRegex) -> gen_server:start_link(?MODULE, [#log{file = File, error_regex = ErrorRegex}], []). +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Initializes the server +%% +%% @spec init(Args) -> {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% @end +%%-------------------------------------------------------------------- init([Log]) -> {ok, [off, Log]}. +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Handling call messages +%% +%% @spec handle_call(Request, From, State) -> +%% {reply, Reply, State} | +%% {reply, Reply, State, Timeout} | +%% {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, Reply, State} | +%% {stop, Reason, State} +%% @end +%%-------------------------------------------------------------------- +handle_call(_Request, _From, State) -> + Reply = ok, + {reply, Reply, State}. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Handling cast messages +%% +%% @spec handle_cast(Msg, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% @end +%%-------------------------------------------------------------------- +handle_cast(_Msg, State) -> + {noreply, State}. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Handling all non call/cast messages +%% +%% @spec handle_info(Info, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% @end +%%-------------------------------------------------------------------- handle_info({log_line, Text}, [off, Log = #log{error_regex = ErrorRegex}]) -> case isError(Text, ErrorRegex) of true -> @@ -36,18 +120,34 @@ handle_info({timeout}, [on, Log = #log{file = File}, Error, Timer, SafeTimer]) - mailer ! {error, File, Error}, {noreply, [off, Log]}. -handle_cast(_Msg, State) -> - {noreply, State}. - -handle_call(_Request, _From, State) -> - {noreply, State}. - +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any +%% necessary cleaning up. When it returns, the gen_server terminates +%% with Reason. The return value is ignored. +%% +%% @spec terminate(Reason, State) -> void() +%% @end +%%-------------------------------------------------------------------- terminate(_Reason, _State) -> shutdown. +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Convert process state when code is changed +%% +%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState} +%% @end +%%-------------------------------------------------------------------- code_change(_OldVsn, State, _Extra) -> {ok, State}. +%%%=================================================================== +%%% Internal functions +%%%=================================================================== isError(Text, ErrorRegex) -> case re:run(Text, ErrorRegex) of {match, _} -> diff --git a/apps/log_monitor/src/log_monitor_app.erl b/apps/log_monitor/src/log_monitor_app.erl index b798e4e..38a9245 100644 --- a/apps/log_monitor/src/log_monitor_app.erl +++ b/apps/log_monitor/src/log_monitor_app.erl @@ -1,8 +1,10 @@ %%%------------------------------------------------------------------- +%%% @author Fabio Salvini +%%% @copyright (C) 2017, Fabio Salvini %% @doc log_monitor public API %% @end +%%% Created : 2 Jul 2017 by Fabio Salvini %%%------------------------------------------------------------------- - -module(log_monitor_app). -behaviour(application). @@ -15,7 +17,6 @@ %%==================================================================== %% API %%==================================================================== - start(_StartType, _StartArgs) -> start_mnesia(), log_monitor_sup:start_link(). @@ -28,7 +29,6 @@ stop(_State) -> %%==================================================================== %% Internal functions %%==================================================================== - start_mnesia() -> Nodes = [node()], %% Stop Mnesia if it is running, cannot create schema otherwise. diff --git a/apps/log_monitor/src/log_monitor_sup.erl b/apps/log_monitor/src/log_monitor_sup.erl index 721bd5d..e50edcf 100644 --- a/apps/log_monitor/src/log_monitor_sup.erl +++ b/apps/log_monitor/src/log_monitor_sup.erl @@ -1,8 +1,10 @@ %%%------------------------------------------------------------------- +%%% @author Fabio Salvini +%%% @copyright (C) 2017, Fabio Salvini %% @doc log_monitor top level supervisor. %% @end +%%% Created : 2 Jul 2017 by Fabio Salvini %%%------------------------------------------------------------------- - -module(log_monitor_sup). -behaviour(supervisor). @@ -18,7 +20,6 @@ %%==================================================================== %% API functions %%==================================================================== - start_link() -> supervisor:start_link({local, ?SERVER}, ?MODULE, []). diff --git a/apps/log_monitor/src/log_sup.erl b/apps/log_monitor/src/log_sup.erl index 078a39a..3a4fa33 100644 --- a/apps/log_monitor/src/log_sup.erl +++ b/apps/log_monitor/src/log_sup.erl @@ -1,12 +1,54 @@ +%%%------------------------------------------------------------------- +%%% @author Fabio Salvini +%%% @copyright (C) 2017, Fabio Salvini +%%% @doc +%%% +%%% @end +%%% Created : 2 Jul 2017 by Fabio Salvini +%%%------------------------------------------------------------------- -module(log_sup). + -behaviour(supervisor). +%% API -export([start_link/2]). + +%% Supervisor callbacks -export([init/1]). +-define(SERVER, ?MODULE). + +%%%=================================================================== +%%% API functions +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @doc +%% Starts the supervisor +%% +%% @spec start_link(File, ErrorRegex) -> {ok, Pid} | ignore | {error, Error} +%% @end +%%-------------------------------------------------------------------- start_link(File, ErrorRegex) -> supervisor:start_link(?MODULE, [File, ErrorRegex]). +%%%=================================================================== +%%% Supervisor callbacks +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Whenever a supervisor is started using supervisor:start_link/[2,3], +%% this function is called by the new process to find out about +%% restart strategy, maximum restart intensity, and child +%% specifications. +%% +%% @spec init(Args) -> {ok, {SupFlags, [ChildSpec]}} | +%% ignore | +%% {error, Reason} +%% @end +%%-------------------------------------------------------------------- init([File, ErrorRegex]) -> SupFlags = #{strategy => one_for_one}, ChildSpecs = [#{ @@ -24,3 +66,7 @@ init([File, ErrorRegex]) -> modules => [watcher] }], {ok, {SupFlags, ChildSpecs}}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== diff --git a/apps/log_monitor/src/logfiles_sup.erl b/apps/log_monitor/src/logfiles_sup.erl index 2241e53..1ecceff 100644 --- a/apps/log_monitor/src/logfiles_sup.erl +++ b/apps/log_monitor/src/logfiles_sup.erl @@ -1,22 +1,45 @@ +%%%------------------------------------------------------------------- +%%% @author Fabio Salvini +%%% @copyright (C) 2017, Fabio Salvini +%%% @doc +%%% +%%% @end +%%% Created : 2 Jul 2017 by Fabio Salvini +%%%------------------------------------------------------------------- -module(logfiles_sup). + -behaviour(supervisor). +%% API -export([start_link/0]). --export([init/1]). -export([add_child/1, remove_child/1]). +%% Supervisor callbacks +-export([init/1]). + +-define(SERVER, ?MODULE). + +%%%=================================================================== +%%% API functions +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @doc +%% Starts the supervisor +%% +%% @spec start_link() -> {ok, Pid} | ignore | {error, Error} +%% @end +%%-------------------------------------------------------------------- start_link() -> - supervisor:start_link({local, ?MODULE}, ?MODULE, []). - -init([]) -> - SupFlags = #{ - strategy => one_for_one, - intensity => 0, - period => 1 - }, - ChildSpecs = [], - {ok, {SupFlags, ChildSpecs}}. + supervisor:start_link({local, ?SERVER}, ?MODULE, []). +%%-------------------------------------------------------------------- +%% @doc +%% Add a child to the supervisor +%% +%% @spec add_child(Args) -> void() +%% @end +%%-------------------------------------------------------------------- add_child(Args = [File, _ErrorRegex]) -> supervisor:start_child( ?MODULE, @@ -29,5 +52,41 @@ add_child(Args = [File, _ErrorRegex]) -> } ). +%%-------------------------------------------------------------------- +%% @doc +%% Remove a child from the supervisor +%% +%% @spec remove_child(File) -> void() +%% @end +%%-------------------------------------------------------------------- remove_child(File) -> supervisor:terminate_child(?MODULE, File). +%%%=================================================================== +%%% Supervisor callbacks +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Whenever a supervisor is started using supervisor:start_link/[2,3], +%% this function is called by the new process to find out about +%% restart strategy, maximum restart intensity, and child +%% specifications. +%% +%% @spec init(Args) -> {ok, {SupFlags, [ChildSpec]}} | +%% ignore | +%% {error, Reason} +%% @end +%%-------------------------------------------------------------------- +init([]) -> + SupFlags = #{ + strategy => one_for_one, + intensity => 0, + period => 1 + }, + ChildSpecs = [], + {ok, {SupFlags, ChildSpecs}}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== diff --git a/apps/log_monitor/src/mailer.erl b/apps/log_monitor/src/mailer.erl index adbad46..39f7a40 100644 --- a/apps/log_monitor/src/mailer.erl +++ b/apps/log_monitor/src/mailer.erl @@ -1,20 +1,101 @@ +%%%------------------------------------------------------------------- +%%% @author Fabio Salvini +%%% @copyright (C) 2017, Fabio Salvini +%%% @doc +%%% +%%% @end +%%% Created : 2 Jul 2017 by Fabio Salvini +%%%------------------------------------------------------------------- -module(mailer). + -behaviour(gen_server). -include_lib("mnesia_tables.hrl"). --export([start_link/0, init/1, terminate/2]). --export([handle_info/2, handle_cast/2, handle_call/3]). --export([code_change/3]). +%% API +-export([start_link/0]). +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-record(state, {}). + +%%%=================================================================== +%%% API +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @doc +%% Starts the server +%% +%% @spec start_link() -> {ok, Pid} | ignore | {error, Error} +%% @end +%%-------------------------------------------------------------------- start_link() -> gen_server:start_link(?MODULE, [], []). +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Initializes the server +%% +%% @spec init(Args) -> {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% @end +%%-------------------------------------------------------------------- init([]) -> register(mailer, self()), timer:send_after(1000, {send_emails}), - {ok, []}. + {ok, #state{}}. +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Handling call messages +%% +%% @spec handle_call(Request, From, State) -> +%% {reply, Reply, State} | +%% {reply, Reply, State, Timeout} | +%% {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, Reply, State} | +%% {stop, Reason, State} +%% @end +%%-------------------------------------------------------------------- +handle_call(_Request, _From, State) -> + Reply = ok, + {reply, Reply, State}. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Handling cast messages +%% +%% @spec handle_cast(Msg, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% @end +%%-------------------------------------------------------------------- +handle_cast(_Msg, State) -> + {noreply, State}. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Handling all non call/cast messages +%% +%% @spec handle_info(Info, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% @end +%%-------------------------------------------------------------------- handle_info({error, File, Text}, State) -> mnesia:activity( transaction, @@ -34,18 +115,34 @@ handle_info({send_emails}, State) -> end, {noreply, State}. -handle_cast(_Msg, State) -> - {noreply, State}. - -handle_call(_Request, _From, State) -> - {noreply, State}. - +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any +%% necessary cleaning up. When it returns, the gen_server terminates +%% with Reason. The return value is ignored. +%% +%% @spec terminate(Reason, State) -> void() +%% @end +%%-------------------------------------------------------------------- terminate(_Reason, _State) -> shutdown. +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Convert process state when code is changed +%% +%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState} +%% @end +%%-------------------------------------------------------------------- code_change(_OldVsn, State, _Extra) -> {ok, State}. +%%%=================================================================== +%%% Internal functions +%%%=================================================================== emails_to_send() -> mnesia:activity( transaction, diff --git a/apps/log_monitor/src/mnesia_tables.hrl b/apps/log_monitor/src/mnesia_tables.hrl index 51ecced..b33d59f 100644 --- a/apps/log_monitor/src/mnesia_tables.hrl +++ b/apps/log_monitor/src/mnesia_tables.hrl @@ -1,3 +1,11 @@ +%%%------------------------------------------------------------------- +%%% @author Fabio Salvini +%%% @copyright (C) 2017, Fabio Salvini +%%% @doc +%%% +%%% @end +%%% Created : 2 Jul 2017 by Fabio Salvini +%%%------------------------------------------------------------------- -ifndef(MNESIA_HRL). -define(MNESIA_HRL, 1). diff --git a/apps/log_monitor/src/utils.erl b/apps/log_monitor/src/utils.erl index a9474a0..3daa7ac 100644 --- a/apps/log_monitor/src/utils.erl +++ b/apps/log_monitor/src/utils.erl @@ -1,9 +1,32 @@ +%%%------------------------------------------------------------------- +%%% @author Fabio Salvini +%%% @copyright (C) 2017, Fabio Salvini +%%% @doc +%%% +%%% @end +%%% Created : 2 Jul 2017 by Fabio Salvini +%%%------------------------------------------------------------------- -module(utils). +%% API -export([flatten/1]). +%%%=================================================================== +%%% API +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @doc +%% Flattens a list. +%% +%% @spec flatten(X) -> list() +%% @end +%%-------------------------------------------------------------------- flatten(X) -> flatten(X,[]). +%%%=================================================================== +%%% Internal functions +%%%=================================================================== flatten([],Acc) -> Acc; flatten([[]|T],Acc) -> flatten(T, Acc); flatten([[_|_]=H|T],Acc) -> flatten(T, flatten(H,Acc)); diff --git a/apps/log_monitor/src/watcher.erl b/apps/log_monitor/src/watcher.erl index e50bb09..e5a4ae5 100644 --- a/apps/log_monitor/src/watcher.erl +++ b/apps/log_monitor/src/watcher.erl @@ -1,13 +1,55 @@ +%%%------------------------------------------------------------------- +%%% @author Fabio Salvini +%%% @copyright (C) 2017, Fabio Salvini +%%% @doc +%%% +%%% @end +%%% Created : 2 Jul 2017 by Fabio Salvini +%%%------------------------------------------------------------------- -module(watcher). + -behaviour(gen_server). --export([start_link/2, init/1, terminate/2]). --export([handle_info/2, handle_cast/2, handle_call/3]). --export([code_change/3]). +%% API +-export([start_link/2]). +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-define(SERVER, ?MODULE). + +-record(state, {}). + +%%%=================================================================== +%%% API +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @doc +%% Starts the server +%% +%% @spec start_link(SupPid, File) -> {ok, Pid} | ignore | {error, Error} +%% @end +%%-------------------------------------------------------------------- start_link(SupPid, File) -> gen_server:start_link(?MODULE, [SupPid, File], []). +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Initializes the server +%% +%% @spec init(Args) -> {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% @end +%%-------------------------------------------------------------------- init([SupPid, File]) -> timer:sleep(1000), config ! {watcher_init, File}, @@ -15,6 +57,47 @@ init([SupPid, File]) -> Port = open_port({spawn, Cmd}, [stderr_to_stdout, exit_status, binary]), {ok, [File, SupPid, Port]}. +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Handling call messages +%% +%% @spec handle_call(Request, From, State) -> +%% {reply, Reply, State} | +%% {reply, Reply, State, Timeout} | +%% {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, Reply, State} | +%% {stop, Reason, State} +%% @end +%%-------------------------------------------------------------------- +handle_call(_Request, _From, State) -> + Reply = ok, + {reply, Reply, State}. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Handling cast messages +%% +%% @spec handle_cast(Msg, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% @end +%%-------------------------------------------------------------------- +handle_cast(_Msg, State) -> + {noreply, State}. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Handling all non call/cast messages +%% +%% @spec handle_info(Info, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% @end +%%-------------------------------------------------------------------- handle_info(Msg, [File, SupPid, Port]) -> case Msg of {Port, {data, Text}} -> @@ -25,18 +108,34 @@ handle_info(Msg, [File, SupPid, Port]) -> {stop, tail_exit, [File]} end. -handle_cast(_Msg, State) -> - {noreply, State}. - -handle_call(_Request, _From, State) -> - {noreply, State}. - +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any +%% necessary cleaning up. When it returns, the gen_server terminates +%% with Reason. The return value is ignored. +%% +%% @spec terminate(Reason, State) -> void() +%% @end +%%-------------------------------------------------------------------- terminate(_Reason, [File]) -> config ! {watcher_terminate, File}, shutdown. +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Convert process state when code is changed +%% +%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState} +%% @end +%%-------------------------------------------------------------------- code_change(_OldVsn, State, _Extra) -> {ok, State}. +%%%=================================================================== +%%% Internal functions +%%%=================================================================== gatherer_pid(SupPid) -> hd([Pid || {Id, Pid, _, _} <- supervisor:which_children(SupPid), Id == gatherer]).