Comments skeleton

This commit is contained in:
Fabio Salvini 2017-07-02 10:42:13 +02:00
parent 8d828abea1
commit 006a241293
11 changed files with 621 additions and 76 deletions

View File

@ -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?

View File

@ -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),

View File

@ -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, _} ->

View File

@ -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.

View File

@ -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, []).

View File

@ -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
%%%===================================================================

View File

@ -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
%%%===================================================================

View File

@ -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,

View File

@ -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).

View File

@ -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));

View File

@ -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]).