From 0c6c4c13b31f2a91568bb3a04e63bc3c878d503c Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Thu, 14 Jun 2018 12:04:52 +0200 Subject: [logger] Stress overload_kill tests in disk_log handler --- lib/kernel/test/logger_disk_log_h_SUITE.erl | 59 ++++++++++++++++++++--------- lib/kernel/test/logger_std_h_SUITE.erl | 13 +++++-- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/lib/kernel/test/logger_disk_log_h_SUITE.erl b/lib/kernel/test/logger_disk_log_h_SUITE.erl index 7225d4b57c..492730bd89 100644 --- a/lib/kernel/test/logger_disk_log_h_SUITE.erl +++ b/lib/kernel/test/logger_disk_log_h_SUITE.erl @@ -1063,7 +1063,7 @@ kill_disabled(cleanup, _Config) -> ok = stop_handler(?MODULE). qlen_kill_new(Config) -> - {_Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config), + {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config), Pid0 = whereis(h_proc_name()), {_,Mem0} = process_info(Pid0, memory), RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER, @@ -1076,7 +1076,7 @@ qlen_kill_new(Config) -> ok = logger:set_handler_config(?MODULE, NewHConfig), MRef = erlang:monitor(process, Pid0), NumOfReqs = 100, - Procs = 2, + Procs = 4, send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice), %% send_burst({n,NumOfReqs}, seq, {chars,79}, notice), receive @@ -1087,8 +1087,8 @@ qlen_kill_new(Config) -> killed -> ct:pal("Slow shutdown, handler process was killed!", []) end, - timer:sleep(RestartAfter + 2000), - true = is_pid(whereis(h_proc_name())), + file_delete(Log), + {ok,_} = wait_for_process_up(RestartAfter * 3), ok after 5000 -> @@ -1100,7 +1100,7 @@ qlen_kill_new(cleanup, _Config) -> ok = stop_handler(?MODULE). mem_kill_new(Config) -> - {_Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config), + {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config), Pid0 = whereis(h_proc_name()), {_,Mem0} = process_info(Pid0, memory), RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER, @@ -1113,7 +1113,7 @@ mem_kill_new(Config) -> ok = logger:set_handler_config(?MODULE, NewHConfig), MRef = erlang:monitor(process, Pid0), NumOfReqs = 100, - Procs = 2, + Procs = 4, send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice), %% send_burst({n,NumOfReqs}, seq, {chars,79}, notice), receive @@ -1124,8 +1124,8 @@ mem_kill_new(Config) -> killed -> ct:pal("Slow shutdown, handler process was killed!", []) end, - timer:sleep(RestartAfter + 2000), - true = is_pid(whereis(h_proc_name())), + file_delete(Log), + {ok,_} = wait_for_process_up(RestartAfter * 3), ok after 5000 -> @@ -1136,6 +1136,8 @@ mem_kill_new(Config) -> mem_kill_new(cleanup, _Config) -> ok = stop_handler(?MODULE). +restart_after() -> + [{timetrap,{minutes,2}}]. restart_after(Config) -> {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config), NewHConfig1 = @@ -1145,14 +1147,16 @@ restart_after(Config) -> ok = logger:set_handler_config(?MODULE, NewHConfig1), MRef1 = erlang:monitor(process, whereis(h_proc_name())), %% kill handler - send_burst({n,100}, {spawn,2,0}, {chars,79}, notice), + send_burst({n,100}, {spawn,4,0}, {chars,79}, notice), receive - {'DOWN', MRef1, _, _, _Info1} -> - timer:sleep(?OVERLOAD_KILL_RESTART_AFTER + 1000), - undefined = whereis(h_proc_name()), + {'DOWN', MRef1, _, _, _Reason1} -> + file_delete(Log), + error = wait_for_process_up(?OVERLOAD_KILL_RESTART_AFTER * 3), ok after 5000 -> + Info1 = logger_std_h:info(?MODULE), + ct:pal("Handler state = ~p", [Info1]), ct:fail("Handler not dead! It should not have survived this!") end, @@ -1166,16 +1170,17 @@ restart_after(Config) -> Pid0 = whereis(h_proc_name()), MRef2 = erlang:monitor(process, Pid0), %% kill handler - send_burst({n,100}, {spawn,2,0}, {chars,79}, notice), + send_burst({n,100}, {spawn,4,0}, {chars,79}, notice), receive - {'DOWN', MRef2, _, _, _Info2} -> - timer:sleep(RestartAfter + 2000), - Pid1 = whereis(h_proc_name()), - true = is_pid(Pid1), + {'DOWN', MRef2, _, _, _Reason2} -> + file_delete(Log), + {ok,Pid1} = wait_for_process_up(RestartAfter * 3), false = (Pid1 == Pid0), ok after 5000 -> + Info2 = logger_std_h:info(?MODULE), + ct:pal("Handler state = ~p", [Info2]), ct:fail("Handler not dead! It should not have survived this!") end, ok. @@ -1539,3 +1544,23 @@ h_proc_name(Name) -> file_delete(Log) -> file:delete(Log). + +wait_for_process_up(T) -> + wait_for_process_up(h_proc_name(),T). + +wait_for_process_up(Name,T) -> + N = (T div 500) + 1, + wait_for_process_up1(Name,N). + +wait_for_process_up1(Name,0) -> + error; +wait_for_process_up1(Name,N) -> + timer:sleep(500), + case whereis(Name) of + Pid when is_pid(Pid) -> + %% ct:pal("Process ~p up (~p tries left)",[Name,N]), + {ok,Pid}; + undefined -> + %% ct:pal("Waiting for process ~p (~p tries left)",[Name,N]), + wait_for_process_up1(Name,N-1) + end. diff --git a/lib/kernel/test/logger_std_h_SUITE.erl b/lib/kernel/test/logger_std_h_SUITE.erl index e0bc79012c..c2cc7653ea 100644 --- a/lib/kernel/test/logger_std_h_SUITE.erl +++ b/lib/kernel/test/logger_std_h_SUITE.erl @@ -995,7 +995,7 @@ qlen_kill_new(Config) -> ct:pal("Slow shutdown, handler process was killed!", []) end, file_delete(Log), - {ok,_} = wait_for_process_up(h_proc_name(), RestartAfter * 3), + {ok,_} = wait_for_process_up(RestartAfter * 3), ok after 5000 -> @@ -1046,7 +1046,7 @@ mem_kill_new(Config) -> ct:pal("Slow shutdown, handler process was killed!", []) end, file_delete(Log), - {ok,_} = wait_for_process_up(h_proc_name(), RestartAfter * 3), + {ok,_} = wait_for_process_up(RestartAfter * 3), ok after 5000 -> @@ -1077,7 +1077,7 @@ restart_after(Config) -> receive {'DOWN', MRef1, _, _, _Reason1} -> file_delete(Log), - error = wait_for_process_up(h_proc_name(),?OVERLOAD_KILL_RESTART_AFTER * 3), + error = wait_for_process_up(?OVERLOAD_KILL_RESTART_AFTER * 3), ok after 5000 -> @@ -1100,7 +1100,7 @@ restart_after(Config) -> receive {'DOWN', MRef2, _, _, _Reason2} -> file_delete(Log), - {ok,Pid1} = wait_for_process_up(h_proc_name(),RestartAfter * 3), + {ok,Pid1} = wait_for_process_up(RestartAfter * 3), false = (Pid1 == Pid0), ok after @@ -1570,6 +1570,9 @@ h_proc_name(Name) -> file_delete(Log) -> file:delete(Log). +wait_for_process_up(T) -> + wait_for_process_up(h_proc_name(),T). + wait_for_process_up(Name,T) -> N = (T div 500) + 1, wait_for_process_up1(Name,N). @@ -1580,7 +1583,9 @@ wait_for_process_up1(Name,N) -> timer:sleep(500), case whereis(Name) of Pid when is_pid(Pid) -> + %% ct:pal("Process ~p up (~p tries left)",[Name,N]), {ok,Pid}; undefined -> + %% ct:pal("Waiting for process ~p (~p tries left)",[Name,N]), wait_for_process_up1(Name,N-1) end. -- cgit v1.2.3 From 40f29ea1f77dec1cc4920b3593091b35b597f8ff Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Thu, 14 Jun 2018 12:21:18 +0200 Subject: [logger] Unregister handler names before terminating --- lib/kernel/src/logger_disk_log_h.erl | 6 +++++- lib/kernel/src/logger_std_h.erl | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/kernel/src/logger_disk_log_h.erl b/lib/kernel/src/logger_disk_log_h.erl index a074d0210e..394c7b7320 100644 --- a/lib/kernel/src/logger_disk_log_h.erl +++ b/lib/kernel/src/logger_disk_log_h.erl @@ -249,7 +249,8 @@ init([Name, max_no_files:=MNF}}, State = #{dl_sync_int := DLSyncInt}]) -> - register(?name_to_reg_name(?MODULE,Name), self()), + RegName = ?name_to_reg_name(?MODULE,Name), + register(RegName, self()), process_flag(trap_exit, true), process_flag(message_queue_data, off_heap), @@ -296,10 +297,12 @@ init([Name, enter_loop(Config1, State1) catch _:Error -> + unregister(RegName), logger_h_common:error_notify({open_disk_log,Name,Error}), proc_lib:init_ack(Error) end; Error -> + unregister(RegName), logger_h_common:error_notify({open_disk_log,Name,Error}), proc_lib:init_ack(Error) end. @@ -426,6 +429,7 @@ terminate(Reason, State = #{id := Name}) -> _ = logger_h_common:cancel_timer(maps:get(rep_sync_tref, State, undefined)), _ = close_disk_log(Name, normal), + unregister(?name_to_reg_name(?MODULE, Name)), logger_h_common:stop_or_restart(Name, Reason, State). code_change(_OldVsn, State, _Extra) -> diff --git a/lib/kernel/src/logger_std_h.erl b/lib/kernel/src/logger_std_h.erl index ce9daa50ab..801d05853a 100644 --- a/lib/kernel/src/logger_std_h.erl +++ b/lib/kernel/src/logger_std_h.erl @@ -229,7 +229,8 @@ log(LogEvent, Config = #{id := Name, init([Name, Config = #{config := HConfig}, State0 = #{type := Type, file_ctrl_sync_int := FileCtrlSyncInt}]) -> - register(?name_to_reg_name(?MODULE,Name), self()), + RegName = ?name_to_reg_name(?MODULE,Name), + register(RegName, self()), process_flag(trap_exit, true), process_flag(message_queue_data, off_heap), @@ -261,10 +262,12 @@ init([Name, Config = #{config := HConfig}, enter_loop(Config1, State1) catch _:Error -> + unregister(RegName), logger_h_common:error_notify({init_handler,Name,Error}), proc_lib:init_ack(Error) end; Error -> + unregister(RegName), logger_h_common:error_notify({init_handler,Name,Error}), proc_lib:init_ack(Error) end. @@ -415,6 +418,7 @@ terminate(Reason, State = #{id:=Name, file_ctrl_pid:=FWPid, false -> ok end, + unregister(?name_to_reg_name(?MODULE, Name)), logger_h_common:stop_or_restart(Name, Reason, State). code_change(_OldVsn, State, _Extra) -> -- cgit v1.2.3 From 1a07345694834bcb68ca2f27d2dc940e0f036f9c Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Thu, 14 Jun 2018 15:19:50 +0200 Subject: [logger] Adjust priority settings in test Now only setting high priority on every second burst sending process, to allow for handler process to be scheduled in every now and then. --- lib/kernel/test/logger_disk_log_h_SUITE.erl | 18 ++++++++++++------ lib/kernel/test/logger_std_h_SUITE.erl | 18 ++++++++++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/lib/kernel/test/logger_disk_log_h_SUITE.erl b/lib/kernel/test/logger_disk_log_h_SUITE.erl index 492730bd89..bb2b5eed57 100644 --- a/lib/kernel/test/logger_disk_log_h_SUITE.erl +++ b/lib/kernel/test/logger_disk_log_h_SUITE.erl @@ -1285,13 +1285,9 @@ send_n_burst(N, seq, Text, Class) -> send_n_burst(N-1, seq, Text, Class); send_n_burst(N, {spawn,Ps,TO}, Text, Class) -> ct:pal("~w processes each sending ~w messages", [Ps,N]), - PerProc = fun() -> - process_flag(priority,high), - send_n_burst(N, seq, Text, Class) - end, MRefs = [begin if TO == 0 -> ok; true -> timer:sleep(TO) end, - monitor(process,spawn_link(PerProc)) end || - _ <- lists:seq(1,Ps)], + monitor(process,spawn_link(per_proc_fun(N,Text,Class,X))) + end || X <- lists:seq(1,Ps)], lists:foreach(fun(MRef) -> receive {'DOWN', MRef, _, _, _} -> @@ -1310,6 +1306,16 @@ send_t_burst(T0, T, Text, Class, N) -> send_t_burst(T0, T, Text, Class, N+1) end. +per_proc_fun(N,Text,Class,X) when X rem 2 == 0 -> + fun() -> + process_flag(priority,high), + send_n_burst(N, seq, Text, Class) + end; +per_proc_fun(N,Text,Class,_) -> + fun() -> + send_n_burst(N, seq, Text, Class) + end. + %%%----------------------------------------------------------------- %%% Formatter callback %%% Using this to send the formatted string back to the test case diff --git a/lib/kernel/test/logger_std_h_SUITE.erl b/lib/kernel/test/logger_std_h_SUITE.erl index c2cc7653ea..76f8a35406 100644 --- a/lib/kernel/test/logger_std_h_SUITE.erl +++ b/lib/kernel/test/logger_std_h_SUITE.erl @@ -1257,13 +1257,9 @@ send_n_burst(N, seq, Text, Class) -> send_n_burst(N-1, seq, Text, Class); send_n_burst(N, {spawn,Ps,TO}, Text, Class) -> ct:pal("~w processes each sending ~w messages", [Ps,N]), - PerProc = fun() -> - process_flag(priority,high), - send_n_burst(N, seq, Text, Class) - end, MRefs = [begin if TO == 0 -> ok; true -> timer:sleep(TO) end, - monitor(process,spawn_link(PerProc)) end || - _ <- lists:seq(1,Ps)], + monitor(process,spawn_link(per_proc_fun(N,Text,Class,X))) + end || X <- lists:seq(1,Ps)], lists:foreach(fun(MRef) -> receive {'DOWN', MRef, _, _, _} -> @@ -1282,6 +1278,16 @@ send_t_burst(T0, T, Text, Class, N) -> send_t_burst(T0, T, Text, Class, N+1) end. +per_proc_fun(N,Text,Class,X) when X rem 2 == 0 -> + fun() -> + process_flag(priority,high), + send_n_burst(N, seq, Text, Class) + end; +per_proc_fun(N,Text,Class,_) -> + fun() -> + send_n_burst(N, seq, Text, Class) + end. + %%%----------------------------------------------------------------- %%% Formatter callback %%% Using this to send the formatted string back to the test case -- cgit v1.2.3 From 5e23103186cb71c64f7f2fa28cbfd8c62d7ee21b Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Wed, 13 Jun 2018 11:48:58 +0200 Subject: [logger] Update documentation --- lib/kernel/doc/src/logger.xml | 33 +++++--- lib/kernel/doc/src/logger_arch.png | Bin 32407 -> 32187 bytes lib/kernel/doc/src/logger_chapter.xml | 137 +++++++++++++++------------------- 3 files changed, 84 insertions(+), 86 deletions(-) diff --git a/lib/kernel/doc/src/logger.xml b/lib/kernel/doc/src/logger.xml index 7f35a5d752..8940c89ab8 100644 --- a/lib/kernel/doc/src/logger.xml +++ b/lib/kernel/doc/src/logger.xml @@ -86,6 +86,14 @@ logger:error("error happened because: ~p", [Reason]). % Without macro built-in filters, see logger_filters. + + +

