关于Java日志系统的一点整理
Posted Java之初学者
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Java日志系统的一点整理相关的知识,希望对你有一定的参考价值。
1 日志关系图
图1.1 日志的大致关系图
Java日志体系大体可以分为三个部分:日志门面(Facade [fəˈsɑ:d])接口、桥接适配器、日志框架具体实现。
Java日志框架有很多种,最简单的是Java自带的java.util.logging,而最经典的是log4j,后来又出现了一个比log4j性能更好的logback,其他的日志框架就不怎么常用了。应用程序直接使用这些具体日志框架的API来满足日志输出需求当然是可以的,但是由于各个日志框架之间的API通常是不兼容的,这样做就使得应用程序丧失了更换日志框架的灵活性。
比直接使用具体日志框架API更合理的选择是使用日志门面接口。日志门面接口提供了一套独立于具体日志框架实现的API,应用程序通过使用这些独立的API就能够实现与具体日志框架的解耦,这跟JDBC是类似的。最早的日志门面接口是commons-logging,但目前最受欢迎的是slf4j。
日志门面接口本身通常并没有实际的日志输出能力,它底层还是需要去调用具体的日志框架API的,也就是实际上它需要跟具体的日志框架结合使用。由于具体日志框架比较多,而且互相也大都不兼容,日志门面接口要想实现与任意日志框架结合可能需要对应的桥接器,就好像JDBC与各种不同的数据库之间的结合需要对应的JDBC驱动一样。
实际情况并不总是简单的“日志门面接口----桥接器----日志框架”这一条单向线。实际上,独立的桥接器有时候是不需要的,而且也并不是只有将日志门面API转调到具体日志框架API的正桥接器,也存在将日志框架API转调到日志门面API的反桥接器。
说白了,所谓“桥接器”,不过就是对某套API的伪实现。这种实现并不是直接去完成API所声明的功能,而是去调用有类似功能的别的API。这样就完成了从“某套API”到“别的API”的转调。如果同时存在A-to-B.jar和B-to-A.jar这两个桥接器,那么可以想象当应用程序开始调用A或者B的API时,会发生什么事。
下图来自slf4j的官方文档的一部分: http://www.slf4j.org/manual
.html#swapping。
由图中的最右边,slf4j-log4j12.jar作为适配器,调用slf4j-api.jar的接口,并为log4j提供调用。
2 关于log的jar包
2.1 slf4j API相关的jar包
slf4j(Simple Logging Facade([fəˈsɑ:d]) for Java) ,官方叫Java简单日志门面,即Java简单日志(接口)层,与JDBC为各数据库厂商提供接口类似,slf4j为各日志系统提供接口,允许用户根据自己的喜好,在项目中通过slf4j接入各种日志系统。
因此,slf4j入口就是众多接口的集合,它不负责具体的日志实现,只在编译时寻找合适的日志系统进行绑定。slf4j所提供的核心API是一些接口以及一个LoggerFactory的工厂类。
2.2 commons-logging相关的jar包
commons-logging 是Apache commons 类库中的一员。Apache commons类库是一个通用的类库,提供了基础的功能,比如说commons-fileupload,commons-httpclient,commons-io,commons-codes等。
commons-logging 能够选择使用Log4j还是JDK Logging,但是它不依赖Log4j,JDK Logging的API。如果项目的classpath中包含了log4j的类库,就会使用log4j,否则就使用JDK Logging。使用commons-logging能够灵活的选择使用那些日志方式,而且不需要修改源代码。
commons-logging相关jar包:
commons-logging: commons-logging的原生全部内容
log4j-jcl: commons-logging到log4j2的桥梁
jcl-over-slf4j: commons-logging到slf4j的桥梁
2.3 slf4j 的桥接适配器jar包
各日志系统不能直接去调用slf4j的API,需要通过该jar包去访问slf4j接口。
slf4j-jdk14: slf4j到jdk-logging的桥梁
slf4j-log4j12: slf4j到log4j1的桥梁
log4j-slf4j-impl: slf4j到log4j2的桥梁
logback-classic: slf4j到logback的桥梁
slf4j-jcl: slf4j到commons-logging的桥梁
2.4 log4j 的jar包
log4j-x.x.x.jar: log4j1的全部内容
log4j-api-x.x.x: log4j2定义的API
log4j-core-x.x.x: log4j2的API实现
2.5 logback 的jar包
logback-core-x.x.x.jar: logback的核心包
logback-classic-x.x.x.jar: logback实现了slf4j的API
2.6 commons-logging日志框架集成
2.6.1 jdk-logging + commons-logging
commons-logging-x.x.x.jar
2.6.2 log4j1 + commons-logging
commons-logging-x.x.x.jar
log4j-1.x.x.jar
2.6.3 log4j2 + commons-logging
commons-logging-x.x.x.jar
log4j-api.jar
log4j-core.jar
log4j-jcl.jar(集成包)
2.6.4 logback + commons-logging
logback-core.jar
logback-classic.jar
slf4j-api、jcl-over-slf4j(2个集成包,可以不再需要commons-logging包)
2.6.5 slf4j + commons-logging
jcl-over-slf4j(集成包,不再需要commons-logging包)
slf4j-api.jar
2.7 slf4j 日志框架集成
2.7.1 slf4j + jdk-logging
slf4j-api
slf4j-jdk14(集成包)
2.7.2 slf4j + log4j1组合应用
slf4j-api-x.x.x.jar
slf4j-log4j12-x.x.x.jar(集成包)
log4j-1.x.x.jar
log4j.properties(也可以是 log4j.xml)
2.7.3 slf4j + log4j2组合应用
slf4j-api-x.x.x.jar
log4j-api.x.x.x.jar
log4j-core.x.x.x.jar
log4j-slf4j-impl-x.x.x.jar(集成包)
log4j2.properties(也可以是 log4j2.xml)
Maven中包引入:
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --> <dependency> |
2.7.4 slf4j + logback
slf4j-api-x.x.x.jar
logback-core-x.x.x.jar
logback-classic-x.x.x.jar(集成包)
2.7.5 JCL + log4j即commons-logging + log4j模式
commons-logging-1.1.jar
log4j-1.x.x.jar
log4j.propertie
注意:common-longing是默认支持log4j的,使用其他日志工具需要做下面的配置:common-logging.properties
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JCategoryLog
2.8 复杂场景
2.8.1 场景介绍
使用log4j1和commons-logging的API进行编程,但是想最终通过logback来进行输出,所以就需要先将log4j1和commons-logging的日志输出转交给slf4j来输出,slf4j再交给logback来输出。将log4j1的输出转给slf4j,这是log4j-over-slf4j做的事;将commons-logging的输出转给slf4j,这是jcl-over-slf4j做的事。
注意以下jar包
log4j-over-slf4j: log4j1到slf4j的桥梁
jcl-over-slf4j: commons-logging到slf4j的桥梁
2.8.2 案例
1) log4j日志输出代码:
package com.aaron.netty.handler.server; // log4j包 |
2) commons-logging日志输出代码:
package com.aaron.netty.handler.server; |
3) jar包引入代码:
<dependency> |
如上代码中,我们使用log4j和commons-logging的API来进行日志的输出,现在在不改变原来代码的情况下,使用logbakc进行日志的输出。
2.8.3 操作步骤
1) 去掉log4j的jar包(必须)、去掉commons-logging的jar包(非必须)
2) 加入以下jar包的依赖
- log4j-over-slf4j (log4j1到slf4j的桥梁)
- jcl-over-slf4j (commons-logging到slf4j的桥梁)
- slf4j-api
- logback-core
- logback-classic
依赖:
<dependency> <dependency> |
3) 在classpath路径下加入logback的配置文件
logback.xml:
<?xml version="1.0" encoding="UTF-8" ?> |
2.8.4 原理
1) 如下图,包log4j-over-slf4j-x.x.x.jar中,在包org.apache.log4j中同样存在类Logger的实现(故不需要更改代码即可无缝切换)。
2) 如下图,在Logger的父类Category中,获取Logger的方式已经变成了slf4j的API。
3) 而在包jcl-over-slf4j-x.x.x.jar中,同样有org.apache.commons.l
ogging.impl.SlF4JLogFactory类继承自commons-logging包下的LogFacto
ry。
4) 最后由logback去实现slf4j的API
3 log4j配置文件详解
关于
2015年5月,Apache宣布Log4J 1.x 停止更新。最新版为1.2.17。如今,Log4J 2.x已更新至2.11。
官方网址:http://logging.apache.org/log4j/2.x/
3.1 log4j作用
1) 将信息送到控制台,文件,GUI组件,Socket等.
2) 控制每条信息的输出格式。
3) 将信息分类,定义信息级别,细致地控制日志的输出。
3.2 日志级别
序号 |
级别 |
描述 |
1 |
trace |
追踪,就是程序推进一下,可以写个trace输出 |
2 |
debug |
调试,一般作为最低级别,trace基本不用。 |
3 |
info |
输出重要的信息,使用较多 |
4 |
warn |
警告,有些信息不是错误信息,但也要给程序员一些提示 |
5 |
error |
错误信息 |
6 |
fatal |
致命错误。级别较高,这种级别不用调试了,重写吧 |
机制:如果一条日志信息的级别大于等于配置文件的级别,就记录。
3.3 配置文件相关节点
3.3.1 根节点Configuration
1) 两个属性:
status : 指定log4j本身的打印日志级别
monitorinterval: 用于指定log4j自动重新配置的间隔时间,单位:秒,最小5s。
2) 两个子节点:Appenders和Loggers
Appenders节点下可以指定不同类型的Appender节点
Loggers节点下可以指定不同类型的Logger节点
3.3.2 Appender节点
3.3.2.1 Appender节点的分类
Log4j2的Appenders充分考虑了日志事件的输出、包装以及过滤转发的可能,包括最基本的输出到本地文件、输出到远程主机,对文件进行封装、注入,并且还能按照日志文件的时间点、文件大小等条件进行自动封存。
常见的有:
- FileAppender: 将日志普通地输出到本地文件
- RollingFileAppender: 让系统按照设定的时间间隔自动封存日志信息,每隔一定时间自动保存一份新增的日志文件,并按照时间戳等指定格式命名
- FlumeAppender: 将几个不同源的日志汇集到一起
- RewriteAppender: 在LogEvent中注入信息
- SMTPAppender: 当产生安全级别达ERROR或FATAL的LogEvent时,给维护人员发送邮件。
- SocketAppender: 按照普通格式将日志信息写到远程主机
- SyslogAppender: 按照RFC5424格式向远程主机发送日志信息
3.3.2.2 ConsoleAppender节点
ConsoleAppender节点:定义输出到控制台的Appender
- name: 指定Appender的名字
- target: SYSTEM_OUT或SYSTEM_ERR,一般默认为前者
- PatternLayout: 输出格式,缺省为%m%n
简单示例:【完整的参数介绍和官方配置示例】
<?xml version="1.0" encoding="UTF-8"?> |
3.3.2.3FileAppender节点
FileAppender节点:定义输出到指定位置的文件的Appender
- name: 指定Appender的名字
- fileName: 指定输出日志的目标文件,带全路径的文件名
- PatternLayout:输出格式,缺省为%m%n
简单示例:【完整的参数设置和官方配置示例】
<?xml version="1.0" encoding="UTF-8"?> |
3.3.2.4 RollingFileAppender节点
RollingFileAppender节点:超过指定大小自动删除旧的创建新的Appender
- name: 指定Appender的名字
- fileName: 指定输出日志的目标文件,带全路径的文件名
- PatternLayout:输出格式,缺省为%m%n
- filePattern 指定新建日志文件的名称格式。
- Policies:指定滚动日志的策略,就是什么时候进行新建日志文件输出日志.
简单示例:【完整的参数设置、TriggeringPolicy和RolloverStrategy的用法示例】
<?xml version="1.0" encoding="UTF-8"?> |
3.3.2.5 SMTPAppender节点
SMTPAppender主要用来给指定的E-mail发送log event(这种情况一般用在event的安全级别超过ERROR或FATAL时)。SMTPAppender有很多重要的参数以完成log event发送到指定E-mail。
主要参数:
- bufferSize,integer,信中所能包含的最大log event的数量。
- layout,Layout,log event的布局格式。默认为SerializedLayout。
- smtpHost,String,要发送到的SMTP的主机名。(此参数是必需的)
- smtpPassword,String,通过SMTP服务器所需的密码。
- smtpPort,integer,SMTP服务的端口号。
- smtpProtocol,String,使用的协议。默认为"smtp"。
简单示例:【完整的参数介绍和官方配置示例】
<?xml version="1.0" encoding="UTF-8"?> |
3.3.2.6 SocketAppender节点
SocketAppender节点:将log event输出到一个远程服务器上(需指定服务器名和端口号),数据可以以任意指定的格式经由TCP或UDP协议发送。
SocketAppender中比较重要的参数有:
- host,String,指定服务器的主机名。(必需)
- immediateFlush,boolean,是否立即flush,还是等待缓存到一定大小后在flush。
- layout,Layout,log event输出的格式。
- port,integer,远程服务器坚挺log event的应用的端口号。
- protocol,String,发送log event所使用的协议,"TCP" 或"UDP"。
- reconnectionDelay,integer,当连接断开时,延迟等待的ms数。
简单示例:【完整的参数介绍和官方配置示例】
<?xml version="1.0" encoding="UTF-8"?> |
3.3.3 Loggers节点
Loggers节点:常见的子节点有Root和Logger
(1) Root节点用来指定项目的根日志,如果不指定Logger,那么默认使用该Root日志输出
level:日志输出级别
AppenderRef:Root的子节点,用来指定该日志输出到哪个Appender
(2) Logger节点用来单独
3.4 布局方式
SimpleLayout:以简单的形式显示
htmlLayout :以HTML表格显示
PatternLayout:自定义形式显示
在Log4J2中基本采用PatternLayout自定义日志布局。
1) 自定义格式
%t:线程名称
%p:日志级别
%c:日志消息所在类名
%m:消息内容
%M:输出执行方法
%d:发生时间,%d{yyyy-MM-ddHH:mm:ss,SSS},输出类似:2011-10-18 22:10:28,921
%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
%L:代码中的行数
%n:换行
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %l - %msg%n"/> |
关于%c(类名)的格式:
Conversion Pattern |
Logger Name |
Result |
%c{1} |
org.apache.commons.Foo |
Foo |
%c{2} |
org.apache.commons.Foo |
commons.Foo |
%c{10} |
org.apache.commons.Foo |
org.apache.commons.Foo |
%c{-1} |
org.apache.commons.Foo |
apache.commons.Foo |
%c{-2} |
org.apache.commons.Foo |
commons.Foo |
%c{-10} |
org.apache.commons.Foo |
org.apache.commons.Foo |
%c{1.} |
org.apache.commons.Foo |
o.a.c.Foo |
%c{1.1.~.~} |
org.apache.commons.test.Foo |
o.a.~.~.Foo |
%c{.} |
org.apache.commons.test.Foo |
....Foo |
3.5 实例
3.5.1 常用的log4j2的配置
<?xml version="1.0" encoding="UTF-8"?> |
注意:
通常我们的项目有时候是以jar包的形式发布出去,但是此时如果你直接使用lo4j2的api的话,相当于别人依赖你的jar的项目也必须加入log4j2的jar包。这样是高度耦合的。我们不建议这样使用,log4j2官方给出了适配slf4j。
然后在项目中使用slf4j的api而不是使用log4j2的api,例如:
将 |
这样当其他项目引入你的jar后,就可以不用强制他们使用log4j2,也不会因为没有log4j2的jar而报错。
3.5.2 异步日志配置
log4j2最强的是支持异步写日志,官方有两种方案:第一种是采用配置开关,第二种则是基于异步标签。注意:异步输出日志需要disruptor-3.3.0.jar或者以上的版本来支持
3.5.2.1 配置开关
在classpath下添加一个名字为log4j2.component.properties文件。内容如下:
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector |
3.5.2.2 异步标签<AsyncLogger>
只需要将你要异步输出的Logger标签改为AsyncLogger标签就行了。
<?xml version="1.0" encoding="UTF-8"?> |
参考文章:
https://blog.csdn.net/zhuyucheng123/article/details/51803852?locationNum=12&fps=1#t0
http://www.360doc.com/content/16/0818/19/11962419_584161930.shtml
https://www.cnblogs.com/nannan0226/p/6392536.html
http://blog.csdn.net/zhuyucheng123/article/details/51803852
http://logging.apache.org/log4j/2.x/manual/configuration.html#Properties
https://my.oschina.net/kkrgwbj/blog/734530
以上是关于关于Java日志系统的一点整理的主要内容,如果未能解决你的问题,请参考以下文章