Comments skeleton
This commit is contained in:
parent
8d828abea1
commit
006a241293
2
TODO.md
2
TODO.md
|
@ -1,5 +1,5 @@
|
||||||
TODO
|
TODO
|
||||||
=====
|
=====
|
||||||
|
- Fix gatherer state.
|
||||||
- Limit number of emails that can be sent in a period of time.
|
- Limit number of emails that can be sent in a period of time.
|
||||||
- gen_fsm for gatherer?
|
- 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).
|
-module(config).
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
-include_lib("mnesia_tables.hrl").
|
-include_lib("mnesia_tables.hrl").
|
||||||
|
|
||||||
-export([status/0]).
|
%% API
|
||||||
-export([reload/0]).
|
-export([start_link/0]).
|
||||||
-export([start_link/0, init/1, terminate/2]).
|
-export([status/0, reload/0]).
|
||||||
-export([handle_info/2, handle_cast/2, handle_call/3]).
|
|
||||||
-export([code_change/3]).
|
%% 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}).
|
-record(state, {statuses}).
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% API
|
||||||
|
%%%===================================================================
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @doc
|
||||||
|
%% Starts the server
|
||||||
|
%%
|
||||||
|
%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
start_link() ->
|
start_link() ->
|
||||||
gen_server:start_link(?MODULE, [], []).
|
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([]) ->
|
init([]) ->
|
||||||
register(config, self()),
|
register(config, self()),
|
||||||
Statuses = ets:new(log_statuses, []),
|
Statuses = ets:new(log_statuses, []),
|
||||||
timer:apply_after(1000, ?MODULE, reload, []),
|
timer:apply_after(1000, ?MODULE, reload, []),
|
||||||
{ok, #state{statuses = Statuses}}.
|
{ok, #state{statuses = Statuses}}.
|
||||||
|
|
||||||
handle_info({watcher_init, File}, State = #state{statuses = Statuses}) ->
|
%%--------------------------------------------------------------------
|
||||||
case ets:lookup(Statuses, File) of
|
%% @private
|
||||||
%% If the File has been removed, do nothing
|
%% @doc
|
||||||
[] -> ok;
|
%% Handling call messages
|
||||||
_ -> ets:insert(Statuses, {File, active})
|
%%
|
||||||
end,
|
%% @spec handle_call(Request, From, State) ->
|
||||||
{noreply, State};
|
%% {reply, Reply, State} |
|
||||||
handle_info({watcher_terminate, File}, State = #state{statuses = Statuses}) ->
|
%% {reply, Reply, State, Timeout} |
|
||||||
case ets:lookup(Statuses, File) of
|
%% {noreply, State} |
|
||||||
%% If the File has been removed, do nothing
|
%% {noreply, State, Timeout} |
|
||||||
[] -> ok;
|
%% {stop, Reason, Reply, State} |
|
||||||
_ -> ets:insert(Statuses, {File, inactive})
|
%% {stop, Reason, State}
|
||||||
end,
|
%% @end
|
||||||
{noreply, State};
|
%%--------------------------------------------------------------------
|
||||||
handle_info(_Msg, State) ->
|
|
||||||
{noreply, State}.
|
|
||||||
|
|
||||||
handle_cast(_Msg, State) ->
|
|
||||||
{noreply, State}.
|
|
||||||
|
|
||||||
handle_call({reload}, _From, State = #state{statuses = Statuses}) ->
|
handle_call({reload}, _From, State = #state{statuses = Statuses}) ->
|
||||||
{ok, File} = application:get_env(log_monitor, logfiles_config),
|
{ok, File} = application:get_env(log_monitor, logfiles_config),
|
||||||
{ok, Terms} = file:consult(File),
|
{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_existing_logfiles(proplists:get_value(existing, LogfilesPartitions), Statuses),
|
||||||
manage_new_logfiles(proplists:get_value(new, LogfilesPartitions), Statuses),
|
manage_new_logfiles(proplists:get_value(new, LogfilesPartitions), Statuses),
|
||||||
{reply, ok, State};
|
{reply, ok, State};
|
||||||
|
|
||||||
handle_call({get_statuses}, _From, State = #state{statuses = Statuses}) ->
|
handle_call({get_statuses}, _From, State = #state{statuses = Statuses}) ->
|
||||||
{reply, ets:tab2list(Statuses), State}.
|
{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) ->
|
terminate(_Reason, _State) ->
|
||||||
shutdown.
|
shutdown.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @private
|
||||||
|
%% @doc
|
||||||
|
%% Convert process state when code is changed
|
||||||
|
%%
|
||||||
|
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
||||||
status() ->
|
%%%===================================================================
|
||||||
gen_server:call(config, {get_statuses}).
|
%%% Internal functions
|
||||||
|
%%%===================================================================
|
||||||
reload() ->
|
|
||||||
gen_server:call(config, {reload}).
|
|
||||||
|
|
||||||
compare_groups(Groups) ->
|
compare_groups(Groups) ->
|
||||||
Old = list_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),
|
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).
|
-module(gatherer).
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
-export([start_link/2, init/1, terminate/2]).
|
%% API
|
||||||
-export([handle_info/2, handle_cast/2, handle_call/3]).
|
-export([start_link/2]).
|
||||||
-export([code_change/3]).
|
|
||||||
|
%% 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(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) ->
|
start_link(File, ErrorRegex) ->
|
||||||
gen_server:start_link(?MODULE, [#log{file = File, error_regex = 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]) ->
|
init([Log]) ->
|
||||||
{ok, [off, 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}]) ->
|
handle_info({log_line, Text}, [off, Log = #log{error_regex = ErrorRegex}]) ->
|
||||||
case isError(Text, ErrorRegex) of
|
case isError(Text, ErrorRegex) of
|
||||||
true ->
|
true ->
|
||||||
|
@ -36,18 +120,34 @@ handle_info({timeout}, [on, Log = #log{file = File}, Error, Timer, SafeTimer]) -
|
||||||
mailer ! {error, File, Error},
|
mailer ! {error, File, Error},
|
||||||
{noreply, [off, Log]}.
|
{noreply, [off, Log]}.
|
||||||
|
|
||||||
handle_cast(_Msg, State) ->
|
%%--------------------------------------------------------------------
|
||||||
{noreply, State}.
|
%% @private
|
||||||
|
%% @doc
|
||||||
handle_call(_Request, _From, State) ->
|
%% This function is called by a gen_server when it is about to
|
||||||
{noreply, State}.
|
%% 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) ->
|
terminate(_Reason, _State) ->
|
||||||
shutdown.
|
shutdown.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @private
|
||||||
|
%% @doc
|
||||||
|
%% Convert process state when code is changed
|
||||||
|
%%
|
||||||
|
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% Internal functions
|
||||||
|
%%%===================================================================
|
||||||
isError(Text, ErrorRegex) ->
|
isError(Text, ErrorRegex) ->
|
||||||
case re:run(Text, ErrorRegex) of
|
case re:run(Text, ErrorRegex) of
|
||||||
{match, _} ->
|
{match, _} ->
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @author Fabio Salvini <fs@fabiosalvini.com>
|
||||||
|
%%% @copyright (C) 2017, Fabio Salvini
|
||||||
%% @doc log_monitor public API
|
%% @doc log_monitor public API
|
||||||
%% @end
|
%% @end
|
||||||
|
%%% Created : 2 Jul 2017 by Fabio Salvini <fs@fabiosalvini.com>
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(log_monitor_app).
|
-module(log_monitor_app).
|
||||||
|
|
||||||
-behaviour(application).
|
-behaviour(application).
|
||||||
|
@ -15,7 +17,6 @@
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API
|
%% API
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|
||||||
start(_StartType, _StartArgs) ->
|
start(_StartType, _StartArgs) ->
|
||||||
start_mnesia(),
|
start_mnesia(),
|
||||||
log_monitor_sup:start_link().
|
log_monitor_sup:start_link().
|
||||||
|
@ -28,7 +29,6 @@ stop(_State) ->
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|
||||||
start_mnesia() ->
|
start_mnesia() ->
|
||||||
Nodes = [node()],
|
Nodes = [node()],
|
||||||
%% Stop Mnesia if it is running, cannot create schema otherwise.
|
%% 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.
|
%% @doc log_monitor top level supervisor.
|
||||||
%% @end
|
%% @end
|
||||||
|
%%% Created : 2 Jul 2017 by Fabio Salvini <fs@fabiosalvini.com>
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(log_monitor_sup).
|
-module(log_monitor_sup).
|
||||||
|
|
||||||
-behaviour(supervisor).
|
-behaviour(supervisor).
|
||||||
|
@ -18,7 +20,6 @@
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API functions
|
%% API functions
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|
||||||
start_link() ->
|
start_link() ->
|
||||||
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
|
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).
|
-module(log_sup).
|
||||||
|
|
||||||
-behaviour(supervisor).
|
-behaviour(supervisor).
|
||||||
|
|
||||||
|
%% API
|
||||||
-export([start_link/2]).
|
-export([start_link/2]).
|
||||||
|
|
||||||
|
%% Supervisor callbacks
|
||||||
-export([init/1]).
|
-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) ->
|
start_link(File, ErrorRegex) ->
|
||||||
supervisor:start_link(?MODULE, [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]) ->
|
init([File, ErrorRegex]) ->
|
||||||
SupFlags = #{strategy => one_for_one},
|
SupFlags = #{strategy => one_for_one},
|
||||||
ChildSpecs = [#{
|
ChildSpecs = [#{
|
||||||
|
@ -24,3 +66,7 @@ init([File, ErrorRegex]) ->
|
||||||
modules => [watcher]
|
modules => [watcher]
|
||||||
}],
|
}],
|
||||||
{ok, {SupFlags, ChildSpecs}}.
|
{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).
|
-module(logfiles_sup).
|
||||||
|
|
||||||
-behaviour(supervisor).
|
-behaviour(supervisor).
|
||||||
|
|
||||||
|
%% API
|
||||||
-export([start_link/0]).
|
-export([start_link/0]).
|
||||||
-export([init/1]).
|
|
||||||
-export([add_child/1, remove_child/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() ->
|
start_link() ->
|
||||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
|
||||||
|
|
||||||
init([]) ->
|
|
||||||
SupFlags = #{
|
|
||||||
strategy => one_for_one,
|
|
||||||
intensity => 0,
|
|
||||||
period => 1
|
|
||||||
},
|
|
||||||
ChildSpecs = [],
|
|
||||||
{ok, {SupFlags, ChildSpecs}}.
|
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @doc
|
||||||
|
%% Add a child to the supervisor
|
||||||
|
%%
|
||||||
|
%% @spec add_child(Args) -> void()
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
add_child(Args = [File, _ErrorRegex]) ->
|
add_child(Args = [File, _ErrorRegex]) ->
|
||||||
supervisor:start_child(
|
supervisor:start_child(
|
||||||
?MODULE,
|
?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) ->
|
remove_child(File) ->
|
||||||
supervisor:terminate_child(?MODULE, 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).
|
-module(mailer).
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
-include_lib("mnesia_tables.hrl").
|
-include_lib("mnesia_tables.hrl").
|
||||||
|
|
||||||
-export([start_link/0, init/1, terminate/2]).
|
%% API
|
||||||
-export([handle_info/2, handle_cast/2, handle_call/3]).
|
-export([start_link/0]).
|
||||||
-export([code_change/3]).
|
|
||||||
|
|
||||||
|
%% 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() ->
|
start_link() ->
|
||||||
gen_server:start_link(?MODULE, [], []).
|
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([]) ->
|
init([]) ->
|
||||||
register(mailer, self()),
|
register(mailer, self()),
|
||||||
timer:send_after(1000, {send_emails}),
|
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) ->
|
handle_info({error, File, Text}, State) ->
|
||||||
mnesia:activity(
|
mnesia:activity(
|
||||||
transaction,
|
transaction,
|
||||||
|
@ -34,18 +115,34 @@ handle_info({send_emails}, State) ->
|
||||||
end,
|
end,
|
||||||
{noreply, State}.
|
{noreply, State}.
|
||||||
|
|
||||||
handle_cast(_Msg, State) ->
|
%%--------------------------------------------------------------------
|
||||||
{noreply, State}.
|
%% @private
|
||||||
|
%% @doc
|
||||||
handle_call(_Request, _From, State) ->
|
%% This function is called by a gen_server when it is about to
|
||||||
{noreply, State}.
|
%% 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) ->
|
terminate(_Reason, _State) ->
|
||||||
shutdown.
|
shutdown.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @private
|
||||||
|
%% @doc
|
||||||
|
%% Convert process state when code is changed
|
||||||
|
%%
|
||||||
|
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% Internal functions
|
||||||
|
%%%===================================================================
|
||||||
emails_to_send() ->
|
emails_to_send() ->
|
||||||
mnesia:activity(
|
mnesia:activity(
|
||||||
transaction,
|
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).
|
-ifndef(MNESIA_HRL).
|
||||||
-define(MNESIA_HRL, 1).
|
-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).
|
-module(utils).
|
||||||
|
|
||||||
|
%% API
|
||||||
-export([flatten/1]).
|
-export([flatten/1]).
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% API
|
||||||
|
%%%===================================================================
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @doc
|
||||||
|
%% Flattens a list.
|
||||||
|
%%
|
||||||
|
%% @spec flatten(X) -> list()
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
flatten(X) -> flatten(X,[]).
|
flatten(X) -> flatten(X,[]).
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% Internal functions
|
||||||
|
%%%===================================================================
|
||||||
flatten([],Acc) -> Acc;
|
flatten([],Acc) -> Acc;
|
||||||
flatten([[]|T],Acc) -> flatten(T, Acc);
|
flatten([[]|T],Acc) -> flatten(T, Acc);
|
||||||
flatten([[_|_]=H|T],Acc) -> flatten(T, flatten(H,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).
|
-module(watcher).
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
-export([start_link/2, init/1, terminate/2]).
|
%% API
|
||||||
-export([handle_info/2, handle_cast/2, handle_call/3]).
|
-export([start_link/2]).
|
||||||
-export([code_change/3]).
|
|
||||||
|
|
||||||
|
%% 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) ->
|
start_link(SupPid, File) ->
|
||||||
gen_server:start_link(?MODULE, [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]) ->
|
init([SupPid, File]) ->
|
||||||
timer:sleep(1000),
|
timer:sleep(1000),
|
||||||
config ! {watcher_init, File},
|
config ! {watcher_init, File},
|
||||||
|
@ -15,6 +57,47 @@ init([SupPid, File]) ->
|
||||||
Port = open_port({spawn, Cmd}, [stderr_to_stdout, exit_status, binary]),
|
Port = open_port({spawn, Cmd}, [stderr_to_stdout, exit_status, binary]),
|
||||||
{ok, [File, SupPid, Port]}.
|
{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]) ->
|
handle_info(Msg, [File, SupPid, Port]) ->
|
||||||
case Msg of
|
case Msg of
|
||||||
{Port, {data, Text}} ->
|
{Port, {data, Text}} ->
|
||||||
|
@ -25,18 +108,34 @@ handle_info(Msg, [File, SupPid, Port]) ->
|
||||||
{stop, tail_exit, [File]}
|
{stop, tail_exit, [File]}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
handle_cast(_Msg, State) ->
|
%%--------------------------------------------------------------------
|
||||||
{noreply, State}.
|
%% @private
|
||||||
|
%% @doc
|
||||||
handle_call(_Request, _From, State) ->
|
%% This function is called by a gen_server when it is about to
|
||||||
{noreply, State}.
|
%% 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]) ->
|
terminate(_Reason, [File]) ->
|
||||||
config ! {watcher_terminate, File},
|
config ! {watcher_terminate, File},
|
||||||
shutdown.
|
shutdown.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @private
|
||||||
|
%% @doc
|
||||||
|
%% Convert process state when code is changed
|
||||||
|
%%
|
||||||
|
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% Internal functions
|
||||||
|
%%%===================================================================
|
||||||
gatherer_pid(SupPid) ->
|
gatherer_pid(SupPid) ->
|
||||||
hd([Pid || {Id, Pid, _, _} <- supervisor:which_children(SupPid), Id == gatherer]).
|
hd([Pid || {Id, Pid, _, _} <- supervisor:which_children(SupPid), Id == gatherer]).
|
||||||
|
|
Loading…
Reference in New Issue
Block a user