当前位置:首 页 > 攻城湿 > 查看文章

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

攻城湿 你是第1671个围观者 0条评论 供稿者: 标签:,

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

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

怎样记日志可以方便Troubleshooting?

1. 对外部的调用封装

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

  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);
  }

2.状态变化

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

  boolean isRunning;

  isRunning = true;
  LOG.info("System is running");

  //...

  isRunning = false;
  LOG.info("System was interrupted by " + Thread.currentThread().getName());

3.系统入口与出口:

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

  void execute(Object input) {
      LOG.debug("Invoke parames : " + input);
      Object result = null;

      //business logic

      LOG.debug("Method result : " + result);
  }

4.业务异常:

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

  try {
      //business logical
  } catch (IOException e) {
      LOG.warn("Description xxx" , e);
  } catch (BusinessException e) {
      LOG.warn("Let me know anything");
  } catch (Exception e) {
      LOG.error("Description xxx", e);
  }

5.非预期执行:

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

  int myValue = xxxx;
  int absResult = Math.abs(myValue);
  if (absResult < 0) {
      LOG.info("Original int " + myValue + "has nagetive abs " + absResult);
  }

6.很少出现的else情况:

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

  Object result = null;
  if (running) {
     result = xxx;
  } else {
     result = yyy;
     LOG.debug("System does not running, we change the final result");
  }

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

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

1. 程序运行时间:

  long startTime = System.currentTime();

  // business logical

  LOG.info("execution cost : " + (System.currentTime() - startTime) + "ms"); 

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

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

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

执行关键的逻辑,做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
 }

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

1. 混淆信息的Log

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

  Connection connection = ConnectionFactory.getConnection();
  if (connection == null) {
      LOG.warn("System initialized unsuccessfully");
  }

2. 记错位置

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

      } catch (ConfigurationException e) {
         e.printStackTrace();
      }

3. 记错级别

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

  LOG.warn("Failed to login by "+username+");

4. 遗漏信息

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

       } catch (Exception ex) {
        log.error(ex);
       }

总结:

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

参考文献

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

作者介绍

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


这家伙很懒,什么都没写!

—— zhaorong

zhaorong
你可能也喜欢Related Posts
众说纷纭Comments
大眼 可爱 大笑 坏笑 害羞 发怒 折磨 快哭了 大哭 白眼 晕 流汗 困 腼腆 惊讶 憨笑 色 得意 骷髅 囧 睡觉 眨眼 亲亲 疑问 闭嘴 难过 淡定 抗议 鄙视 猪头
小提示:直接粘贴图片到输入框试试
努力发送中...
  • 评论最多
  • 最新评论
  • 随机文章
footer logo
未经许可请勿自行使用、转载、修改、复制、发行、出售、发表或以其它方式利用本网站之内容
Copyright © zhaorong All Rights Reserved. 滇ICP备15006105号-1