文档章节

Java日志框架研究及常见配置

clannadyue
 clannadyue
发布于 2015/10/14 13:49
字数 3362
阅读 1095
收藏 8
点赞 0
评论 0
    按照基本的定义,日志即是对程序运行过程中关键事件的记录;大体日志分为运行日志和开发日志,运行日志在业务层面记录一些关键事件,为后面的跟踪运行提供帮助,而开发日志大多数时候是调试日志,根据事件流的输出来调试程序;因为开发人员本身的关注领域,运行日志可能制作的比较少,难以达到跟踪业务流的作用,而即使是开发日志,因为开发的调试有各种技巧,即使是跟踪事件流,使用println也比日志配置简单多了,这是一个投资回报的问ti,而人经常性的是短视的,调试可能在这些人眼里根本不需要认真对待,没有前期的事件记录规划,随着系统规模膨胀,执行流增多,执行事件保障,这时候没有一种合理的“开关”机制来选择查看感兴趣事件流,那结局是明晰的,日志不止提供了一种树形的开关结构,它还有灵活的输出控制,在Java常用日志框架Log4J还提供了JMX等接口,可以通过管理面板来监控和修改日志记录行为,这无疑是非常诱人的。
    大体上Java体系中比较常用的日志框架如下

日志框架

支持日志级别

Log4J

FATAL ERROR WARN INFO DEBUG TRACE

Java Logging API

SEVERE WARNING INFO CONFIG FINE FINER FINEST

Apache Commons Logging

FATAL ERROR WARN INFO DEBUG TRACE

SLF4J

ERROR WARN INFO DEBUG TRACE

Logback

ERROR WARN INFO DEBUG TRACE

Jboss logging

FATAL ERROR WARN INFO DEBUG TRACE

按照我比较有限的经验,我大多时候使用的是Log4J1.x版本,在配置一些开源框架时,可能需要到 Apache Commons LoggingSLF4J,在配置Jboss系工具和框架的时候需要用到Jboss logging(例如Hibernate),其他日志框架如Java Logging,为Java自带的,功能上比较简单,用的也不是很多 ,而另一个Logback,这是一个号称Log4J继承者的新一代日志框架,因为我对“新一代”这个名词比较不感冒,我还没有怎么看,感兴趣的可以看看。
    基本上,日志级别是很相似的,这不仅仅是Java生态范围内,整个编程行业应该都有共识,通过日志级别来标记事件的轻重缓急,我们可以通过这个条件进行过滤,显示我们感兴趣的内容,关于日志级别之间的相互关系,这个比较简单,这里就不再说了。

    优秀的编程设计原则中有一条“依赖倒置”,要依赖抽象,不要依赖具体,具体的实践就是面向接口设计了,优秀的项目都会定义高层次抽象,通过封装隐藏多余的信息,这样在代码变动或者想不修改原有代码扩展的时候(开闭原则),能够相对容易的满足这些需求,而这些日志框架设计结构中则充分发挥了面向接口设计的优良传统,日志框架的核心接口是Logger类(接口),其他部分则是围绕此类(接口)展开,这里我们看两个定义例子,SLF4J的Logger定义如下


Apache Commons Logging的Log定义如下


因为其他的日志框架实在都太“重量级”了,方法太多,这里就不贴出定义了,日志框架定义了基本的接口,通过提供一个Facade,而后端由谁去实现就不那么重要了,这里面Apache Commons Logging、SLF4J、Jboss logging都容许其他后端实现为别的日志框架(大部分为Java Logging 、Log4J,差异化的部分在讲这些日志框架的时候再详细叙述),如何将Facade的请求转为后端可识别请求,知道一点设计模式的人应该马上想到适配器模式,这里,我们想给出几个日志框架如何实现这个接口适配的解决方法,我们一一道来。
      Apache Commons Logging

这是标准的适配器模式,没有什么好讲的,Apache Commons Logging提供的实际工作类如下

这里面我们比较熟悉的是JDK自带的Java Logging和Log4J,其他几个因为不怎么常用就不说了,关于Apache Commons Logging如何选择具体的实现类,这个可以从LogFactory的实现类中查找到逻辑,逻辑代码如下:

因为代码比较长,这里只贴出关键部分逻辑,可以看得很清楚,用户通过配置文件指定后端实现,反之通过查找类路径来选择具体实现类。
SLF4J

SLF4J也存在上述类似的适配方式,这里我们给出SLF4J有些不同的bridge方式,其形式类似适配,如下

