Comments skeleton
This commit is contained in:
parent
8d828abea1
commit
006a241293
2
TODO.md
2
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?
|
||||
|
|
|
@ -1,45 +1,98 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%%% @author Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%% @copyright (C) 2017, Fabio Salvini
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 2 Jul 2017 by Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%%-------------------------------------------------------------------
|
||||
-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),
|
||||
|
|
|
@ -1,18 +1,102 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%%% @author Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%% @copyright (C) 2017, Fabio Salvini
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 2 Jul 2017 by Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%%-------------------------------------------------------------------
|
||||
-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, _} ->
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%%% @author Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%% @copyright (C) 2017, Fabio Salvini
|
||||
%% @doc log_monitor public API
|
||||
%% @end
|
||||
%%% Created : 2 Jul 2017 by Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-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.
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%%% @author Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%% @copyright (C) 2017, Fabio Salvini
|
||||
%% @doc log_monitor top level supervisor.
|
||||
%% @end
|
||||
%%% Created : 2 Jul 2017 by Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(log_monitor_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
@ -18,7 +20,6 @@
|
|||
%%====================================================================
|
||||
%% API functions
|
||||
%%====================================================================
|
||||
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
|
||||
|
||||
|
|
|
@ -1,12 +1,54 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%%% @author Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%% @copyright (C) 2017, Fabio Salvini
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 2 Jul 2017 by Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%%-------------------------------------------------------------------
|
||||
-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
|
||||
%%%===================================================================
|
||||
|
|
|
@ -1,22 +1,45 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%%% @author Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%% @copyright (C) 2017, Fabio Salvini
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 2 Jul 2017 by Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%%-------------------------------------------------------------------
|
||||
-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
|
||||
%%%===================================================================
|
||||
|
|
|
@ -1,20 +1,101 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%%% @author Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%% @copyright (C) 2017, Fabio Salvini
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 2 Jul 2017 by Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%%-------------------------------------------------------------------
|
||||
-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,
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%%% @author Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%% @copyright (C) 2017, Fabio Salvini
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 2 Jul 2017 by Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%%-------------------------------------------------------------------
|
||||
-ifndef(MNESIA_HRL).
|
||||
-define(MNESIA_HRL, 1).
|
||||
|
||||
|
|
|
@ -1,9 +1,32 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%%% @author Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%% @copyright (C) 2017, Fabio Salvini
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 2 Jul 2017 by Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%%-------------------------------------------------------------------
|
||||
-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));
|
||||
|
|
|
@ -1,13 +1,55 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%%% @author Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%% @copyright (C) 2017, Fabio Salvini
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 2 Jul 2017 by Fabio Salvini <fs@fabiosalvini.com>
|
||||
%%%-------------------------------------------------------------------
|
||||
-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]).
|
||||
|
|
Loading…
Reference in New Issue
Block a user