Since Logger is new in Erlang/OTP 21.0, we do reserve the right + to introduce changes to the Logger API and functionality in + patches following this release. These changes might or might not + be backwards compatible with the initial version.

+
+ @@ -939,7 +947,8 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). - HModule:adding_handler(Config1) -> {ok, Config2} | {error, Reason} + HModule:adding_handler(Config1) -> {ok, Config2} | {error, + Reason} An instance of this handler is about to be added. Config1 = Config2 = @@ -948,9 +957,10 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).

This callback function is optional.

-

The function is called when an new handler is about to be - added, and the purpose is to verify the configuration and - initiate all resources needed by the handler.

+

The function is called on a temporary process when an new + handler is about to be added. The purpose is to verify the + configuration and initiate all resources needed by the + handler.

The handler identity is associated with the id key in Config1.

If everything succeeds, the callback function can add @@ -972,9 +982,9 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).

This callback function is optional.

-

The function is called when the configuration for a handler - is about to change, and the purpose is to verify and act on - the new configuration.

+

The function is called on a temporary process when the + configuration for a handler is about to change. The purpose + is to verify and act on the new configuration.

Config1 is the existing configuration and Config2 is the new configuration.

The handler identity is associated with the id key @@ -999,7 +1009,8 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).

This callback function is mandatory.