这个结构有些复杂,这里是SLF4J到Log4J的桥接,我们看到Log4jLoggerFactory提供了类似的适配功能,这种方式的好处,按照官方文档的说法是提供了编译时绑定,排除了运行时的探测方式,性能会好一些,看着这图有些抽象,这里给出一个具体的应用场景,如下
   Spring日志配置
    Spring项目使用了Apache Commons Logging日志框架,因为该日志框架比较老旧,我们一般使用Log4J作为其后端实现,通过上面的介绍,我们知道只要将Log4J放入ClassPath中就可以了,如果使用maven,在依赖中添加Log4J就可以了,这里如何使用SLF4J的桥接,结果有些复杂,首先需要去掉Apache Commons Logging依赖,然后添加Spring到SLF4J的Bridge,然后使用一个后端实现Log4J,因此在添加一个SLF4J到Log4J的Bridge,最后是Log4J实现,用maven管理的话,结果如下
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.2.2.BUILD-SNAPSHOT</version>
        <exclusions>
            <exclusion>
                <!--排除commons-logging依赖-->
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <!--commons-logging到SLF4J之间的Bridge-->
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.5.8</version>
    </dependency>
<dependency>
        <!--SLF4J接口-->
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.5.8</version>
    </dependency>
    <dependency>
        <!--SLF4J到Log4J之间的Bridge-->
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.5.8</version>
    </dependency>
    <dependency>
        <!--Log4J实现-->
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.14</version>
    </dependency>
</dependencies>

这种方式比较复杂,因为在平时工作中没有用过SLF4J日志框架,所以这种方式看起来有些多此一举,但考虑到SLF4J作为事实上的Java Logging标准,如何更加有效的在不同前端Facade Logger接口到后端实现之间自由适配,SLF4J提供了一个很好的形式,如下


前端到后端的适配能够更加方便,这确实是一个非常有趣的想法。
Jboss logging

    事实上这个日志框架貌似不是很出名,但是基本上Jboss系的产品、框架都会使用这个日志框架,因此,我们也需要好好的学习一下,该日志结构如下

这里的也是一种适配器方式,只是最终暴露的使用接口是特定的LoggerProvider,查找特定日志框架的LoggerProvider是由LoggerProviders提供的,代码如下

代码显示在LoggerProviders加载时就开始查找特定LoggerProvider,具体查找逻辑如下

上面看到的是通过配置文件查找

后半部分是根据ClassPath查找。
Jboss logging比较奇特的地方是其提供了一个JBossLogManagerLogger,这个Logger使用的内部Logger为JBoss容器托管日志管理器,这个可以注意一下

上面分析了日志框架前端Facade和后端实现如何适配,现在我们选取一个具体的框架来给出一些常见配置,希望能够对大家有用,我们选取的就是Log4J,因为其他框架我使用的频率比较低,二来因为日志框架的概念都类似,熟悉了一个其他的应该也可以快速掌握,下面让我们展开对Log4J的论述。
    Log4J来自于Apache社区,是目前应用最广的一个日志框架,官方提供了两个大的版本,为Log4J 1.x和Log4J 2.x,这两个主版本连官网链接都不一样,看来Log4J 2.x应该针对前一版本问ti而重新设计,以至于导致和前一版本的不兼容,但因为Log4J 1.x普及的根深蒂固,很多日志框架没有及时跟上对Log4J 2.x后端的支持,Log4J 2.x彻底替换掉Log4J 1.x还有很长的一段路要走。

    这里我们给出的是Log4J 1.x的版本介绍,关于Log4J 2.x,我们有机会再进行探索;在Log4J的体系里,有三个最重要的概念:Logger、Appender、Layout,Logger即为日志写入入口,Appender定义了将日志时间输出的策略,Layout给出输出的格式,三者的关系如下

因为Log4J中有Category的概念,这里我把它看成一个Logger,三者的关系这样看起来比较明显,Logger接收日志记录,Appender接收Logger发来的日志事件,然后根据Layout定义格式进行输出,这里没有什么好讲的,我们开始讲如何配置。
    Log4J 1.x有两种配置方式,一种是Java properties文件,一种是XML,第一种用的比较多一些,这个和Log4J 2.x正好相反,配置文件配置主要配置上面三个对象,配置Logger,然后配置使用哪种具体Appender,然后定义格式,看一个例子,如下:

log4j.rootLogger=DEBUG, A1

log4j.appender.A1=org.apache.log4j.ConsoleAppender

log4j.appender.A1.layout=org.apache.log4j.PatternLayout

log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
如上,一定要定义的Logger是root Logger,这里构成了一个类似树形结构,顶部节点定义默认行为,子节点可以对行为进行修改定制,这里定义rootLogger使用DEBUG级别,使用A1这个Appender,注意这里的写法:第一个为日志级别,后面可以跟很多个Appender;线面定义了这个具体的Appender A1,我们看到其使用的是ConsoleAppender,后面我们给这个Appender指定Layout,这里的Layout为PatternLayout,这个比较常用,最后一行定义了日志格式,这种格式写法类似于printf那种格式化字符串,里面的占位符构成为"%[格式修饰符]日志含义符号"(中括号里的为可选),格式修饰符比较简单,“-”代表靠左对其,不加就是靠右对其,后面的数字代表了该日志内容部分的最少显示长度,如果有“.”,"."之后为该日志内容最长显示长度,超过长度会进行裁短;后面的日志含义符号如下表

