用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

erlang日志功能。的更多相关文章

  1. .NET跨平台之旅:增加文件日志功能遇到的挫折

    在将我们的ASP.NET 5示例站点(about.cnblogs.com)升级至ASP.NET 5 RC1的时候,我们增加了控制台日志功能. 在ASP.NET 5添加日志功能很简单,只需在projec ...

  2. 01Spring_基本jia包的导入andSpring的整体架构and怎么加入日志功能

    1.什么是Spring : v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:u ...

  3. Spring AOP 实现写事件日志功能

    什么是AOP?AOP使用场景?AOP相关概念?Spring AOP组件?如何使用Spring AOP?等等这些问题请参考博文:Spring AOP 实现原理 下面重点介绍如何写事件日志功能,把日志保存 ...

  4. jboss7访问日志功能及使用goaccess工具分析

    网络上虽然很多文章分别讲到jboss7的访问日志如何配置,goaccess工具怎么分析nginx/tomcat等日志.但将两者放在一起即“通过goaccess分析jboss访问日志”的倒是没搜索到. ...

  5. 干货:yii日志功能详解

    转载请注明来自souldak,微博:@evagle 一.基本日志功能 详细的介绍查看官网的document:http://www.yiiframework.com/doc/guide/1.1/en/t ...

  6. MongoDB实战指南(四):MongoDB的Journaling日志功能

    mongoDB的Journaling日志功能与常见的log日志是不一样的,mongoDB也有log日志,它只是简单记录了数据库在服务器上的启动信息.慢查询记录.数据库异常信息.客户端与数据库服务器连接 ...

  7. SSIS从理论到实战,再到应用(6)----SSIS的自带日志功能

    原文:SSIS从理论到实战,再到应用(6)----SSIS的自带日志功能 上期回顾: SSIS从理论到实战,再到应用(5)----流程控制之Foreach循环 博主最近新负责了一个ssis大项目的架构 ...

  8. Nginx之旅系列 - Nginx日志功能 PK Linux内核printk

    题记:Nginx之旅系列是用来记录Nginx从使用到源码学习的点点滴滴,分享学习Nginx的快乐 Nginx 首页: http://nginx.org/ Nginx日志功能 PK Linux内核pri ...

  9. (译)Windsor入门教程---第五部分 添加日志功能

    介绍     现在我们已经有了基础的框架了,是时候添加内容了,那么我们首先应该考虑的就是在应用程序中添加日志功能.我们会使用Windsor来配置,在这一部分,你将学习Windsor之外的其他功能. L ...

随机推荐

  1. mmap和shm共享内存的区别和联系

    共享内存的创建 根据理论: 1. 共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制.共享内存可以通过mmap()映射普通文件(特殊情况下还可以采用匿 ...

  2. 第四组 12月8号sprint会议

    会议时间:12月8号,16:30会议地点:蛙鸣湖旁小树林 会议进程:   1.首先对到场人员进行点名   2.对程序主要功能进行讨论,每人都可以自由发言,然后分配每个成员的任务,并决定实现第一个功能: ...

  3. ruby Matrix 输出 格式化

    require 'matrix' class Matrix def to_pretty_s s = "" i = 0 while i < self.column_size s ...

  4. 读取XML 发送网页版邮件

    DataSet ds = new DataSet(); ds.ReadXml(AppDomain.CurrentDomain.BaseDirectory + "XML\\Mail.xml&q ...

  5. 选择流程—— switch if else结构

    一.switch switch(表达式){ case 常量1: 语句; break; case 常量2: 语句; break; … default; 语句; } 例题:运用switch结构实现购物管理 ...

  6. PHP数组合并 array_merge 与 + 的差异

    在PHP数组合并出过几次问题都没记住,写下来加强一点记忆 PHP数组在合并时,使用 array_merge 与 + 的差异: 1.array_merge(array $array1 [, array  ...

  7. mysql 简单优化方法

    优化步骤:1.查看SQL是否可以优化.2.查看索引是否可以优化.3.查看表结构是否可以优化. show table status from databases like 'tablename%'; / ...

  8. Python.Module.site

    site " This module is automatically imported during initialization. The automatic import can be ...

  9. HTML颜色代码表

      #000000   #2F0000   #600030   #460046   #28004D   #272727   #4D0000   #820041   #5E005E   #3A006F ...

  10. ubuntu如何傻瓜式安装eric6

    最近在搞PyQt5,听闻eric6是一个不错的IDE,但就是配置起来略蛋疼. 在网上搜到不少教程,都是要先编译安装Qt5, PyQt5, sip, qscintilla2, qscintilla2又分 ...