日志记录是在软件开发过程中常常需要考虑的关键因素。

当产品运行出错时,日志文件通常是我们进行错误分析的首要选择。

而且,在很多情况下,它们是我们手上唯一可以用来查明发生状况和问题根本原因的信息。

可见,正确记录需要的信息是极其重要的。

以下5条日志规则,让我们可以检查和改进在代码中操作日志记录的方式。

同时也请注意,我们既不会讨论怎么配置一个日志引擎,也不会相互比较。

规则1、日志是面向读者的

日志消息不仅要对书写(日志)代码的人有意义,也应该对日志文件的读者有意义。

这似乎是一条很明显但却经常违背的规则。

ERROR: Save failure - SQLException .....

举个例子吧,我们来看看下面这条日志信息:

ERROR: Save failure - SQLException .....

保存什么呢?这条消息在开发者看来是能说明一些问题的,但是对于正在苦苦查看产品问题的可怜家伙来说,却毫无用处。

RROR: Save failure- Entity=Person, Data=[id=123 surname="Mario"] - SQLException....

更合适的信息是这样的:

RROR: Save failure- Entity=Person, Data=[id=123 surname="Mario"] - SQLException....

这就解释了你想要存储的东西(这里是一个 Person,是一个 JPA 实体)以及这个 Person 实例相关的内容。

请注意相关这个单词,并不是指泛泛的全体:我们不应该让无价值的信息使日志文件变得乱糟糟,比如说完整打印所有的实体字段。

通常,实体名字和其逻辑关键字足以识别在表格中的一条记录了。

规则2、匹配日志等级和执行环境

在 Java 系统中提供的所有日志管理工具和引擎都有日志等级(ERROR、INFO……)的概念,这将有可能过滤掉等级过低的消息。

例如,Java util logging 使用如下的等级:SEVERE、WARN、INFO、FINE、FINER、FINEST(+ CONFIG 和 OFF)。相反,两个最受欢迎的日志管理工具, Apache Commons Logging 和 SLFJ 更倾向于如下的等级:FATAL、ERROR、WARN、INFO、DEBUG、TRACE。

日志过滤等级则需要取决于代码的开发阶段:成品与仍处在测试、集成环境下的代码日志等级就不能相同。

更具体的来说,日志等级也应该参考代码的归属情况。

一般而言,我们自己的应用程序代码应该比使用的任何第三方开发库拥有更详细的日志记录。

比如说,Apache 的通用调试消息出现在我们的日志文件中,就没有多大意义。

我通常像这样配置日志记录:

  • 成品阶段: 我的代码是 INFO 等级,第三方库是 WARN。
  • 测试、集成阶段:我的代码是 DEBUG 等级,第三方库是 WARN(或者如果需要的话是 INFO)。
  • 开发阶段:任何有意义的信息。

注意:个人而言,我不建议使用 TRACE/FINEST 等级(我并不是唯一持这种观点的人,可以参考 这里的例子)。

我并没有发现 DEBUG 和 TRACE 有多大的区别,而年轻团队的成员常常苦恼于到底是使用 DEBUG 还是 TRACE 。

根据 KISS 原则,我建议只使用 RROR、WARN、INFO 和 DEBUG 等级。

规则3、提交前去除编码帮助日志

编码时,我们常常会使用 logger 或是 System.out 在代码中添加日志消息,来更好地掌握应用程序在执行、调试期间发生的状况。

