• Erlang中日志管理


    http://blog.sina.com.cn/s/blog_96b8a1540101317g.html

    一、基本概念

     

    Erlang中,通过两个概念管理错误事情:事件管理器(event manager)和事件处理句柄(event handles)。通常各种错误、警告和消息事件都会有Erlang运行时系统发送给事件管理器。在Erlang中,默认的事情管理器为error logger,其进程名注册为error_logger。默认情况下error_logger把这些事件直接输出到控制台上。

     

           在系统启动的一开始,error_logger只有一个简单的事件处理句柄,该处理句柄只是做缓冲和原始格式的打印操作。查看error_logger的源码,可以看到其启动过程如下:

     

    -spec start() -> {'ok', pid()} | {'error', any()}.

     

    start() ->

        case gen_event:start({local, error_logger}) of

        {ok, Pid} ->

            simple_logger(?buffer_size),

            {ok, Pid};

        Error -> Error

        end.

     

    -spec start_link() -> {'ok', pid()} | {'error', any()}.

     

    start_link() ->

        case gen_event:start_link({local, error_logger}) of

        {ok, Pid} ->

            simple_logger(?buffer_size),

            {ok, Pid};

        Error -> Error

    end.

     

    OK,只是简单的注册了一个进程,看看simple_logger的内容:

     

    simple_logger(Buffer_sizewhen is_integer(Buffer_size) ->

    gen_event:add_handler(error_logger, error_logger, Buffer_size).

     

    看来error_logger在一开始的时候除了充当manager,也担当了handler的角色。

     

    在启动的过程中,kernel application使用一个标准的事件处理句柄来代替之前的那个简单版本,这个版本会将输出到控制台的结果做个漂亮的格式化。当然,可以通过kernel的配置选项来修改上述行为,例如将结果输出到文件或者干脆什么都不干(忽略任何event)。口说无凭,还是继续看源码吧:

    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

     

    可以看出,如果我们真的希望什么都不做,那么应该传递参数 silent,而不是false,因为false情况下原来的原始处理句柄并没有被移除掉。

     

    打开命令提示符,做个简单的实验(>表示命令提示符)

     

    实验一,定制为false参数:

     

    > erl -kernel error_logger false  //传递false参数

    2> error_logger:error_msg("Haha").  // 尝试产生一个error event

    ok{error_logger,{{

    2010,2> 3,10},{15,9,1}},"Haha",[]}  //这里是结果

     

    实验二,定制为silent参数:

     

    > erl -kernel error_logger silent  //传递silent 参数

    1>  error_logger:error_msg("Haha").

    ok   // 看到这里只有ok,没有其他任何信息了!

    2>

     

    三、SASL

     

    SASL全称System Architecture Support Libraries,提供如下几个服务:

    alarm_handler

    overload

    rb

    release_handler

    systools

    SASL带有error_logger的事件处理句柄用于格式化SASL错误和crash报告,这些句柄如下:

    sasl_report_tty_h   sasl_report_file_h   error_logger_mf_h

    细节参考OTP文档可知。

    SASL的默认event handler会将crash报告、supervisor和进程报告输出到控制台,如果你希望看到这些信息,那么在erlang启动时需要加上指定的参数以启动sasl

    为了方便日志的查看,通常sasl和其他日志是分开输出的,可以在启动erl时使用如下命令行参数:

    -sasl sasl_error_logger {file,"/data/ log/sasl.log"}

     

     

    四、站在巨人的肩膀上

     

    这里并不打算介绍一个gen_event behavior模块的写法,而是想介绍一个非常强大、成熟的一个日志系统:ejabberd的日志系统。它包含两个部分:

    dynamic_compile.erl   动态编译基础模块

    ejabberd_logger_h.erl  这是个gen_event behavior模块,可以定制我们写日志的行为

    ejabberd_loglevel.h    这个是ejabberd日志系统的精华,可以在运行时动态调节日志的输出级别。

     

    用法很简单:

    error_logger:add_report_handler(ejabberd_logger_h, LogPath),

    ejabberd_loglevel:set(4) //级别4是info日志

     

    原理很简单,利用code模块的load_binary来实现动态代码替换,但是确实非常强大,可以在需要的时候打开某些特定级别的日志,在系统负载高的时候或者不需要的时候关闭它。

  • 相关阅读:
    jbpm 为任务自由选择办理人
    我永远的 dell 15r
    select radio readonly
    面向对象的5条基本设计原则
    Java数据库缓存思路
    作为java应届生,面试求职那点事
    项目开发中数据字典设计实现缓存
    oracle 优化 —— 分区表
    myeclipse快捷键
    win8 安装myeclipse 失败 MyEclipse ForSpring 安装失败
  • 原文地址:https://www.cnblogs.com/fvsfvs123/p/4303744.html
Copyright © 2020-2023  润新知