Error regex as external parameter and monitoring

This commit is contained in:
Fabio Salvini 2017-06-12 14:27:21 +02:00
parent 37a16d1924
commit 810b6c0ada
4 changed files with 37 additions and 30 deletions

View File

@ -1,13 +1,12 @@
-module(config). -module(config).
-behaviour(gen_server). -behaviour(gen_server).
-export([monitor_log/1]). -export([monitor_log/2]).
-export([logfiles/0]).
-export([start_link/0, init/1, terminate/2]). -export([start_link/0, init/1, terminate/2]).
-export([handle_info/2, handle_cast/2, handle_call/3]). -export([handle_info/2, handle_cast/2, handle_call/3]).
-export([code_change/3]). -export([code_change/3]).
-define(INTERVAL, 60000). % One minute
start_link() -> start_link() ->
gen_server:start_link(?MODULE, [], []). gen_server:start_link(?MODULE, [], []).
@ -15,11 +14,14 @@ init([]) ->
register(config, self()), register(config, self()),
{ok, Storage} = application:get_env(log_monitor, storage), {ok, Storage} = application:get_env(log_monitor, storage),
{ok, Logfiles} = dets:open_file(Storage, []), {ok, Logfiles} = dets:open_file(Storage, []),
%% erlang:send_after(?INTERVAL, self(), trigger), Statuses = ets:new(log_statuses, []),
{ok, [Logfiles]}. {ok, [Logfiles, Statuses]}.
handle_info(trigger, State) -> handle_info({watcher_init, File}, State = [_Logfiles, Statuses]) ->
erlang:send_after(?INTERVAL, self(), trigger), ets:insert(Statuses, {File, enabled}),
{noreply, State};
handle_info({watcher_terminate, File}, State = [_Logfiles, Statuses]) ->
ets:insert(Statuses, {File, disabled}),
{noreply, State}; {noreply, State};
handle_info(_Msg, State) -> handle_info(_Msg, State) ->
{noreply, State}. {noreply, State}.
@ -27,14 +29,17 @@ handle_info(_Msg, State) ->
handle_cast(_Msg, State) -> handle_cast(_Msg, State) ->
{noreply, State}. {noreply, State}.
handle_call({monitor, File}, _From, [Logfiles]) -> handle_call({monitor, File, ErrorRegex}, _From, State = [Logfiles, Statuses]) ->
case dets:lookup(Logfiles, File) of case dets:lookup(Logfiles, File) of
[] -> [] ->
dets:insert(Logfiles, {File, "ERROR"}), dets:insert(Logfiles, {File, ErrorRegex}),
supervisor:start_child(logfiles_sup, [File]), ets:insert(Statuses, {File, disabled}),
{reply, ok, [Logfiles]}; supervisor:start_child(logfiles_sup, [File, ErrorRegex]),
_ -> {reply, duplicate, [Logfiles]} {reply, ok, State};
end. _ -> {reply, duplicate, State}
end;
handle_call({get_statuses}, _From, State = [_Logfiles, Statuses]) ->
{reply, ets:tab2list(Statuses), State}.
terminate(_Reason, _State) -> terminate(_Reason, _State) ->
shutdown. shutdown.
@ -42,6 +47,8 @@ terminate(_Reason, _State) ->
code_change(_OldVsn, State, _Extra) -> code_change(_OldVsn, State, _Extra) ->
{ok, State}. {ok, State}.
monitor_log(File) -> monitor_log(File, ErrorRegex) ->
config ! {monitor, File}, gen_server:call(config, {monitor, File, ErrorRegex}).
gen_server:call(config, {monitor, File}).
logfiles() ->
gen_server:call(config, {get_statuses}).

View File

@ -1,15 +1,13 @@
-module(gatherer). -module(gatherer).
-behaviour(gen_server). -behaviour(gen_server).
-export([start_link/1, init/1, terminate/2]). -export([start_link/2, init/1, terminate/2]).
-export([handle_info/2, handle_cast/2, handle_call/3]). -export([handle_info/2, handle_cast/2, handle_call/3]).
-export([code_change/3]). -export([code_change/3]).
-record(log, {file, error_regex}). -record(log, {file, error_regex}).
%% start_link(File, ErrorRegex) -> start_link(File, ErrorRegex) ->
start_link(File) ->
ErrorRegex = "ERROR",
gen_server:start_link(?MODULE, [#log{file = File, error_regex = ErrorRegex}], []). gen_server:start_link(?MODULE, [#log{file = File, error_regex = ErrorRegex}], []).
init([Log]) -> init([Log]) ->

View File

@ -1,17 +1,17 @@
-module(log_sup). -module(log_sup).
-behaviour(supervisor). -behaviour(supervisor).
-export([start_link/1]). -export([start_link/2]).
-export([init/1]). -export([init/1]).
start_link(File) -> start_link(File, ErrorRegex) ->
supervisor:start_link(?MODULE, [File]). supervisor:start_link(?MODULE, [File, ErrorRegex]).
init(File) -> init([File, ErrorRegex]) ->
SupFlags = #{strategy => one_for_one}, SupFlags = #{strategy => one_for_one},
ChildSpecs = [#{ ChildSpecs = [#{
id => gatherer, id => gatherer,
start => {gatherer, start_link, [File]}, start => {gatherer, start_link, [File, ErrorRegex]},
restart => permanent, restart => permanent,
shutdown => 5000 shutdown => 5000
}, },

View File

@ -10,18 +10,19 @@ start_link(SupPid, File) ->
init([SupPid, File]) -> init([SupPid, File]) ->
timer:sleep(1000), timer:sleep(1000),
config ! {watcher_init, File},
Cmd = "/usr/bin/tail -n0 --follow=name " ++ File, Cmd = "/usr/bin/tail -n0 --follow=name " ++ File,
Port = open_port({spawn, Cmd}, [stderr_to_stdout, exit_status, binary]), Port = open_port({spawn, Cmd}, [stderr_to_stdout, exit_status, binary]),
{ok, [SupPid, Port]}. {ok, [File, SupPid, Port]}.
handle_info(Msg, [SupPid, Port]) -> handle_info(Msg, [File, SupPid, Port]) ->
case Msg of case Msg of
{Port, {data, Text}} -> {Port, {data, Text}} ->
GathererPid = gatherer_pid(SupPid), GathererPid = gatherer_pid(SupPid),
GathererPid ! {log_line, Text}, GathererPid ! {log_line, Text},
{noreply, [SupPid, Port]}; {noreply, [File, SupPid, Port]};
{Port, {exit_status, _Status}} -> {Port, {exit_status, _Status}} ->
{stop, tail_exit, []} {stop, tail_exit, [File]}
end. end.
handle_cast(_Msg, State) -> handle_cast(_Msg, State) ->
@ -30,7 +31,8 @@ handle_cast(_Msg, State) ->
handle_call(_Request, _From, State) -> handle_call(_Request, _From, State) ->
{noreply, State}. {noreply, State}.
terminate(_Reason, _State) -> terminate(_Reason, [File]) ->
config ! {watcher_terminate, File},
shutdown. shutdown.
code_change(_OldVsn, State, _Extra) -> code_change(_OldVsn, State, _Extra) ->