首页 >> 大全

学习Java日志框架之——搞懂log4j

2023-12-04 大全 22 作者:考证青年

文章目录 三、使用实例 3、日志输出级别4、自定义配置文件的基本使用及源码分析 5、打开日志输出的详细信息 6、自定义日志输出格式 7、将日志输出到文件 8、将日志按照文件大小拆分 9、将日志输出到数据库 10、自定义配置

系列文章目录

学习Java日志框架之——搞懂JUL(java.util.)

学习Java日志框架之——搞懂log4j

学习Java日志框架之——搞懂日志门面(JCL+SLF4J)

学习日志框架之——搞懂

学习日志框架之——入门

扩展——打印自定义日志输出格式,将日志输出为json或自定义

一、Log4j简介

Log4j(Log for java)是的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX 守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码,所以说,我们使用log4j技术,主要使用的是其配置文件。

官方网站:

注! Boot1.4版本以后就不再支持log4j,应运而生的是,后续有时间再进行学习。

二、Log4j组件介绍

Log4j主要由 (日志记录器)、(输出控制器)和 (日志格式化器)组成。其中 控制日志的输出以及输出级别(JUL做日志级别Level); 指定日志的输出方式(输出到控制台、文件等); 控制日志信息的输出格式。

1、

日志记录器,负责收集处理日志记录,实例的命名就是类的全限定名,如com.demo.log4j.XX, 的名字大小写敏感,其命名有继承机制:例如:name为com.demo.log4j的会继承 name为com.demo。

Log4J中有一个特殊的叫做“root”,他是所有的根,也就意味着其他所有的都会直接 或者间接地继承自root。root 可以用.()方法获取。

例如:

com.demo.log4j.XX 儿子

com.demo.log4j 父亲

com.demo 爷爷

上辈所做的日志属性设置,会直接的影响到子辈。

自log4j 1.2版以来, 类已经取代了 类。对于熟悉早期版本的log4j的人来说, 类可以被视为 类的别名。

关于日志级别信息,例如DEBUG、INFO、WARN、ERROR…级别是分大小的,DEBUG < INFO < WARN < ERROR,分别用来指定这条日志信息的重要程度,Log4j输出日志的规则是:只输出级别不低于设定级别的日志信息,假设级别设定为INFO,则INFO、WARN、ERROR级别的日志信息都会输出,而级别比INFO低的DEBUG则不会输出。

2、

2、记录日志以及定义日志的级别仅仅是Log4j的基本功能,Log4j日志系统还提供许多强大的功能,比如允许把日志输出到不同的地方,如控制台()、文件(Files)等,可以根据天数或者文件大小产生新的文件,可以以流的形式发送到其它地方等等。

常用:

3、

有时用户希望根据自己的喜好格式化自己的日志输出,Log4j可以在的后面附加来完成这个功能。提供四种日志输出样式,如根据HTML样式、自由指定样式、包含日志级别与信息的样式和包含日志时间、线程、类别等信息的样式。

常用:

(1)日志输出格式说明

使用可以自定义格式输出,是我们最常用的方式

这种格式化输出采用类似于 C 语言的 函数的打印格式格式化日志信息,具体的占位符及其含义如下:

可以在 % 与字符之间加上修饰符来控制最小宽度、最大宽度和文本的对其方式。如:

三、使用实例 1、引入依赖

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

后续使用的类,都是org..log4j包下的类。

2、入门案例

log4j需要先初始化配置信息,否则会提示:

log4j:WARN No could be found for (com.demo..log4j.).

log4j:WARN the log4j .

需要先初始化配置信息。

//加载初始化配置
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个级别的日志输出,分别为:

其中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)使用自定义配置信息(源码分析)

首先我们分析.静态方法:

// org.apache.log4j.Logger#getLogger(java.lang.Class)
static public Logger getLogger(Class clazz) {// LogManager:日志管理器return LogManager.getLogger(clazz.getName());
}

中有着很多常量信息,他们代表的就是不同形式(后缀名不同)的配置文件,我们最常使用到的肯定是log4j.属性文件(语法简单,使用方便)

