写点什么

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

  • 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:1918873

评论

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

后端开发实战总结 | 签约计划第二季|后端

阿Q说代码

内容合集 签约计划第二季 技术专题合集

博文推荐|使用 Pulsar IO 打造流数据管道

Apache Pulsar

Java 开源 架构 云原生 Apache Pulsar

长连接网关技术专题(六):石墨文档单机50万WebSocket长连接架构实践

JackJiang

websocket 即时通讯 IM 网关

高校企业双向赋能,首届飞桨启航菁英计划圆满结束

百度大脑

人工智能 百度 飞桨

语法糖甜不甜?巧用枚举实现“状态”转换限制

阿Q说代码

枚举 签约计划第二季 语法糖 订单状态转换

恒源云(GPUSHARE)_GPU白嫖大法来袭!

恒源云

深度学习 gpu 算力加速

Flink CDC 系列 - 构建 MySQL 和 Postgres 上的 Streaming ETL

Apache Flink

大数据 flink 编程 后端 实时计算

大数据中不同文件格式的比较

吴脑的键客

大数据 云存储

【活动报名】Apache ShardingSphere Dev Meetup 重启!

SphereEx

开源项目 开源社区 ShardingSphere Meetup SphereEx

还在用BeanUtils拷贝对象?MapStruct才是王者!【附源码】

阿Q说代码

Java MapStruct 签约计划第二季 深拷贝与浅拷贝

PackML从会到不会——标签(3)

陈的错题集

标准化 PackML

Spark从入门到精通

冇先生

『上线』OpenSEC SIGs 终于成立了!

SphereEx

开源社区 ShardingSphere SphereEx 中文开源 OpenSEC

【量化】股市技术分析利器之TA-Lib(一)

恒生LIGHT云社区

量化投资 量化

Android技术分享| ViewPager2离屏加载,实现抖音上下视频滑动

anyRTC开发者

android 音视频 移动开发 ViewPager 视频滑动

对象存储手把手教七 | 存储空间授权策略 Bucket Policy

QingStor分布式存储

分布式系统 对象存储 分布式存储 分布式,

实战篇:Security+JWT组合拳 | 附源码

阿Q说代码

spring security JWT 签约计划第二季 权限验证

看了这么多年西游记,你可知道孙悟空是如何召唤土地公公的吗?

阿Q说代码

Java 观察者模式 签约计划第二季 事件通知机制

全程干货,用 python 下载某站全部【免抠图片】,图片背景透明,格式PNG

梦想橡皮擦

12月日更

如何在 ShardingSphere 中开发自己的 DistSQL

SphereEx

Java 数据库 ShardingSphere database SphereEx

用户登录设计之双token设计

CRMEB

「Spark从精通到重新入门(一)」Spark 中不可不知的动态优化

尔达Erda

云计算 大数据 spark 开发者 感悟

实战篇:断点续传?文件秒传?手撸大文件上传

阿Q说代码

断点续传 签约计划第二季 文件秒传 文件分块 文件合并

看了同事写的代码,我竟然开始默默的模仿了。。。

阿Q说代码

策略模式 多态 签约计划第二季 自定义参数解析器 统一验签

IoT Stack 2.0升级物模型及数据交互协议, 大幅提升物联网方案交付速度

百度大脑

人工智能 百度 物联网

看FusionInsight Spark如何支持JDBCServer的多实例特性

华为云开发者联盟

大数据 SQL语句 FusionInsight Spark JDBCServer 多实例

Flink 是如何统一批流引擎的

编程江湖

大数据 flink

如果还不懂如何使用 Consumer 接口,来公司我当面给你讲!

阿Q说代码

函数式接口 签约计划第二季 consumer 实战讲解 supplier

WeTest小程序质量专项方案推出,小程序异常监控内测招募中

WeTest

Linux学习方法《Linux一学就会》Linux系统进程管理

侠盗安全

Linux linux运维 运维工程师 云计算架构师

秒过!度目智慧通行让常态化防疫更高效

百度大脑

人工智能 人脸识别

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