红帽白皮书新鲜出炉!点击获取,让你的云战略更胜一筹! 了解详情
写点什么

程序那些事:日志记录的作用和方法

  • 2012-11-06
  • 本文字数:2271 字

    阅读完需:约 7 分钟

程序中记录日志一般有两个目的:Troubleshooting 和显示程序运行状态。好的日志记录方式可以提供我们足够多定位问题的依据。日志记录大家都会认为简单,但如何通过日志可以高效定位问题并不是简单的事情。这里列举下面三个方面的内容,辅以代码示例,总结如何写好日志,希望对他人有所启发和帮助:

  • 怎样记日志可以方便 Troubleshooting
  • 程序运行状态可以记哪些
  • 应该避免怎样的日志方式

怎样记日志可以方便 Troubleshooting?

1. 对外部的调用封装

程序中对外部系统与模块的依赖调用前后都记下日志,方便接口调试。出问题时也可以很快理清是哪块的问题

复制代码
1. LOG.debug("Calling external system:" + parameters);
2. Object result = null;
3. try {
4. result = callRemoteSystem(params);
5. LOG.debug("Called successfully. result is " + result);
6. } catch (Exception e) {
7. LOG.warn("Failed at calling xxx system . exception : " + e);
8. }

2. 状态变化

程序中重要的状态信息的变化应该记录下来,方便查问题时还原现场,推断程序运行过程

复制代码
1. boolean isRunning;
2.
3. isRunning = true;
4. LOG.info("System is running");
5.
6. //...
7.
8. isRunning = false;
9. LOG.info("System was interrupted by " + Thread.currentThread().getName());

3. 系统入口与出口:

这个粒度可以是重要方法级或模块级。记录它的输入与输出,方便定位

复制代码
1. void execute(Object input) {
2. LOG.debug("Invoke parames : " + input);
3. Object result = null;
4.
5. //business logic
6.
7. LOG.debug("Method result : " + result);
8. }

4. 业务异常:

任何业务异常都应该记下来:

复制代码
1. try {
2. //business logical
3. } catch (IOException e) {
4. LOG.warn("Description xxx" , e);
5. } catch (BusinessException e) {
6. LOG.warn("Let me know anything");
7. } catch (Exception e) {
8. LOG.error("Description xxx", e);
9. }
10.

5. 非预期执行:

为程序在“有可能”执行到的地方打印日志。如果我想删除一个文件,结果返回成功。但事实上,那个文件在你想删除之前就不存在了。最终结果是一致的,但程序得让我们知道这种情况,要查清为什么文件在删除之前就已经不存在

复制代码
1. int myValue = xxxx;
2. int absResult = Math.abs(myValue);
3. if (absResult < 0) {
4. LOG.info("Original int " + myValue + "has nagetive abs " + absResult);
5. }

6. 很少出现的 else 情况:

else 可能吞掉你的请求,或是赋予难以理解的最终结果

复制代码
1. Object result = null;
2. if (running) {
3. result = xxx;
4. } else {
5. result = yyy;
6. LOG.debug("System does not running, we change the final result");
7. }

程序运行状态可以记哪些?

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

1. 程序运行时间:

复制代码
1. long startTime = System.currentTime();
2.
3. // business logical
4.
5. LOG.info("execution cost : " + (System.currentTime() - startTime) + "ms"); 

2. 大批量数据的执行进度:

复制代码
1. LOG.debug("current progress: " + (currentPos * 100 / totalAmount) + "%");

3. 关键变量及正在做哪些重要的事情:

执行关键的逻辑,做 IO 操作等等

复制代码
1. String getJVMPid() {
2. String pid = "";
3. // Obtains JVM process ID
4. LOG.info("JVM pid is " + pid);
5. return pid;
6. }
7.
8. void invokeRemoteMethod(Object params) {
9. LOG.info("Calling remote method : " + params);
10. //Calling remote server
11. }

应该避免怎样的日志方式?

