网站地图
首页
新闻
电影新闻
电视新闻
人物新闻
专题策划
影评
最新影评
新片热评
经典赏析
媒体评论
电影院
北京影讯
上海影讯
广州影讯
深圳影讯
成都影讯
电影库
典藏佳片
全球新片
即将上映
票房榜
社区
日志
相册
电影
好友
专辑
收藏
影视杂谈
明星时尚
文化休闲
群组
话题
达人
排行榜
电影榜
电视榜
人物榜
日志榜
话题榜

变奏曲,十一月……

永远不要说永远……

http://i.mtime.com/844165/

您当前的位置: 社区>> 博客>>

编辑 | 删除 erlang large日志系统代码阅读(五):lager

GOK358405961 发布于:

-module(lager).


-include("lager.hrl").


%% API

-export([start/0,

        log/3, log/4,

        trace/2, trace/3, trace_file/2, trace_file/3, trace_console/1, trace_console/2,

        clear_all_traces/0, stop_trace/1, status/0,

        get_loglevel/1, set_loglevel/2, set_loglevel/3, get_loglevels/0,

        minimum_loglevel/1, posix_error/1,

        safe_format/3, safe_format_chop/3,dispatch_log/5, pr/2]).


-type log_level() :: debug | info | notice | warning | error | critical | alert | emergency.

-type log_level_number() :: 0..7.


-export_type([log_level/0, log_level_number/0]).


%% API


