文章目录
系列文章目录
学习Java日志框架之——搞懂JUL(java.util.logging)
学习Java日志框架之——搞懂log4j
学习Java日志框架之——搞懂日志门面(JCL+SLF4J)
学习日志框架之——搞懂logback
学习日志框架之——log4j2入门
log4j2扩展——打印自定义日志输出格式,将日志输出为json或自定义
一、Log4j简介
Log4j(Log for java)是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码,所以说,我们使用log4j技术,主要使用的是其配置文件。
官方网站: http://logging.apache.org/log4j/1.2/
注!Spring Boot1.4版本以后就不再支持log4j,应运而生的是log4j2,后续有时间再进行学习。
二、Log4j组件介绍
Log4j主要由 Loggers (日志记录器)、Appenders(输出控制器)和 Layout(日志格式化器)组成。其中 Loggers 控制日志的输出以及输出级别(JUL做日志级别Level);Appenders 指定日志的输出方式(输出到控制台、文件等);Layout 控制日志信息的输出格式。
1、Loggers
日志记录器,负责收集处理日志记录,实例的命名就是类的全限定名,如com.demo.log4j.XX, Logger的名字大小写敏感,其命名有继承机制:例如:name为com.demo.log4j的logger会继承 name为com.demo。
Log4J中有一个特殊的logger叫做“root”,他是所有logger的根,也就意味着其他所有的logger都会直接 或者间接地继承自root。root logger可以用Logger.getRootLogger()方法获取。
例如:
com.demo.log4j.XX 儿子
com.demo.log4j 父亲
com.demo 爷爷
上辈所做的日志属性设置,会直接的影响到子辈。
自log4j 1.2版以来, Logger 类已经取代了 Category 类。对于熟悉早期版本的log4j的人来说, Logger 类可以被视为 Category 类的别名。
关于日志级别信息,例如DEBUG、INFO、WARN、ERROR…级别是分大小的,DEBUG < INFO < WARN < ERROR,分别用来指定这条日志信息的重要程度,Log4j输出日志的规则是:只输出级别不低于设定级别的日志信息,假设Loggers级别设定为INFO,则INFO、WARN、ERROR级别的日志信息都会输出,而级别比INFO低的DEBUG则不会输出。
2、Appenders
2、记录日志以及定义日志的级别仅仅是Log4j的基本功能,Log4j日志系统还提供许多强大的功能,比如允许把日志输出到不同的地方,如控制台(Console)、文件(Files)等,可以根据天数或者文件大小产生新的文件,可以以流的形式发送到其它地方等等。
常用Appenders:
- ConsoleAppender 将日志输出到控制台
- FileAppender :将日志输出到文件中
- DailyRollingFileAppender :将日志输出到一个日志文件,并且每天输出到一个新的文件
- RollingFileAppender :将日志信息输出到一个日志文件,并且指定文件的尺寸,当文件大小达到指定尺寸时,会自动把文件改名,同时产生一个新的文件
- JDBCAppender :把日志信息保存到数据库中
3、Layouts
有时用户希望根据自己的喜好格式化自己的日志输出,Log4j可以在Appenders的后面附加Layouts来完成这个功能。Layouts提供四种日志输出样式,如根据HTML样式、自由指定样式、包含日志级别与信息的样式和包含日志时间、线程、类别等信息的样式。
常用Layouts:
- HTMLLayout :格式化日志输出为HTML表格形式
- SimpleLayout :简单的日志输出格式化,打印的日志格式如默认INFO级别的消息
- PatternLayout :最强大的格式化组件,可以根据自定义格式输出日志,如果没有指定转换格式, 就是用默认的转换格式
(1)PatternLayout日志输出格式说明
使用PatternLayout可以自定义格式输出,是我们最常用的方式
这种格式化输出采用类似于 C 语言的 printf 函数的打印格式格式化日志信息,具体的占位符及其含义如下:
- %m 输出代码中指定的日志信息
- %p 输出优先级,即 DEBUG、INFO 等
- %n 换行符(Windows平台的换行符为 “\n”,Unix 平台为 “\n”)
- %r 输出自应用启动到输出该 log 信息耗费的毫秒数
- %c 输出打印语句所属的类的全名
- %t 输出产生该日志的线程全名
- %d 输出服务器当前时间,默认为 ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日 HH:mm:ss}
- %l 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。如:Test.main(Test.java:10)
- %F 输出日志消息产生时所在的文件名称
- %L 输出代码中的行号
- %% 输出一个 “%” 字符
- %x:输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
可以在 % 与字符之间加上修饰符来控制最小宽度、最大宽度和文本的对其方式。如:
- %5c 输出category名称,最小宽度是5,category<5,默认的情况下右对齐
- %-5c 输出category名称,最小宽度是5,category<5,"-"号指定左对齐,会有空格
- %.5c 输出category名称,最大宽度是5,category>5,就会将左边多出的字符截掉,<5不会有空格
- %20.30c category名称<20补空格,并且右对齐,>30字符,就从左边交远销出的字符截掉
三、使用实例
1、引入依赖
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
后续使用的类,都是org.apache.log4j包下的类。
2、入门案例
log4j需要先初始化配置信息,否则会提示:
log4j:WARN No appenders could be found for logger (com.demo.logger.log4j.Log4jTest01).
log4j:WARN Please initialize the log4j system properly.
需要先初始化配置信息。
//加载初始化配置
BasicConfigurator.configure();
Logger logger = Logger.getLogger(Log4jTest01.class);
logger.info("info信息");
// 执行结果:
// 2 [main] INFO com.demo.logger.log4j.Log4jTest01 - info信息
(1)初始化配置源码分析
// org.apache.log4j.BasicConfigurator#configure
static public void configure() {
Logger root = Logger.getRootLogger();
root.addAppender(new ConsoleAppender(
new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));
}
// 默认日志输出格式
public final static String TTCC_CONVERSION_PATTERN = "%r [%t] %p %c %x - %m%n";
3、日志输出级别
日志级别说明:
Log4j提供了8个级别的日志输出,分别为:
- ALL 最低等级 用于打开所有级别的日志记录
- TRACE 程序推进下的追踪信息,这个追踪信息的日志级别非常低,一般情况下是不会使用的
- DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的,主要是配合开发,在开发过程中打印一些重要的运行信息
- INFO 消息的粗粒度级别运行信息
- WARN 表示警告,程序在运行过程中会出现的有可能会发生的隐形的错误,注意,有些信息不是错误,但是这个级别的输出目的就是为了给程序员以提示
- ERROR 系统的错误信息,发生的错误不影响系统的运行,一般情况下,如果不想输出太多的日志,则使用该级别即可
- FATAL 表示严重错误,它是那种一旦发生系统就不可能继续运行的严重错误,如果这种级别的错误出现了,表示程序可以停止运行了
- OFF 最高等级的级别,用户关闭所有的日志记录
其中debug是我们在没有进行设置的情况下,默认的日志输出级别。
//加载初始化配置
BasicConfigurator.configure();
Logger logger = Logger.getLogger(Log4jTest01.class);
logger.fatal("fatal信息");
logger.error("error信息");
logger.warn("warn信息");
logger.info("info信息");
logger.debug("debug信息");
logger.trace("trace信息");
/*
输出内容:
0 [main] FATAL com.demo.logger.log4j.Log4jTest01 - fatal信息
0 [main] ERROR com.demo.logger.log4j.Log4jTest01 - error信息
0 [main] WARN com.demo.logger.log4j.Log4jTest01 - warn信息
0 [main] INFO com.demo.logger.log4j.Log4jTest01 - info信息
0 [main] DEBUG com.demo.logger.log4j.Log4jTest01 - debug信息
*/
4、自定义配置文件的基本使用及源码分析
(1)使用默认配置信息(源码分析)
上面我们分析了初始化配置的源代码:
// org.apache.log4j.BasicConfigurator#configure
static public void configure() {
// 创建了根节点的对象
Logger root = Logger.getRootLogger();
// 根节点添加了ConsoleAppender对象(表示默认打印到控制台,自定义的格式化输出)
root.addAppender(new ConsoleAppender(
new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));
}
// 默认日志输出格式
public final static String TTCC_CONVERSION_PATTERN = "%r [%t] %p %c %x - %m%n";
(2)使用自定义配置信息(源码分析)
首先我们分析Logger.getLogger静态方法:
// org.apache.log4j.Logger#getLogger(java.lang.Class)
static public Logger getLogger(Class clazz) {
// LogManager:日志管理器
return LogManager.getLogger(clazz.getName());
}
LogManager中有着很多常量信息,他们代表的就是不同形式(后缀名不同)的配置文件,我们最常使用到的肯定是log4j.properties属性文件(语法简单,使用方便)
// LogManager
static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";
static final public String DEFAULT_CONFIGURATION_KEY="log4j.configuration";
static final public String CONFIGURATOR_CLASS_KEY="log4j.configuratorClass";
public static final String DEFAULT_INIT_OVERRIDE_KEY ="log4j.defaultInitOverride";
在LogManager的static静态代码块中,实现了对配置文件的查找:
// 系统默认要从当前的类路径下找到log4j.properties,如果当前的项目是maven工程,那么理应在resources路径下去找
Loader.getResource(DEFAULT_CONFIGURATION_FILE);
同样在LogManager的static静态代码块中,对配置文件进行了加载:
OptionConverter.selectAndConfigure(url, configuratorClassName,
LogManager.getLoggerRepository());
// org.apache.log4j.helpers.OptionConverter#selectAndConfigure
static public void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) {
Configurator configurator = null;
String filename = url.getFile();
if(clazz == null && filename != null && filename.endsWith(".xml")) {
clazz = "org.apache.log4j.xml.DOMConfigurator";
}
if(clazz != null) {
LogLog.debug("Preferred configurator class: " + clazz);
configurator = (Configurator) instantiateByClassName(clazz,
Configurator.class,
null);
if(configurator == null) {
LogLog.error("Could not instantiate configurator ["+clazz+"].");
return;
}
} else {
// 作为属性文件的加载,执行相应的properties配置对象
configurator = new PropertyConfigurator();
}
configurator.doConfigure(url, hierarchy);
}
在PropertyConfigurator中,里面的常量信息就是我们在properties属性文件中的各种属性配置项,其中rootLogger和appender是必需要配置的:
public class PropertyConfigurator implements Configurator {
protected Hashtable registry = new Hashtable(11);
protected LoggerFactory loggerFactory = new DefaultCategoryFactory();
static final String CATEGORY_PREFIX = "log4j.category.";
static final String LOGGER_PREFIX = "log4j.logger.";
static final String FACTORY_PREFIX = "log4j.factory";
static final String ADDITIVITY_PREFIX = "log4j.additivity.";
static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory";
static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger";
static final String APPENDER_PREFIX = "log4j.appender.";
static final String RENDERER_PREFIX = "log4j.renderer.";
static final String THRESHOLD_PREFIX = "log4j.threshold";
public static final String LOGGER_FACTORY_KEY = "log4j.loggerFactory";
private static final String RESET_KEY = "log4j.reset";
static final private String INTERNAL_ROOT_NAME = "root";
通过对log4j.appender和log4j.rootLogger的处理,我们得出以下结论:
# 配置根节点logger
# 要以逗号的方式来切割字符串,log4j.rootLogger的取值,其中可以有多个值,使用逗号进行分隔
# 切割后的第一个值是日志的级别,第2~第n个值,就是我们配置的其他的信息,这个信息就是appenderName
# 例如:log4j.rootLogger=日志级别,appenderName1,appenderName2,appenderName3....
log4j.rootLogger=trace,console
#配置appender输出方式 输出到控制台
# 通过代码String prefix = "log4j.appender." + appenderName;我们需要自定义一个appendername,我们起名叫做console
log4j.appender.console=org.apache.log4j.ConsoleAppender
#配置输出到控制台的格式
# 通过代码:String layoutPrefix = prefix + ".layout"; 我们可以得知需要这样配置payout:
log4j.appender.console.layout=org.apache.log4j.PatternLayout
(3)自定义配置文件的基本使用
我们使用如上的配置,不需要默认的配置了,编写如下代码测试:
Logger logger = Logger.getLogger(Log4jTest01.class);
logger.fatal("fatal信息");
logger.error("error信息");
logger.warn("warn信息");
logger.info("info信息");
logger.debug("debug信息");
logger.trace("trace信息");
/*
打印结果:
fatal信息
error信息
warn信息
info信息
debug信息
trace信息
*/
5、打开日志输出的详细信息
(1)源码分析
在LogManager的静态代码块以及其他初始化日志配置的地方,会调用LogLog.debug方法进行日志输出:
if(url != null) {
LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
try {
OptionConverter.selectAndConfigure(url, configuratorClassName,
LogManager.getLoggerRepository());
} catch (NoClassDefFoundError e) {
LogLog.warn("Error during default initialization", e);
}
} else {
LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
}
// org.apache.log4j.helpers.LogLog#debug(java.lang.String)
public static void debug(String msg) {
if(debugEnabled && !quietMode) { // !quietMode默认就是true,debugEnabled 默认是false
System.out.println(PREFIX+msg);
}
}
我们只需要将LogLog的debugEnabled 设置为true,就可以输出log的debug日志了。
(2)代码实例
// 开启log的debug
LogLog.setInternalDebugging(true);
Logger logger = Logger.getLogger(Log4jTest01.class);
logger.fatal("fatal信息");
logger.error("error信息");
logger.warn("warn信息");
logger.info("info信息");
logger.debug("debug信息");
logger.trace("trace信息");
/*
打印结果:
log4j: Trying to find [log4j.xml] using context classloader sun.misc.Launcher$AppClassLoader@18b4aac2.
log4j: Trying to find [log4j.xml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource().
log4j: Trying to find [log4j.properties] using context classloader sun.misc.Launcher$AppClassLoader@18b4aac2.
log4j: Using URL [file:/E:/java/myspringboot/target/classes/log4j.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/E:/java/myspringboot/target/classes/log4j.properties
log4j: Parsing for [root] with value=[trace,console].
log4j: Level token is [trace].
log4j: Category root set to TRACE
log4j: Parsing appender named "console".
log4j: Parsing layout options for "console".
log4j: End of parsing for "console".
log4j: Parsed "console" options.
log4j: Finished configuring.
fatal信息
error信息
warn信息
info信息
debug信息
trace信息
*/
我们可以看到,我们的配置文件的地址以及配置内容等详细信息。
6、自定义日志输出格式
上面我们介绍过,Layout总共有三种,一种是我们之前使用过的SimpleLayout,另一种是将日志转换为html输出的HTMLLayout。
但是我们最常用的还是PatternLayout,进行自定义输出格式。
(1)PatternLayout源码分析
setConversionPattern方法就是PatternLayout的核心方法,内部使用就是ognl表达式。相当于将conversionPattern配置到pattern中了。
// org.apache.log4j.PatternLayout#setConversionPattern
public void setConversionPattern(String conversionPattern) {
pattern = conversionPattern;
head = createPatternParser(conversionPattern).parse();
}
如果不通过setConversionPattern设置的话,默认就是%m%n。
(2)代码实例
例如我们修改配置文件:
# 配置根节点logger
# 切割后的第一个值是日志的级别,第2~第n个值,就是我们配置的其他的信息,这个信息就是appenderName
log4j.rootLogger=trace,console
#配置appender输出方式 输出到控制台
log4j.appender.console=org.apache.log4j.ConsoleAppender
#配置输出到控制台的格式
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.conversionPattern=[%10p]%r %c [%t] %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n
/*
%m 输出代码中指定的日志信息
%p 输出优先级,及 DEBUG、INFO 等
%n 换行符(Windows平台的换行符为 "\n",Unix 平台为 "\n")
%r 输出自应用启动到输出该 log 信息耗费的毫秒数
%c 输出打印语句所属的类的全名
%t 输出产生该日志的线程全名
%d 输出服务器当前时间,默认为 ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日 HH:mm:ss}
%l 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。如:Test.main(Test.java:10)
%F 输出日志消息产生时所在的文件名称
%L 输出代码中的行号
%% 输出一个 "%" 字符
可以在 % 与字符之间加上修饰符来控制最小宽度、最大宽度和文本的对其方式
[%10p]:[]中必须有10个字符,由空格来进行补齐,信息右对齐
[%-10p]:[]中必须有10个字符,由空格来进行补齐,信息左对齐,应用较广泛
*/
Logger logger = Logger.getLogger(Log4jTest01.class);
logger.fatal("fatal信息");
logger.error("error信息");
logger.warn("warn信息");
logger.info("info信息");
logger.debug("debug信息");
logger.trace("trace信息");
7、将日志输出到文件
(1)FileAppender源码分析
通过FileAppender的set方法,可以在配置文件中将属性进行配置:
以及其父类WriterAppender,也可以通过set方法将属性进行设置。
(2)配置实例
# 配置根节点logger
# 切割后的第一个值是日志的级别,第2~第n个值,就是我们配置的其他的信息,这个信息就是appenderName
log4j.rootLogger=trace,file
#配置appender输出方式 输出到文件
log4j.appender.file=org.apache.log4j.FileAppender
#配置输出到文件中的格式
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.conversionPattern=[%-10p]%r %c%t%d{yyyy-MM-dd HH:mm:ss:SSS} %m%n
#第一个file是我们自己命名的appenderName,第二个file是用来指定文件位置的属性
log4j.appender.file.file=D://log4j.log
#配置输出字符编码
log4j.appender.file.encoding=UTF-8
# 表示是否追加信息,默认为true
log4j.appender.file.append=false
# 缓冲区的大小,默认为8*1024
log4j.appender.file.bufferSize=4*1024
8、将日志按照文件大小拆分
日志太多了,不方便管理和维护怎么办?
FileAppender为我们提供了好用的子类来进一步的对于文件输出进行处理:RollingFileAppender、DailyRollingFileAppender
(1)RollingFileAppender源码分析
RollingFileAppender是FileAppender的子类,这个类表示使用按照文件大小进行拆分的方式进行操作。
// 表示默认文件大小,默认10MB
protected long maxFileSize = 10*1024*1024;
// 指定日志文件个数
protected int maxBackupIndex = 1;
假如我们配置只要文件超过1MB,那么则生成另外一个文件,文件的数量最多是5个
文件1 记录日志 1MB
文件2 记录日志 1MB
…
…
文件5 1MB
如果5个文件不够怎么办,作为日志管理来讲,也不可能让日志无休止的继续增长下去
所以,覆盖文件的策略是,按照时间来进行覆盖,原则就是保留新的,覆盖旧的
(2)RollingFileAppender配置实例
#配置根节点logger
log4j.rootLogger=trace,console
#RollingFileAppender的配置,我们可以针对于实际含义起名
log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.conversionPattern=[%-10p]%r %c%t%d{yyyy-MM-dd HH:mm:ss:SSS} %m%n
log4j.appender.rollingFile.file=D://test//log4j.log
log4j.appender.rollingFile.encoding=UTF-8
#指定日志文件内容大小
log4j.appender.rollingFile.maxFileSize=1MB
#指定日志文件的数量
log4j.appender.rollingFile.maxBackupIndex=5
(3)DailyRollingFileAppender源码分析
DailyRollingFileAppender也是FileAppender的子类,这个类表示使用按照时间进行拆分的方式进行操作。
private String datePattern = "'.'yyyy-MM-dd";
默认是按照天进行拆分的。
如果是大型的项目,可以根据天进行拆分,或者如果是小型的项目,可以根据周,月进行拆分
(4)DailyRollingFileAppender配置实例
# 配置根节点logger
# 切割后的第一个值是日志的级别,第2~第n个值,就是我们配置的其他的信息,这个信息就是appenderName
log4j.rootLogger=trace,dailyRollingFile
#DailyRollingFileAppender的配置,我们可以针对于实际含义起名
log4j.appender.dailyRollingFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyRollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.dailyRollingFile.layout.conversionPattern=[%-10p]%r %c%t%d{yyyy-MM-dd HH:mm:ss:SSS} %m%n
log4j.appender.dailyRollingFile.file=D://test//log4j.log
log4j.appender.dailyRollingFile.encoding=UTF-8
log4j.appender.dailyRollingFile.datePattern='.'yyyy-MM-dd HH-mm-ss
9、将日志输出到数据库
(1)创建表
字段的制定可以根据需求进行调整。
CREATE TABLE tbl_log(
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) DEFAULT NULL COMMENT '项目名称',
createTime varchar(255) DEFAULT NULL COMMENT '创建时间',
level varchar(255) DEFAULT NULL COMMENT '日志级别',
category varchar(255) DEFAULT NULL COMMENT '所在类的全路径',
fileName varchar(255) DEFAULT NULL COMMENT '文件名称',
message varchar(255) DEFAULT NULL COMMENT '日志消息',
PRIMARY KEY(id)
)
(2)配置文件
需要导入数据库相关驱动
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.21</version>
</dependency>
配置文件:
#配置根节点logger
log4j.rootLogger=trace,logDB
#配置appender输出方式 输出到数据库表
log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.logDB.layout=org.apache.log4j.PatternLayout
log4j.appender.logDB.Driver=com.mysql.jdbc.Driver
log4j.appender.logDB.URL=jdbc:mysql://localhost:3306/test
log4j.appender.logDB.User=root
log4j.appender.logDB.Password=123456
log4j.appender.logDB.Sql=INSERT INTO tbl_log(name,createTime,level,category,fileName,message) values('project_log','%d{yyyy-MM-dd HH:mm:ss}','%p','%c','%F','%m')
10、自定义Logger配置
我们以前所创建出来的Logger对象,默认都是继承rootLogger的,我们也可以自定义logger,让其他logger来继承这个logger。
这种继承关系就是按照包结构的关系来进行指定的
例如我们一直使用的Logger logger = Logger.getLogger(Log4jTest01.class);
路径就是:com.demo.log4j.test.Log4jTest01
它的父logger就是上层的路径或者是更上层的路径
例如:
com.demo.log4j.test
com.demo.log4j
…
com
假如说我们这样配置:
#配置根节点logger
log4j.rootLogger=trace,console
#配置自定义logger
log4j.logger.com.demo.log4j.test=info,file
我们测试发现:
从输出位置来看,控制台输出了信息,日志文件也输出了信息,所以可以得出结论,如果根节点的logger和自定义父logger配置的输出位置是不同的,则取二者的并集,配置的位置都会进行输出操作。
如果二者配置的日志级别不同,以按照我们自定的父logger的级别输出为主。
(1)自定义logger的应用场景
我们之所以要自定义logger,就是为了针对不同系统信息做更加灵活的输出操作。
例如,我们可以指定不同包下的日志级别不同
#配置根节点logger
log4j.rootLogger=trace,console
#配置自定义logger
log4j.logger.com.demo.log4j.test=info,file
#配置自定义logger
log4j.logger.com.demo.service.test=debug,file
#配置自定义logger
log4j.logger.com.demo.controller.test=info,rollingFile
注意!日志的输出位置,也就是appenderName,如果rootLogger配置了console,自定义logger也配置了console,会打印两遍,其他的appender也是一样的。所以不要配置重复。