符号

意义

c(小写)

输出日志的类别

C(大写)

输出触发日志请求的类的全称

d

输出日志事件的日期时间

F

输出日志请求类文件名

l

输出请求日志调用位置信息

L

输出请求日志代码行号

m

输出应用提供的日志消息

M

输出请求日志方法名

n

输出平台特定的行分隔符

p

输出日志级别

r

输出从程序启动到现在的毫秒数

t

输出生成这个日志事件线程的名字


这里在给出一个例子
log4j.rootLogger=DEBUG, A1

log4j.appender.A1=org.apache.log4j.ConsoleAppender

log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%p [%t] %c{2} (%M:%L) - %m%n

log4j.logger.org.apache.log4j.examples=INFO, A2

log4j.appender.A2=org.apache.log4j.FileAppender
log4j.appender.A2.File=${user.home}/test

#如果test文件存在就先清空它
log4j.appender.A2.Append=false

log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%5r %-5p [%t] %c{2} - %m%n
上面的例子稍微复杂一些,这里设定了一个rootLogger,并制定了其日志级别和Appender,后面定义了一个名为org.apache.log4j.examples 的Logger,这个Logger又定义了日志级别和Appender,通过这里的例子可以看出Log4J这种树形的关系具有足够的灵活性。
    关于XML的配置,这里给出一个实例,大家可以根据上面对properties的理解来配置XML,如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j=' http://jakarta.apache.org/log4j/'>
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
        </layout>
    </appender>
    <category name="org.apache.log4j.xml">
        <priority value="info" />
    </category>
    <Root>
        <priority value ="debug" />
        <appender-ref ref="STDOUT" />
    </Root>
</log4j:configuration>
这里的category如前面分析结构时所说,可以认为其就是一个Logger,这个结构也比较一目了然,没有什么要讲的,大家可以根据自己的实际需要来调整结构。
这里还有个问ti是配置文件命名的问ti,默认情况下,如果配置文件命名为log4j.xml或log4j.properties时Log4J会自动加载,如果因为某种原因不能这样命名,那么久需要编码来实现配置的加载了,代码片段如下
String resource =
                "/app/resources/example.properties";
        URL configFileResource =
                InitUsingPropertiesFile.class.getResource(resource);
        PropertyConfigurator.configure(configFileResource);

日志框架就写这些吧,希望能对大家有所帮助,对单一常用日志框架的详细解析,有机会在写吧

© 著作权归作者所有

共有 人打赏支持
clannadyue
粉丝 4
博文 3
码字总数 12754
作品 0
青岛
程序员
Jenkins 教程(一)实现自动化打包及邮件通知

个人不喜欢装腔作势一堆专业术语放上去,让大多数人看不懂来提升逼格(所谓的专家),所以我简单的介绍jenkins是干啥的。本文使用jenkins,就是让它把git仓库里的东西取出来,然后在jenkins容器...

FantJ ⋅ 05/26 ⋅ 0

转: 面试感悟:3年工作经验java程序员应有的技能

第一阶段:三年 我认为三年对于程序员来说是第一个门槛,这个阶段将会淘汰掉一批不适合写代码的人。这一阶段,我们走出校园,迈入社会,成为一名程序员,正式从书本上的内容迈向真正的企业级...

欧阳海阳 ⋅ 06/01 ⋅ 0

编写高性能 Java 代码的最佳实践

摘要:本文首先介绍了负载测试、基于APM工具的应用程序和服务器监控,随后介绍了编写高性能Java代码的一些最佳实践。最后研究了JVM特定的调优技巧、数据库端的优化和架构方面的调整。以下是译...

这篇文章 ⋅ 06/20 ⋅ 0

【转载】一名3年工作经验的程序员应该具备的技能(写得很好,果断转)

因为和同事有约定再加上LZ自己也喜欢做完一件事之后进行总结,因此有了这篇文章。这篇文章大部分内容都是面向整个程序员群体的,当然因为LZ本身是做Java开发的,因此有一部分内容也是专门面向...

jackto原 ⋅ 05/24 ⋅ 0

少走弯路,给Java 1~5 年程序员的建议

今天LZ是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈每个阶段要学习的内容甚至是一些书籍。这一部分的内容,同样适用于一些希望转行到Java的同学。 在大家看之前,LZ要先声...

重走Java ⋅ 05/29 ⋅ 0

用大白话告诉你啥是Java开发

Java,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台的总称。用Java实现的HotJava浏览器(支持Java applet)显示了Java的魅力:跨平台、动态的Web、Internet计算。从此...

