log4j

Posted 天空奇点

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了log4j相关的知识,希望对你有一定的参考价值。

01 日志概览

日志系统一共分为桥接模式、适配模式,非适配模式三种模式

1.1 桥接模式

1.2 适配模式

log4j


1.3 非适配模式


02 log4j

日志整个流程是日志记录者(loggers)将message通过某种布局(layouts)输出到不同的终端(appenders),如文件、标准输出流中。可以看出日志中三大核心要件是loggers、layouts、appenders。

2.1 三者之间关系图

2.2 Logger组件

2.2.1 Logger日志的继承关系

loggers是树形的继承关系,它的树形关系是通过命名系统来表达的。根节点是通过Logger.getRootLogger()静态方法进行检索的,其它节点是通过Logger.getLogger()方法来检索的

1 祖先关系

    如com是com.example.demo祖先

2 父子关系

    如com.example是com.example.demo父亲

3 根节点

  • 根节点总是存在的

  • 根节点不能通过名称来检索

2.2.2 Logger日志记录等级及继承关系

1 记录等级

logger日志有六个记录等级分别如下:TRACE、DEBUG、INFO、WRAN、ERROR、FATAL

package org.apache.log4j; public class Logger {  // Creation & retrieval methods:  public static Logger getRootLogger();  public static Logger getLogger(String name);  // printing methods:  public void trace(Object message);  public void debug(Object message);  public void info(Object message);  public void warn(Object message);  public void error(Object message);  public void fatal(Object message);   // generic printing method:      public void log(Level l, Object message)   }

2 继承关系

logger之间的等级也存在继承关系,但这里的继承关系是重载关系,如果子Logger定义自己的Level,那么它就不需要继承父类的level

  • 为了保证所有的日志最终都继承一个日志水平,根节点的总是会分配一个日志水平的

  • 基本规则:如果一个日志请求level是p,它的Logger日志水平是q,如p>=q, 那么这个请求是可用

  • 等级水平:DEBUG < INFO < WRAN < ERROR < FATAL

  • 注意:通过相同名称得到的实例总是同一个实例,使用单例模式

// 通过名称 "com.foo"得到一个日志实例 Logger logger = Logger.getLogger("com.foo"); // 现在设置它的等级,正常情况下,不是通过代码进行进行设置的,它通常是通过配置文件进行设置的。 logger.setLevel(Level.INFO); Logger barlogger = Logger.getLogger("com.foo.Bar"); // 这个请求方法是可用的,因为 WARN >= INFO. logger.warn("Low fuel level."); // 这个请求方法是不可用的, 因为 DEBUG < INFO. logger.debug("Starting search for nearest gas station."); // 通过名称"com.foo.Bar"获取的日志实例,它的日志等级将继承“com.far”名称的实例等级,因此下面的请求是可用的,因为INFO >= INFO barlogger.info("Located nearest gas station."); // 请求是不可用的, 因为 DEBUG < INFO. barlogger.debug("Exiting gas station search");

2.3 Appender组件

日志系统可以把日志同时输出到多个不同的终端(Appender),终端可以是控制面板、文件、图形界面、远程socket服务,JMS等。

  • 定义:appender就是输出的终端,可以输出到不同的终端,如上面描述的,同时还提供日志的异步写入。

  • 一个Logger可以绑定多个终端,即一条日志记录可以同时输出到不同的终端。

  • 每个可用的日志请求都将转发到高于Appender等级的所有的Appender中

  • appender Additivtiy规则:每个可用的日志请求都会发送到与该logger关联的apender和该logger的每一个父logger的Appender。

2.4 Layout组件

使用appender可用输出到不同的终端,layout可以对输出的日志以什么格式显示进行控制,一个appender只能对应一个layout。

一般推荐使用PatternLayout,它类似C语言中printf模式。

1 通用布局格式

格式一

 %r [%t] %-5p %c %x - %m%n

格式二

 %-6r [%15.15t] %-5p %30.30c %x - %m%n

2 常用的转换说明符

转换说明符

含义

示例

%c

logger名字空间的全名称,如果加上{<层数>}表示列出最内层到指定层数的名字空间

假设当前logger名称空间为com.foo.bar

%c 终端打印出来的是com.foo.bar

%c{2} 终端打印出来的是com.foo

%20c 如果名字空间长度小于20,左边通过补充空格进行填充

%-20c 如果名字空间长度小于20,右边通过补充空格进行填充

%.30c 如果名字空间长度大于30,截去多余的空间

%C

列出调用logger请求的全限定类名

假设调用当前的全限定类名为com.foo.bar.Demo

%C 终端输出的是com.foo.bar.Demo

%d

显示日志记录的格式,使用{<日期格式>},如果没有指定日期格式,默认是用ISO8601格式

%d{yyyy-MM-dd HH:mm:ss, SSS} 终端显示的日期格式为2020-01-11 21:10:10 117

%F

显示调用日志请求的源文件名称

%F 终端输出的是Demo.class

%l

输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数

%l 终端输出的是Demo.main(Demo.java:110)

%L

输出日志请求的在源文件的代码行数

%L 终端输出的是 110

%m

显示应用程序的输出消息

%m 终端输出 parse json exception

%M

调用日志请求的方法名

%M 终端输出的是main

%n

当前平台的换行符


%p

显示当前日志的优先级

%p 终端输出的是error

%r

从程序启动时到调用日志请求的毫秒数

%r 终端输出的 1110

%t

日志请求的线程名称

%t Demo

%x

按线程NDC(线程堆栈)顺序输出日志


%X

按MDC(Mapped Diagnostic Context,线程映射表)输出日志。通常用于多个客户端连接同一台服务器,方便服务器区分是那个客户端访问留下来的日志。


%%

显示一个百分号

%% 终端输出的是%

2.5 配置

Log4j支持两种配置文件方式,分别是xml和properties(key=value)格式。

实际上,log4j配置文件就是配置上面三个组件

2.5.1 配置logger

logger配置root logger和其它应用logger的方式

1 配置root logger

格式

log4j.rootLogger=[${logLevel}],[${appenderName1}],[${appenderName2}],....

示例

log4j.rootLogger=info,console,file

2 配置其他logger(推荐使用类名的全路径)

格式

log4j.logger.${loggerName}=[${logLevel}],[${appenderName1}],[${appenderName2}],....

示例

log4j.logger.org.springframework=error

2.5.2 配置日志输出终端

语法格式

log4j.logger.${appenderName}= 全限定类名(可以是内置Appender,也可以是自定义的Appender)

2.5.3 配置日志输出格式

log4j.logger.${appenderName}.layout=全限定类名(一般使用内置Layout类)

2.6 log4j最佳实践

2.6.1 引入jar

<!--slf4j api接口--> <dependency>  <groupId>org.slf4j</groupId>  <artifactId>slf4j-api</artifactId>  <version>1.7.25</version> </dependency> <!--log4j 实现--> <dependency>  <groupId>log4j</groupId>  <artifactId>log4j</artifactId>  <version>1.2.17</version> </dependency> <!--用于log4j适配slf4j--> <dependency>  <groupId>org.slf4j</groupId>  <artifactId>slf4j-log4j12</artifactId>  <version>1.7.21</version></dependency>

2.6.2 配置文件

# # Log4J Settings for log4j 1.2.x (via jakarta-commons-logging) # # The five logging levels used by Log are (in order): 
# # 1. DEBUG (the least serious) # # 2. INFO # # 3. WARN # # 4. ERROR # # 5. FATAL (the most serious) # # Set root logger level to INFO and append to stdout log4j.rootLogger=DEBUG,stdout,file
# # stdoutlog4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout # # Pattern to output the caller's file name and line number. log4j.appender.stdout.layout.ConversionPattern=[LOG-DMEO]%-d{HH:mm:ss SS} %5p (%c:%L) - %m%n
# # filelog4j.appender.file=org.apache.log4j.DailyRollingFileAppender log4j.appender.file.File=/logs/gift/log-demo.log log4j.appender.file.DatePattern='.'yyyy-MM-dd log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[LOG-DEMO]%-d{yyyy-MM-dd HH:mm:ss SS} [%c]-[%p] %m%n
# # Print only messages of level INFO or above in the package noModule. log4j.logger.noModule=FATAL # # Spring Stuff log4j.logger.org.springframework=INFO # # application self log4j.logger.com.log=INFO

2.6.3 加载日志

使用Log4jConfigListener(Spring)进行动态加载,具体功能如下

参数

描述

log4jRefreshInterval

定时刷新配置文件,即使修改log4j.properties配置文件,不需要重启web。只需要在web.xml配置即可

log4jConfigLocation

获取classpath路径下log4j.properties配置文件

<listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class</listener> <context-param>   <param-name>log4jConfigLocation</param-name>   <param-value>classpath:log4j.properties</param-value> </context-param> <context-param>   <param-name>log4jRefreshInterval</param-name>   <param-value>60000</param-value> </context-param>

03 日志规范

3.1 通用规范

  • 应用中不可直接使用日志系统(Log4j、logback)中API,而是依赖使用日志框架中SLF4J中的API,使用门面模式的日志框架,有利维护和各个类的日志处理方式统一

  • 在日志输出时,字符串变量之间的拼接方式使用占位符的方式,如logger.info("process trade with id : {}", id);

  • 避免重复打印日志,浪费磁盘空间,务必在log4j.xml中设置additivity=false。如<logger name="com.taobao.dubbo.config" additivity="false">

  • 异常信息应该包含两类信息:案发现场信息和异常堆栈信息,如logger.error(各类参数或对象toString()+ "_" + e.getMessage(), e),如果不做处理,那么通过关键字throws往上抛。

  • 可以使用warn日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从,如非必要,请不要在此场景打出 error 级别,避免频繁报警。

  • 尽量用英文来描述日志错误信息,如果日志中的错误信息用英文描述不清楚的话使用中文描述即可,否则容易产生歧义

3.2 服务器日志和应用日志分离

很多开发同学都没有意识到将不同模块()日志分离带来的好处。实际上服务器日志、应用日志分离将有利于问题排查和快速定位问题。

## Rules reminder: ## TRACE < DEBUG < INFO < WARN < ERROR < FATAL ## Global logging configuration log4j.rootLogger=info,console, system ## Console output... log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=[%p]	%d	[%t] %c (%F:%L) - %m%n 
## File output... log4j.appender.system=org.apache.log4j.DailyRollingFileAppender log4j.appender.system.File=${LOG_DIR}/system.loglog4j.appender.system.Append=truelog4j.appender.system.Threshold=INFO log4j.appender.defaultLogger.DatePattern='.'yyyy-MM-dd log4j.appender.system.layout=org.apache.log4j.PatternLayout log4j.appender.system.layout.ConversionPattern=%d [%p] [%t] %c (%F:%L): %m%n 
## 3rdparty logging configuration log4j.logger.org.springframework=WARN ## My logging(Application) logging configuration log4j.logger.com.log.demo.mbrowser=INFO, businesslog4j.additivity.com.log.demo.business=false ## File output... log4j.appender.business=org.apache.log4j.DailyRollingFileAppender log4j.appender.business.File=${LOG_DIR}/mbrowser.log log4j.appender.business.Append=true log4j.appender.business.Threshold=INFO log4j.appender.defaultLogger.DatePattern='.'yyyy-MM-dd log4j.appender.business.layout=org.apache.log4j.PatternLayout log4j.appender.business.layout.ConversionPattern=%d [%p] [%t] %c (%F:%L): %m%n


04 日志官方文档

【1】apache commons loggings 

http://commons.apache.org/proper/commons-logging/

【2】slf4j http://www.slf4j.org/

【3】log4j http://logging.apache.org/log4j/1.2/

【4】log4j2 http://logging.apache.org/log4j/2.x/

【5】logback http://logback.qos.ch/


以上是关于log4j的主要内容,如果未能解决你的问题,请参考以下文章

log4j怎样控制只输出自己写的代码的日志,不输出框架中的日志

Log4j反序列化远程代码执行漏洞(CVE-2019-17571)

由log4j远程执行漏洞说起

混合 log4j 1.x 和 log4j 2

Java 标准日志工具 Log4j 的使用(附源代码)

log4jspringboot项目启动 ,使用的druid数据源,log4j报错 log4j:WARN Please initialize the log4j system properly.(代码片