// 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";

在的静态代码块中,实现了对配置文件的查找:

// 系统默认要从当前的类路径下找到log4j.properties,如果当前的项目是maven工程,那么理应在resources路径下去找
Loader.getResource(DEFAULT_CONFIGURATION_FILE);

同样在的静态代码块中,对配置文件进行了加载:

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);
}

在中,里面的常量信息就是我们在属性文件中的各种属性配置项,其中和是必需要配置的:

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.和log4j.的处理,我们得出以下结论:

# 配置根节点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)源码分析

在的静态代码块以及其他初始化日志配置的地方,会调用.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 默认是falseSystem.out.println(PREFIX+msg);}
}

我们只需要将的 设置为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、自定义日志输出格式

上面我们介绍过,总共有三种,一种是我们之前使用过的,另一种是将日志转换为html输出的。

但是我们最常用的还是,进行自定义输出格式。

(1)源码分析

方法就是的核心方法,内部使用就是ognl表达式。相当于将配置到中了。

// org.apache.log4j.PatternLayout#setConversionPattern
public void setConversionPattern(String conversionPattern) {pattern = conversionPattern;head = createPatternParser(conversionPattern).parse();
}

如果不通过设置的话,默认就是%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=[p]%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 输出代码中的行号%% 输出一个 "%" 字符可以在 % 与字符之间加上修饰符来控制最小宽度、最大宽度和文本的对其方式[p]:[]中必须有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)源码分析

通过的set方法,可以在配置文件中将属性进行配置:

以及其父类,也可以通过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、将日志按照文件大小拆分

日志太多了,不方便管理和维护怎么办?

为我们提供了好用的子类来进一步的对于文件输出进行处理:、nder

(1)源码分析

是的子类,这个类表示使用按照文件大小进行拆分的方式进行操作。

// 表示默认文件大小,默认10MB
protected long maxFileSize = 10*1024*1024;
// 指定日志文件个数
protected int  maxBackupIndex  = 1;

假如我们配置只要文件超过1MB,那么则生成另外一个文件,文件的数量最多是5个

文件1 记录日志 1MB

文件2 记录日志 1MB

文件5 1MB

如果5个文件不够怎么办,作为日志管理来讲,也不可能让日志无休止的继续增长下去

所以,覆盖文件的策略是,按照时间来进行覆盖,原则就是保留新的,覆盖旧的

(2)配置实例

#配置根节点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)nder源码分析

nder也是的子类,这个类表示使用按照时间进行拆分的方式进行操作。

private String datePattern = "'.'yyyy-MM-dd";

默认是按照天进行拆分的。

如果是大型的项目,可以根据天进行拆分,或者如果是小型的项目,可以根据周,月进行拆分

(4)nder配置实例

# 配置根节点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>mysqlgroupId><artifactId>mysql-connector-javaartifactId><version>5.1.21version>
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、自定义配置

我们以前所创建出来的对象,默认都是继承的,我们也可以自定义,让其他来继承这个。

这种继承关系就是按照包结构的关系来进行指定的

例如我们一直使用的 = .(.class);

路径就是:com.demo.log4j.test.

它的父就是上层的路径或者是更上层的路径

例如:

com.demo.log4j.test

com.demo.log4j

com

假如说我们这样配置:

#配置根节点logger
log4j.rootLogger=trace,console#配置自定义logger
log4j.logger.com.demo.log4j.test=info,file

我们测试发现:

从输出位置来看,控制台输出了信息,日志文件也输出了信息,所以可以得出结论,如果根节点的和自定义父配置的输出位置是不同的,则取二者的并集,配置的位置都会进行输出操作。

如果二者配置的日志级别不同,以按照我们自定的父的级别输出为主。

(1)自定义的应用场景

我们之所以要自定义,就是为了针对不同系统信息做更加灵活的输出操作。

例如,我们可以指定不同包下的日志级别不同

#配置根节点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

注意!日志的输出位置,也就是,如果配置了,自定义也配置了,会打印两遍,其他的也是一样的。所以不要配置重复。

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了