日志打印规范及技巧学习总结

一、日志打印级别

  • DEBUG(调试)
    开发调试日志。一般来说,在系统实际运行过程中,不会输出该级别的日志。因此,开发人员可以打印任何自己觉得有利于了解系统运行状态的东东。不过很多场景下,过多的DEBUG日志,并不是好事,建议是按照业务逻辑的走向打印。
  • INFO(通知)
    INFO日志级别主要用于记录系统运行状态等关联信息。该日志级别,常用于反馈系统当前状态给最终用户。所以,在这里输出的信息,应该对最终用户具有实际意义,也就是最终用户要能够看得明白是什么意思才行。
  • WARN(警告)
    WARN日志常用来表示系统模块发生问题,但并不影响系统运行。 此时,进行一些修复性的工作,还能把系统恢复到正常的状态。
  • ERROR(错误)
    此信息输出后,主体系统核心模块正常工作,需要修复才能正常工作。 就是说可以进行一些修复性的工作,但无法确定系统会正常的工作下去,系统在以后的某个阶段,很可能会因为当前的这个问题,导致一个无法修复的错误(例如宕机),但也可能一直工作到停止也不出现严重问题。

二、日志打印规范

1. 【强制】应用中不可直接使用日志系统 (Log 4 j 、 Logback) 中的 API ,而应依赖使用日志框架
SLF 4 J 中的 API ,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Abc.class);
  1. 【强制】日志文件推荐至少保存 15 天,因为有些异常具备以“周”为频次发生的特点。

可以结合实际业务需求,基于按天,和按照容量配置appender。例如,按天保存接口对接基本关键数值记录日志,按照容量保存接口对接详细日志。

  1. 【强制】应用中的扩展日志 ( 如打点、临时监控、访问日志等 )
  • 命名方式:appName _ logType _ logName . log 。
  • 日志类型( logType),推荐分类有stats / desc / monitor / visit 等
  • 日志描述(logName)
    这种命名的好处:通过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。推荐对日志进行分类,如将错误日志和业务日志分开存放,便于开发人员查看,也便于通过日志对系统进行及时监控。
    正例: mppserver 应用中单独监控时区转换异常,如:mppserver _ monitor _ timeZoneConvert . log
  1. 【强制】对 trace / debug / info 级别的日志输出,必须使用条件输出形式或者使用占位符的方式。
    说明: logger . debug( " Processing trade with id : " + id + " and symbol : " + symbol)。如果日志级别是 warn ,上述日志不会打印,但是会执行字符串拼接操作,如果 symbol 是对象,会执行 toString() 方法,浪费了系统资源,执行了上述操作,最终日志却没有打印。
    正例: ( 占位符 )
    logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
  1. 【强制】避免重复打印日志,浪费磁盘空间,务必在 log 4 j . xml 中设置 additivity = false 。
    正例: <logger name="com.taobao.dubbo.config" additivity="false">
  1. 【强制】异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字 throws 往上抛出。
    正例: logger.error(各类参数或者对象 toString + "_" + e.getMessage(), e);
  1. 【推荐】谨慎地记录日志。生产环境禁止输出 debug 日志 ; 有选择地输出 info 日志 ; 如果使用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时删除这些观察日志。
    说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。记录日志时请思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?
  1. 【参考】可以使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从。注意日志输出的级别, error 级别只记录系统逻辑出错、异常等重要的错误信息。如非必要,请不要在此场景打出 error 级别。

三、日志打印技巧

问题排查的日志

  • 对接外部的调用封装
    程序中对接外部系统与模块的依赖调用前后都记下日志,方便接口调试。出问题时也可以很快理清是哪块的问题
LOG.debug("Calling external system:" + parameters);  
Object result = null;  
try {  
    result = callRemoteSystem(params);  
    LOG.debug("Called successfully. result is " + result);  
} catch (Exception e) {  
    LOG.warn("Failed at calling xxx system . exception : " + e);  
}  
  • 状态变化:
    程序中重要的状态信息的变化应该记录下来,方便查问题时还原现场,推断程序运行过程
