|
|
@ -12,34 +12,16 @@ trace相关代码整理 |
|
|
|
* 支持各种日志级别(debug、info、notice、warning、error、critical、alert、emergency) |
|
|
|
* 使用解析转换进行转换,以允许捕获 Module/Function/Line/Pid 等信息 |
|
|
|
* 当没有处理程序正在使用日志级别时(例如。没有事件被发送到日志处理器 |
|
|
|
* 支持多个后端(backends), 包括控制台和文件 |
|
|
|
* 支持多个后端(bkds), 包括控制台和文件 |
|
|
|
* 支持多个接收器(sinks) |
|
|
|
* 将常见的OTP错误消息改写为更易读的消息 |
|
|
|
* 支持在编译时遇到的漂亮打印record |
|
|
|
* 在面对较大或较多的日志消息时,不会出现节点内存不足的情况 |
|
|
|
* 绕过日志大小截断的可选特性("unsafe") |
|
|
|
* 支持内部时间和日期旋转,以及外部旋转工具 |
|
|
|
* Syslog style日志级别比较标志 |
|
|
|
* 彩色的终端输出 |
|
|
|
* 可选负载削减设置高水位线杀死(并重新安装)后,可配置冷却定时器的接收器(sinks) |
|
|
|
* 重写term 格式化函数,这样更有效率 |
|
|
|
|
|
|
|
使用 |
|
|
|
----- |
|
|
|
在应用程序中使用eLog,需要将其定义为rebar dep,或者使用其他方法将其包含在Erlang的dep路径中。然后添加下面的编译选项: |
|
|
|
|
|
|
|
|
|
|
|
在记录任何消息之前,您需要启动eLog应用程序。eLog模块的start函数负责启动 加载并启动eLog需要的任何依赖项 |
|
|
|
|
|
|
|
```erlang |
|
|
|
eLog:start(). |
|
|
|
``` |
|
|
|
|
|
|
|
配置选项 |
|
|
|
------------- |
|
|
|
要配置eLog的后端,你需要使用一个应用程序变量(可能在app.config中): |
|
|
|
|
|
|
|
每个后端可用的配置选项都列在它们的模块文档中。 |
|
|
|
* 重写日志的format函数,这样更有效率 |
|
|
|
|
|
|
|
接受器(Sinks) |
|
|
|
----- |
|
|
@ -48,69 +30,45 @@ eLog传统上支持名为`eLogEmm`的单一接收器(sink)(实现为`gen_emm`管 |
|
|
|
|
|
|
|
### 接收器的配置 |
|
|
|
|
|
|
|
要使用多个接收器(超出lager和lager_event的内置接收器),您需要: |
|
|
|
要使用多个接收器(超出eLog和eLog_event的内置接收器),您需要: |
|
|
|
|
|
|
|
1. 设置rebar.config |
|
|
|
2. 在app.config中配置后端 |
|
|
|
|
|
|
|
#### 名字 |
|
|
|
|
|
|
|
每个接收器都有两个名称:一个原子类似于模块名用作发送消息,而该原子后面附加`_lager_event`后面附加用于后端配置。 |
|
|
|
|
|
|
|
这反映了旧的行为:lager:info,critical或debug等)是一种将消息发送到名为`lager_event`的接收器。 现在开发人员可以调用`audit:info`或`myCompanyName:debug` |
|
|
|
只要对应的`audit_lager_event`或`myCompanyName_lager_event`接收器已配置。 |
|
|
|
|
|
|
|
#### rebar.config |
|
|
|
|
|
|
|
include a list of sink names (without the `_lager_event` suffix) in `erl_opts`: |
|
|
|
`{lager_extra_sinks, [audit]}` |
|
|
|
|
|
|
|
#### Runtime requirements |
|
|
|
|
|
|
|
To be useful, sinks must be configured at runtime with backends. |
|
|
|
|
|
|
|
In `app.config` for the project that requires lager, for example, extend the lager configuration to include |
|
|
|
an `extraSinks` tuple with backends (aka "handlers") and optionally `asyncThreshold` and |
|
|
|
`asyncThrWindow` values (see **Overload Protection** |
|
|
|
below). If async values are not configured, no overload protection will be applied on that sink. |
|
|
|
|
|
|
|
```erlang |
|
|
|
[{eLog, [ |
|
|
|
{logRoot, "/tmp"}, |
|
|
|
%% Default handlers for lager/lager_event |
|
|
|
{handlers, [ |
|
|
|
{lager_console_backend, [{level, info}]}, |
|
|
|
{lager_file_backend, [{file, "error.log"}, {level, error}]}, |
|
|
|
{lager_file_backend, [{file, "console.log"}, {level, info}]} |
|
|
|
]}, |
|
|
|
|
|
|
|
%% Any other sinks |
|
|
|
{extraSinks, [ |
|
|
|
{audit_lager_event,[{handlers, [{lager_file_backend, [{file, "sink1.log"}, {level, info}]}]}, {asyncThreshold, 500}, {asyncThrWindow, 50}]} |
|
|
|
|
|
|
|
]} |
|
|
|
|
|
|
|
{logRoot, "/tmp"}, |
|
|
|
%% Default handlers for eLog |
|
|
|
{handlers, [ |
|
|
|
{lgBkdConsole, [{level, info}]}, |
|
|
|
{lgBkdFile, [{file, "error.log"}, {level, error}]}, |
|
|
|
{lgBkdFile, [{file, "console.log"}, {level, info}]} |
|
|
|
]}, |
|
|
|
|
|
|
|
%% Any other sinks |
|
|
|
{extraSinks, [ |
|
|
|
{auditLgEvent, [{handlers, [{lgBkdFile, [{file, "sink1.log"}, {level, info}]}]}, {asyncThreshold, 500}, {asyncThrWindow, 50}]} |
|
|
|
]} |
|
|
|
]}]. |
|
|
|
``` |
|
|
|
|
|
|
|
自定义格式 |
|
|
|
----------------- |
|
|
|
All loggers have a default formatting that can be overriden. A fmtTer is any module that |
|
|
|
exports `format(#lager_log_message{},Config#any())`. It is specified as part of the configuration for the backend: |
|
|
|
exports `format(#lgMsg{}, Config#any())`. It is specified as part of the configuration for the backend: |
|
|
|
|
|
|
|
```erlang |
|
|
|
{eLog, [ |
|
|
|
{handlers, [ |
|
|
|
{lager_console_backend, [{level, info}, {fmtTer, lager_default_formatter}, |
|
|
|
{fmtCfg, [time, " [",severity, "] ", message, "\n"]}]}, |
|
|
|
{lager_file_backend, [{file, "error.log"}, {level, error}, {fmtTer, lager_default_formatter}, |
|
|
|
{fmtCfg, [date, " ", time, " [", severity, "] ",pid, " ", message, "\n"]}]}, |
|
|
|
{lager_file_backend, [{file, "console.log"}, {level, info}]} |
|
|
|
{lgBkdConsole, [{level, info}, {fmtTer, lgFmtTer},{fmtCfg, [time, " [",severity, "] ", message, "\n"]}]}, |
|
|
|
{lgBkdFile, [{file, "error.log"}, {level, error}, {fmtTer, lgFmtTer}, {fmtCfg, [date, " ", time, " [", severity, "] ",pid, " ", message, "\n"]}]}, |
|
|
|
{lgBkdFile, [{file, "console.log"}, {level, info}]} |
|
|
|
]} |
|
|
|
]}. |
|
|
|
``` |
|
|
|
|
|
|
|
包括lager_default_formatter。这使用类似于Erlang的iolist的结构(称为“ semi-iolist”)为日志消息提供了一种通用的默认格式 : |
|
|
|
包括lgFmtTer。这使用类似于Erlang的iolist的结构(称为“ semi-iolist”)为日志消息提供了一种通用的默认格式 : |
|
|
|
|
|
|
|
配置中的任何传统iolist元素均按原样打印。 配置中的原子被视为较大元数据的占位符,并从日志消息中提取。 占位符date,time,message,sev并severity会一直存在。 |
|
|
|
sev是缩写的严重性,它被解释为严重性级别的大写单字母编码(例如'debug'-> $D) 占位符pid,file,line,module,function,和node 永远如果使用解析变换存在。 |
|
|
@ -133,10 +91,10 @@ Examples: |
|
|
|
|
|
|
|
错误记录器集成 |
|
|
|
------------------------ |
|
|
|
error_logger贮藏啤酒还提供了一个处理程序模块,该模块将传统的erlang错误消息转换为更友好的格式,并将其发送到贮藏啤酒中,以像常规贮藏啤酒日志调用一样对待。 |
|
|
|
要禁用此功能,请将更大的应用程序变量设置error_logger_redirect为false。您也可以通过设置变量OTP和牛仔消息禁用重新格式化 errLoggerFmtRaw 为 true。 |
|
|
|
error_logger eLog还提供了一个处理程序模块,该模块将传统的erlang错误消息转换为更友好的格式,并将其发送到贮藏啤酒中,以像常规贮藏啤酒日志调用一样对待。 |
|
|
|
要禁用此功能,请将更大的应用程序变量设置errLoggerRedirect为false。您也可以通过设置变量OTP和牛仔消息禁用重新格式化 errLoggerFmtRaw 为 true。 |
|
|
|
|
|
|
|
如果您将自己的处理程序安装到中error_logger,则可以通过使用error_logger_whitelist环境变量和允许的处理程序列表来告诉lager使其不被处理。 |
|
|
|
如果您将自己的处理程序安装到中error_logger,则可以通过使用errLoggerWhitelist环境变量和允许的处理程序列表来告诉eLog使其不被处理。 |
|
|
|
|
|
|
|
``` |
|
|
|
{errLoggerWhitelist, [my_handler]} |
|
|
@ -146,19 +104,18 @@ error_logger贮藏啤酒还提供了一个处理程序模块,该模块将传 |
|
|
|
|
|
|
|
崩溃日志中的消息受最大消息大小的限制,可以通过crashLogMsgSize应用程序变量指定最大消息大小。 |
|
|
|
|
|
|
|
如果已定义来自的消息,error_logger则将其重定向到接收error_logger_lager_event器,以便可以将其重定向到另一个日志文件。 |
|
|
|
如果已定义来自的消息,error_logger则将其重定向到接收器lgErrLoggerH,以便可以将其重定向到另一个日志文件。 |
|
|
|
|
|
|
|
例如: |
|
|
|
|
|
|
|
``` |
|
|
|
[{lager, [ |
|
|
|
[{eLog, [ |
|
|
|
{extraSinks, |
|
|
|
[ |
|
|
|
{error_logger_lager_event, |
|
|
|
[{handlers, [ |
|
|
|
{lager_file_backend, [{file, "error_logger.log"}, {level, info}]}] |
|
|
|
}] |
|
|
|
}] |
|
|
|
{error_logger_event, |
|
|
|
[{handlers, [ |
|
|
|
{lgBkdFile, [{file, "error_logger.log"}, {level, info}]}]}] |
|
|
|
}] |
|
|
|
}] |
|
|
|
}]. |
|
|
|
``` |
|
|
@ -170,7 +127,7 @@ will send all `error_logger` messages to `error_logger.log` file. |
|
|
|
|
|
|
|
### 异步模式 |
|
|
|
|
|
|
|
在Lager 2.0之前,Lagergen_event的核心纯粹是在同步模式下运行。异步模式速度更快,但是无法防止消息队列过载。从更大的2.0开始,gen_event采用了一种混合方法。 |
|
|
|
在eLog 2.0之前,eLog的核心纯粹是在同步模式下运行。异步模式速度更快,但是无法防止消息队列过载。从更大的2.0开始,gen_event采用了一种混合方法。 |
|
|
|
它轮询自己的邮箱大小,并根据邮箱大小在同步和异步之间切换消息传递。 |
|
|
|
|
|
|
|
```erlang |
|
|
@ -202,7 +159,7 @@ or for a specific sink, using the option: |
|
|
|
{flushQueue, true | false} |
|
|
|
``` |
|
|
|
|
|
|
|
如果flush_queue为true,则可以设置消息队列长度阈值,在该阈值处将开始丢弃消息。默认阈值为0,这意味着如果flush_queue为true,则超过高水位标记时将丢弃消息,而不管消息队列的长度如何。用于控制阈值的选项是error_logger: |
|
|
|
如果flushQueue为true,则可以设置消息队列长度阈值,在该阈值处将开始丢弃消息。默认阈值为0,这意味着如果flushQueue为true,则超过高水位标记时将丢弃消息,而不管消息队列的长度如何。用于控制阈值的选项是error_logger: |
|
|
|
|
|
|
|
```erlang |
|
|
|
{errLoggerFlushThr, 1000} |
|
|
@ -226,33 +183,30 @@ and for sinks: |
|
|
|
``` |
|
|
|
|
|
|
|
这意味着,如果接收器的邮箱大小超过1000条消息,请杀死整个接收器并在5000毫秒后重新加载它。如果需要,此行为也可以安装到其他水槽中。 |
|
|
|
默认情况下,管理器杀手未安装到任何接收器中。如果killer_reinstall_after未指定冷却时间,则默认为5000。 |
|
|
|
默认情况下,管理器杀手未安装到任何接收器中。如果killerReTime未指定冷却时间,则默认为5000。 |
|
|
|
|
|
|
|
"不安全" |
|
|
|
-------- |
|
|
|
不安全的代码路径会绕过普通的啤酒格式代码,并使用与OTP中的error_logger相同的代码。这可以稍微提高您的日志记录代码的速度(在基准测试期间,我们测得的改进幅度为0.5-1.3%;其他报告的改进则更好。) |
|
|
|
不安全的代码路径会绕过普通的格式代码,并使用与OTP中的error_logger相同的代码。这可以稍微提高您的日志记录代码的速度(在基准测试期间,我们测得的改进幅度为0.5-1.3%;其他报告的改进则更好。) |
|
|
|
这是一个危险的功能。它不会保护您免受大型日志消息的侵害-大型消息可能会杀死您的应用程序,甚至由于内存耗尽而导致Erlang VM死机,因为在故障级联中反复复制大量术语。我们强烈建议此代码路径仅用于上限大小约为500字节的有边界的日志消息。 |
|
|
|
如果日志消息有可能超过该限制,则应使用常规的更大的消息格式化代码,该代码将提供适当的大小限制并防止内存耗尽。 如果要格式化不安全的日志消息,则可以使用严重性级别(照常),然后使用_unsafe。这是一个例子: |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:info_unsafe("The quick brown ~s jumped over the lazy ~s", ["fox", "dog"]). |
|
|
|
``` |
|
|
|
|
|
|
|
运行时日志级别更改 |
|
|
|
------------------------ |
|
|
|
您可以通过执行以下操作在运行时更改任何大型后端的日志级别: |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:set_loglevel(lager_console_backend, debug). |
|
|
|
eLog:setLoglevel(lgBkdFileConsole, debug). |
|
|
|
``` |
|
|
|
|
|
|
|
Or, for the backend with multiple handles (files, mainly): |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:set_loglevel(lager_file_backend, "console.log", debug). |
|
|
|
eLog:setLoglevel(lgBkdFile, "console.log", debug). |
|
|
|
``` |
|
|
|
|
|
|
|
Lager会跟踪任何后端使用的最低日志级别,并禁止生成低于该级别的消息。这意味着当没有后端使用调试消息时,调试日志消息实际上是免费的。一个简单的基准测试,它可以在不超过最小阈值的情况下完成一百万条调试日志消息,而所需时间不到半秒。 |
|
|
|
eLog会跟踪任何后端使用的最低日志级别,并禁止生成低于该级别的消息。这意味着当没有后端使用调试消息时,调试日志消息实际上是免费的。一个简单的基准测试,它可以在不超过最小阈值的情况下完成一百万条调试日志消息,而所需时间不到半秒。 |
|
|
|
|
|
|
|
Syslog样式日志级别比较标志 |
|
|
|
-------------------------------------- |
|
|
@ -314,88 +268,16 @@ See the `.app.src` file for further details. |
|
|
|
|
|
|
|
自定义日志轮换 |
|
|
|
------------------- |
|
|
|
Custom log rotator could be configured with option for `lager_file_backend` |
|
|
|
|
|
|
|
```erlang |
|
|
|
{rotator, lager_rotator_default} |
|
|
|
``` |
|
|
|
|
|
|
|
The module should provide the following callbacks as `lager_rotator_behaviour` |
|
|
|
|
|
|
|
```erlang |
|
|
|
%% @doc Create a log file |
|
|
|
-callback(createLogFile(Name :: list(), Buffer :: {integer(), integer()} | any()) -> |
|
|
|
{ok, {FD :: file:io_device(), Inode :: integer(), Size :: integer()}} | {error, any()}). |
|
|
|
|
|
|
|
%% @doc Open a log file |
|
|
|
-callback(openLogFile(Name :: list(), Buffer :: {integer(), integer()} | any()) -> |
|
|
|
{ok, {FD :: file:io_device(), Inode :: integer(), Size :: integer()}} | {error, any()}). |
|
|
|
|
|
|
|
%% @doc Ensure reference to current target, could be rotated |
|
|
|
-callback(ensureLogFile(Name :: list(), FD :: file:io_device(), Inode :: integer(), |
|
|
|
Buffer :: {integer(), integer()} | any()) -> |
|
|
|
{ok, {FD :: file:io_device(), Inode :: integer(), Size :: integer()}} | {error, any()}). |
|
|
|
|
|
|
|
%% @doc Rotate the log file |
|
|
|
-callback(rotateLogFile(Name :: list(), Count :: integer()) -> |
|
|
|
ok). |
|
|
|
``` |
|
|
|
|
|
|
|
系统日志支持 |
|
|
|
-------------- |
|
|
|
Lager syslog输出作为单独的应用程序提供: lager_syslog。它被打包为一个单独的应用程序,因此更大的啤酒本身并不间接依赖于端口驱动程序。请参阅lager_syslog自述文件以获取配置信息。 |
|
|
|
|
|
|
|
其他后端 |
|
|
|
-------------- |
|
|
|
There are lots of them! Some connect log messages to AMQP, various logging analytic |
|
|
|
services ([bunyan](https://github.com/Vagabond/lager_bunyan_formatter), |
|
|
|
[loggly](https://github.com/kivra/lager_loggly), etc), and |
|
|
|
more. [Looking on hex](https://hex.pm/packages?_utf8=✓&search=lager&sort=recent_downloads) or using "lager BACKEND" |
|
|
|
where "BACKEND" is your preferred log solution on your favorite search engine is a good starting point. |
|
|
|
|
|
|
|
异常漂亮的印刷 |
|
|
|
---------------------- |
|
|
|
Up to OTP 20: |
|
|
|
|
|
|
|
```erlang |
|
|
|
try |
|
|
|
foo() |
|
|
|
catch |
|
|
|
Class:Reason -> |
|
|
|
lager:error( |
|
|
|
"~nStacktrace:~s", |
|
|
|
[lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})]) |
|
|
|
end . |
|
|
|
``` |
|
|
|
|
|
|
|
On OTP 21+: |
|
|
|
|
|
|
|
```erlang |
|
|
|
try |
|
|
|
foo() |
|
|
|
catch |
|
|
|
Class:Reason:Stacktrace -> |
|
|
|
lager:error( |
|
|
|
"~nStacktrace:~s", |
|
|
|
[lager:pr_stacktrace(Stacktrace, {Class, Reason})]) |
|
|
|
end . |
|
|
|
``` |
|
|
|
|
|
|
|
记录漂亮的印刷 |
|
|
|
---------------------- |
|
|
|
Lager的parse转换将跟踪其遇到的任何记录定义,并将它们存储在模块的属性中。然后,您可以在运行时通过使用lager:pr/2函数来打印任何记录,该记录是使用较大的parse转换编译的模块所知道的,该 函数接受记录和知道该记录的模块: |
|
|
|
`lager:pr/2` function, which takes the record and the module that knows about the record: |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:info("My state is ~p", [lager:pr(State, ?MODULE)]) |
|
|
|
{rotator, lgRotatorIns} |
|
|
|
``` |
|
|
|
The module should provide the following callbacks as `lgRotatorExm` |
|
|
|
|
|
|
|
Often, `?MODULE` is sufficent, but you can obviously substitute that for a literal module name. |
|
|
|
`lager:pr` also works from the shell. |
|
|
|
|
|
|
|
彩色端子输出 |
|
|
|
----------------------- |
|
|
|
If you have Erlang R16 or higher, you can tell lager's console backend to be colored. Simply add to lager's application |
|
|
|
If you have Erlang R16 or higher, you can tell eLog's console backend to be colored. Simply add to eLog's application |
|
|
|
environment config: |
|
|
|
|
|
|
|
```erlang |
|
|
@ -407,7 +289,7 @@ If you don't like the default colors, they are also configurable; see the `.app. |
|
|
|
The output will be colored from the first occurrence of the atom color in the formatting configuration. For example: |
|
|
|
|
|
|
|
```erlang |
|
|
|
{lager_console_backend, [{level, info}, {fmtTer, lager_default_formatter}, |
|
|
|
{lgBkdConsole, [{level, info}, {fmtTer, lgFmtTer}, |
|
|
|
{fmtCfg, [time, color, " [", severity, "] ", message, "\e[0m\r\n"]}]]} |
|
|
|
``` |
|
|
|
|
|
|
@ -416,51 +298,51 @@ order to reset the color after each log message. |
|
|
|
|
|
|
|
Tracing |
|
|
|
------- |
|
|
|
Lager支持基于日志消息属性重定向日志消息的基本支持。啤酒会自动在日志消息呼叫站点捕获pid,模块,功能和行。但是,您可以添加所需的任何其他属性: |
|
|
|
eLog支持基于日志消息属性重定向日志消息的基本支持。啤酒会自动在日志消息呼叫站点捕获pid,模块,功能和行。但是,您可以添加所需的任何其他属性: |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:warning([{request, RequestID}, {vhost, Vhost}], "Permission denied to ~s", [User]) |
|
|
|
eLog:warning([{request, RequestID}, {vhost, Vhost}], "Permission denied to ~s", [User]) |
|
|
|
``` |
|
|
|
|
|
|
|
然后,除了默认的跟踪属性外,您还可以基于请求或虚拟主机进行跟踪: |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:trace_file("logs/example.com.error", [{vhost, "example.com"}], error) |
|
|
|
eLog:trace_file("logs/example.com.error", [{vhost, "example.com"}], error) |
|
|
|
``` |
|
|
|
|
|
|
|
要在过程的整个生命周期中保留元数据,可以使用lager:md/1将元数据存储在过程字典中: |
|
|
|
要在过程的整个生命周期中保留元数据,可以使用eLog:md/1将元数据存储在过程字典中: |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:md([{zone, forbidden}]) |
|
|
|
eLog:md([{zone, forbidden}]) |
|
|
|
``` |
|
|
|
|
|
|
|
请注意,lager:md将仅接受由原子键控的键/值对的列表。 您也可以省略最后一个参数,日志级别默认为 debug。 跟踪到控制台是类似的: |
|
|
|
请注意,eLog:md将仅接受由原子键控的键/值对的列表。 您也可以省略最后一个参数,日志级别默认为 debug。 跟踪到控制台是类似的: |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:trace_console([{request, 117}]) |
|
|
|
eLog:trace_console([{request, 117}]) |
|
|
|
``` |
|
|
|
|
|
|
|
在上面的示例中,省略了日志级别,但是如果需要,可以将其指定为第二个参数。 您还可以在过滤器中指定多个表达式,或将*原子用作通配符以匹配具有该属性的任何消息,而不管其值如何。您也可以使用特殊值!来表示,仅在不存在此键的情况下才选择。 |
|
|
|
还支持跟踪到现有日志文件(但请参阅下面的“多接收器支持”): |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:trace_file("log/error.log", [{module, mymodule}, {function, myfunction}], warning) |
|
|
|
eLog:trace_file("log/error.log", [{module, mymodule}, {function, myfunction}], warning) |
|
|
|
``` |
|
|
|
|
|
|
|
要查看活动的日志后端和跟踪,可以使用该lager:status() 功能。要清除所有活动迹线,可以使用lager:clear_all_traces()。 |
|
|
|
要查看活动的日志后端和跟踪,可以使用该eLog:status() 功能。要清除所有活动迹线,可以使用eLog:clear_all_traces()。 |
|
|
|
|
|
|
|
要删除特定跟踪,请在创建跟踪时存储该跟踪的句柄,然后将其传递给lager:stop_trace/1: to `lager:stop_trace/1`: |
|
|
|
要删除特定跟踪,请在创建跟踪时存储该跟踪的句柄,然后将其传递给eLog:stop_trace/1: to `eLog:stop_trace/1`: |
|
|
|
|
|
|
|
```erlang |
|
|
|
{ok, Trace} = lager:trace_file("log/error.log", [{module, mymodule}]), |
|
|
|
{ok, Trace} = eLog:trace_file("log/error.log", [{module, mymodule}]), |
|
|
|
... |
|
|
|
lager:stop_trace(Trace) |
|
|
|
eLog:stop_trace(Trace) |
|
|
|
``` |
|
|
|
|
|
|
|
跟踪到pid有点特殊情况,因为pid并不是序列化良好的数据类型。要按pid进行跟踪,请使用pid作为字符串: |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:trace_console([{pid, "<0.410.0>"}]) |
|
|
|
eLog:trace_console([{pid, "<0.410.0>"}]) |
|
|
|
``` |
|
|
|
|
|
|
|
### 过滤表达式 |
|
|
@ -475,7 +357,7 @@ lager:trace_console([{pid, "<0.410.0>"}]) |
|
|
|
* `>=` - greater than or equal |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:trace_console([{request, '>', 117}, {request, '<', 120}]) |
|
|
|
eLog:trace_console([{request, '>', 117}, {request, '<', 120}]) |
|
|
|
``` |
|
|
|
|
|
|
|
Using `=` is equivalent to the 2-tuple form. |
|
|
@ -485,7 +367,7 @@ Using `=` is equivalent to the 2-tuple form. |
|
|
|
作为啤酒3.3.1,你也可以使用的特殊滤光器构成键 all或any。例如,上面的过滤器示例可以表示为: |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:trace_console([{all, [{request, '>', 117}, {request, '<', 120}]}]) |
|
|
|
eLog:trace_console([{all, [{request, '>', 117}, {request, '<', 120}]}]) |
|
|
|
``` |
|
|
|
|
|
|
|
any在过滤器之间具有“或样式”逻辑评估的效果;all 表示过滤器之间的“ AND样式”逻辑评估。这些合成过滤器期望附加过滤器表达式的列表作为它们的值。 |
|
|
@ -499,29 +381,29 @@ any在过滤器之间具有“或样式”逻辑评估的效果;all 表示过 |
|
|
|
如果使用多个接收器,则应注意跟踪的限制。 跟踪特定于接收器,可以通过跟踪过滤器进行指定: |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:trace_file("log/security.log", [{sink, audit_event}, {function, myfunction}], warning) |
|
|
|
eLog:trace_file("log/security.log", [{sink, audit_event}, {function, myfunction}], warning) |
|
|
|
``` |
|
|
|
|
|
|
|
如果未指定接收器,则将使用默认的更大接收器。 |
|
|
|
|
|
|
|
这有两个后果: |
|
|
|
|
|
|
|
跟踪无法拦截发送到其他接收器的消息。 lager:trace_file仅当指定了相同的接收器时,才能跟踪到已经通过打开的文件。 可以通过打开多条迹线来改善前者。后者可以通过重新配置更大的文件后端来解决,但尚未解决。 |
|
|
|
跟踪无法拦截发送到其他接收器的消息。 eLog:trace_file仅当指定了相同的接收器时,才能跟踪到已经通过打开的文件。 可以通过打开多条迹线来改善前者。后者可以通过重新配置更大的文件后端来解决,但尚未解决。 |
|
|
|
|
|
|
|
### 配置跟踪 |
|
|
|
|
|
|
|
Lager支持从其配置文件启动跟踪。定义它们的关键字是traces,其后是一个元组属性列表,该元组定义了后端处理程序和必需列表中的零个或多个过滤器,后跟一个可选的消息严重性级别。 |
|
|
|
eLog支持从其配置文件启动跟踪。定义它们的关键字是traces,其后是一个元组属性列表,该元组定义了后端处理程序和必需列表中的零个或多个过滤器,后跟一个可选的消息严重性级别。 |
|
|
|
|
|
|
|
一个例子看起来像这样: |
|
|
|
|
|
|
|
```erlang |
|
|
|
{lager, [ |
|
|
|
{eLog, [ |
|
|
|
{handlers, [...]}, |
|
|
|
{traces, [ |
|
|
|
%% handler, filter, message level (defaults to debug if not given) |
|
|
|
{lager_console_backend, [{module, foo}], info}, |
|
|
|
{{lager_file_backend, "trace.log"}, [{request, '>', 120}], error}, |
|
|
|
{{lager_file_backend, "event.log"}, [{module, bar}]} %% implied debug level here |
|
|
|
{lgBkdConsole, [{module, foo}], info}, |
|
|
|
{{lgBkdFile, "trace.log"}, [{request, '>', 120}], error}, |
|
|
|
{{lgBkdFile, "event.log"}, [{module, bar}]} %% implied debug level here |
|
|
|
]} |
|
|
|
]}. |
|
|
|
``` |
|
|
@ -534,26 +416,11 @@ Lager支持从其配置文件启动跟踪。定义它们的关键字是traces, |
|
|
|
|
|
|
|
在编译时设置动态元数据 |
|
|
|
---------------------------------------- |
|
|
|
Lager支持通过注册回调函数从外部源提供元数据。即使进程死亡,该元数据也将在整个进程中保持不变。 |
|
|
|
eLog支持通过注册回调函数从外部源提供元数据。即使进程死亡,该元数据也将在整个进程中保持不变。 |
|
|
|
|
|
|
|
通常,您不需要使用此功能。但是,它在以下情况下很有用: |
|
|
|
|
|
|
|
seq_trace提供的跟踪信息 有关您的应用程序的上下文信息 默认占位符未提供的持久性信息 在每次记录调用之前必须设置元数据的情况 您可以使用{lager_parse_transform_functions, X} |
|
|
|
选项添加回调。仅在使用时可用parse_transform。在钢筋中,您可以将其添加erl_opts如下: |
|
|
|
|
|
|
|
```erlang |
|
|
|
{erl_opts, [{parse_transform, lager_transform}, |
|
|
|
{lager_function_transforms, |
|
|
|
[ |
|
|
|
%% Placeholder Resolve type Callback tuple |
|
|
|
{metadata_placeholder, on_emit, {module_name, function_name}}, |
|
|
|
{other_metadata_placeholder, on_log, {module_name, function_name}} |
|
|
|
]}]}. |
|
|
|
``` |
|
|
|
|
|
|
|
第一个原子是用于自定义格式化程序中的替换的占位符原子。有关更多信息,请参见自定义格式。 |
|
|
|
|
|
|
|
第二个原子是解析类型。此参数指定要在发出消息时或在记录调用时解决的回调。您必须指定atomon_emit或on_log。没有要使用的“正确”解析类型,因此请阅读每种的用法/注意事项,然后选择最适合您要求的选项。 |
|
|
|
seq_trace提供的跟踪信息 有关您的应用程序的上下文信息 默认占位符未提供的持久性信息 |
|
|
|
|
|
|
|
on_emit: |
|
|
|
|
|
|
@ -619,25 +486,14 @@ seq_trace() -> |
|
|
|
|
|
|
|
在编译时设置截断限制 |
|
|
|
-------------------------------------------- |
|
|
|
Lager默认将消息截断为4096字节,您可以使用该{lager_truncation_size, X}选项进行更改。在钢筋中,您可以将其添加到 erl_opts: |
|
|
|
`erl_opts`: |
|
|
|
|
|
|
|
```erlang |
|
|
|
{erl_opts, [{parse_transform, lager_transform}, {lager_truncation_size, 1024}]}. |
|
|
|
``` |
|
|
|
|
|
|
|
You can also pass it to `erlc`, if you prefer: |
|
|
|
|
|
|
|
``` |
|
|
|
erlc -pa lager/ebin +'{parse_transform, lager_transform}' +'{lager_truncation_size, 1024}' file.erl |
|
|
|
``` |
|
|
|
eLog默认将消息截断为4096字节,您可以使用该{eLog_truncation_size, X}选项进行更改。在钢筋中,您可以将其添加到 erl_opts: |
|
|
|
|
|
|
|
禁止应用程序和主管启动/停止日志 |
|
|
|
----------------------------------------------------- |
|
|
|
如果您不想在应用程序的调试级别看到主管和应用程序启动/停止日志,则可以使用以下配置将其关闭: |
|
|
|
|
|
|
|
```erlang |
|
|
|
{lager, [{suppressAppStartStop, true}, |
|
|
|
{eLog, [{suppressAppStartStop, true}, |
|
|
|
{suppressSupStartStop, true}]} |
|
|
|
``` |
|
|
|
|
|
|
@ -646,13 +502,13 @@ erlc -pa lager/ebin +'{parse_transform, lager_transform}' +'{lager_truncation_si |
|
|
|
贮藏啤酒提供了一种使用sys“调试功能”的集成方式。您可以通过执行以下操作在目标进程中安装调试功能: |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:install_trace(Pid, notice). |
|
|
|
eLog:install_trace(Pid, notice). |
|
|
|
``` |
|
|
|
|
|
|
|
You can also customize the tracing somewhat: |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:install_trace(Pid, notice, [{count, 100}, {timeout, 5000}, {format_string, "my trace event ~p ~p"]}). |
|
|
|
eLog:install_trace(Pid, notice, [{count, 100}, {timeout, 5000}, {format_string, "my trace event ~p ~p"]}). |
|
|
|
``` |
|
|
|
|
|
|
|
跟踪选项当前为: |
|
|
@ -663,13 +519,13 @@ lager:install_trace(Pid, notice, [{count, 100}, {timeout, 5000}, {format_string, |
|
|
|
完成以下操作后,您可以删除跟踪: |
|
|
|
|
|
|
|
```erlang |
|
|
|
lager:remove_trace(Pid). |
|
|
|
eLog:remove_trace(Pid). |
|
|
|
``` |
|
|
|
|
|
|
|
If you want to start an OTP process with tracing enabled from the very beginning, you can do something like this: |
|
|
|
|
|
|
|
```erlang |
|
|
|
gen_server:start_link(mymodule, [], [{debug, [{install, {fun lager:trace_func/3, lager:trace_state(undefined, notice, [])}}]}]). |
|
|
|
gen_server:start_link(mymodule, [], [{debug, [{install, {fun eLog:trace_func/3, eLog:trace_state(undefined, notice, [])}}]}]). |
|
|
|
``` |
|
|
|
|
|
|
|
trace_state函数的第三个参数是上面记录的“选项”列表。 |
|
|
@ -683,9 +539,9 @@ ID}以允许通过nodetool远程跟踪节点以进行标准输出: |
|
|
|
```erlang |
|
|
|
GL = erlang:group_leader(), |
|
|
|
Node = node(GL), |
|
|
|
lager_app:start_handler(lager_event, {lager_console_backend, Node}, |
|
|
|
[{group_leader, GL}, {level, none}, {id, {lager_console_backend, Node}}]), |
|
|
|
case lager:trace({lager_console_backend, Node}, Filter, Level) of |
|
|
|
eLog_app:start_handler(eLog_event, {eLog_console_backend, Node}, |
|
|
|
[{group_leader, GL}, {level, none}, {id, {eLog_console_backend, Node}}]), |
|
|
|
case eLog:trace({eLog_console_backend, Node}, Filter, Level) of |
|
|
|
... |
|
|
|
``` |
|
|
|
|
|
|
|