一 日志概述
日志文件
日志文件是用于记录系统操作事件的文件集合,分为调试日志和系统日志
日志框架
-
日志门面
JCL、slf4j
-
日志实现
JUL、logback、log4j、log4j2
二 JUL
Java Util Logging,Java原生日志框架
使用
import java.util.logging.*;
public class JULTest {
@Test
public void test() throws Exception {
//获取日志记录器对象
Logger logger=Logger.getLogger("com.web02.JULTest");
//日志记录输出
logger.info("hello jul");
//通用方法记录日志
logger.log(Level.INFO,"info msg");
//占位符方式输出变量值
String name="hhf";
Integer age=21;
logger.log(Level.INFO,"info msg: {0},{1}",new Object[]{name,age});
}
}
日志级别
- SEVERE:严重错误
- WARNING:警告
- INFO:普通信息
- CONFIG:配置信息
- FINE、FINER、FINEST:用于debug记录
- ALL:启用所有消息的日志记录
- OFF:关闭日志记录
控制台默认输出前三个级别的日志
自定义配置日志级别
@Test
public void testLogConfig() throws Exception {
Logger logger=Logger.getLogger("com.web02.JULTest");
//关闭系统默认配置
logger.setUseParentHandlers(false);
//创建ConsoleHandler,控制台输出
ConsoleHandler consoleHandler=new ConsoleHandler();
//创建简单格式转换对象
SimpleFormatter simpleFormatter=new SimpleFormatter();
//进行关联
consoleHandler.setFormatter(simpleFormatter);
logger.addHandler(consoleHandler);
//自定义配置日志级别
logger.setLevel(Level.ALL);
consoleHandler.setLevel(Level.ALL);
//创建FileHandler,文件输出
FileHandler fileHandler=new FileHandler("jul.log");
fileHandler.setFormatter(simpleFormatter);
fileHandler.setLevel(Level.ALL);
logger.addHandler(fileHandler);
logger.config("config");
}
Logger对象父子关系
用getParent()获取Logger父对象
所有日志记录器的顶级父元素是LogManager$RootLogger
自定义配置文件
resources下新建logging.properties
#RootLogger默认处理器
handlers=java.util.logging.ConsoleHandler,java.util.logging.FileHandler
#RootLogger默认日志级别
.level=ALL
#自定义Logger
com.web02.JULTest.handlers=java.util.logging.ConsoleHandler
com.web02.JULTest.level=CONFIG
com.web02.JULTest.useParentHandlers=false
#日志文件路径
java.util.logging.FileHandler.pattern=my.log
#日志文件内容大小
java.util.logging.FileHandler.limit=50000
#日志文件数量
java.util.logging.FileHandler.count=1
java.util.logging.FileHandler.formatter=java.util.logging.XMLFormatter
#指定追加方式
java.util.logging.FileHandler.append=true
#控制台处理器的日志级别
java.util.logging.ConsoleHandler.level=ALL
#控制台处理器的消息格式对象
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
#控制台处理器的字符集
java.util.logging.ConsoleHandler.encoding=UTF-8
#消息格式
java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n
@Test
public void testLogProperties() throws Exception {
//通过类加载器读取配置文件
InputStream ins=JULTest.class.getClassLoader().getResourceAsStream("logging.properties");
//创建LogManager
LogManager logManager=LogManager.getLogManager();
//加载配置文件
logManager.readConfiguration(ins);
Logger logger=Logger.getLogger("com.web02.JULTest");
logger.config("config");
}
原理
三 Log4j
简单使用
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
import org.apache.log4j.Logger;
import org.apache.log4j.helpers.LogLog;
import org.junit.Test;
public class Log4jTest {
@Test
public void test() throws Exception {
//初始化配置信息
BasicConfigurator.configure();
//获取日志记录器对象
Logger logger=Logger.getLogger(Log4jTest.class);
//日志级别
logger.fatal("fatal");//严重错误
logger.error("error");//错误信息
logger.warn("warn");//警告信息
logger.info("msg");//运行信息
logger.debug("debug");//调试信息
logger.trace("trace");//追踪信息
}
}
组件
Loggers
日志记录器,负责收集处理日志记录
Appenders
指定日志输出的位置
分为ConsoleAppender, FileAppender, DailyRollingFileAppender, RollingFileAppender, JDBCAppender
Layout
控制日志输出的格式
分为HTMLLayout, SimpleLayout, PatternLayout
配置文件
resources下新建log4j.properties
#指定日志级别,使用的appender
log4j.rootLogger=trace,console
#指定控制台输出的appender
log4j.appender.console=org.apache.log4j.ConsoleAppender
#指定消息格式layout
log4j.appender.console.layout=org.apache.log4j.PatternLayout
#指定消息格式内容
log4j.appender.console.layout.conversionPattern=%r [%t] %p %c %x - %m%n
开启log4j内置日志记录
LogLog.setInternalDebugging(true);
FileAppender配置
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.conversionPattern=%r [%t] %p %c %x - %m%n
log4j.appender.file.file=log4j.log
log4j.appender.file.encoding=UTF-8
RollingFileAppender配置
#按照文件大小拆分
log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.conversionPattern=%r [%t] %p %c %x - %m%n
log4j.appender.rollingFile.file=log4j.log
log4j.appender.rollingFile.encoding=UTF-8
log4j.appender.rollingFile.maxFileSize=1MB
log4j.appender.rollingFile.maxBackupIndex=10
DailyRollingFileAppender配置
log4j.appender.dailyFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyFile.layout=org.apache.log4j.PatternLayout
log4j.appender.dailyFile.layout.conversionPattern=%r [%t] %p %c %x - %m%n
log4j.appender.dailyFile.file=log4j.log
log4j.appender.dailyFile.encoding=UTF-8
log4j.appender.dailyFile.datePattern='.'yyyy-MM-dd-HH-mm-ss
JDBCAppender配置
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=xxx
log4j.appender.logDB.Password=xxx
log4j.appender.logDB.Sql=xxx
自定义logger设置
log4j.logger.com.web02=info,file
四 JCL
Jakarta Commons Logging,Apache提供的一个通用日志API,为所有Java日志实现提供一个统一接口
使用
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
public class JCLTest {
@Test
public void test() {
Log log= LogFactory.getLog(JCLTest.class);
log.info("info");
}
}
优势
- 面向接口开发,减少代码耦合
- 可灵活切换日志框架
- 统一API,方便学习使用
- 统一配置
原理
- 通过LogFactory动态加载Log实现类
- 查找符合条件的日志实现,包括Log4JLogger, Jdk14Logger, Jdk13LumberjackLogger, SimpleLog
- 获取具体的日志实现
五 Slf4j
简单使用
<!--slf4j日志门面-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.28</version>
</dependency>
<!--slf4j内置实现-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Slf4jTest {
public static final Logger LOGGER= LoggerFactory.getLogger(Slf4jTest.class);
@Test
public void test() {
LOGGER.error("error");
LOGGER.warn("warn");
LOGGER.info("info");//默认级别
LOGGER.debug("debug");
LOGGER.trace("trace");
String name="log";
LOGGER.info("{}",name);
try {
int a=1/0;
} catch (Exception ex) {
LOGGER.error("error",ex);
}
}
}
日志绑定
只能绑定一个日志实现,如果出现多个默认使用第一个
绑定logback
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
绑定slf4j-nop
<!--日志开关-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.25</version>
</dependency>
绑定log4j
<!--适配器-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
绑定JUL
<!--适配器-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.5.6</version>
</dependency>
日志桥接器
举例:项目由log4j切换为slf4j+logback
<!--配置log4j桥接器-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
桥接器和适配器不能同时存在,否则会出现栈溢出异常
六 Logback
分为三个模块
- logback-core
- logback-classic
- logback-access
使用
<!--slf4j日志门面-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.28</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogbackTest {
public static final Logger LOGGER= LoggerFactory.getLogger(LogbackTest.class);
@Test
public void test() {
LOGGER.error("error");
LOGGER.warn("warn");
LOGGER.info("info");
LOGGER.debug("debug");//默认级别
LOGGER.trace("trace");
}
}
配置文件
logback会依次读取以下配置文件,如果都不存在会使用默认配置
- logback.groovy
- logback-test.xml
- logback.xml
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!--配置集中管理属性-->
<property name="pattern" value="%-5level %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L %thread %m%n"></property>
<!--控制台输出appender-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--控制输出流对象-->
<target>System.err</target>
<!--消息格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
</appender>
<!--root logger配置-->
<root level="ALL">
<appender-ref ref="console"></appender-ref>
</root>
</configuration>
FileAppender配置
<property name="pattern" value="%-5level %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L %thread %m%n"></property>
<property name="log_dir" value="/logs"></property>
<!--文件输出appender-->
<appender name="file" class="ch.qos.logback.core.FileAppender">
<!--文件保存路径-->
<file>${log_dir}/logback.log</file>
<!--消息格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
</appender>
<!--html文件输出appender-->
<appender name="htmlfile" class="ch.qos.logback.core.FileAppender">
<!--文件保存路径-->
<file>${log_dir}/logback.html</file>
<!--消息格式配置-->
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<pattern>${pattern}</pattern>
</layout>
</encoder>
</appender>
<root level="ALL">
<appender-ref ref="file"></appender-ref>
<appender-ref ref="htmlfile"></appender-ref>
</root>
拆分Appender配置
<property name="pattern" value="%-5level %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L %thread %m%n"></property>
<property name="log_dir" value="/logs"></property>
<appender name="rollfile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--文件保存路径-->
<!--<file>${log_dir}/roll_logback.log</file>-->
<!--消息格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
<!--指定拆分规则-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--按照时间,压缩格式用log.gz-->
<fileNamePattern>${log_dir}/roll.%d{yyyy-MM-dd-HH-mm-ss}.log%i</fileNamePattern>
<!--按照文件大小-->
<maxFileSize>1MB</maxFileSize>
</rollingPolicy>
</appender>
<root level="ALL">
<appender-ref ref="rollfile"></appender-ref>
</root>
过滤器
<appender name="rollfile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--文件保存路径-->
<!--<file>${log_dir}/roll_logback.log</file>-->
<!--消息格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
<!--指定拆分规则-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--按照时间,压缩格式用log.gz-->
<fileNamePattern>${log_dir}/roll.%d{yyyy-MM-dd-HH-mm-ss}.log%i</fileNamePattern>
<!--按照文件大小-->
<maxFileSize>1MB</maxFileSize>
</rollingPolicy>
<!--日志级别过滤器-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--过滤规则-->
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
异步日志
<!--异步日志,提升性能-->
<appender name="async" class="ch.qos.logback.classic.AsyncAppender">
<!--指定某个具体appender-->
<appender-ref ref="rollfile"></appender-ref>
</appender>
<root level="ALL">
<appender-ref ref="async"></appender-ref>
</root>
自定义logger
<!--自定义logger additivity:自定义logger是否继承rootlogger-->
<logger name="com.web02" level="info" additivity="false">
<appender-ref ref="console"></appender-ref>
</logger>
log4j.properties->logback.xml
http://logback.qos.ch/translator/
logback-access
与Servlet容器(Tomcat、Jetty)集成,提供HTTP访问日志功能
七 Log4j2
slf4j+log4j2
<!--slf4j日志门面-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.28</version>
</dependency>
<!--log4j2日志门面-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.2</version>
</dependency>
<!--log4j2日志实现-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.10.0</version>
</dependency>
<!--log4j2适配器-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.9.1</version>
</dependency>
配置文件
<?xml version="1.0" encoding="utf-8" ?>
<!--status:输出的日志级别,monitorInternal:自动加载配置文件的间隔时间-->
<Configuration status="debug" monitorInternal="5">
<!--配置集中管理属性-->
<properties>
<property name="log_home">/logs</property>
</properties>
<!--控制台输出appender-->
<Appenders>
<Console name="Console" target="SYSTEM_ERR">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}"></PatternLayout>
</Console>
<File name="file" fileName="${log_home}/myfile.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}"></PatternLayout>
</File>
<RandomAccessFile name="accessfile" fileName="${log_home}/myfile.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}"></PatternLayout>
</RandomAccessFile>
<RollingFile name="rollingfile" fileName="${log_home}/myfile.log"
filePattern="/logs/$${date:yyyy-MM-dd}/rolllog-%d{yyyy-MM-dd-HH-mm}-%i.log">
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"></ThresholdFilter>
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}"></PatternLayout>
<Policies>
<OnStartupTriggeringPolicy></OnStartupTriggeringPolicy>
<SizeBasedTriggeringPolicy size="1 MB"></SizeBasedTriggeringPolicy>
<TimeBasedTriggeringPolicy></TimeBasedTriggeringPolicy>
</Policies>
<DefaultRolloverStrategy max="30"></DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Console"></AppenderRef>
</Root>
</Loggers>
</Configuration>
异步日志
<!--异步日志依赖-->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.4</version>
</dependency>
配置异步Appender:
<Appenders>
<File name="file" fileName="${log_home}/myfile.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}"></PatternLayout>
</File>
<Async name="Async">
<AppenderRef ref="file"></AppenderRef>
</Async>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Async"></AppenderRef>
</Root>
</Loggers>
配置异步Logger:
全局配置
log4j2.component.properties
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
混合配置
<!--自定义异步Logger,includeLocation关闭行号信息,additivity不继承rootlogger-->
<AsyncLogger name="com.web02" level="trace" includeLocation="false" additivity="false">
<AppenderRef ref="file"></AppenderRef>
</AsyncLogger>
使用异步日志,AsyncAppender, AsyncLogger, 全局日志不能同时出现
无垃圾模式
使用重用对象、缓冲区、尽可能不分配临时对象的手段,提高性能
八 SpringBoot日志
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
springboot默认使用slf4j作为日志门面,使用logback作为日志实现
配置
logback-spring.xml:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!--配置集中管理属性-->
<property name="pattern" value="%-5level %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L %thread %m%n"></property>
<!--控制台输出appender-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--控制输出流对象-->
<target>System.err</target>
<!--消息格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<springProfile name="dev">
<pattern>${pattern}</pattern>
</springProfile>
<springProfile name="pro">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}</pattern>
</springProfile>
</encoder>
</appender>
<!--root logger配置-->
<root level="ALL">
<appender-ref ref="console"></appender-ref>
</root>
</configuration>
#指定环境,使用不同的日志格式
spring.profiles.active=dev
切换为log4j2
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!--排除logback-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>