void aMethod(String aParam) {
  LOGGER.debug(“Enter in aMethod”);
  if (“no”.equals(aParam)) {
  LOGGER.debug(“User says no”);
  ….

比如这样的代码:

void aMethod(String aParam) {
  LOGGER.debug(“Enter in aMethod”);
  if (“no”.equals(aParam)) {
  LOGGER.debug(“User says no”);
  ….

这些消息显示被调用的方法并且备份内部变量及方法参数值,主要是为了追踪应用程序的行为。这在非测试驱动开发中相当受欢迎。

但糟糕的是,一旦代码发布(测试之后成为成品)这些消息通常就无用武之地了。

所以,这条规则简单来说就是:一旦你已经完成开发工作,在将代码提交到使用中的 SCM 系统(git、svn……)之前,要去除所有临时的和不必要的日志消息。

这条规则并不是要求去除所有的 DEBUG 消息,只是针对那些在应用程序完成和发布后就没有意义的消息,或者是说当我们有理由相信应用程序能正确运行时就失去意义的那些消息。

规则4、log DEBUG消息之前检查日志等级

根据第2条规则,在产品日志中,我们只会显示 ERROR、WARN、INFO 等级的消息,但是在代码中我们也可以使用一些不会影响产品运行的 DEBUG 消息。

if ( LOGGER.isDebugEnabled((){
 LOGGER.debug (…….)
 }

每次你想要 log 一个 DEBUG 消息时(在使用了规则3后的留下的所有消息),需要在前面添加一个检查来明确是否启用了 DEBUG 日志:

if ( LOGGER.isDebugEnabled((){
 LOGGER.debug (…….)
 }

这种做法可以阻止代码去创建日志消息和调用 logger,提高产品运行程序的效率。

规则5、了解你的 logger

我们使用 logger 方法的方式可能会带来巨大的开销:

  • 创建消息字符串
  • 组织包含在消息字符串中的数据

我们应该查阅所选择的日志管理工具、引擎的 javadoc 文档,了解使用它们 logger 的最有效的方法。

LOGGER.info(“Person name is “ + person.getName());

例如,我们可以创建一条这样的消息:

LOGGER.info(“Person name is “ + person.getName());

这就创建了不必要的字符串实例。

LOGGER.info(“Person name is {}“, person.getName());

使用SLF4J,正确的用法应该是:

LOGGER.info(“Person name is {}“, person.getName());

这里的格式化字符串是常量,不可变消息只有在允许 logging 的情况下才会被创建。

Java日志记录的5条规则的更多相关文章

  1. Java 日志记录规则

    Java 日志记录规则 规则一:日志是面向读者的 我们不应该让无价值的信息使日志文件变得乱糟糟,比如说完整打印所有的实体字段. 通常,实体名字和其逻辑关键字足以识别在表格中的一条记录了. 规则二:匹配 ...

  2. Java学习笔记(十九)——Java 日志记录 AND log4j

    [前面的话] 学习的进度应该稍微在快一点. Java日志到了必须学习怎么使用的时候了,因为在项目中要进行使用.基础性文章,选择性阅读. [结构] java日志对调试,记录运行,问题定位都起到了很重要的 ...

  3. Java日志记录的事儿

    一.java日志组件 1.common-logging common-logging是apache提供的一个通用的日志接口.用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者jdk自带的 ...

  4. (网页)Java日志记录框架Logback配置详解(企业级应用解决方案)(转)

    转自CSDN: 前言 Logback是现在比较流行的一个日志记录框架,它的配置比较简单学习成本相对较低,所以刚刚接触该框架的朋友不要畏惧,多花点耐心很快就能灵活应用了.本篇博文不会具体介绍Logbac ...

  5. Java日志记录工具SLF4J介绍

    SLF4J是什么 SLF4J是一个包装类,典型的facade模式的工具,对用户呈现统一的操作方式,兼容各种主流的日志记录框架,典型的有log4j/jdk logging/nop/simple/jaka ...

  6. Java日志记录--log4j and logback

    问题的引入: 把所有的信息打印在控制台上不行吗? 01.控制台有行数限制: 02.System.out.println()影响系统性能: 03.如果我们需要对一些用户的行为习惯进行分析,我们找不到用户 ...

  7. Java日志 #01# 入门

    很多人在学习完一个东西之后就会忘掉自己作为初学者时的体验.. 例如刚接触git的时候自己也是一头雾水,然后别人问起来,老是会说:xxxx#!@#,就是这么回事儿,有什么不好懂的. 其实从不懂到懂,再到 ...

  8. NLog日志记录

    配置NLog         NLog支持 .Net 4.5 以及以上版本!              首先去下载NLog的DLL下载地址:http://nlog-project.org/downlo ...

  9. Java 日志框架终极教程

    概述 对于现代的 Java 应用程序来说,只要被部署到真实的生产环境,其日志的重要性就是不言而喻的,很难想象没有任何日志记录功能的应用程序被运行于生产环境中.日志 API 所能提供的功能是多种多样的, ...

随机推荐

  1. 一、C# 概述

    1.托管执行环境 2.程序集 3.关键字:C#保留字 4.除了C#定义的关键字之外,开发者可以提供他们自己的名称,编程语言将这些名称称为标识符 5.如果关键字包含一个"@"前缀,那 ...

  2. 一个js加css加html完成的HTML

    效果图: 代码: HTML: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "htt ...

  3. js Module模式

    // 创建一个立即调用的匿名函数表达式// return一个变量,其中这个变量里包含你要暴露的东西// 返回的这个变量将赋值给counter,而不是外面声明的function自身 var counte ...

  4. WinForm控件复杂数据绑定常用数据源(对Combobox,DataGridView等控件DataSource赋值的多种方法)

    开始以前,先认识一下WinForm控件数据绑定的两种形式,简单数据绑定和复杂数据绑定. 1) 简单数据绑定 简单的数据绑定是将用户控件的某一个属性绑定至某一个类型实例上的某一属性.采用如下形式进行绑定 ...

  5. 疯狂的表单-html5新增表单元素和属性

    疯狂的表单 2015/11/27 16:44:07 从三方面来介绍html5表单的新特性 表单结构更灵活 要提交数据的控件可以布局在form标签之外,看下面的代码,表单元素可以写到form元素之外,只 ...

  6. etTimeout与setInterval方法的区别

    etTimeout与setInterval方法的区别 setTimeout()用于设定在指定的时间之后执行对应的函数或代码.,在全局作用域下执行 setTimeout(code,time[,args… ...

  7. python 过滤html方法

    from HTMLParser import HTMLParser class MLStripper(HTMLParser): """ 过滤html方法 "&q ...

  8. C语言的编译过程和GCC编译参数

    C语言的编译一般有三个步骤: 预编译: gcc -E -o a.e a.c 预编译a.c文件,生成的目标文件名为a.e 预编译就是将include包含的头文件内容替换到C文件中,同时删除代码中没用的注 ...

  9. strstr_while模型

    #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string. ...

  10. [BZOJ 1028] [JSOI2007] 麻将 【枚举+贪心判断】

    题目链接:BZOJ - 1028 题目分析 枚举听的是哪种牌,再枚举成对的是哪种牌,再贪心判断: 从1到n枚举每一种牌,如果这种牌的个数小于0,就返回不合法. 将这种牌的张数 % 3, 剩下的只能和 ...