%% @doc Start the application. Mainly useful for using `-s lager' as a command

%% line switch to the VM to make lager start on boot.

%启动lager

start() -> start(lager).


start(App) ->%启动lager

    start_ok(App, application:start(App, permanent)).


start_ok(_App, ok) -> ok;

start_ok(_App, {error, {already_started, _App}}) -> ok;

start_ok(App, {error, {not_started, Dep}}) ->

    ok = start(Dep),

    start(App);

start_ok(App, {error, Reason}) ->

    erlang:error({app_start_failed, App, Reason}).



%通知各个handler处理log信息

-spec dispatch_log(log_level(), list(), string(), list() | none, pos_integer()) ->  ok | {error, lager_not_running}.

dispatch_log(Severity, Metadata, Format, Args, Size) when is_atom(Severity)->

    case whereis(lager_event) of%查找log_event进程

        undefined ->

            %% lager isn't running

            {error, lager_not_running};

        Pid ->

            {LevelThreshold,TraceFilters} = lager_config:get(loglevel,{?LOG_NONE,[]}),%获取log_level掩码和Trace规则

            SeverityAsInt=lager_util:level_to_num(Severity),

            case (LevelThreshold band SeverityAsInt) /= 0 orelse TraceFilters /= [] of

                true ->%log_level达到打印级别或者存在Trace规则

                    Destinations = case TraceFilters of%根据过滤规则获取后端列表

                        [] ->

                            [];

                        _ ->

                            lager_util:check_traces(Metadata,SeverityAsInt,TraceFilters,[])

                    end,

                    case (LevelThreshold band SeverityAsInt) /= 0 orelse Destinations /= [] of

                        true ->

                            Timestamp = lager_util:format_time(),%获取格式化的时间

                            Msg = case Args of

                                A when is_list(A) ->%格式化Args

                                    safe_format_chop(Format,Args,Size);

                                _ ->

                                    Format

                            end,

                            gen_event:sync_notify(Pid, {log, lager_msg:new(Msg, Timestamp,%通知log_event

                                        Severity, Metadata, Destinations)});

                        false ->

                            ok

                    end;

                _ ->

                    ok

            end

    end.


%% @doc Manually log a message into lager without using the parse transform.

%打印日志信息

-spec log(log_level(), pid() | atom() | [tuple(),...], list()) -> ok | {error, lager_not_running}.

log(Level, Pid, Message) when is_pid(Pid); is_atom(Pid) ->

    dispatch_log(Level, [{pid,Pid}], Message, [], ?DEFAULT_TRUNCATION);

log(Level, Metadata, Message) when is_list(Metadata) ->

    dispatch_log(Level, Metadata, Message, [], ?DEFAULT_TRUNCATION).


%% @doc Manually log a message into lager without using the parse transform.

%打印日志信息

-spec log(log_level(), pid() | atom() | [tuple(),...], string(), list()) -> ok | {error, lager_not_running}.

log(Level, Pid, Format, Args) when is_pid(Pid); is_atom(Pid) ->

    dispatch_log(Level, [{pid,Pid}], Format, Args, ?DEFAULT_TRUNCATION);

log(Level, Metadata, Format, Args) when is_list(Metadata) ->

    dispatch_log(Level, Metadata, Format, Args, ?DEFAULT_TRUNCATION).


%将满足Filter的日志打印到文件File中

trace_file(File, Filter) ->

    trace_file(File, Filter, debug).


%将满足Filter且log_level>=Level的日志打印到文件File中

trace_file(File, Filter, Level) ->

    Trace0 = {Filter, Level, {lager_file_backend, File}},

    case lager_util:validate_trace(Trace0) of%验证Trace信息是否有效

        {ok, Trace} ->

            Handlers = gen_event:which_handlers(lager_event),

            %% check if this file backend is already installed

            Res = case lists:member({lager_file_backend, File}, Handlers) of

                false ->

                    %% install the handler

                    supervisor:start_child(lager_handler_watcher_sup,%通知log_event进程启动相应handler,此时log_level为none

                        [lager_event, {lager_file_backend, File}, {File, none}]);

                _ ->

                    {ok, exists}

            end,

            case Res of

              {ok, _} ->

                %% install the trace.

                {MinLevel, Traces} = lager_config:get(loglevel),

                case lists:member(Trace, Traces) of

                  false ->

                    lager_config:set(loglevel, {MinLevel, [Trace|Traces]});%将Trace信息添加到config ets中

                  _ ->

                    ok

                end,

                {ok, Trace};

              {error, _} = E ->

                E

            end;

        Error ->

            Error

    end.


%将满足Filter的日志打印到控制台

trace_console(Filter) ->

    trace_console(Filter, debug).


%将满足Filter且log_level>=Level的日志打印到控制台

trace_console(Filter, Level) ->

    trace(lager_console_backend, Filter, Level).


%将满足Filter的日志打印指定后端

trace(Backend, Filter) ->

    trace(Backend, Filter, debug).


%将满足Filter且log_level>=Level的日志打印指定后端

trace(Backend, Filter, Level) ->

    Trace0 = {Filter, Level, Backend},

    case lager_util:validate_trace(Trace0) of%验证Trace信息是否有效

        {ok, Trace} ->

            {MinLevel, Traces} = lager_config:get(loglevel),

            case lists:member(Trace, Traces) of

                false ->

                    lager_config:set(loglevel, {MinLevel, [Trace|Traces]});%将Trace信息添加到config ets中

                _ -> ok

            end,

            {ok, Trace};

        Error ->

            Error

    end.


%停止对指定Tarce的打印过滤

stop_trace({_Filter, _Level, Target} = Trace) ->

    {Level, Traces} = lager_config:get(loglevel),

    NewTraces =  lists:delete(Trace, Traces),

    %MinLevel = minimum_loglevel(get_loglevels() ++ get_trace_levels(NewTraces)),

    lager_config:set(loglevel, {Level, NewTraces}),%重设config ets中的Trace信息

    case get_loglevel(Target) of%获取指定handler的log_level

        none ->%log_level为none(说明是通过trace_file建立的后端)

            %% check no other traces point here

            case lists:keyfind(Target, 3, NewTraces) of%察看相应的handler有没有其他Trace

                false ->

                    gen_event:delete_handler(lager_event, Target, []);%没有则删除handler

                _ ->

                    ok

            end;

        _ ->

            ok

    end,

    ok.


%停止所有的打印过滤

clear_all_traces() ->

    {Level, _Traces} = lager_config:get(loglevel),

    lager_config:set(loglevel, {Level, []}),

    lists:foreach(fun(Handler) ->

          case get_loglevel(Handler) of

            none ->

              gen_event:delete_handler(lager_event, Handler, []);%删除所有log_level为none的handler

            _ ->

              ok

          end

      end, gen_event:which_handlers(lager_event)).


%获取状态

status() ->

    Handlers = gen_event:which_handlers(lager_event),

    Status = ["Lager status:\n",

        [begin

                    Level = get_loglevel(Handler),

                    case Handler of

                        {lager_file_backend, File} ->

                            io_lib:format("File ~s at level ~p\n", [File, Level]);

                        lager_console_backend ->

                            io_lib:format("Console at level ~p\n", [Level]);

                        _ ->

                            []

                    end

            end || Handler <- Handlers],

        "Active Traces:\n",

        [begin

                    LevelName = case Level of

                        {mask, Mask} ->

                            case lager_util:mask_to_levels(Mask) of

                                [] -> none;

                                Levels -> hd(Levels)

                            end;

                        Num ->

                            lager_util:num_to_level(Num)

                    end,

                    io_lib:format("Tracing messages matching ~p at level ~p to ~p\n",

                        [Filter, LevelName, Destination])

            end || {Filter, Level, Destination} <- element(2, lager_config:get(loglevel))]],

    io:put_chars(Status).


%% @doc Set the loglevel for a particular backend.

%设置指定后端handler的log_level

set_loglevel(Handler, Level) when is_atom(Level) ->

    Reply = gen_event:call(lager_event, Handler, {set_loglevel, Level}, infinity),

    %% recalculate min log level

    {_, Traces} = lager_config:get(loglevel),

    MinLog = minimum_loglevel(get_loglevels()),

    lager_config:set(loglevel, {MinLog, Traces}),

    Reply.


%% @doc Set the loglevel for a particular backend that has multiple identifiers

%% (eg. the file backend).

%设置指定后端handler的log_level(该handler有多个标识)

set_loglevel(Handler, Ident, Level) when is_atom(Level) ->

    Reply = gen_event:call(lager_event, {Handler, Ident}, {set_loglevel, Level}, infinity),

    %% recalculate min log level

    {_, Traces} = lager_config:get(loglevel),

    MinLog = minimum_loglevel(get_loglevels()),

    lager_config:set(loglevel, {MinLog, Traces}),

    Reply.


%% @doc Get the loglevel for a particular backend. In the case that the backend

%% has multiple identifiers, the lowest is returned

%获取指定handler的log_level

get_loglevel(Handler) ->

    case gen_event:call(lager_event, Handler, get_loglevel, infinity) of

        {mask, Mask} ->

            case lager_util:mask_to_levels(Mask) of

                [] -> none;

                Levels -> hd(Levels)

            end;

        X when is_integer(X) ->

            lager_util:num_to_level(X);

        Y -> Y

    end.


%% @doc Try to convert an atom to a posix error, but fall back on printing the

%% term if its not a valid posix error code.

%输出POSIX错误

posix_error(Error) when is_atom(Error) ->

    case erl_posix_msg:message(Error) of

        "unknown POSIX error" -> atom_to_list(Error);

        Message -> Message

    end;

posix_error(Error) ->

    safe_format_chop("~p", [Error], ?DEFAULT_TRUNCATION).


%% @private

get_loglevels() ->%获取所有handler的log_level,并返回列表

    [gen_event:call(lager_event, Handler, get_loglevel, infinity) ||

        Handler <- gen_event:which_handlers(lager_event)].


%% @private

%找出log_level列表中等级最低的level并计算掩码

minimum_loglevel(Levels) ->

    lists:foldl(fun({mask, Mask}, Acc) ->

                Mask bor Acc;

            (Level, Acc) when is_integer(Level) ->

                {mask, Mask} = lager_util:config_to_mask(lager_util:num_to_level(Level)),

                Mask bor Acc;

            (_, Acc) ->

                Acc

        end, 0, Levels).


%% @doc Print the format string `Fmt' with `Args' safely with a size