1. 混淆信息的 Log

日志应该是清晰准确的: 当看到日志的时候,你知道是因为连接池取不到连接导致的问题么?

复制代码
1. Connection connection = ConnectionFactory.getConnection();
2. if (connection == null) {
3. LOG.warn("System initialized unsuccessfully");
4. }

2. 记错位置

产品代码中,使用 console 记录日志,导致没有找到日志。

复制代码
1. } catch (ConfigurationException e) {
2. e.printStackTrace();
3. }

3. 记错级别

记错级别常常发生,常见的如:混淆代码错误和用户错误, 如登录系统中,如果恶意登录,那系统内部会出现太多 WARN,从而让管理员误以为是代码错误。可以反馈用户以错误,但是不要记录用户错误的行为,除非想达到控制的目的。

复制代码
1. LOG.warn("Failed to login by "+username+");

4. 遗漏信息

这里可能包含两种情况:(1)用户自己少写了信息, 导致毫无参考价值;(2)用户调用 log 的方式导致丢失信息,如下例,没有 stack trace.

复制代码
1. } catch (Exception ex) {
2. log.error(ex);
3. }

总结:

日志记录在程序员日常编程实践中必须面对的事情,本文针对这个话题谈了下自己的体会,希望读者能有所收益。多有不足,请多包涵。

参考文献

http://www.infoq.com/cn/articles/10-java-questions-easy-to-ignore

作者介绍

冶秀刚, 平台工程师,从事分布式收集与存储系统的研究与开发,爱好读书,喜欢涉猎各类能长见识的内容


给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2012-11-06 00:1918373

评论

发布
暂无评论
发现更多内容

架构训练营模块七作业

喻高咏        

架构训练营 模块七

Python——While 循环for循环与 break 语句

在即

9月日更

linux之tree命令

入门小站

Linux

架构实战营 模块七 作业

脉醉

#架构实战营

架构训练营 模块六

小卷儿

模块7作业

柱林

架构实战营模块 7 作业

zlz

css中塌陷问题指的是什么,margin和padding应该怎么区分

你好bk

CSS html css3 大前端

计算机中遇到的单位该怎么换算

耳东@Erdong

计算机 9月日更 单位换算

架构实战营模块七作业

子豪sirius

架构实战营

又一款Nginx 管理可视化神器!通过界面完成配置监控,一条龙

Summer

Java nginx 学习 程序员 IT

HTML字符实体大全

入门小站

工具

都江堰市建成区块链场景创新实验室!

CECBC

深入了解Spring之ConfigurationClassPostProcessor

邱学喆

@Bean @ComponentScan @PropertySource @Import @ImportResource

模块七作业

Mr.He

架构实战营

[架构实战营]模块七作业

xyu

#架构实战营

聊聊 Jmeter 如何并发执行 Python 脚本

星安果

Python Jmeter 并发 文件上传

模块七-游戏商城异地多活架构设计

babos

#架构实战营

模块七作业

河马先生

架构实战营

14. DeepMind--会打游戏的人工智能

数据与智能

人工智能

架构实战营第一期--模块七作业

clay

架构实战营

模块七 作业

Geek_35a345

专利分析:数字人民币的“双离线”支付问题

CECBC

王者荣耀商城异地多活架构设计

feitian

🏆【Alibaba工具型技术系列】「EasyExcel技术专题」摒除OOM!让你的Excel操作变得更加优雅和安全

洛神灬殇

EasyExcel Apache POI Alibaba 9月日更

模块七作业

VE

架构实战营

学读代码比学写代码更重要

baiyutang

编程 工程规约 9月日更

模块七作业

袁小芬

QUIC简介及简单示例

devpoint

QUIC http3 9月日更

数字化转型潮起 金融机构“科技范儿”十足

CECBC

架构实战营模块 7 作业-王者荣耀商城异地多活架构设计

蔸蔸

程序那些事:日志记录的作用和方法_Java_冶秀刚_InfoQ精选文章