Java 日志(Logging)与协同调试

Java 日志(Logging)与协同调试

对于一个应用程序来说日志记录是必不可少的一部分,不仅线上问题追踪,基于日志的业务逻辑统计分析离不日志,按约定编写日志,对于团队协同开发也是至关重要的。

“队友看不懂你的代码”这绝对正确的假设。那如何把集成测试或开发中发现问题相关详细信息告诉问题人(异常输出常是天书),而不要两人坐在一起联合调试?利用日志,打印出业务类(Java 约定每个类都是唯一负责人的)的重要信息是最有价值的,通过研究业务类之间协同关系,调试者就能快速理解业务场景上下文(Context),发现问题所在。

1、日志历史与框架

1.1 历史与发展1

  • 1996年早期,欧洲安全电子市场项目组决定编写它自己的程序跟踪API(Tracing API)。经过不断的完善,这个API终于成为一个十分受欢迎的Java日志软件包,即Log4j。后来Log4j成为Apache基金会项目中的一员。
  • 期间Log4j近乎成了Java社区的日志标准。据说Apache基金会还曾经建议sun引入Log4j到java的标准库中,但Sun拒绝了。
  • 2002年Java1.4发布,Sun推出了自己的日志库JUL(Java Util Logging),其实现基本模仿了Log4j的实现。在JUL出来以前,log4j就已经成为一项成熟的技术,使得log4j在选择上占据了一定的优势。
  • 接着,Apache推出了Jakarta Commons Logging,JCL只是定义了一套日志接口(其内部也提供一个Simple Log的简单实现),支持运行时动态加载日志组件的实现,也就是说,在你应用代码里,只需调用Commons Logging的接口,底层实现可以是log4j,也可以是Java Util Logging。
  • 后来(2006年),Ceki Gülcü不适应Apache的工作方式,离开了Apache。然后先后创建了slf4j(日志门面接口,类似于Commons Logging)和Logback(Slf4j的实现)两个项目,并回瑞典创建了QOS公司,QOS官网上是这样描述Logback的:The Generic,Reliable Fast&Flexible Logging Framework(一个通用,可靠,快速且灵活的日志框架)。
  • 现今,Java日志领域被划分为两大阵营:Commons Logging阵营和SLF4J阵营。Commons Logging在Apache大树的笼罩下,有很大的用户基数。但有证据表明,形式正在发生变化。2013年底有人分析了GitHub上30000个项目,统计出了最流行的100个Libraries,可以看出slf4j的发展趋势更好:

    Java 日志(Logging)与协同调试_第1张图片

    junit 和 slf4j 真是好 CP。即正规开发团队绝对多数成对使用两个包,初学者或临时项目两者都不用。

  • Apache眼看有被Logback反超的势头,于2012-07重写了log4j 1.x,成立了新的项目Log4j 2。Log4j 2具有logback的所有特性。

1.2 常用日志框架

  • Log4j Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的。
  • Log4j 2 Apache Log4j 2是apache开发的一款Log4j的升级产品。
  • Commons Logging Apache基金会所属的项目,是一套Java日志接口,叫Jakarta Commons Logging,或 Commons Logging。
  • Slf4j 类似于Commons Logging,是一套简易Java日志门面,本身并无日志的实现。(Simple Logging Facade for Java,缩写Slf4j)。
  • Logback 一套日志组件的实现(slf4j阵营)。
  • Jul (Java Util Logging),自Java1.4以来的官方日志实现。

2、编程与使用

2.1 Log4j简易入门

(1)建立包依赖

打开 pom.xml (如 hello world 程序),在 dependencies 下添加

    
    <dependency>
      <groupId>log4jgroupId>
      <artifactId>log4jartifactId>
      <version>1.2.17version>
    dependency>

存盘后,很快就完成了下载,添加的外部库就有了。

(2)配置日志输出

在 main 下创建 resources 目录,创建 log 4.properties 文本文件2:

#可以设置级别:debug < info < warn < error
#debug: 显示debug, info, warn, error
#info: 显示info, warn, error
#warn: 显示warn, error
#error: 只显示error
#日志的输出级别由rootLogger和普通Logger设置的最高级别决定。

#log4j.rootLogger=debug,appender1
#log4j.rootLogger=info,appender1
log4j.rootLogger=warn,appender1
#log4j.rootLogger=error,appender1

#选择以下日志输出类
#org.apache.log4j.ConsoleAppender(控制台),
#org.apache.log4j.FileAppender(文件),
#org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),
#org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件),
#org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

#输出到控制台
log4j.appender.appender1=org.apache.log4j.ConsoleAppender
#样式为TTCCLayout
log4j.appender.appender1.layout=org.apache.log4j.TTCCLayout

#这里配置的是类所在的包test.log4j, 逗号之前未配置日志输出级别,默认为根logger的级别
log4j.logger.test.log4j=, TEST
log4j.appender.TEST=org.apache.log4j.ConsoleAppender
log4j.appender.TEST.layout=org.apache.log4j.TTCCLayout

如果你要自定义输出个格式,建议阅读3。

(3)日志输出

程序如图:

Java 日志(Logging)与协同调试_第2张图片

编程中 IDE 问题:

  • 使用 Intellij Idea, 如果不自动导入,检查“File -> settings… -> Edtor -> General -> Auto import” 开启自动导入。
  • 由于很多包都用了 Logger 这个类名,则使用 Alt + Enter 选择 import org.apache.log4j.Logger

注意:需要做日志的类,一定在开始生成静态的 logger 对象,参数一定是这个类的类型。

输出结果:

