zoukankan      html  css  js  c++  java
  • erlang日志功能。

    用cowboy这个库,没有日志功能,所以研究了otp提供的日志功能。

    1.启动SASL的方式


    erl –boot start_sasl 默认配置文件下启动SASL, {env, [{sasl_error_logger, tty},{errlog_type, all}]},,见源码 sasl.app文件。

    erl -boot start_sasl -config xxxx.config  启动指定配置文件例如 elog1.config ,elog2.config 。。。配置文件默认目录是ebin,可自己指定目录。

    还可以用 application:start(sasl). 在代码里启动应用。默认会读取代码ebin下的sasl.app,可去源码复制一份sasl.app然后修改 env参数。

    sasl是通过application:get_env(sasl,xxx) 获得配置信息 。

    2、sasl配置文件:

    {env, [{sasl_error_logger, {file,"../../logs/error_logs/THELOG"}},%将sasl信息输出到文件中(不记录error_logger发送的信息)。另外,tty :输出sasl信息到shell中(默认配置),false:不输出sasl信息。
         {errlog_type, all}, %过滤sasl_error_logger中的输出信息(error,progress)
         {error_logger_mf_dir,"../../logs/error_logs"}, %循环日志路径(记录sasl信息以及error_logger发送的信息)。
         {error_logger_mf_maxbytes,10485760},  %限定单个日志大小。
         {error_logger_mf_maxfiles,10}  %限定日志个数。
     ]}

    3、error_logger:

    参考官方文档

    设置日志error_logger输出日志到文件:error_logger:logfile({open,Filename}).

    注: 每次执行error_logger:logfile({open,Filename}).都会删掉之前Filename文件。

    4、自定义日志功能:

    由于业务需要,我想按照日期切分日志,该日志主要是为了记录业务操作。

    思路:每次写日志到日志文件,先判断日志文件的最新修改日期是否跟当前日期一致,不一致就对该日志文件重命名(后缀添加日期),并重新创建日志文件。

    daylog_app.erl:

    -module(daylog_app).
    -behaviour(application).
    -export([init/1]).
    -export([start/0,start/2,stop/1]).
    -define(SERVER,?MODULE).
    -define(LOGFILE,"info.log").
    
    start() ->
     application:start(daylog).
    
    start(_StartType,_StartArgs) ->
     LogFile = get_app_env(log_file,?LOGFILE),
     supervisor:start_link({local,?SERVER},?MODULE,[daylog,LogFile]).
    
    stop(_State) ->
     ok.
    
    
    init([Module,LogFile]) ->
     Element = {Module,{Module,start_link,[LogFile]},
     temporary,2000,worker,[Module]}, %%如何启动和管理子进程
     Children = [Element] ,
     RestartStrategy = {one_for_one,0,1}, %%重启策略 
     {ok,{RestartStrategy,Children}}. %%监督规范
    
    %%----------------------------------------------------------------------
    %% Internal functions
    %%----------------------------------------------------------------------
    get_app_env(Opt, Default) ->
     case application:get_env(daylog, Opt) of
     {ok, Val} -> Val;
     _ ->
     case init:get_argument(Opt) of
     [[Val | _]] -> Val;
     error -> Default
     end 
     end.

    daylog.erl

    %%%-------------------------------------------------------------------
    %%% Author : kingson <kingsoncai2013@gmail.com>
    %%% Description : Cutting logs every day.
    %%%
    %%% Created : 4 Mar 2015 by kingson <kingsoncai2013@gmail.com>
    %%%-------------------------------------------------------------------
    -module(daylog).
    
    -behaviour(gen_server).
    
    %% API
    -export([start_link/1]).
    
    %% gen_server callbacks
    -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
     terminate/2, code_change/3]).
    
    -export([add_logfiles/1,info_log/1,info_log/2,logger/2,logger/3]).
    
    -define(SERVER,?MODULE).
    -record(state, {filename,other_files}).
    
    add_logfiles(Files) ->
     gen_server:cast(?SERVER,{add_logfile,Files}).
    
    info_log(Msg) -> %通知类型日志(默认)
     info_log(Msg,[]).
    info_log(Format,Data) ->
     gen_server:cast(?SERVER,{accept,Format,Data}).
    
    logger(FileName,Msg) ->
     logger(FileName,Msg,[]).
    logger(FileName,Format,Data) ->
     gen_server:cast(?SERVER,{accept,FileName,Format,Data}).
    
    
    %%====================================================================
    %% API
    %%====================================================================
    %%--------------------------------------------------------------------
    %% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
    %% Description: Starts the server
    %%--------------------------------------------------------------------
    start_link(LogFile) when is_list(LogFile) ->
     gen_server:start_link({local, ?SERVER}, ?MODULE, [LogFile], []).
    
    %%====================================================================
    %% gen_server callbacks
    %%====================================================================
    
    %%--------------------------------------------------------------------
    %% Function: init(Args) -> {ok, State} |
    %% {ok, State, Timeout} |
    %% ignore |
    %% {stop, Reason}
    %% Description: Initiates the server
    %%--------------------------------------------------------------------
    init([LogFile]) ->
     process_flag(trap_exit, true),
     {ok,F} = file:open(LogFile,[append]),
     put(LogFile,F),
     {ok, #state{filename=LogFile},0}.
    
    %%--------------------------------------------------------------------
    %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
    %% {reply, Reply, State, Timeout} |
    %% {noreply, State} |
    %% {noreply, State, Timeout} |
    %% {stop, Reason, Reply, State} |
    %% {stop, Reason, State}
    %% Description: Handling call messages
    %%--------------------------------------------------------------------
    handle_call(_Request, _From, State) ->
     Reply = ok,
     {reply, Reply, State}.
    
    %%--------------------------------------------------------------------
    %% Function: handle_cast(Msg, State) -> {noreply, State} |
    %% {noreply, State, Timeout} |
    %% {stop, Reason, State}
    %% Description: Handling cast messages
    %%--------------------------------------------------------------------
    handle_cast({accept,Format,Data}, #state{filename=FileName}=State) ->
     write(Format,Data,FileName),
     {noreply, State};
    
    handle_cast({accept,FileName,Format,Data},State) ->
     write(Format,Data,FileName),
     {noreply,State};
    
    handle_cast({add_logfile,LogFiles},State) ->
     open_files(LogFiles),
     State2 = State#state{other_files=LogFiles},
     {noreply,State2};
     
    
    handle_cast(_Msg, State) ->
     {noreply, State}.
    
    %%--------------------------------------------------------------------
    %% Function: handle_info(Info, State) -> {noreply, State} |
    %% {noreply, State, Timeout} |
    %% {stop, Reason, State}
    %% Description: Handling all non call/cast messages
    %%--------------------------------------------------------------------
    handle_info(timeout, State) ->
     gen_server:cast(?SERVER,{accept,"Has started daylog application~n",[]}),
     {noreply, State};
    
    handle_info(_Info, State) ->
     {noreply, State}.
    
    %%--------------------------------------------------------------------
    %% Function: terminate(Reason, State) -> void()
    %% Description: This function is called by a gen_server when it is about to
    %% terminate. It should be the opposite of Module:init/1 and do any necessary
    %% cleaning up. When it returns, the gen_server terminates with Reason.
    %% The return value is ignored.
    %%--------------------------------------------------------------------
    terminate(_Reason, State) ->
     #state{filename=FileName,other_files=OtherFiles} = State,
     close_files(OtherFiles),
     F = get(FileName),
     io:format("Has stoped daylog application~n"),
     io:format(F,"Has stoped daylog application~n",[]),
     file:close(F),
     ok.
    
    %%--------------------------------------------------------------------
    %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
    %% Description: Convert process state when code is changed
    %%--------------------------------------------------------------------
    code_change(_OldVsn, State, _Extra) ->
     {ok, State}.
    
    %%--------------------------------------------------------------------
    %%% Internal functions
    %%--------------------------------------------------------------------
    
    write(Format,Data,Filename) ->
     LocalTime = calendar:local_time(),
     case filelib:last_modified(Filename) of
     {Last_Modified_Date,_} -> 
     {Today,_} = LocalTime,
     {Date_diff,_} = calendar:time_difference({Last_Modified_Date,{0,0,0}},{Today,{0,0,0}}),
     if Date_diff /= 0 -> %not the same date
     {Y,M,D} = Last_Modified_Date,
     Newname = Filename ++ "." ++ integer_to_list(Y) ++ "-" ++ integer_to_list(M) ++ "-" ++ integer_to_list(D), 
     file:close(get(Filename)),
     file:rename(Filename,Newname), 
     {ok,F} = file:open(Filename,[append]),
     put(Filename,F);
     true -> false
     end;
     0 -> false % the file does not exist.
     end,
     FileHandle = get(Filename),
     {{Year,Month,Day},{Hour,Minute,Second}} = LocalTime,
     do_write(FileHandle,"[~p-~p-~p T ~p:~p:~p] ", [Year,Month,Day,Hour,Minute,Second]), 
     Format2 = Format ++ "~n",
     do_write(FileHandle,Format2,Data).
    
    do_write(FileHandle,Format,Data) ->
     io:format(Format, Data),
     io:format(FileHandle,Format,Data).
     
    
    open_files([]) ->
     ok;
    open_files([File|Others]) ->
     {ok,FileHandle} = file:open(File,[append]),
     put(File,FileHandle),
     open_files(Others).
    
    close_files([]) ->
     ok;
    close_files([File|Others]) ->
     FileHandle = get(File),
     file:close(FileHandle),
     close_files(Others).

    daylog.app

    {application,daylog, %%应用名
    [ {description,""}, 
     {vsn,"0.1.0"},
     {modules,[]}, %%应用中的模块,可留空。 
     {registered,[]}, %%进程注册名,没进行实际注册操作,用于告知otp系统哪个进程注册了哪个名字,可留空
     {applications,[kernel,stdlib]}, %%先行启动的所有应用,不能留空
     {mod,{daylog_app,[]}}, %%指定应用启动模块,不能留空
     {env,[{log_file,"../../logs/info.log"}]}
    ]}.

    compile.sh

    for f in *.erl;do erlc +debug_info -o ../ebin $f;done

    reference.txt

    API Reference:
    Module:daylog
    
    add_logfiles(Files):
     Types:
     Files : a list for filenames 
    
    info_log(Msg):
     Types:
     Msg: string
     descript:output log to default file which is descripted in ebin/daylog.app.
     
    info_log(Format,Datas)
     Types:
     Format: string
     Datas: list for data
    
    logger(FileName,Msg) ->
     Types:
     FileName: string
     Msg: String
    
    logger(FileName,Format,Datas) ->
     Types:
     FileName: string
     Format: string
     Datas: list for data
  • 相关阅读:
    Java线程
    腾讯2012.9.23校园招聘笔试题
    腾讯2011.10.15校园招聘笔试题
    腾讯2013年实习生笔试题目
    腾讯2012.4.25实习生招聘笔试题(2)
    腾讯2012.4.25实习生招聘笔试题
    优酷土豆2012.9.12校园招聘笔试题
    谷歌面试题:在半径为1的圆中随机选取一点
    Reservoir Sampling
    微软面试15道
  • 原文地址:https://www.cnblogs.com/kingson-blog/p/4835044.html
Copyright © 2011-2022 走看看