热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

erlang日志功能。

用cowboy这个库,没有日志功能,所以研究了otp提供的日志功能。1.启动SASL的方式erl–bootstart_sasl默认配置文件下启动SASL,{env,[{sasl_e

用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 
%%% Description : Cutting logs every day.
%%%
%%% Created : 4 Mar 2015 by kingson 
%%%-------------------------------------------------------------------
-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日志功能。


推荐阅读
  • WebSocket与Socket.io的理解
    WebSocketprotocol是HTML5一种新的协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • NotSupportedException无法将类型“System.DateTime”强制转换为类型“System.Object”
    本文介绍了在使用LINQ to Entities时出现的NotSupportedException异常,该异常是由于无法将类型“System.DateTime”强制转换为类型“System.Object”所导致的。同时还介绍了相关的错误信息和解决方法。 ... [详细]
  • 本文介绍了Java集合库的使用方法,包括如何方便地重复使用集合以及下溯造型的应用。通过使用集合库,可以方便地取用各种集合,并将其插入到自己的程序中。为了使集合能够重复使用,Java提供了一种通用类型,即Object类型。通过添加指向集合的对象句柄,可以实现对集合的重复使用。然而,由于集合只能容纳Object类型,当向集合中添加对象句柄时,会丢失其身份或标识信息。为了恢复其本来面貌,可以使用下溯造型。本文还介绍了Java 1.2集合库的特点和优势。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 解决Sharepoint 2013运行状况分析出现的“一个或多个服务器未响应”问题的方法
    本文介绍了解决Sharepoint 2013运行状况分析中出现的“一个或多个服务器未响应”问题的方法。对于有高要求的客户来说,系统检测问题的存在是不可接受的。文章详细描述了解决该问题的步骤,包括删除服务器、处理分布式缓存留下的记录以及使用代码等方法。同时还提供了相关关键词和错误提示信息,以帮助读者更好地理解和解决该问题。 ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
author-avatar
mobiledu2502884483
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有