The function is called when all primary filters and all handler filters for the handler in question have passed for - the given log event.

+ the given log event. It is called on the client process, that + is, the process that issued the log event.

The handler identity is associated with the id key in Config.

The handler must log the event.

@@ -1017,9 +1028,9 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).

This callback function is optional.

-

The function is called when a handler is about to be - removed, and the purpose is to release all resources used by - the handler.

+

The function is called on a temporary process when a + handler is about to be removed. The purpose is to release + all resources used by the handler.

The handler identity is associated with the id key in Config.

The return value is ignored by Logger.

diff --git a/lib/kernel/doc/src/logger_arch.png b/lib/kernel/doc/src/logger_arch.png index a9b9a658b4..a3a863c511 100644 Binary files a/lib/kernel/doc/src/logger_arch.png and b/lib/kernel/doc/src/logger_arch.png differ diff --git a/lib/kernel/doc/src/logger_chapter.xml b/lib/kernel/doc/src/logger_chapter.xml index f7df0a3e6e..6e1eab8a8e 100644 --- a/lib/kernel/doc/src/logger_chapter.xml +++ b/lib/kernel/doc/src/logger_chapter.xml @@ -48,6 +48,13 @@ handler, replace it by a custom handler, and install additional handlers.

+ +

Since Logger is new in Erlang/OTP 21.0, we do reserve the right + to introduce changes to the Logger API and functionality in + patches following this release. These changes might or might not + be backwards compatible with the initial version.