Hello World!
[main] WARN com.mycompany.helloworld.App - This is warn message
[main] ERROR com.mycompany.helloworld.App - This is error message

2.2 SLF4J 快速入门

Simple Logging Facade for Java (SLF4J) 作为其他各种日志框架的门面(Facade)或抽象(Abstraction),为应用程序提供一致的服务。可在部署期间再选择与环境匹配的日志实现。

SLF4J 没有实现日志配置与输出,只实现了应用程序访问日志的门面,官方4图表达的很清晰:

Java 日志(Logging)与协同调试_第3张图片

SLF4J 相当成功,这意味程序员不需要学习任何日志的知识,仅需要掌握 SLF4J 就够了。具体日志的实现与配置,拿来就用。 因此,它获取了与 Junit 类似的地位,成为事实的日志标准。

(1)SLF4J 配置

看上图,我们用 slf4j 做日志标准,log4j1.2 做实现,则 pom.xml 配置如下:


<dependency>
    <groupId>org.slf4jgroupId>
    <artifactId>slf4j-log4j12artifactId>
    <version>1.7.21version>
dependency>

使用上图第三排作为依赖,应用会自动添加所有正确的依赖。

(2)日志输出

程序如图:

Java 日志(Logging)与协同调试_第4张图片

程序中在也没有与 log4j 相关的类了,LoggerFactory 是生产日志类的工程(Factory Pattern/设计模式),Java 程序员看了多很亲切。关键是输出结果一样!!!

输出结果:

Hello World!
[main] WARN com.mycompany.helloworld.App - This is waring message
[main] ERROR com.mycompany.helloworld.App - This is error message

slf4j 输出是与 print 语句一致的,程序员感觉很好。

3、日志级别与协同开发

3.1 日志级别

日志记录器(Logger)的可用级别Level (不包括自定义级别 Level), 以下内容就是摘自log4j API (5“>http://jakarta.apache.org/log4j/docs/api/index.html)6,这里仅列举了程序中用到的四种:

  • DEBUG Level指出细粒度信息事件对调试应用程序是非常有帮助的。
  • INFO level表明 消息在粗粒度级别上突出强调应用程序的运行过程。
  • WARN level表明会出现潜在错误的情形。
  • ERROR level指出虽然发生错误事件,但仍然不影响系统的继续运行。

日志记录器(Logger)的行为是分等级的。分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、ALL或者您定义的级别。制到应用程序中相应级别的日志信息的开关。比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少。

3.2 协同开发

(1)个体调试

个体开发通常只需要 debug, warn, error。
Debug 就是程序员查看程序的执行过程工具,例如,执行 sql 前打印 SQL 语句等;
Warn 就是程序员检查输入和关键点数据脱离期望的位置的输出,例如,输入为 null 等;
Error 几乎就是异常处理位置的输出。例如,连接异常断开等。

程序员通常这样做细粒度配置 log4j ,例如:

log4j.logger.org.apache=warn
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG 

这时 jdbc 这些类的细节都打印出来,这对分析局部数据访问问题是绝对有效的。

(2)协同调试

对于分布式开发的程序员,给出上述信息要么太多,要么不够。这些程序员需要什么样的信息支持调试呢?如果知道一些软件设计,如设计的如下顺序图(网上下载的图,不代表作者观点)

Java 日志(Logging)与协同调试_第5张图片

这个设计图反映了控制器、业务服务、数据存取类协同过程。通常,这些类是不同程序员实现的。
现在,数据库中有用户信息,但如何用日志显示登陆过程中对象协作过程呢? Info 信息闪亮登场了

通常我们在这些对象公有方法的开始,例如在登陆服务登陆方法的开始:
logger.info("Enter login with user={} and key={}",user.name, user.key);
在测试与调试阶段,通过合适的日志配置,例如:

log4j.rootLogger=warn,appender1
...
log4j.logger.com.mycompany.myproject=info

日志输出则得到如设计图要求的对象协作过程,以及其中的关键上下文信息。
粗粒度级别 信息的理解不是概念,而是持续构建实践的关键之一。

3.3 日志使用注意事项

  • 所有程序员必须了解 debug, info, warn, error 的使用,才能保证持续集成产生有价值的信息;
  • 必须了解生成日志的时间成本。由于每产生一条日志大约需要耗时 10ms ,生产系统日志级别必须在 error 或以上;

你必须知道程序开发是创造性劳动。即程序员和摄影师、画家一样,有了好的 ideal,必须在最短时间内写完,根本没太多时间考虑测试,日志等后期工作。如同摄影师,在街头就是迅速构思并完成拍照,美化等交给 PS 后期。但是,没有好的后期工作,保证好产品也很难。

4、小结

本文描述了日志门面 slj4f 和 log4j 的使用,重点讲述了日志在产品每日构建中的重要作用。其中,很多编程约定是程序员必须遵守的,约定胜于配置!

本文也涉及了一些设计模式,例如:门面模式、工厂模式。了解这些模式,对中级编程至关重要。

【参考】


  1. Java常用日志框架介绍,http://www.cnblogs.com/chenhongliang/p/5312517.html ↩
  2. log4j和slf4j ,http://www.cnblogs.com/maxupeng/archive/2011/07/25/2116378.html ↩
  3. log4j详解与实战,http://www.iteye.com/topic/378077 ↩
  4. SLF4J user manual, http://www.slf4j.org/manual.html ↩
  5. Log4j 日志级别,http://wang09si.blog.163.com/blog/static/17017180420141017114242755/ ↩
  6. Log4j 日志级别,http://wang09si.blog.163.com/blog/static/17017180420141017114242755/ ↩

你可能感兴趣的:(Java&Spring)