注意二者在包名上的区别,考虑到目前使用的大多是Log4j 2,Log4j的使用就不单开一节做介绍了。
Log4j : org.apache.log4j.xxx
Log4j 2 : org.apache.logging.
log4j.xxx
<dependencies>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-apiartifactId>
<version>2.20.0version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>2.20.0version>
dependency>
dependencies>
你可能还会见到Log4j 2的说法,Log4j 2是Log4j的更新一代版本。总共有六个日志级别,数值越小越严重。
(1)
TRACE (600)
: 最不严重的日志级别,通常用来打印细粒度信息,如进入与退出一个函数的过程信息、变量值信息以及其它可以帮助你理解代码之间内部工作关系的细节信息。
(2)DEBUG (500)
: 可以用来追踪一个函数是否有正确执行。
(3)INFO (400)
: it is used for informational messages that record events that occur during the normal operation of your application,such as user authentication, API calls, or database access. These messages help you understand what’s happening within your application.
(4)WARN (300)
: events logged at this level indicate potential issues that might require your attention before they become significant problems.
(5)ERROR (200)
: it is used to record unexpected errors that occur during the course of program execution.
(6)FATAL (100)
: this is the most severe log level, and it indicates an urgent situation affecting your application’s core component that should be addressed immediately.
打印日志有个规律,配置文件如果要打印TRACE级别,那么比TRACE级别高的DEBUG级别一定不可避免会被打印出来,其它的以此类推。
除了这六个级别以外,你也可以自定义级别,定义方法如下
package com.example;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Level;
public class App {
protected static final Logger logger = LogManager.getLogger();
public static void main(String[] args) {
logger.log(Level.getLevel("VERBOSE"), "a verbose message");
}
}
还有就是log4j可以定义你的日志输出目标位置,是console控制台、还是files文件、亦或是database数据库或者云环境等。假设下面这段内容是log4j2.xml
的文件内容,最终的日志会输出到当前项目根目录下的./logs/app.log
文件中。
<Configuration status="INFO">
<Appenders>
<File name="file" fileName="./logs/app.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
File>
Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="file" />
Root>
Loggers>
Configuration>
同时,为了防止文件无限度的增长,需要让log4j开辟一个新文件去存储,这可以用RollingFile
来实现,即文件滚动。还是在上一段xml
的基础上,修改了一点内容。那么可以看到,日志会输出至.gz
后缀的压缩文件,一旦文件到了1KB,就会新建另一个.gz
后缀的压缩文件,这里选1KB是为了方便运行观察效果,实际中肯定是选百MB或GB级别的。
<Configuration status="INFO">
<Appenders>
<RollingFile name="rolling" fileName="logs/app.log"
filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="250 MB" />
Policies>
RollingFile>
Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="rolling" />
Root>
Loggers>
Configuration>
除了根据大小刷新日志,还有定时刷新日志的功能,更多功能具体请看参考文章[1],不过这篇文章在cron
表达式与OnStartupTriggeringPolicy
处有错误,不能全部都信。
除了PatternLayout
规定的格式,我们还可以用JSON
、XML
格式来打印日志,可以用JsonLayout
来打印JSON
格式的日志,首先要添加jar
包依赖
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.15.0version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-coreartifactId>
<version>2.15.0version>
dependency>
<Configuration status="INFO">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<JsonLayout />
Console>
Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="console" />
Root>
Loggers>
Configuration>
运行
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
public class Log4j_JSON {
protected static final Logger logger = LogManager.getLogger();
public static void main(String[] args) {
ThreadContext.put("orderNumber", "1234567890");
ThreadContext.put("buyerName", "jack");
ThreadContext.put("destination", "xxxxxxxxxx");
logger.info("Order shipped successfully."+ThreadContext.getContext());
ThreadContext.clearAll();
}
}
这是打印效果
{
"instant" : {
"epochSecond" : 1702643420,
"nanoOfSecond" : 977000000
},
"thread" : "main",
"level" : "INFO",
"loggerName" : "lyp.basic.logFrame.Log4j_JSON",
"message" : "Order shipped successfully.{buyerName=jack, destination=xxxxxxxxxx, orderNumber=1234567890}",
"endOfBatch" : false,
"loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
"threadId" : 1,
"threadPriority" : 5
}
你也可以配置自己的json模版,具体看文章里的教程。
什么是同步(Synchronism)?一件一件事情来,等结果执行完成再开始下一件。
什么是异步(ASynchronism,前面就多了个A)?事情一起开始,有结果再汇报,然后再处理。我们的日常生活就是异步的,所以不要觉得异步反人性,它可能反编程直觉,但绝对是符合事物本质逻辑的。 所以打日志这种事情,交给手下的日志框架去完成,打印完了汇报下就可以,这就是异步打印日志。但异步打印日志也有缺点,比如
(1) 内存占比增加
(2) 系统崩溃时,可能丢失数据
(3) 日志信息顺序混乱,这可能给debug带来困难
(4)
这里文章[1]没讲明白,另找文章。
Logtail
: Cloud-based log management platforms.
参考视频或文章链接 |
---|
[1] How to Get Started with Log4j for Logging in Java |
[2] log4j - Apache |
[3] 《详解log4j2(上) - 从基础到实战》 |
[4] Example code of log4j log4j2 and slf4j |
[5] 异步打印日志缺依赖看这篇《log4j2 AsyncLogger错误 NoClassDefFoundError: com/lmax/disruptor/EventFactory》 |
略,有兴趣请看文章。
参考视频或文章链接 |
---|
Introduction to SLF4J,也包含一些对Logpack的介绍 |
A Guide To Logback |
SLF4j = Simple Logging Facade for Java (abbreviated SLF4J)
,Facade
意思为房屋外观,还有一种设计模式叫外观模式(也叫门面模式),名字正好就是Facade Pattern,故SLF4j
的全部意思是 “Java的简单日志外观”,SLF4j
支持不同的日志框架(e.g., java.util.logging
, logback
, Log4j
)。
It offers a generic API, making the logging independent of the actual implementation.This allows for different logging frameworks to coexist.它提供了一个通用的API接口,使得logging本身是独立于具体实现的。这使得SLF4J可以运行各种不同的日志框架共存。
SLF4J如何引用Log4j 2?
<dependencies>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>2.0.9version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-slf4j2-implartifactId>
<version>2.22.0version>
dependency>
<dependency>
<groupId>com.lmaxgroupId>
<artifactId>disruptorartifactId>
<version>3.4.4version>
dependency>
dependencies>
参考视频或文章链接 |
---|
SLF4J Manaul - Offical Website |
Introduction to SLF4J |
Log4j 2 SLF4J Binding - Apache |
首先,Log4j 2
与SLF4j
并非同一事物,虽然在搜索Log4j 2
时,时常会搜索出混杂了SLF4j
与Log4j 2
的内容。
参考视频或文章链接 |
---|
Java Logging Frameworks Comparison: SLF4j vs Log4j vs Logback vs Log4j2 [Differences] |
《最通俗易懂的 JAVA slf4j,log4j,log4j2,logback 关系与区别以及完整集成案例》 |