boolean isRunning = true;  
LOG.info("System is running");  
//...  
isRunning = false;  
LOG.info("System was interrupted by " + Thread.currentThread().getName()); 
  • 系统入口与出口:
这个粒度可以是重要方法级或模块级。记录它的输入与输出,方便定位 
void execute(Object input) {  
    LOG.debug("Invoke parames : " + input);  
    Object result = null;  
      
    //business logical  
      
    LOG.debug("Method result : " + result);  
}  
  • 业务异常:
    任何业务异常都应该记下来
try {  
    //business logical  
} catch (IOException e) {  
    LOG.warn("Description xxx" , e);  
} catch (BusinessException e) {  
    LOG.warn("Let me know anything",e);  
} catch (Exception e) {  
    LOG.error("Description xxx", e);  
}  
  
void invoke(Object primaryParam) {  
    if (primaryParam == null) {  
        LOG.warn(原因...);  
        return;  
    }  
} 
  • 非预期执行:
    为程序在“有可能”执行到的地方打印日志。如果我想删除一个文件,结果返回成功。但事实上,那个文件在你想删除之前就不存在了。最终结果是一致的,但程序得让我们知道这种情况,要查清为什么文件在删除之前就已经不存在呢
int myValue = xxxx;  
int absResult = Math.abs(myValue);  
if (absResult < 0) {  
    LOG.info("Original int " + myValue + "has nagetive abs " + absResult);  
}  
  • 很少出现的else情况:
    else可能吞掉你的请求,或是赋予难以理解的最终结果
Object result = null;  
if (running) {  
   result = xxx;  
} else {  
   result = yyy;  
   LOG.debug("System does not running, we change the final result");  
}  

程序运行状态的日志

程序在运行时就像一个机器人,我们可以从它的日志看出它正在做什么,是不是按预期的设计在做,所以这些正常的运行状态是要有的。

  • 程序运行时间:
long startTime = System.currentTime();  
  
// business logical  
  
LOG.info("execution cost : " + (System.currentTime() - startTime) + "ms");  

大批量数据的执行进度:

LOG.debug("current progress: " + (currentPos * 100 / totalAmount) + "%"); 

关键变量及正在做哪些重要的事情:
执行关键的逻辑,做IO操作等等

String getJVMPid() {  
   String pid = "";  
   // Obtains JVM process ID  
   LOG.info("JVM pid is " + pid);  
   return pid;  
}  
  
void invokeRemoteMethod(Object params) {  
    LOG.info("Calling remote method : " + params);  
    //Calling remote server  
} 

四、需要规避的问题

  • 频繁打印大数据量日志:
    当日志产生的速度大于日志文件写磁盘的速度,会导致日志内容积压在内存中,导致内存泄漏。

  • 无意义的Log:
    日志不包含有意义的信息: 你肯定想知道的是哪个文件不存在吧

File file = new File("xxx");  
if (!file.isExist()) {  
    LOG.warn("File does not exist"); //Useless message  
} 
  • 混淆信息的Log:
    日志应该是清晰准确的: 当看到日志的时候,你知道是因为连接池取不到连接导致的问题么?
Connection connection = ConnectionFactory.getConnection();  
if (connection == null) {  
    LOG.warn("System initialized unsuccessfully");  
}  

参考:
《阿里巴巴开发手册》
Logger日志级别说明及设置方法、说明
闲谈程序中如何打印log

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容

  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 4,817评论 1 13
  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 4,907评论 0 6
  • idea 添加注释/** 然后回车 选中代码块 Ctrl+Shift+/ 重点推荐阅读:https://www....
    Helen_Cat阅读 19,403评论 0 37
  • From:Python之日志处理(logging模块) - 云游道士 - 博客园 https://www.cnbl...
    vigny的先生阅读 2,640评论 3 5
  • 程序员的日常离不开日志,日志就好比私人秘书,负责运行周期一切trace工作。优秀的日志实践能极大帮助地程序员快速定...
    Java架构阅读 789评论 0 3