Random text by shino
Table of Contents
シェルを起動してみてみる
1> logger:get_config().
#{handlers =>
[#{config =>
#{handler_pid => <0.69.0>,
mode_tab => #Ref<0.624384036.2451177473.63388>,
type => standard_io},
filter_default => stop,
filters =>
[{remote_gl,{fun logger_filters:remote_gl/2,stop}},
{domain,{fun logger_filters:domain/2,
{log,super,[otp,sasl]}}},
{no_domain,{fun logger_filters:domain/2,
{log,undefined,[]}}}],
formatter =>
{logger_formatter,#{legacy_header => true,single_line => false}},
id => default,level => all,module => logger_std_h}],
module_levels => [],
primary =>
#{filter_default => log,filters => [],level => notice}}
disk_log
に書く、などが選択可能2つのハンドラーがある場合の構成図
logger:Level/1,2,3
で構成される。
logger:log(Level,Arg1[,Arg2[,Arg3]])
もある。マクロをみてみる。 lib/kernel/include/logger.hrl
から抜粋。
-define(LOG_INFO(A),?DO_LOG(info,[A])).
-define(LOG_INFO(A,B),?DO_LOG(info,[A,B])).
-define(LOG_INFO(A,B,C),?DO_LOG(info,[A,B,C])).
-define(LOCATION,#{mfa=>{?MODULE,?FUNCTION_NAME,?FUNCTION_ARITY},
line=>?LINE,
file=>?FILE}).
-define(DO_LOG(Level,Args),
case logger:allow(Level,?MODULE) of
true ->
apply(logger,macro_log,[?LOCATION,Level|Args]);
false ->
ok
end).
-endif.
lib/kernel/src/logger_internal.hrl
から抜粋
-define(LOG_NONE,-1).
-define(EMERGENCY,0).
-define(ALERT,1).
-define(CRITICAL,2).
-define(ERROR,3).
-define(WARNING,4).
-define(NOTICE,5).
-define(INFO,6).
-define(DEBUG,7).
-define(LOG_ALL,10).
logger:error("The file does not exist: ~ts",[Filename])
logger:notice("Something strange happened!")
レポートの例
logger:debug(#{got => connection_request, id => Id, state => State},
#{report_cb => fun(R) -> {"~p",[R]} end})
logger:set_process_metadata/1
, logger:update_process metadata/1
?LOG_ERROR("Connection closed",#{context => server})
{FilterFun, Extra}
FilterFun
: arity 2 の関数、Extra
は任意Extra
を設定する。stop
, ignore
またはログイベント(変更したものでも良い)を返すstop
の場合、ログイベントは破棄される。
ignore
の場合、ログイベントを理解できなかったことを示す
filter_default
オプション
ignore
を返した場合、またはフィルタがない場合の挙動を設定するlog
stop
に設定すると Logger は対応するイベントを破棄する関数
logger:add_primary_filter/2
, logger:remove_primary_filter/1
logger:add_handler_filter/3
, logger:remove_handler_filter/2
logger:get_config/0
logger:get_primary_config/0
logger:get_handler_config/1
logger_filters:domain/2
, logger_filters:level/2
, logger_filters:progress/2
,
logger_filters:remote_gl/2
logger_filters:domain/2
の実行例
16> logger_filters:domain(#{meta => #{domain => [my_app]}}, {log, equal, [my_app]}).
#{meta => #{domain => [my_app]}}
17> logger_filters:domain(#{meta => #{domain => [my_app]}}, {log, equal, [otp]}).
ignore
使用例
logger:set_handler_config(default, filter_default, log).
Filter = {fun logger_filters:domain/2, {stop, sub, [otp, sasl]}}.
logger:add_handler_filter(default, no_sasl, Filter).
log/2
をエキスポートしたモジュールとして定義される。log(LogEvent, Config) -> void()
adding_handler/1
, changing_config/2
, removing_handler/1
logger_std_h
logger_disk_log_h
disk_log
を使う以外は logger_std_h
と同じerror_logger
error_logger
イベントハンドラーが
error_logger:add_report_handler/1,2
で追加された時に開始される。error_logger
イベントハンドラーは存在するが、
OTP 21.0 以降では追加されない。error_logger
まわりでソースをいくつか参照しておく。
error_logger:add_report_hander
は logger
と gen_event
に
ハンドラーを登録しているadd_report_handler(Module, Args) when is_atom(Module) ->
_ = logger:add_handler(?MODULE,?MODULE,#{level=>info,filter_default=>log}),
gen_event:add_handler(?MODULE, Module, Args).
error_logger:start
は logger_sup
に自分を追加して
start_link
で gen_event
プロセスを開始しているstart() ->
case whereis(?MODULE) of
undefined ->
ErrorLogger =
#{id => ?MODULE,
start => {?MODULE, start_link, []},
restart => transient,
shutdown => 2000,
type => worker,
modules => dynamic},
case supervisor:start_child(logger_sup, ErrorLogger) of
{ok,_} ->
ok;
Error ->
Error
end;
_ ->
ok
end.
start_link() ->
gen_event:start_link({local, ?MODULE},
[{spawn_opt,[{message_queue_data, off_heap}]}]).
HModule:log/2
の引数2から、ハンドラー設定として受け取るFModule
format(LogEvent,FConfig) -> FormattedLogEntry
FConfig
check_config(FConfig)
get_primary_config/0
set_primary_config/1,2
update_primary_config/1
add_primary_filter/2
remove_primary_filter/1
get_handler_config/0,1
set_handler_config/2,3
update_handler_config/2
add_handler_filter/3
remove_handler_filter/2
update_formatter_config/2,3
logger = [Config]
logger_level
で設定するlogger_sasl_compatible
で設定するConfig
は次のうちから任意の数
{handler, default, undefined}
{handler, HandlerId, Module, HandelrConfig}
{filters, FilterDefault, [Filter]}
{module_level, Level, [Module]}
logger_level = Level
logger_sasl_compatible = true | false
[{kernel,
[{logger,
[{handler, default, logger_std_h, % {handler, HandlerId, Module,
#{config => #{type => {file,"log/erlang.log"}}}} % Config}
]}]}].
[{kernel,
[{logger,
[{handler, default, logger_std_h,
#{formatter => {logger_formatter, #{single_line => true}}}}
]}]}].
[{kernel,
[{logger,
[{handler, default, logger_std_h,
#{formatter => {logger_formatter,
#{template => [time," ",pid," ",msg,"\n"]}}}}
]}]}].
[{kernel,
[{logger,
[{handler, default, logger_std_h,
#{level => error,
config => #{type => {file, "log/erlang.log"}}}},
{handler, info, logger_std_h,
#{level => debug,
config => #{type => {file, "log/debug.log"}}}}
]}]}].
error_logger:error_report/1,2
と error_logger:error_msg/1,2
、また
warning と info についての関連関数は、
Logger の logger:log(Level,Report,Metadata)
にフォワードされる
Level
は関数名から決まるReport
はログメッセージを含むMetadata
はレガシー error_logger
との互換性を保つために使うことが出来る
追加情報を持っているlogger_formatter
の設定 legacy_header
が true
になっているsasl_report_tty_h
, sasl_report_file_h
ハンドラーで処理されていたerror
レベルのログイベントで、
Kernel で開始されるでふととハンドラーを通じてログ出力されるinfo
レベルログイベントで 発行され、デフォルトの
プライマリログレベルが notice
のため出力されない
info
に設定するlogger_sasl_compatible
を
true
に設定するdomain
フィールドが [otp, sasl]
であるgen_server.erl
から error_logger 互換の呼び出し部分抜粋:
error_info(Reason, Name, From, Msg, Mod, State, Debug) ->
?LOG_ERROR(#{label=>{gen_server,terminate},
name=>Name,
last_message=>Msg,
state=>format_status(terminate, Mod, get(), State),
reason=>Reason,
client_info=>client_stacktrace(From)},
#{domain=>[otp],
report_cb=>fun gen_server:format_log/1,
error_logger=>#{tag=>error}}),
error_logger.erl
では #{error_logger => #{tag => Tag}}
で拾う:
do_log(Level,{Format,Args},#{?MODULE:=#{tag:=Tag}}=Meta)
error_logger はその他の形式は捨てる
logger_sup
|
(child)
|
+-- error_logger (gen_event)
| - logger のハンドラー
| - error_logger:start() で開始される
(gen_event handler)
|
+-- error_logger_lager_h
- error_logger (gen_event) のハンドラー
- sup. tree としては lager_handler_watcher_sup 配下に居る
(略)
(略)
logger_std_h
と logger_disk_log_h
は過負荷保護の
メカニズムを持っている
sync_mode_qlen
sync_mode_qlen
よりもキュー長が短くなったらまた非同期モードで動作するdrop_mode_qlen
flush_qlen
sync_mode_qlen =< drop_mode_qlen =< flush_qlen
drop_mode_qlen > 1
sync_mode_qlen
がゼロの場合、すべてのイベントは同期的に処理される
sync_mode_qlen
が drop_mode_qlen
と同じ値の場合、同期モードが無効化される
drop_mode_qlen
が flush_qlen
と同じ値の場合、破棄モードは無効化される設定例
logger:add_handler(my_standard_h, logger_std_h,
#{config => #{type => {file,"./system_info.log"},
sync_mode_qlen => 100,
drop_mode_qlen => 1000,
flush_qlen => 2000}}).
burst_limit_enabled
true
でバースト制御有効、false
で無効true
burst_limit_max_count
burst_limit_window_time
の期間に処理しうる最大のイベント数burst_limit_window_time
burst_limit_max_count
を見よ設定例
logger:add_handler(my_disk_log_h, logger_disk_log_h,
#{config => #{file => "./my_disk_log",
burst_limit_enable => true,
burst_limit_max_count => 20,
burst_limit_window_time => 500}}).
overload_kill_enable
true
でこの機能を有効化、false
で無効化false
overload_kill_qlen
overload_kill_mem_size
overload_kill_restart_after
infinity
を指定すると再起動されないNote
logger_formatter(3)
を参照のこと
[logger_filters](http://erlang.org/doc/man/logger_filters.html#domain-2}
TODO
sys.config
で default ハンドラーを無効化すると生き残るsys.config
[
{kernel, [
{logger,
[
%% デフォルトの Logger ハンドラーを無効化
{handler, default, undefined}
]}
].
起動直後の Logger 設定、simple ハンドラーが居る:
#{handlers =>
[#{filter_default => log,filters => [],
formatter => {logger_formatter,#{}},
id => error_logger,level => info,module => error_logger},
#{filter_default => stop,
filters =>
[{remote_gl,{fun logger_filters:remote_gl/2,stop}},
{domain,{fun logger_filters:domain/2,
{log,super,[otp,sasl]}}},
{no_domain,{fun logger_filters:domain/2,
{log,undefined,[]}}}],
formatter => {logger_formatter,#{}},
id => simple, %% simple ハンドラー
level => all,
module => logger_simple_h}],
module_levels => [],
primary =>
#{filter_default => log,filters => [],level => notice}}
erlang.log.*
に流れてしまうので困る[
{kernel, [
{logger,
[
%% デフォルトの Logger ハンドラーを無効化
%% ソースコード上ここは参照されないが、ドキュメントにあるとおりにしておく
{handler, default, undefined}
]},
%% simple ハンドラーを無効化する
{error_logger, silent}
].
この設定で起動したときの Logger 設定、simple が居ない(Lager を上げているので error_logger がある):
#{handlers =>
[#{filter_default => log,filters => [],
formatter => {logger_formatter,#{}},
id => error_logger,level => info,module => error_logger}],
module_levels => [],
primary =>
#{filter_default => log,filters => [],level => notice}}