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

变奏曲,十一月……

永远不要说永远……

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

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

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

GOK358405961 发布于:

-module(lager_transform).


-include("lager.hrl").


-export([parse_transform/2]).


%% @private

parse_transform(AST, Options) ->%Option来自erlang编译选项,部分可在rebar.config中的erl_opts定义

    TruncSize = proplists:get_value(lager_truncation_size, Options, ?DEFAULT_TRUNCATION),%获取log max size

    put(truncation_size, TruncSize),%保存log max size

    erlang:put(records, []),

    %% .app file should either be in the outdir, or the same dir as the source file

    guess_application(proplists:get_value(outdir, Options), hd(AST)),%尝试获取App name,hd(AST)中保存了filename的信息

    walk_ast([], AST).%遍历AST


walk_ast(Acc, []) ->

    insert_record_attribute(Acc);

walk_ast(Acc, [{attribute, _, module, {Module, _PmodArgs}}=H|T]) ->%-module(Module, {PmodArgs...}) (有这种形式吗??)

    %% A wild parameterized module appears!

    put(module, Module),%保存moduel信息

    walk_ast([H|Acc], T);%继续遍历

walk_ast(Acc, [{attribute, _, module, Module}=H|T]) ->%-module(Module)

    put(module, Module),%保存moduel信息

    walk_ast([H|Acc], T);%继续遍历

walk_ast(Acc, [{function, Line, Name, Arity, Clauses}|T]) ->%FunName(Arity) -> Clauses

    put(function, Name),%保存function信息

    walk_ast([{function, Line, Name, Arity,%遍历函数语句

                walk_clauses([], Clauses)}|Acc], T);

walk_ast(Acc, [{attribute, _, record, {Name, Fields}}=H|T]) ->%-record({Name, {Fields...}})

    FieldNames = lists:map(fun({record_field, _, {atom, _, FieldName}}) ->%获取record field 列表

                FieldName;

            ({record_field, _, {atom, _, FieldName}, _Default}) ->

                FieldName

        end, Fields),

    stash_record({Name, FieldNames}),%保存record字段列表到进程字典

    walk_ast([H|Acc], T);%继续遍历

walk_ast(Acc, [H|T]) ->

    walk_ast([H|Acc], T).


walk_clauses(Acc, []) ->%遍历函数语句

    lists:reverse(Acc);

walk_clauses(Acc, [{clause, Line, Arguments, Guards, Body}|T]) ->

    walk_clauses([{clause, Line, Arguments, Guards, walk_body([], Body)}|Acc], T).%遍历函数体


walk_body(Acc, []) ->

    lists:reverse(Acc);

walk_body(Acc, [H|T]) ->

    walk_body([transform_statement(H)|Acc], T).%对函数体中每一条语句进行转换


transform_statement({call, Line, {remote, _Line1, {atom, _Line2, lager},%转换lager:Severity(Args...)形式

            {atom, _Line3, Severity}}, Arguments0} = Stmt) ->

    case lists:member(Severity, ?LEVELS) of

        true ->

            %在代码里DefaultAttrs0 = [{module, Module}, {function, Function}, {line, Line}, 

            %                        {pid, pid_to_list(self())}, {node, node()}]

            DefaultAttrs0 = {cons, Line, {tuple, Line, [

                        {atom, Line, module}, {atom, Line, get(module)}]},

                    {cons, Line, {tuple, Line, [

                                {atom, Line, function}, {atom, Line, get(function)}]},

                        {cons, Line, {tuple, Line, [

                                    {atom, Line, line},

                                    {integer, Line, Line}]},

                        {cons, Line, {tuple, Line, [

                                    {atom, Line, pid},

                                    {call, Line, {atom, Line, pid_to_list}, [

                                            {call, Line, {atom, Line ,self}, []}]}]},

                        {cons, Line, {tuple, Line, [

                                    {atom, Line, node},

                                    {call, Line, {atom, Line, node}, []}]},

                         {nil, Line}}}}}},

            DefaultAttrs = case erlang:get(application) of

                undefined ->

                    DefaultAttrs0;

                App ->

                    %% stick the application in the attribute list

                    %代码中DefaultAttrs = [{application, App}, {module, Module}, {function, Function}, 

                    %                     {line, Line}, {pid, pid_to_list(self())}, {node, node()}]

                    concat_lists({cons, Line, {tuple, Line, [

                                    {atom, Line, application},

                                    {atom, Line, App}]},

                            {nil, Line}}, DefaultAttrs0)

            end,

            {Traces, Message, Arguments} = case Arguments0 of%将参数转换为{Attrs++DefaultAttrs, Format, Args}形式

                [Format] ->%代码中参数只有字符串

                    {DefaultAttrs, Format, {atom, Line, none}};

                [Arg1, Arg2] ->%代码中参数为[Format, Args]或者[Attr, Format]形式

                    %% some ambiguity here, figure out if these arguments are

                    %% [Format, Args] or [Attr, Format].

                    %% The trace attributes will be a list of tuples, so check

                    %% for that.

                    case Arg1 of

                        {cons, _, {tuple, _, _}, _} ->%[Attrs, Format]形式

                            {concat_lists(Arg1, DefaultAttrs),

                                Arg2, {atom, Line, none}};

                        _ ->%[Format,Args]形式

                            {DefaultAttrs, Arg1, Arg2}

                    end;

                [Attrs, Format, Args] ->%代码中参数为[Attrs, Format, Args]形式

                    {concat_lists(Attrs, DefaultAttrs), Format, Args}

            end,

            %在代码里转换为lager:dispatch_log(Severity, Traces, Message, Arguments, get(truncation_size))

            {call, Line, {remote, Line, {atom,Line,lager},{atom,Line,dispatch_log}},

                [

                    {atom,Line,Severity},

                    Traces,

                    Message,

                    Arguments,

                    {integer, Line, get(truncation_size)}

                ]

            };

            false ->

                Stmt

        end;