%% limit of `Limit'. If the format string is invalid, or not enough

%% arguments are supplied 'FORMAT ERROR' is printed with the offending

%% arguments. The caller is NOT crashed.


%将信息截取到指定长度并格式化(长度不够不截取)

safe_format(Fmt, Args, Limit) ->

    safe_format(Fmt, Args, Limit, []).


safe_format(Fmt, Args, Limit, Options) ->

    try lager_trunc_io:format(Fmt, Args, Limit, Options)

    catch

        _:_ -> lager_trunc_io:format("FORMAT ERROR: ~p ~p", [Fmt, Args], Limit)

    end.


%% @private

safe_format_chop(Fmt, Args, Limit) ->

    safe_format(Fmt, Args, Limit, [{chomp, true}]).


%% @doc Print a record lager found during parse transform

%用于测试

pr(Record, Module) when is_tuple(Record), is_atom(element(1, Record)) ->

    try Module:module_info(attributes) of

        Attrs ->

            case lists:keyfind(lager_records, 1, Attrs) of

                false ->

                    Record;

                {lager_records, Records} ->

                    RecordName = element(1, Record),

                    RecordSize = tuple_size(Record) - 1,

                    case lists:filter(fun({Name, Fields}) when Name == RecordName,

                                length(Fields) == RecordSize ->

                                    true;

                                (_) ->

                                    false

                            end, Records) of

                        [] ->

                            Record;

                        [{RecordName, RecordFields}|_] ->

                            {'$lager_record', RecordName,

                                lists:zip(RecordFields, tl(tuple_to_list(Record)))}

                    end

            end

    catch

        error:undef ->

            Record

    end;

pr(Record, _) ->

    Record.

回复 (0) | 收藏 (0) | 3594 次阅读 |

日志分类