+
+
Overview

A log event consists of a log level, the @@ -84,11 +91,11 @@ section Filters for more details.

If a log event passes through all primary filters and all - handler filters for a specific handler, Logger forwards the event - to the handler callback. The handler formats and prints the - event to its destination. See - section Handlers for - more details.

+ handler filters for a specific handler, Logger forwards the + event to the handler callback. The handler formats and + prints the event to its destination. See + section Handlers for more + details.

Everything up to and including the call to the handler callbacks is executed on the client process, that is, the process where the log event was issued. It is up to the handler @@ -113,10 +120,11 @@ Log Level

The log level indicates the severity of a event. In - accordance with the Syslog protocol, RFC-5424, eight log - levels can be specified. The following table lists all - possible log levels by name (atom), integer value, and - description:

+ accordance with the Syslog protocol, + RFC + 5424, eight log levels can be specified. The following + table lists all possible log levels by name (atom), integer + value, and description:

@@ -337,7 +345,7 @@ logger:debug(#{got => connection_request, id => Id, state => State}, Handlers

A handler is defined as a module exporting at least the - following function:

+ following callback function:

log(LogEvent, Config) -> void()
@@ -934,50 +942,50 @@ error_logger:add_report_handler/1,2.
- Example: Add a handler to log debug events to file + Example: Add a handler to log info events to file

When starting an Erlang node, the default behaviour is that all - log events on level info or more severe, are logged to the - terminal via the default handler. To also log debug events, you - can either change the primary log level to debug:

+ log events on level notice or more severe, are logged to + the terminal via the default handler. To also log info events, + you can either change the primary log level to info:

-1> logger:set_primary_config(level, debug).
+1> logger:set_primary_config(level, info).
 ok

or set the level for one or a few modules only:

-2> logger:set_module_level(mymodule, debug).
+2> logger:set_module_level(mymodule, info).
 ok
-

This allows debug events to pass through to the default handler, - and be printed to the terminal as well. If there are many debug +

This allows info events to pass through to the default handler, + and be printed to the terminal as well. If there are many info events, it can be useful to print these to a file instead.

-

First, set the log level of the default handler to info, - preventing it from printing debug events to the terminal:

+

First, set the log level of the default handler + to notice, preventing it from printing info events to the + terminal:

-3> logger:set_handler_config(default, level, info).
+3> logger:set_handler_config(default, level, notice).
 ok

Then, add a new handler which prints to file. You can use the handler module logger_std_h, - and specify type {file,File}. The default handler level - is all, so you don't need to specify that:

+ and specify type {file,File}.:

-4> Config = #{config => #{type => {file,"./debug.log"}}}.
-#{config => #{type => {file,"./debug.log"}}}
-5> logger:add_handler(debugger, logger_std_h, Config).
+4> Config = #{config => #{type => {file,"./info.log"}}, level => info}.
+#{config => #{type => {file,"./info.log"}},level => info}
+5> logger:add_handler(myhandler, logger_std_h, Config).
 ok

Since filter_default defaults to log, this - handler now receives all log events. If you want debug events - only in the file, you must add a filter to stop all non-debug + handler now receives all log events. If you want info events + only in the file, you must add a filter to stop all non-info events. The built-in filter logger_filters:level/2 can do this:

-6> logger:add_handler_filter(debugger, stop_non_debug,
-                             {fun logger_filters:level/2, {stop, neq, debug}}).
+6> logger:add_handler_filter(myhandler, stop_non_info,
+                             {fun logger_filters:level/2, {stop, neq, info}}).
 ok

See section Filters for - more information about the filters and the filter_default - configuration parameter.

+ more information about the filters and the filter_default + configuration parameter.

@@ -1023,63 +1031,42 @@ ok

A simple handler that prints to the terminal can be implemented as follows:

--module(myhandler). +-module(myhandler1). -export([log/2]). -log(LogEvent, #{formatter := {FModule, FConfig}) -> +log(LogEvent, #{formatter := {FModule, FConfig}}) -> io:put_chars(FModule:format(LogEvent, FConfig)). -

A simple handler which prints to file can be implemented like - this:

- --module(myhandler). --export([adding_handler/1, removing_handler/1, log/2]). --export([init/1, handle_call/3, handle_cast/2, terminate/2]). - -adding_handler(Config) -> - {ok, Fd} = file:open(File, [append, {encoding, utf8}]), - {ok, Config#{myhandler_fd => Fd}}. - -removing_handler(#{myhandler_fd := Fd}) -> - _ = file:close(Fd), - ok. - -log(LogEvent,#{myhandler_fd := Fd, formatter := {FModule, FConfig}}) -> - io:put_chars(Fd, FModule:format(LogEvent, FConfig)). - - - -

The above handlers do not have any overload - protection, and all log events are printed directly from the - client process.

-

For information and examples of overload protection, please - refer to - section Protecting the - Handler from Overload, and the implementation - of logger_std_h - and logger_disk_log_h - .

-
- -

Below is a simpler example of a handler which logs through one - single process.

+

Notice that the above handler does not have any overload + protection, and all log events are printed directly from the + client process.

+

For information and examples of overload protection, please + refer to + section Protecting the + Handler from Overload, and the implementation + of logger_std_h + and logger_disk_log_h + .

+

The following is a simpler example of a handler which logs to a + file through one single process:

--module(myhandler). +-module(myhandler2). -export([adding_handler/1, removing_handler/1, log/2]). -export([init/1, handle_call/3, handle_cast/2, terminate/2]). adding_handler(Config) -> - {ok, Pid} = gen_server:start(?MODULE, Config), - {ok, Config#{myhandler_pid => Pid}}. + MyConfig = maps:get(config,Config,#{file => "myhandler2.log"}), + {ok, Pid} = gen_server:start(?MODULE, MyConfig, []), + {ok, Config#{config => MyConfig#{pid => Pid}}}. -removing_handler(#{myhandler_pid := Pid}) -> +removing_handler(#{config := #{pid := Pid}}) -> gen_server:stop(Pid). -log(LogEvent,#{myhandler_pid := Pid} = Config) -> +log(LogEvent,#{config := #{pid := Pid}} = Config) -> gen_server:cast(Pid, {log, LogEvent, Config}). -init(#{myhandler_file := File}) -> +init(#{file := File}) -> {ok, Fd} = file:open(File, [append, {encoding, utf8}]), {ok, #{file => File, fd => Fd}}. @@ -1090,7 +1077,7 @@ handle_cast({log, LogEvent, Config}, #{fd := Fd} = State) -> do_log(Fd, LogEvent, Config), {noreply, State}. -terminate(Reason, #{fd := Fd}) -> +terminate(_Reason, #{fd := Fd}) -> _ = file:close(Fd), ok. -- cgit v1.2.3