远方Java ⋅ 06/14 ⋅ 0

JVM 即时编译器 - GraalVM

Graal — 新的 JVM 即时编译器 GraalVM 是新一代的高性能跨语言虚拟机,用于运行 JavaScript、Python 3、Ruby、R、基于 JVM 的语言,如 Java、Scala、Kotlin 和基于 LLVM 的语言,如 C 和 C+...

匿名 ⋅ 2014/09/29 ⋅ 2

Java程序员编程学习—Java新手职业生涯规划分享

Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于PC、数据中心、游戏控制台、科学超级计算机、移动电话和互...

Java小辰 ⋅ 05/17 ⋅ 0

阿里资深技术专家:在各阶段中,3年经验的程序员应具备哪些技术能力(进阶必看)

3年工作经验的Java程序员应该具备哪些技术能力,这可能是Java程序员们比较关心的内容。我这里要说明一下,以下列举的内容不是都要会的东西,但是你掌握得越多,最终能得到的评价、拿到的薪水...

茶轴的青春 ⋅ 05/03 ⋅ 0

学好Java只需要做到这7点,年薪20W很简单~

大道至简,所以扎实有用的方法,其实都是很简单的,难在踏踏实实的执行过程。今天为大家介绍的就是Java学习的7个看起来非常简单的方法,快学起来吧。 为什么要学习java? Java是目前最流行的...

欧阳海阳 ⋅ 06/05 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

10个免费的服务器监控工具

监控你的WEB服务器或者WEB主机运行是否正常与健康是非常重要的。你要确保用户始终可以打开你的网站并且网速不慢。服务器监控工具允许你收集和分析有关你的Web服务器的数据。 有许多非常好的服...

李朝强 ⋅ 26分钟前 ⋅ 0

压缩工具之zip-tar

zip 支持目录压缩。使用yum安装zip包,使用yum安装unzip包 zip 1.txt.zip 1.txt #将1.txt文件压缩,新生成的压缩文件为1.txt.zip,原文件保留 zip -r 123.zip 123/ #-r对目录操作。将123/目录...

ZHENG-JY ⋅ 27分钟前 ⋅ 0

Dubbo @Activate注解使用和实现解析

Activate注解标识一个扩展是否被激活和使用,可以放在定义的类上和方法上,dubbo用它在SPI扩张类定义上,标识这个扩展实现激活的条件和时机,先看下定义: /** * Activate * <p/> * ...

哲别0 ⋅ 34分钟前 ⋅ 0

6.5 zip压缩工具 tar打包 打包并压缩

1.tar tar命令格式 [-zjxcvfpP] filename tar -z:表示同时用gzip压缩。 -j:表示同时用bzip2压缩。 -J:表示同时用xz压缩。 -x:表示解包或者解压缩。 -t:表示查看tar包里的文件。 -c:表示建...

oschina130111 ⋅ 36分钟前 ⋅ 0

Linux系统工程狮养成记

如今的社会,随着时代的发展,出现了很多职业,像电子类,计算机类的专业,出现了各种各样的工程师,有算法工程师,java工程师,前端工程师,后台工程师,Linux工程师,运维工程师等等,不同...

六库科技 ⋅ 42分钟前 ⋅ 0

Linux 机器的渗透测试命令备忘表

如下是一份 Linux 机器的渗透测试备忘录,是在后期开发期间或者执行命令注入等操作时的一些典型命令,设计为测试人员进行本地枚举检查之用。 此外,你还可以从这儿(https://gbhackers.com/c...

寰宇01 ⋅ 44分钟前 ⋅ 0

windows 安装java开发环境,配置jdk

下载jdk安装文件 链接:https://pan.baidu.com/s/1UEKPjnAdMqNj612B39Pfsg 密码:ipqx 如果javac无法使用 1,检查环境变量名称中是否有空格。。。,去除后即可 2,将JAVA_HOME替换为原始路径...

阿豪boy ⋅ 45分钟前 ⋅ 0

简析log4j的实现方式

刚加入新公司,对日志的要求比较严格,对此特意花了几天时间看了一下log4j的源码,大概了解了一下log4j的实现方式,总结如下: log4j的实现分为两个步骤:log4j.xml的加载,logger的使用 这里...

zdatbit ⋅ 今天 ⋅ 0

win环境下jdk7与jdk8共存配置

1.jdk安装包 jdk安装包 安装步骤略 2.jdk等配置文件修改 在安装JDK1.8时(本机先安装jdk1.7再安装的jdk1.8),会将java.exe、javaw.exe、javaws.exe三个文件copy到了C:\Windows\System32,这...

泉天下 ⋅ 今天 ⋅ 0

windows profesional 2017 build problem

.net framework .... https://stackoverflow.com/questions/43330915/could-not-load-file-or-assembly-microsoft-build-frameworkvs-2017...

机油战士 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部