erlang 日志的一些思考

爱⌒轻易说出口 提交于 2020-03-21 16:35:48

3 月,跳不动了?>>>

版本信息

  • Erlang18.3
  • 参考Erlang22.2中logger_formatter.erl文件

模板化的日志文件

  • 1.设置模板格式
%% 默认的日志模板
-define(DEFAULT_FORMAT_TEMPLATE_HEADER,
    [[logger_formatter,header],"\n(",registername,":",pid,":",module,":",line, ")", mfa,":", msg, "\n"]).`

即设置默认的日志模板格式,最后的结构就是:

  • 2.代码分析
-type log_event() :: #{
					   level =>level(),   % 日志打印等级
					   msg => {io:format(),[term()]},  % 日志内容格式
					   meta=>metadata()      % 额外需要的参数  
					  }.
-type metadata() ::{
					pid =>pid(),   % 日志打印的进程id
					gl => pid(),  % group_leader,
					time => interger(),  % 时间戳
					mfa =>{module(),atom(),term()}, 
					line => non_neg_integer()  % 日志打印的行数
						atom() => term()  % 其他的信息
				   }.
-type config() :: {
				   depath =>pos_integer() | unlimted,  % 表明可显示的长度,超过则用 ... 表示
				   legacy_header => boolean(),  %  是否使用默认的头部
				   max_size =>non_neg_integer(),  % 最大长度
				   single_line => boolean(),  % 是否单行显示
				   template => template()   % 自定义模板
				  }.
-spec format(LogEvent, Config) -> string() when
			LogEvent :: log_event(),
			Config :: config().

其中logevent参数主要是这是消息打印信息相关的设置,config则用来限制消息打印的格式,长度等信息

Erlang的数据结构类型

  • tuple 元组格式
  • list 列表格式
  • float 浮点型
  • integer 整型
  • char 字符
  • string 字符串
  • pid 进程
  • refrence() 引用
  • atom() 原子

Erlang的输出格式

  • ~w
  • ~p/~tp
  • ~s/~ts
    ..... 未完

Erlang的数据结构

  • record(record_tag{ arg1,arg2})
  • maps()

字符编码

  • 默认erlang使用的是latin1(可通过io:printable_range()查看)
  • 转换为unicode编码:unicode:characters_to_binary()
  • 转换为utf8:xmerl_ucs:to_utf8()

清理文本格式

string_p1([]) ->[];
string_p1([$\n|T]) -> string_p1(T);    % 换行符
string_p1([$\r|T]) -> string_p1(T);    % 回车符
string_p1([$\s|T]) -> string_p1(T);    % 空格
string_p1([$\t|T]) -> string_p1(T);		%水平制表符
string_p1([$\v|T]) -> string_p1(T);		%垂直制表符
string_p1([$\b|T]) -> string_p1(T);		%退格
string_p1([$\f|T]) -> string_p1(T);		%换页键
string_p1([$\e|T]) -> string_p1(T);		%ESC(换码-溢出)
string_p1([$#|T]) -> string_p1(T);
string_p1([H|T]) ->
   [H|string_p1(T)].

工作中遇到的问题

  • 1.通过format之后,写入文件时无法写入;启动erl设置 +pc unicode
    原因:是因为format之后文件格式是latin1,所以不能写入文件;但是,如果是系统的堆栈是可以的,表明系统内部是已经编码为unicode,但如果是代码中的,则编码格式是latin1,需要转码;转码为unicode之后,在werl框中会乱码,需要注意。
  • 2.需要将日志发送到央服,但是央服的数据格式是asc码的转换,不能显示成中文字符
    原因:unicode格式不能直接保存到数据库中,数据库设置格式是utf-8,所以需要将unicode转码为utf-8
    注意:如果存在中文,直接讲format的生成字符串直接进行utf8转码会报错,需要io_lib:format("~ts",[LogInfo])之后才行。
  • 3.在远程http写库是,如果是数据库报错,会一直写不进去,后来查明,是因为央服日志会对收到的信息进行检测,如果有mysql相关语句,或者特殊字符,都会失败
    注意:不能直接发送数据库的报错,并且对特殊字符进行过滤

测试用例

?ERR("player:~w  not skill:~w  add skill:~w  old:~w  new:~w", [111111, [111,222], 584, [1,2,3],[4,5,6]]),
    ?ERR("玩家 新 ,,,,,,,,"),
    ?ERR("玩家:~w  不存在的技能:~w  新加技能点:~w  旧:~w  新:~w", [111111, [111,222], 584, [1,2,3],[4,5,6]]),
    ?DEBUG("玩家:~w  不存在的技能:~w  新加技能点:~w  旧:~w  新:~w", [111111, [111,222], 584, [1,2,3],[4,5,6]]),
    ?WARNING("玩家:~w  不存在的技能:~w  新加技能点:~w  旧:~w  新:~w", [111111, [111,222], 584, [1,2,3],[4,5,6]]),
    ?INFO("玩家:~w  不存在的技能:~w  新加技能点:~w  旧:~w  新:~w", [111111, [111,222], 584, [1,2,3],[4,5,6]]),
    ?ERR("float:~p,tuple = ~p, makeref=~p, list = ~tp, pid = ~p, int=~p ", [1.114, {1,2,3},make_ref(),[1,34,5],self(),123]),
    1/0,
    throw("test log"),

关于Erl22.2鱼Erl18.3

  • 1.Erl22.2做了很多底层的优化,提供了更加丰富的接口类型
  • 2.Erl18.3已经有点过时,如果可以,建议升级版本
  • 3.虽然老爷子也强调maps的的使用,想要放弃record,但是从实际的开发来看,record也是有他特有的优势,maps也确实好用

总结

  • 1.处理问题一定要有条理,才能做到心平气和,更快更稳妥的解决问题
  • 2.一定要对系统有个全面的了解,修改彻底,避免漏掉,而造成一些无法预知的错误
  • 3.测试!测试!测试!优化!优化!优化!
  • 4.一定要搞清楚源码,才能做一些修改,不然会有很多副作用,也要看源码的测试用例,可以加深理解
  • 5.碰到陌生的代码,一定要相信会看懂的,时间问题罢了,我看这个源码也是看了有一周左右,才动手修改,做自己的定制
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!