檢視原始碼 日誌記錄實用指南
使用,特別是設定 Logger 有時可能會很困難,因為有許多不同的選項可以更改,而且通常有多種方法可以達到相同的結果。本使用者指南試圖透過提供許多不同的 Logger 使用範例來提供幫助。
如需更多 Logger 實際使用案例的範例,Fred Hebert 的部落格文章Erlang/OTP 21 的新日誌記錄器是一個很好的起點。
注意
如果您發現本指南中缺少某些常見的 Logger 用法,請在 github 上開啟一個 pull request,並提出建議的補充內容
取得 Logger 資訊
列印主要的 Logger 設定。
1> logger:i(primary).
Primary configuration:
Level: notice
Filter Default: log
Filters:
(none)
也可以使用 logger:get_primary_config()
來取得設定。
另請參閱
- logger:i()
- 記錄使用者指南中的「設定」
列印所有處理器的設定。
2> logger:i(handlers).
Handler configuration:
Id: default
Module: logger_std_h
Level: all
Formatter:
Module: logger_formatter
Config:
legacy_header: true
single_line: false
Filter Default: stop
Filters:
Id: remote_gl
Fun: fun logger_filters:remote_gl/2
Arg: stop
Id: domain
Fun: fun logger_filters:domain/2
Arg: {log,super,[otp,sasl]}
Id: no_domain
Fun: fun logger_filters:domain/2
Arg: {log,undefined,[]}
Handler Config:
burst_limit_enable: true
burst_limit_max_count: 500
burst_limit_window_time: 1000
drop_mode_qlen: 200
filesync_repeat_interval: no_repeat
flush_qlen: 1000
overload_kill_enable: false
overload_kill_mem_size: 3000000
overload_kill_qlen: 20000
overload_kill_restart_after: 5000
sync_mode_qlen: 10
type: standard_io
您也可以使用 logger:i(HandlerName)
列印特定處理器的設定,或使用 logger:get_handler_config()
取得設定,或使用 logger:get_handler_config(HandlerName)
取得特定處理器的設定。
另請參閱
logger:i()
- 記錄使用者指南中的「設定」
設定 Logger
我的進度報告去哪裡了?
在 OTP-21 中,預設的主要日誌等級是 notice
。這表示預設情況下,許多日誌訊息不會列印。這包括監督者的進度報告。為了取得進度報告,您需要將主要日誌等級提高到 info
$ erl -kernel logger_level info
=PROGRESS REPORT==== 4-Nov-2019::16:33:11.742069 ===
application: kernel
started_at: nonode@nohost
=PROGRESS REPORT==== 4-Nov-2019::16:33:11.746546 ===
application: stdlib
started_at: nonode@nohost
Eshell V10.5.3 (abort with ^G)
1>
設定 Logger 格式器
為了更好地適應您現有的日誌記錄基礎架構,Logger 可以以您想要的任何方式格式化其日誌訊息。您可以選擇使用內建的格式器,也可以自行建構。
單行設定
由於單行記錄是內建格式器的預設值,您只需提供空映射作為設定。以下範例使用 sys.config
來變更格式器設定。
$ cat sys.config
[{kernel,
[{logger,
[{handler, default, logger_std_h,
#{ formatter => {logger_formatter, #{ }}}}]}]}].
$ erl -config sys
Eshell V10.5.1 (abort with ^G)
1> logger:error("Oh noes, an error").
1962-10-03T11:07:47.466763-04:00 error: Oh noes, an error
但是,如果您只想為目前的會期變更它,您也可以這樣做。
1> logger:set_handler_config(default, formatter, {logger_formatter, #{}}).
ok
2> logger:error("Oh noes, another error").
1962-10-04T15:34:02.648713-04:00 error: Oh noes, another error
另請參閱
將檔案和行號新增至日誌條目
您可以使用格式器範本來變更列印到日誌的內容
$ cat sys.config
[{kernel,
[{logger,
[{handler, default, logger_std_h,
#{ formatter => {logger_formatter,
#{ template => [time," ", file,":",line," ",level,": ",msg,"\n"] }}}}]}]}].
$ erl -config sys
Eshell V10.5.1 (abort with ^G)
1> logger:error("Oh noes, more errors",#{ file => "shell.erl", line => 1 }).
1962-10-05T07:37:44.104241+02:00 shell.erl:1 error: Oh noes, more errors
請注意,檔案和行號必須由 logger:log/3
的呼叫者新增至中繼資料中,否則 Logger 將不知道呼叫的位置。如果您使用 kernel/include/logger.hrl
中的 ?LOG_ERROR
巨集,則會自動新增檔案和行號。
另請參閱
設定處理器
將日誌列印到檔案
我們不將日誌列印到 stdout,而是將它們列印到輪換的檔案日誌。
$ cat sys.config
[{kernel,
[{logger,
[{handler, default, logger_std_h,
#{ config => #{ file => "log/erlang.log",
max_no_bytes => 4096,
max_no_files => 5},
formatter => {logger_formatter, #{}}}}]}]}].
$ erl -config sys
Eshell V10.5.1 (abort with ^G)
1> logger:error("Oh noes, even more errors").
ok
2> erlang:halt().
$ cat log/erlang.log
2019-10-07T11:47:16.837958+02:00 error: Oh noes, even more errors
另請參閱
logger_std_h
- 記錄使用者指南中的「處理器」
僅限偵錯的處理器
新增一個將 debug
日誌事件列印到檔案的處理器,而預設處理器只將最高 notice
等級的事件列印到標準輸出。
$ cat sys.config
[{kernel,
[{logger_level, all},
{logger,
[{handler, default, logger_std_h,
#{ level => notice }},
{handler, debug, logger_std_h,
#{ filters => [{debug,{fun logger_filters:level/2, {stop, neq, debug}}}],
config => #{ file => "log/debug.log" } }}
]}]}].
$ erl -config sys
Eshell V10.5.1 (abort with ^G)
1> logger:error("Oh noes, even more errors").
=ERROR REPORT==== 9-Oct-2019::14:40:54.784162 ===
Oh noes, even more errors
ok
2> logger:debug("A debug event").
ok
3> erlang:halt().
$ cat log/debug.log
2019-10-09T14:41:03.680541+02:00 debug: A debug event
在上面的設定中,我們首先將主要日誌等級提高到最高,以便偵錯日誌事件到達處理器。然後,我們將預設處理器設定為僅記錄 notice 和以下等級的事件,處理器的預設日誌等級是 all
。然後,使用篩選器設定偵錯處理器,以停止任何不是偵錯等級訊息的日誌訊息。
也可以使用 logger
模組在已執行的系統中進行相同的變更。然後,您可以這樣做
$ erl
1> logger:set_handler_config(default, level, notice).
ok
2> logger:add_handler(debug, logger_std_h, #{
filters => [{debug,{fun logger_filters:level/2, {stop, neq, debug}}}],
config => #{ file => "log/debug.log" } }).
ok
3> logger:set_primary_config(level, all).
ok
重要的是,在調整預設處理器的等級之前,請勿提高主要日誌等級,否則您的標準輸出可能會被偵錯日誌訊息淹沒。
另請參閱
logger_std_h
- 記錄使用者指南中的「篩選器」
記錄
要記錄什麼以及如何記錄
記錄某些內容的最簡單方法是使用 Logger 巨集,並向巨集提供報告。例如,如果您要記錄錯誤
?LOG_ERROR(#{ what => http_error, status => 418, src => ClientIP, dst => ServerIP }).
這會在預設日誌中列印以下內容
=ERROR REPORT==== 10-Oct-2019::12:13:10.089073 ===
dst: {8,8,4,4}
src: {8,8,8,8}
status: 418
what: http_error
如果您使用單行格式器,則會列印以下內容
2019-10-10T12:14:11.921843+02:00 error: dst: {8,8,4,4}, src: {8,8,8,8}, status: 418, what: http_error
另請參閱
- 記錄使用者指南中的「日誌訊息」
回呼報告和事件列印
如果您想進行結構化記錄,但仍然希望控制最終日誌訊息的格式,您可以在中繼資料中加入 report_cb
作為日誌事件的一部分。
ReportCB = fun(#{ what := What, status := Status, src := Src, dst := Dst }) ->
{ok, #hostent{ h_name = SrcName }} = inet:gethostbyaddr(Src),
{ok, #hostent{ h_name = DstName }} = inet:gethostbyaddr(Dst),
{"What: ~p~nStatus: ~p~nSrc: ~s (~s)~nDst: ~s (~s)~n",
[What, Status, inet:ntoa(Src), SrcName, inet:ntoa(Dst), DstName]}
end,
?LOG_ERROR(#{ what => http_error, status => 418, src => ClientIP, dst => ServerIP },
#{ report_cb => ReportCB }).
這會列印以下內容
=ERROR REPORT==== 10-Oct-2019::13:29:02.230863 ===
What: http_error
Status: 418
Src: 8.8.8.8 (dns.google)
Dst: 192.121.151.106 (erlang.org)
請注意,列印項目的順序已變更,而且我還新增了 IP 位址的反向 DNS 查詢。當使用單行格式器時,這不會列印得那麼漂亮,但是您也可以使用具有 2 個引數的 report_cb 函數,其中第二個引數是格式化選項。
另請參閱
- 記錄使用者指南中的「日誌訊息」
- Logger 回呼報告
篩選器
篩選器用於在日誌事件到達處理器之前移除或變更它們。
處理程序篩選器
如果我們只想要來自特定處理程序的偵錯訊息,則可以使用類似以下的篩選器來執行此操作
%% Initial setup to use a filter for the level filter instead of the primary level
PrimaryLevel = maps:get(level, logger:get_primary_config()),
ok = logger:add_primary_filter(primary_level,
{fun logger_filters:level/2, {log, gteq, PrimaryLevel}}),
logger:set_primary_config(filter_default, stop),
logger:set_primary_config(level, all),
%% Test that things work as they should
logger:notice("Notice should be logged"),
logger:debug("Should not be logged"),
%% Add the filter to allow PidToLog to send debug events
PidToLog = self(),
PidFilter = fun(LogEvent, _) when PidToLog =:= self() -> LogEvent;
(_LogEvent, _) -> ignore end,
ok = logger:add_primary_filter(pid, {PidFilter,[]}),
logger:debug("Debug should be logged").
需要進行一些設定,才能讓篩選器決定是否應該允許特定處理程序記錄。這是因為預設的主要日誌等級是 notice,並且在主要篩選器之前強制執行。因此,為了讓 pid 篩選器有用,我們必須將主要日誌等級提高到 all
,然後新增一個等級篩選器,該篩選器只讓 notice 或更高等級的某些訊息通過。完成設定後,可以輕鬆新增一個篩選器,允許特定的 pid 通過。
請注意,透過篩選器而不是透過等級進行主要日誌等級篩選的成本要高得多,因此請務必測試您的系統是否可以處理額外的負載,然後再在生產節點上啟用它。
另請參閱
網域
網域用於指定特定日誌事件的來源子系統。預設處理器預設只會記錄網域為 [otp]
或沒有網域的事件。如果您想將 SSL 日誌事件包含到預設處理器日誌中,您可以這樣做
1> logger:add_handler_filter(default,ssl_domain,
{fun logger_filters:domain/2,{log,sub,[otp,ssl]}}).
2> application:ensure_all_started(ssl).
{ok,[crypto,asn1,public_key,ssl]}
3> ssl:connect("www.erlang.org",443,[{log_level,debug}]).
%% lots of text