- 浏览: 39094 次
- 来自: 深圳
文章分类
最新评论
-
ZacMa:
哈哈,突然感觉里面没怎么介绍,全是贴代码了
<8>redis及erl-redis阅读 -
惊涛翻案:
马博士,给我开课吧
<8>redis及erl-redis阅读
erlang中日志管理主要有error_loggger 模块,这个模块在系统启动时候就会启动,不过要自己配置是如何管理,整个管理是通过gen_event来注册事件来管理的
常用的
erl -kernel error_logger tty
erl -kernel error_logger false
erl -kernel error_loggger silent
erl -kernel error_logger \{file,\"filename\"\}
这几种方法,tyy是打印终端,false是默认,也是终端,silent是什么也不做,file是写到日志文件,看代码
start_link() ->
case gen_event:start_link({local, error_logger}) of
{ok, Pid} ->
simple_logger(?buffer_size),
{ok, Pid};
Error -> Error
end.
simple_logger(Buffer_size) when is_integer(Buffer_size) ->
gen_event:add_handler(error_logger, error_logger, Buffer_size).
就是将自己error_logger模块设置为handler;
当用户调用函数info_msg/2, error_msg/2 如何呢?
info_msg(Format, Args) ->
notify({info_msg, group_leader(), {self(), Format, Args}}).
notify(Msg) ->
gen_event:notify(error_logger, Msg).
handle_event(Event, State) ->
handle_event2(Event, State).
handle_event2(Event, {1, Lost, Buff}) ->
display(tag_event(Event)),
{ok, {1, Lost+1, Buff}};
handle_event2(Event, {N, Lost, Buff}) ->
Tagged = tag_event(Event),
display(Tagged),
{ok, {N-1, Lost, [Tagged|Buff]}};
handle_event2(_, State) ->
{ok, State}.
最后调用dispaly就是显示了,就是把信息格式化输出
那么是如何将信息输出到文件,或者干脆就不输出呢,
在启动的过程中,kernel application使用一个标准的事件处理句柄来代替之前的那个简单版本,这个版本会将输出到控制台的结果做个漂亮的格式化。当然,可以通过kernel的配置选项来修改上述行为,例如将结果输出到文件或者干脆什么都不干
kernel.erl文件:
start(_, []) ->
case supervisor:start_link({local, kernel_sup}, kernel, []) of
{ok, Pid} ->
Type = get_error_logger_type(),
error_logger:swap_handler(Type),
{ok, Pid, []};
Error -> Error
end.
首先,kernel把自己注册为一个名为kernel_sup的监控树进程,其次立刻就更换了error_logger的处理句柄。go on:
get_error_logger_type() ->
case application:get_env(kernel, error_logger) of
{ok, tty} -> tty;
{ok, {file, File}} when is_list(File) -> {logfile, File};
{ok, false} -> false;
{ok, silent} -> silent;
undefined -> tty; % default value
{ok, Bad} -> exit({bad_config, {kernel, {error_logger, Bad}}})
end.
代码很容易理解,根据配置来决定以何种方式处理日志。
二、定制Kernel选项
继续接着上面的代码往下走:
swap_handler(tty) ->
gen_event:swap_handler(error_logger, {error_logger, swap},
{error_logger_tty_h, []}),
simple_logger();
swap_handler({logfile, File}) ->
gen_event:swap_handler(error_logger, {error_logger, swap},
{error_logger_file_h, File}),
simple_logger();
swap_handler(silent) ->
gen_event:delete_handler(error_logger, error_logger, delete),
simple_logger();
swap_handler(false) ->
ok. % keep primitive event handler as-is
swap_handler就是替换日志的处理handle
当用户设置了 参数就将 handler替换为error_logger_tty_h或者error_logger_file_h模块来处理
error_logger_tty就是格式化,然后用终端输出
error_logger_file就是文件处理
error_logger_file_h.erl
首先初始化打开文件
%% This one is used when we takeover from the simple error_logger.
init({File, {error_logger, Buf}}) ->
case init(File, error_logger) of
{ok, {Fd, File, PrevHandler}} ->
write_events(Fd, Buf),
{ok, {Fd, File, PrevHandler}};
Error ->
Error
end;
接下来就是各种处理,以info_msg 为例
handle_event(Event, {Fd, File, PrevHandler}) ->
write_event(Fd, tag_event(Event)),
{ok, {Fd, File, PrevHandler}};
write_event(Fd, {Time, {info_msg, _GL, {Pid, Format, Args}}}) ->
T = write_time(maybe_utc(Time), "INFO REPORT"),
case catch io_lib:format(add_node(Format,Pid), Args) of
S when is_list(S) ->
io:format(Fd, T ++ S, []);
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
io:format(Fd, T ++ F, [Format,Args])
end;
也就是如果你在error_logger注册事件,那么来的event包含的信息格式就是
info_msg, group_leader(), {self(), Format, Args}
需要自己处理,才能够得到合理的格式,例如
error_logger:add_file_handler(file_logger).
file_logger.erl代码如下
-module(file_logger).
-behaviour(gen_event).
-export([init/1, handle_event/2, terminate/2]).
init(File) ->
{ok, Fd} = file:open(File, write),
{ok, Fd}.
handle_event(ErrorMsg, Fd) ->
io:format(Fd, "***Error*** ~p~n", [ErrorMsg]),
{ok, Fd}.
terminate(_Args, Fd) ->
file:close(Fd)._logger, "mzh").
那么当调用error_logger:info_msg("aaaaa").时候,在文件mzh中就
***Error*** {info_msg,<0.24.0>,{<0.57.0>,"aaaa",[]}}
看来不经过格式化输出的信息很难懂啊
error_logger的信息打印有很多接口,
例如
info_msg
info_report
error_msg
error_report
warn_report 这些,有什么区别呢?以info信息为例
info_msg就是将信息写入文件,info_report呢
info_repot/1也同样写如,
info_report/2是将信息写入自定义的handle里面
info_report(Type, Report) -> ok
Types:
Type = any()
Report = report()
Sends a user defined information report event to the error logger. An event handler to handle the event is supposed to have been added. The event is ignored by the standard event handler.
最后还有warning_report/2要看系统的设置,
用warning_map()获取,也可以在启动时候,用erl +W(i,w)来设置
从error_logger_file_h.erl的write_event可以看出,系统代码,没有处理 type为
info_report, error_report的代码,也就是info_report/2, error_report/2,而
info_report/1,和error_report/1的type会被转化为std_info,照常处理
write_event(Fd, {Time, {info_report, _GL, {Pid, std_info, Rep}}}) ->
T = write_time(maybe_utc(Time), "INFO REPORT"),
S = format_report(Rep),
io:format(Fd, T ++ S ++ add_node("", Pid), []);
如果自己想要记录另一份log,只需要拷贝error_logger_file_h.erl稍作改动,注册自己的handler即可,
erlang的日志系统经常使用rb, 启动时候通过
erl -config log
也可以两个同时使用,就是记录两处log日志
erl -boot start_sasl \
-kernel error_logger \{file,\"mzh3\"\} \
-config log
就ok,
部分代码分析来自http://www.qingliangcn.com/2010/03/erlang%E4%B8%AD%E6%97%A5%E5%BF%97%E7%AE%A1%E7%90%86%E4%B8%89%E4%B8%A4%E8%AF%9D/
常用的
erl -kernel error_logger tty
erl -kernel error_logger false
erl -kernel error_loggger silent
erl -kernel error_logger \{file,\"filename\"\}
这几种方法,tyy是打印终端,false是默认,也是终端,silent是什么也不做,file是写到日志文件,看代码
start_link() ->
case gen_event:start_link({local, error_logger}) of
{ok, Pid} ->
simple_logger(?buffer_size),
{ok, Pid};
Error -> Error
end.
simple_logger(Buffer_size) when is_integer(Buffer_size) ->
gen_event:add_handler(error_logger, error_logger, Buffer_size).
就是将自己error_logger模块设置为handler;
当用户调用函数info_msg/2, error_msg/2 如何呢?
info_msg(Format, Args) ->
notify({info_msg, group_leader(), {self(), Format, Args}}).
notify(Msg) ->
gen_event:notify(error_logger, Msg).
handle_event(Event, State) ->
handle_event2(Event, State).
handle_event2(Event, {1, Lost, Buff}) ->
display(tag_event(Event)),
{ok, {1, Lost+1, Buff}};
handle_event2(Event, {N, Lost, Buff}) ->
Tagged = tag_event(Event),
display(Tagged),
{ok, {N-1, Lost, [Tagged|Buff]}};
handle_event2(_, State) ->
{ok, State}.
最后调用dispaly就是显示了,就是把信息格式化输出
那么是如何将信息输出到文件,或者干脆就不输出呢,
在启动的过程中,kernel application使用一个标准的事件处理句柄来代替之前的那个简单版本,这个版本会将输出到控制台的结果做个漂亮的格式化。当然,可以通过kernel的配置选项来修改上述行为,例如将结果输出到文件或者干脆什么都不干
kernel.erl文件:
start(_, []) ->
case supervisor:start_link({local, kernel_sup}, kernel, []) of
{ok, Pid} ->
Type = get_error_logger_type(),
error_logger:swap_handler(Type),
{ok, Pid, []};
Error -> Error
end.
首先,kernel把自己注册为一个名为kernel_sup的监控树进程,其次立刻就更换了error_logger的处理句柄。go on:
get_error_logger_type() ->
case application:get_env(kernel, error_logger) of
{ok, tty} -> tty;
{ok, {file, File}} when is_list(File) -> {logfile, File};
{ok, false} -> false;
{ok, silent} -> silent;
undefined -> tty; % default value
{ok, Bad} -> exit({bad_config, {kernel, {error_logger, Bad}}})
end.
代码很容易理解,根据配置来决定以何种方式处理日志。
二、定制Kernel选项
继续接着上面的代码往下走:
swap_handler(tty) ->
gen_event:swap_handler(error_logger, {error_logger, swap},
{error_logger_tty_h, []}),
simple_logger();
swap_handler({logfile, File}) ->
gen_event:swap_handler(error_logger, {error_logger, swap},
{error_logger_file_h, File}),
simple_logger();
swap_handler(silent) ->
gen_event:delete_handler(error_logger, error_logger, delete),
simple_logger();
swap_handler(false) ->
ok. % keep primitive event handler as-is
swap_handler就是替换日志的处理handle
当用户设置了 参数就将 handler替换为error_logger_tty_h或者error_logger_file_h模块来处理
error_logger_tty就是格式化,然后用终端输出
error_logger_file就是文件处理
error_logger_file_h.erl
首先初始化打开文件
%% This one is used when we takeover from the simple error_logger.
init({File, {error_logger, Buf}}) ->
case init(File, error_logger) of
{ok, {Fd, File, PrevHandler}} ->
write_events(Fd, Buf),
{ok, {Fd, File, PrevHandler}};
Error ->
Error
end;
接下来就是各种处理,以info_msg 为例
handle_event(Event, {Fd, File, PrevHandler}) ->
write_event(Fd, tag_event(Event)),
{ok, {Fd, File, PrevHandler}};
write_event(Fd, {Time, {info_msg, _GL, {Pid, Format, Args}}}) ->
T = write_time(maybe_utc(Time), "INFO REPORT"),
case catch io_lib:format(add_node(Format,Pid), Args) of
S when is_list(S) ->
io:format(Fd, T ++ S, []);
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
io:format(Fd, T ++ F, [Format,Args])
end;
也就是如果你在error_logger注册事件,那么来的event包含的信息格式就是
info_msg, group_leader(), {self(), Format, Args}
需要自己处理,才能够得到合理的格式,例如
error_logger:add_file_handler(file_logger).
file_logger.erl代码如下
-module(file_logger).
-behaviour(gen_event).
-export([init/1, handle_event/2, terminate/2]).
init(File) ->
{ok, Fd} = file:open(File, write),
{ok, Fd}.
handle_event(ErrorMsg, Fd) ->
io:format(Fd, "***Error*** ~p~n", [ErrorMsg]),
{ok, Fd}.
terminate(_Args, Fd) ->
file:close(Fd)._logger, "mzh").
那么当调用error_logger:info_msg("aaaaa").时候,在文件mzh中就
***Error*** {info_msg,<0.24.0>,{<0.57.0>,"aaaa",[]}}
看来不经过格式化输出的信息很难懂啊
error_logger的信息打印有很多接口,
例如
info_msg
info_report
error_msg
error_report
warn_report 这些,有什么区别呢?以info信息为例
info_msg就是将信息写入文件,info_report呢
info_repot/1也同样写如,
info_report/2是将信息写入自定义的handle里面
info_report(Type, Report) -> ok
Types:
Type = any()
Report = report()
Sends a user defined information report event to the error logger. An event handler to handle the event is supposed to have been added. The event is ignored by the standard event handler.
最后还有warning_report/2要看系统的设置,
用warning_map()获取,也可以在启动时候,用erl +W(i,w)来设置
从error_logger_file_h.erl的write_event可以看出,系统代码,没有处理 type为
info_report, error_report的代码,也就是info_report/2, error_report/2,而
info_report/1,和error_report/1的type会被转化为std_info,照常处理
write_event(Fd, {Time, {info_report, _GL, {Pid, std_info, Rep}}}) ->
T = write_time(maybe_utc(Time), "INFO REPORT"),
S = format_report(Rep),
io:format(Fd, T ++ S ++ add_node("", Pid), []);
如果自己想要记录另一份log,只需要拷贝error_logger_file_h.erl稍作改动,注册自己的handler即可,
erlang的日志系统经常使用rb, 启动时候通过
erl -config log
也可以两个同时使用,就是记录两处log日志
erl -boot start_sasl \
-kernel error_logger \{file,\"mzh3\"\} \
-config log
就ok,
部分代码分析来自http://www.qingliangcn.com/2010/03/erlang%E4%B8%AD%E6%97%A5%E5%BF%97%E7%AE%A1%E7%90%86%E4%B8%89%E4%B8%A4%E8%AF%9D/
发表评论
-
erlang版本安装相关问题 <32>
2014-05-10 15:54 627<1> erlang R1603安装后,crytp ... -
关于iolist<30>
2014-01-15 10:42 630iolist是比较常用的数据结构. iolist的 ... -
erlang 字符编码 <29>
2014-01-14 16:31 1264用mochiweb通过网页发送中文到服务器,结果服务器显示乱码 ... -
<27>erlang record
2013-11-19 11:19 778平时总是忘记record的某些使用方法,每次使用都要翻文档, ... -
<26>io:format io_lib:format
2013-11-14 11:07 1318使用io_lib时候要注意参数,尤其是封装json串的时候,否 ... -
<24>用error_logger间隔记录日志
2013-10-22 16:09 654执行下面的代码 test:start(). test.erl ... -
<23>erlang 数据存储
2013-10-15 22:15 1664做为后端开发者,经常 ... -
<22> erlang中的数学计算函数相关
2013-10-10 10:34 16351. 幂函数 match:pow(m,n) 表示m的n次幂 ... -
<20>erlang中的类型和函数说明
2013-09-15 11:25 984erlang是一种动态类型的语言(运行时才决定数据类型),可以 ... -
<19>erlang中的时间,日期
2013-09-06 11:21 1198时间函数涉及的数据类型: DATA TYPES datetim ... -
<18>Efficient guide 之List handling
2013-08-31 18:45 6791 Deep and flat lists lists:fl ... -
<17>Efficiency Guide之Function
2013-08-27 22:30 5811. 函数模式匹配 模式匹配,在函数头,case和receiv ... -
<16>Efficiency Guide之Common Caveats
2013-08-11 11:07 814(1) ++ 如果做一个list的反转,不要这样, naiv ... -
<15> lists模块补充
2013-08-05 20:12 830%% 对list模块经常用到的进行补充 %% 1 对所有元素进 ... -
<15> lists模块解析和补充
2013-07-24 17:57 12%% 对list模块经常用到的进行补充 %% 1 对所有元素 ... -
<12>简述erlang的几种错误
2013-04-14 23:31 11851) badarg Bad argument. The ar ... -
<11>erlang中方便使用的模块和命令(2)
2013-04-06 22:33 802(1) 进程字典到底用不用,很多人推荐使用 http:// ... -
<9>rabbitmq网络层
2013-01-31 00:20 818抽离出了网络层, 逻辑层待以后研究 https://gith ... -
<8>redis及erl-redis阅读
2013-01-16 10:14 8551 redis的功能相当的强大,里面的发布订阅pub/su ... -
<7>pg2 分析
2012-12-08 13:42 1260网上看到erlang的pg2模块似乎没人推荐使用,但是还是有不 ...
相关推荐
logrj.logger.helloappLogger=WARN<br> 以上代码定义了一个Logger组件,名为helloappLogger,并为它分配了一个日志级别WARN,(一共有5种日志级别:FATAL,ERROR,WARN,INFO,DEBUG)<br> 它的日志级别为WARN,在程序口,它的...
(*Logger Interface*)<br> ILogger=interface<br> ['{E43E419D-26AD-48e6-8097-19622CC2043E}']<br> function WriteLog(<br> FileName : String;<br> LogString : String;<br> CloseFileAfterWrote : BOOL = true<br...
在上面的代码中,我们通过`LogManager.getLogger(Main.class)`获取了一个Logger实例,并使用`info`和`error`方法记录日志。这些日志将按照`log4j2.xml`的配置被发送到Kafka。 最后,确保Kafka服务已经启动并且正确...
<item>"bt-pan"</item> </string-array> 2、干掉BT(特别是rtl8723bs的): R:\wyb\rtl8188eu_sina33m_sc3817\android\device\softwinner\astar-d7\astar_d7.mk PRODUCT_PACKAGES += Launcher3 PRODUCT_...
<integer name="def_screen_off_timeout">1800000</integer> <bool name="def_lockscreen_disabled">true</bool> 7、请严重注意,全志在这里埋坑了!(坑爹无敌!) Android里面调入配置文件:nvram.txt,里面...
<logger name="com.basis" level="error" additivity="false"> <appender-ref ref="mqAsyncAppender" /> </logger> ``` 这段配置会将`com.basis`包下所有级别的错误日志发送到RabbitMQ,并通过`mqAsyncAppender`...
3. **使用**:在代码的关键位置,我们可以通过调用日志器的方法(如`info()`、`debug()`、`error()`等)来记录日志信息。 四、高级特性 - **自定义日志格式**:`sca_logger_python`可能支持自定义日志格式,包括...
private readonly ILogger<MyClass> _logger = NLog.LogManager.Setup().SetupExtensions(e => e.AutoLoadAssemblies(false)).CreateLogger<MyClass>(); [TestMethod] public void TestDoSomething_WithError() ...
<fileNamePattern>logs/error.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>...
要安装和使用`rpa_logger`,开发者需要先解压`rpa_logger-0.1.1.tar.gz`,然后在命令行中运行`python setup.py install`或者利用`pip`的install选项,例如`pip install path/to/rpa_logger-0.1.1.tar.gz`。...
<item>"bt-pan"</item> </string-array> 3、 R:\wyb\ap6212a0_a33_sc3817r\android\device\softwinner\astar-y3\astar_y3.mk # ap6181/6210/6330 sdio wifi fw and nvram #$(call inherit-product-if-exists, ...
总的来说,"logger.rar_Logger.py_sunlightek2_日志"提供的`logger.py`模块,是为程序开发提供日志记录功能的工具,通过合理使用,可以极大地提高开发和维护的效率。在使用前,需要了解其具体接口和配置方法,以便于...
`sca_logger_python`可能提供了一套完善的方法,帮助开发者定义不同级别的日志,如CRITICAL、ERROR、WARNING、INFO、DEBUG等,以适应不同的应用场景。 在`sca_logger_python-1.4.tar.gz`压缩包内,通常会包含以下...
安装完成后,开发者可以在项目中导入并使用spk_logger提供的功能,例如初始化logger,设置日志级别,添加处理器等。 总结来说,spk_logger-0.1.4-py3-none-any.whl是一个针对Python 3的后端开发日志库,旨在帮助...
为了使用这个库,开发者首先需要解压`melange_logger-0.0.2.tar.gz`,然后在命令行中运行`pip install .`(如果当前目录是解压后的目录)或者`pip install path/to/melange_logger-0.0.2`(如果不在当前目录)。...
6. **批量上传**:为了提高效率,`es_logger`可能采用批量上传的方式,将多条日志一次性发送到Elasticsearch,降低网络通信开销。 7. **性能优化**:库可能经过优化,减少了不必要的计算和内存消耗,确保在高负载下...
总的来说,"algorithm_logger"是一个面向算法开发的日志管理工具,它的`whl`分发包形式使得安装和使用变得简单。无论你是算法工程师还是数据科学家,这个库都值得你去探索和利用,以提升你的工作效率和代码质量。
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n</pattern> </layout> </SMTP> </appenders> <loggers> <root level="error"> <appender-ref ref="SmtpAppender" /> </root> </...
使用"pipeline_logger"时,应遵循一些最佳实践,如设置合适的日志级别,避免过度记录导致性能影响;在关键代码段使用上下文管理器,确保日志正确关闭;以及合理配置日志处理器,确保日志数据的安全存储和备份。 ...