transform_statement({call, Line, {remote, Line1, {atom, Line2, boston_lager},%转换boston_lager:Severity(Args...)形式

            {atom, Line3, Severity}}, Arguments}) ->

        NewArgs = case Arguments of

          %把Arguments中所有r替换成h(真心不知道为什么)

          [{string, L, Msg}] -> [{string, L, re:replace(Msg, "r", "h", [{return, list}, global])}];

          [{string, L, Format}, Args] -> [{string, L, re:replace(Format, "r", "h", [{return, list}, global])}, Args];

          Other -> Other

        end,

        transform_statement({call, Line, {remote, Line1, {atom, Line2, lager},%首先转换为lager:Severity(Args...)形式

              {atom, Line3, Severity}}, NewArgs});

transform_statement(Stmt) when is_tuple(Stmt) ->%转换tuple中的所有元素

    list_to_tuple(transform_statement(tuple_to_list(Stmt)));

transform_statement(Stmt) when is_list(Stmt) ->%转换list中的所有元素

    [transform_statement(S) || S <- Stmt];

transform_statement(Stmt) ->%普通语句直接输出

    Stmt.


%% concat 2 list ASTs by replacing the terminating [] in A with the contents of B

concat_lists({nil, _Line}, B) ->%AST的列表连接

    B;

concat_lists({cons, Line, Element, Tail}, B) ->

    {cons, Line, Element, concat_lists(Tail, B)}.


stash_record(Record) ->%保存record字段列表到进程字典

    Records = case erlang:get(records) of

        undefined ->

            [];

        R ->

            R

    end,

    erlang:put(records, [Record|Records]).


insert_record_attribute(AST) ->%将record信息保存在AST中

    lists:foldl(fun({attribute, Line, module, _}=E, Acc) ->

                [E, {attribute, Line, lager_records, erlang:get(records)}|Acc];

            (E, Acc) ->

                [E|Acc]

        end, [], AST).


guess_application(Dirname, Attr) when Dirname /= undefined ->%尝试获取App name

    case find_app_file(Dirname) of

        no_idea ->

            %% try it based on source file directory (app.src most likely)

            guess_application(undefined, Attr);

        _ ->

            ok

    end;

guess_application(undefined, {attribute, _, file, {Filename, _}}) ->

    Dir = filename:dirname(Filename),

    find_app_file(Dir);

guess_application(_, _) ->

    ok.


find_app_file(Dir) ->

    case filelib:wildcard(Dir++"/*.{app,app.src}") of%查找.app文件或者.app.src文件

        [] ->

            no_idea;

        [File] ->%查找成功

            case file:consult(File) of%解析文件

                {ok, [{application, Appname, _Attributes}|_]} ->

                    erlang:put(application, Appname);%保存App name

                _ ->

                    no_idea

            end;

        _ ->

            %% multiple files, uh oh

            no_idea

    end.

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

日志分类