本文主要介绍logback的配置、使用,以及日志记录级别、记录方式。
MAVEN 引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>demo</artifactId>
<groupId>com.example</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>log</artifactId>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
</dependencies>
</project>
添加测试类
结构如下
代码如下
package com.example.log.a;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class A {
final static Logger logger = LoggerFactory.getLogger(A.class);
public static void log(){
logger.debug("a.log");
logger.info("a.log");
logger.warn("a.log");
logger.error("a.log");
}
}
package com.example.log.b;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class B {
static final Logger logger = LoggerFactory.getLogger(B.class);
public static void log(){
logger.debug("b.log");
logger.info("b.log");
logger.warn("b.log");
logger.error("b.log");
}
}
package com.example.log;
import com.example.log.a.A;
import com.example.log.b.B;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Test {
public static final Logger logger = LoggerFactory.getLogger(Test.class);
public static void log(){
logger.debug("a.log");
logger.info("a.log");
logger.warn("a.log");
logger.error("a.log");
}
public static void main(String[] args) {
A.log();
B.log();
Test.log();
}
}
添加配置文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="d:/logs/" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!--myibatis log configure-->
<logger name="com.example.log.a" level="INFO"/>
<logger name="com.example.log.b" level="DEBUG">
<appender-ref ref="FILE" />
</logger>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
<!--<appender-ref ref="FILE" />-->
</root>
</configuration>
运行结果
控制台输出
2021-01-20 08:47:48.542 [main] INFO com.example.log.a.A - a.log
2021-01-20 08:47:48.572 [main] WARN com.example.log.a.A - a.log
2021-01-20 08:47:48.572 [main] ERROR com.example.log.a.A - a.log
2021-01-20 08:47:48.627 [main] DEBUG com.example.log.b.B - b.log
2021-01-20 08:47:48.627 [main] INFO com.example.log.b.B - b.log
2021-01-20 08:47:48.627 [main] WARN com.example.log.b.B - b.log
2021-01-20 08:47:48.627 [main] ERROR com.example.log.b.B - b.log
2021-01-20 08:47:48.627 [main] INFO com.example.log.Test - a.log
2021-01-20 08:47:48.627 [main] WARN com.example.log.Test - a.log
2021-01-20 08:47:48.627 [main] ERROR com.example.log.Test - a.log
配置文件中logger可以理解为指定包的日志记录级别设置,在logback.xml中com.example.log.a包的级别为INFO,所以控制台没有输出debug日志。
同时logger 默认继承root的appender-ref,即采用控制台输出,若logger有自定义的appender-ref 则再继承的基础上使得自定义输出配置生效。例如:
com.example.log.b 包添加自定义配置 File,在本地磁盘记录日志,所以在控制台输出b包日志外,还在本地磁盘生成日志文件,输出如下
内容如下:
2021-01-20 08:47:48.627 [main] DEBUG com.example.log.b.B - b.log
2021-01-20 08:47:48.627 [main] INFO com.example.log.b.B - b.log
2021-01-20 08:47:48.627 [main] WARN com.example.log.b.B - b.log
2021-01-20 08:47:48.627 [main] ERROR com.example.log.b.B - b.log
进阶一:日志记录到数据库
修改logback配置,增加DB记录,设置URL、数据库账户,密码
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
<dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
<driverClass>com.mysql.jdbc.Driver</driverClass>
<url>jdbc:mysql://127.0.0.1:3306/logdemo</url>
<user>root</user>
<password></password>
</dataSource>
</connectionSource>
</appender>
<!--myibatis log configure-->
<logger name="com.example.log.a" level="INFO">
<appender-ref ref="DB"/>
</logger>
数据库建表:这里只贴出来MYSQL建表代码
-- Logback: the reliable, generic, fast and flexible logging framework.
-- Copyright (C) 1999-2010, QOS.ch. All rights reserved.
--
-- See http://logback.qos.ch/license.html for the applicable licensing
-- conditions.
-- This SQL script creates the required tables by ch.qos.logback.classic.db.DBAppender
--
-- The event_id column type was recently changed from INT to DECIMAL(40)
-- without testing.
DROP TABLE logging_event_property
DROP TABLE logging_event_exception
DROP TABLE logging_event
CREATE TABLE logging_event
(
timestmp DECIMAL(20) NOT NULL,
formatted_message VARCHAR(4000) NOT NULL,
logger_name VARCHAR(254) NOT NULL,
level_string VARCHAR(254) NOT NULL,
thread_name VARCHAR(254),
reference_flag SMALLINT,
arg0 VARCHAR(254),
arg1 VARCHAR(254),
arg2 VARCHAR(254),
arg3 VARCHAR(254),
caller_filename VARCHAR(254) NOT NULL,
caller_class VARCHAR(254) NOT NULL,
caller_method VARCHAR(254) NOT NULL,
caller_line CHAR(4) NOT NULL,
event_id DECIMAL(40) NOT NULL identity,
PRIMARY KEY(event_id)
)
CREATE TABLE logging_event_property
(
event_id DECIMAL(40) NOT NULL,
mapped_key VARCHAR(254) NOT NULL,
mapped_value VARCHAR(1024),
PRIMARY KEY(event_id, mapped_key),
FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
)
CREATE TABLE logging_event_exception
(
event_id DECIMAL(40) NOT NULL,
i SMALLINT NOT NULL,
trace_line VARCHAR(254) NOT NULL,
PRIMARY KEY(event_id, i),
FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
)
结构如下:
运行代码,抛出异常:无法确认服务器时区,修改URL
11:12:52,899 |-WARN in ch.qos.logback.core.db.DriverManagerConnectionSource@7139992f - Could not discover the dialect to use. java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specific time zone value if you want to utilize time zone support.
at java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specific time zone value if you want to utilize time zone support.
<url>jdbc:mysql://127.0.0.1:3306/logdemo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false</url>
运行结果如下:
数据库中成功记录,但是仔细看控制台,发现有个错误如下图:
11:14:56,817 |-ERROR in ch.qos.logback.core.joran.spi.Interpreter@33:75 - no applicable action for [dataSource], current ElementPath is [[configuration][appender][connectionSource][dataSource]]
查看源码,发现Interpreter应该是解析XML节点的,XML解析错误,上网搜索后得知,该类不支持datasource,所以重新修改logback配置后如下图:
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
<driverClass>com.mysql.jdbc.Driver</driverClass>
<url>jdbc:mysql://127.0.0.1:3306/logdemo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false</url>
<user>root</user>
<password></password>
</connectionSource>
</appender>
运行代码,结果如下:没有额外的有关logback错误日志。
进阶二:自定义记录
日志记录到数据库是为了能作为后续服务器维护的参考,以及数据统计的依据。比如,查看多少人在指定日期内登录过服务器,以及谁在这段时间修改过数据。
具体操作如下
查看logger.info代码提示,如下图所示,logger接口有很多info接口,这些接口的如下图
结合数据库查看表logging_event,看到正好有4个字段arg0,arg1,arg2,arg3,
测试如下
logger.info("a.log","zhangsan","15008");
结果如下
可以看到日志记录中增加了这条数据,这些数据可以用作日志统计时作为参数查询。
进阶三:跨模块日志级别影响
新建模块logmodule,新建测试类C,如下
package com.example.log.c;
import com.example.log.a.A;
import com.example.log.b.B;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class C {
final static Logger logger = LoggerFactory.getLogger(C.class);
public static void log(){
logger.debug("a.log");
logger.info("a.log");
logger.warn("a.log");
logger.error("a.log");
logger.info("a.log","zhangsan","15008");
}
public static void main(String[] args) {
C.log();
A.log();
B.log();
}
}
修改log模块数据库日志记录级别
<!--myibatis log configure-->
<logger name="com.example.log.b" level="DEBUG">
<appender-ref ref="FILE" />
</logger>
在运行C,结果如下
在log模块,限制的info级别完全记录,模块logmodule基础了log模块的记录级别,综上测试,模块之间日志级别可以继承,通过包的限定。
进阶四:日志展示、统计