目录
前言
我们先来简单了解一下Logback,它是log4j的升级版,都是同一个作者。
Logback超轻量级日志框架,性能是老版log4j的10倍以上,占用内存更小。
Logback 的架构非常的通用,适用不同的使用场景。Logback 被分成三个不同的模块:logback-core,logback-classic,logback-access。
logback-core 是其它两个模块的基础。logback-classic 模块可以看作是 log4j 的一个优化版本,它天然的支持 SLF4J,所以你可以随意的从其它日志框架(例如:log4j 或者 java.util.logging)切回到 logack。
logback-access 可以与 Servlet 容器进行整合,例如:Tomcat、Jetty。它提供了 http 访问日志的功能。
本文将集成到现有项目中,采用Lombok+Logback+slf4j
将实现日志输出:邮件,数据库,控制台,文件
以及动态加载日志配置内容,无需重启项目
Coding
Maven
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
无需单独再引入slf4j-api,logback-classic里面已经有了
logback配置文件
以下是 logback 的初始化步骤:
- logback 会在类路径下寻找名为 logback-test.xml 的文件。
- 如果没有找到,logback 会继续寻找名为 logback.groovy 的文件。
- 如果没有找到,logback 会继续寻找名为 logback.xml 的文件。
- 如果没有找到,将会通过 JDK 提供的 ServiceLoader 工具在类路径下寻找文件 META-INFO/services/ch.qos.logback.classic.spi.Configurator,该文件的内容为实现了
Configurator
接口的实现类的全限定类名。- 如果以上都没有成功,logback 会通过 BasicConfigurator 为自己进行配置,并且日志将会全部在控制台打印出来。
最后一步的目的是为了保证在所有的配置文件都没有被找到的情况下,提供一个默认的(但是是非常基础的)配置。
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
将日志信息打印到控制台,格式化时间,级别为debug,作用是针对大于等于debug级别的log内容。
默认就是debug,所以level="debug"可写可不写,但为了阅读性还是写上。
Test
package com.finance.www.log;
import lombok.extern.slf4j.Slf4j;
/**
* @author 954L
* @create 2020/4/30 10:55
*/
@Slf4j
public class LogbackTest {
public static void main(String[] args) {
log.trace("trace");
log.debug("debug");
log.info("info");
log.warn("warn");
log.error("error");
}
}
package com.finance.www.log;
import lombok.extern.slf4j.Slf4j;
/**
* @author 954L
* @create 2020/4/30 10:55
*/
@Slf4j
public class LogbackTest {
public static void main(String[] args) {
try {
System.out.println(1/0);
} catch (Exception e) {
log.error("程序异常", e);
}
}
}
@Slf4j注解是lombok里的,等同于:
public static final Logger log = LoggerFactory.getLogger(LogbackTest.class);
输出到文件
这也是目前最广泛的做法了,一天一个log文件,可以指定查看某天的日志文件内容,排查线上问题利器!优点就不具体说了。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--输出到控制台-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger [%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--输出到文件地址 ${catalina.base}:tomcat目录-->
<substitutionProperty name="logbase" value="${catalina.base}/logs/myLog/"/>
<!--输出到info文件配置-->
<appender name="logInfoFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger [%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--error级别-->
<level>ERROR</level>
<!--onMatch="ACCEPT" 表示匹配该级别及以上
onMatch="DENY" 表示不匹配该级别及以上-->
<onMatch>DENY</onMatch>
<!-- onMismatch="ACCEPT" 表示匹配该级别以下
onMismatch="DENY" 表示不匹配该级别以下的-->
<onMismatch>ACCEPT</onMismatch>
</filter>
<!--
通过rollingPolicy设置日志滚动的策略,这是使用按照时间滚动
fileNamePattern属性设置滚动生成文件的格式,这里设置的精确到天,也就是按照天滚动,如果时间设置精确到秒,就按秒来滚动
maxHistory属性设定最大的文件数,比如按天滚动,这里设置了30天,在第31天日志生成的时候,第一天的日志就会被删掉
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件名策略-->
<FileNamePattern>${logbase}info/%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
</appender>
<!--输出到error文件配置-->
<appender name="logErrorFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger [%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--error级别-->
<level>ERROR</level>
<!--onMatch="ACCEPT" 表示匹配该级别及以上
onMatch="DENY" 表示不匹配该级别及以上-->
<onMatch>ACCEPT</onMatch>
<!-- onMismatch="ACCEPT" 表示匹配该级别以下
onMismatch="DENY" 表示不匹配该级别以下的-->
<onMismatch>DENY</onMismatch>
</filter>
<!--
通过rollingPolicy设置日志滚动的策略,这是使用按照时间滚动
fileNamePattern属性设置滚动生成文件的格式,这里设置的精确到天,也就是按照天滚动,如果时间设置精确到秒,就按秒来滚动
maxHistory属性设定最大的文件数,比如按天滚动,这里设置了30天,在第31天日志生成的时候,第一天的日志就会被删掉
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件名策略-->
<FileNamePattern>${logbase}error/%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
<appender-ref ref="logInfoFile" />
<appender-ref ref="logErrorFile" />
</root>
</configuration>
上述将info级别及以下跟error级别的日志区分在不同的文件里,方便我们针对性处理,因为你可不想以后在一堆debug日志里找一个error
Test
我们在web接口添加如下代码
try {
System.out.println(1/0);
} catch (Exception e) {
log.info("测试异常", e);
log.error("测试异常", e);
}
效果符合预期,堆栈信息均有打印
输出到邮件
与其等出bug再看异常日志还不如直接在发生异常的时候就发送邮件到邮箱,这样就能快速发现解决问题。
这里就还是用网易爹的邮箱了,我几乎所有发送邮件都是用网易的....
发送邮件是用logback的SMTPAppender,依赖javax.mail
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
SMTPAppender的属性如下表所示:
属性名 | 类型 | 描述 |
---|---|---|
smtpHost | String | SMTP 服务器的主机名。强制性的。 |
smtpPort | int | SMPT 服务监听的端口。默认为 25. |
to | String | 接收者的邮件地址。触发事件发送给接收者。多个收件人可以使用逗号(,)分隔,或者使用多个 <to> 元素来指定。 |
from | String | SMTPAppender 使用的发件人,格式遵循邮件通用格式,如果你想要包含发送者的名字,使用这种格式 " Adam Smith <[email protected]>",那么邮件将会显示收件人为 " Adam Smith \[email protected]\" |
subject | String | 邮件的主题。它可以是通过 PatternLayout 转换后的有效值。关于 Layout 将在接下来的章节讨论。 邮件应该有一个主题行,对应触发的邮件信息。 假设 subject 的值为:"Log: %Logger - %msg",触发事件的 logger 名为 "com.foo.Bar",并且日志信息为 "Hello world"。那么发出的邮件信息将会有一个名为 "Log: com.foo.Bar - Hello World" 的主题行。默认情况下,这个属性的值为 "%logger{20} - %m" |
discriminator | Discriminator | 在 Discriminator 的帮助下,SMTPAppender 根据 discriminator 返回的值可以将不同日志事件分散到不同的缓冲区中。默认的 discriminator 将返回同一个值,所以所有的事件都使用同一个缓冲区。 |
evaluator | IEvaluator | 通过创建一个新的 元素来声明此选项。通过 class 属性指定 class 的名字表示用户希望通过哪个类来满足 SMTPAppender 的 Evaluator 的需要。如果没有指定此选项,当触发一个大于等于 ERROR 级别的事件时, SMTPAppender 将会被分配一个 OnErrorEvaluator 的实例。logback 配备了几个其它的 evaluator,分别叫 OnMarkerEvaluator (将在下面讨论),一个相对强大的 evaluator 叫 JaninoEventEvaluator (在其它章节讨论) 以及最近版本才有的一个更加强大的 evaluator 叫 GEventEvaluator 。 |
cyclicBufferTracker | CyclicBufferTracker |
从名字可以看出,是一个 CyclicBufferTracker 的实例追踪循环缓冲区。它基于 discriminator 返回的 key (见上)。如果你不想指定一个 cyclicBufferTracker,那么将会自动创建一个 CyclicBufferTracker 的实例。默认的,这个实例用来保留事件的循环缓冲区的大小为 256。你需要改变 bufferSize 选项的大小(见下面) |
username | String | 默认为 null |
password | String | 默认为 null |
STARTTLS | boolean | 如果为 true,那么 appender 将会发送 STARTTLS 命令(如果服务器支持)将连接变成 SSL 连接。注意,连接初始的时候是为加密的。默认为 false。 |
SSL | boolean | 如果为 true,将通过 SSL 连接服务器。默认为 false。 |
charsetEncoding | String | 邮件信息将会通过 charset]https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html) 进行编码。默认编码为 "UTF-8" |
localhost | String | 一旦 SMTP 客户端的主机名没有配置正确,例如客户端的 hostname 不是全限定的,那么服务端会拒绝客户端发送的 HELO/EHLO 命令。为了解决这个问题,你可以将 localhost 的值设置为客户端主机的全限定名。详情见 com.sun.mail.smtp 包文档中的 "mail.smtp.localhost" 属性。(这个网站已经关闭了...) |
asynchronousSending | boolean | 决定邮件传输是否是异步进行。默认为 'true'。但是,在某些特定的情况下,异步发送不怎么合适。例如,当发生一个严重错误时,你的应用使用 SMTPAppender 去发送一个警告,然后退出。但是相关线程可能没有时间去发送警告邮件。在这种情况下,你可以设置该属性的值为 'false'。 |
includeCallerData | boolean | 默认为 false。如果 asynchronousSending 的值为 true,并且你希望在日志中看到调用者的信息,你可以设置该属性的值为 true |
sessionViaJNDI | boolean | SMTPAppender 基于 javax.mail.Session 来发送邮件信息。默认情况下,该属性的值为 false,所以需要用户指定相关属性通过 SMTPAppender 来构建 javax.mail.Session 实例。如果设置为 true,javax.mail.Session 实例将会通过 JNDI 来获取。参见 jndiLocation 属性。通过 JNDI 获取 Session 实例可以减少需要配置的数量,使你的应用减少重复(dryer)的工作。更多关于在 Tomcat 配置 JNDI 的信息请参考 JNDI Resources How-to。注意 :通过 JNDI 获取 Session 的时候请移除 web 应用下 WEB-INF/lib 文件夹下的 mail.jar 与 activation.jar。 |
jndiLocation | String | JNDI 中放置 javax.mail.Session 的地方。默认为:" java:comp/env/mail/Session " |
使用网易邮箱需单独配置一下,我这轻车熟路了,就不再说了,附带一篇我以前的blog,里面有步骤
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--输出到控制台-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger [%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--输出到文件地址 ${catalina.base}:tomcat目录-->
<substitutionProperty name="logbase" value="${catalina.base}/logs/myLog/"/>
<!--输出到info文件配置-->
<appender name="logInfoFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger [%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--error级别-->
<level>ERROR</level>
<!--onMatch="ACCEPT" 表示匹配该级别及以上
onMatch="DENY" 表示不匹配该级别及以上-->
<onMatch>DENY</onMatch>
<!-- onMismatch="ACCEPT" 表示匹配该级别以下
onMismatch="DENY" 表示不匹配该级别以下的-->
<onMismatch>ACCEPT</onMismatch>
</filter>
<!--
通过rollingPolicy设置日志滚动的策略,这是使用按照时间滚动
fileNamePattern属性设置滚动生成文件的格式,这里设置的精确到天,也就是按照天滚动,如果时间设置精确到秒,就按秒来滚动
maxHistory属性设定最大的文件数,比如按天滚动,这里设置了30天,在第31天日志生成的时候,第一天的日志就会被删掉
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件名策略-->
<FileNamePattern>${logbase}info/%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
</appender>
<!--输出到error文件配置-->
<appender name="logErrorFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger [%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--error级别-->
<level>ERROR</level>
<!--onMatch="ACCEPT" 表示匹配该级别及以上
onMatch="DENY" 表示不匹配该级别及以上-->
<onMatch>ACCEPT</onMatch>
<!-- onMismatch="ACCEPT" 表示匹配该级别以下
onMismatch="DENY" 表示不匹配该级别以下的-->
<onMismatch>DENY</onMismatch>
</filter>
<!--
通过rollingPolicy设置日志滚动的策略,这是使用按照时间滚动
fileNamePattern属性设置滚动生成文件的格式,这里设置的精确到天,也就是按照天滚动,如果时间设置精确到秒,就按秒来滚动
maxHistory属性设定最大的文件数,比如按天滚动,这里设置了30天,在第31天日志生成的时候,第一天的日志就会被删掉
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件名策略-->
<FileNamePattern>${logbase}error/%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
</appender>
<!--输出到邮箱-->
<appender name="logErrorEmail" class="ch.qos.logback.classic.net.SMTPAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--error级别-->
<level>ERROR</level>
<!--onMatch="ACCEPT" 表示匹配该级别及以上
onMatch="DENY" 表示不匹配该级别及以上-->
<onMatch>ACCEPT</onMatch>
<!-- onMismatch="ACCEPT" 表示匹配该级别以下
onMismatch="DENY" 表示不匹配该级别以下的-->
<onMismatch>DENY</onMismatch>
</filter>
<smtpHost>smtp.163.com</smtpHost>
<To>[email protected]</To>
<To>[email protected]</To>
<username>xxx</username>
<password>password</password>
<From>[email protected]</From>
<asynchronousSending>false</asynchronousSending>
<Subject>TESTING Email Function: %logger{20} - %m</Subject>
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger [%msg]%n</pattern>
</layout>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
<appender-ref ref="logInfoFile" />
<appender-ref ref="logErrorFile" />
<appender-ref ref="logErrorEmail" />
</root>
</configuration>
- smtpHost:邮件服务器地址,网易固定值:smtp.163.com
- To:收件人邮箱地址,可配置多个
- username:发件人名称(非邮箱地址)
- password:邮箱授权码(非账号登录密码)
- From:发送方邮箱地址
- asynchronousSending:是否异步发送邮件(默认:true)
- Subject:邮件内容
效果图:
输出到数据库
个人不是很喜欢这种方式,但是有提供的话,顺带尝试一下把
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--输出到控制台-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger [%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--输出到文件地址 ${catalina.base}:tomcat目录-->
<substitutionProperty name="logbase" value="${catalina.base}/logs/myLog/"/>
<!--输出到info文件配置-->
<appender name="logInfoFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger [%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--error级别-->
<level>ERROR</level>
<!--onMatch="ACCEPT" 表示匹配该级别及以上
onMatch="DENY" 表示不匹配该级别及以上-->
<onMatch>DENY</onMatch>
<!-- onMismatch="ACCEPT" 表示匹配该级别以下
onMismatch="DENY" 表示不匹配该级别以下的-->
<onMismatch>ACCEPT</onMismatch>
</filter>
<!--
通过rollingPolicy设置日志滚动的策略,这是使用按照时间滚动
fileNamePattern属性设置滚动生成文件的格式,这里设置的精确到天,也就是按照天滚动,如果时间设置精确到秒,就按秒来滚动
maxHistory属性设定最大的文件数,比如按天滚动,这里设置了30天,在第31天日志生成的时候,第一天的日志就会被删掉
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件名策略-->
<FileNamePattern>${logbase}info/%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
</appender>
<!--输出到error文件配置-->
<appender name="logErrorFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger [%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--error级别-->
<level>ERROR</level>
<!--onMatch="ACCEPT" 表示匹配该级别及以上
onMatch="DENY" 表示不匹配该级别及以上-->
<onMatch>ACCEPT</onMatch>
<!-- onMismatch="ACCEPT" 表示匹配该级别以下
onMismatch="DENY" 表示不匹配该级别以下的-->
<onMismatch>DENY</onMismatch>
</filter>
<!--
通过rollingPolicy设置日志滚动的策略,这是使用按照时间滚动
fileNamePattern属性设置滚动生成文件的格式,这里设置的精确到天,也就是按照天滚动,如果时间设置精确到秒,就按秒来滚动
maxHistory属性设定最大的文件数,比如按天滚动,这里设置了30天,在第31天日志生成的时候,第一天的日志就会被删掉
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件名策略-->
<FileNamePattern>${logbase}error/%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
</appender>
<!--输出到邮箱-->
<appender name="logErrorEmail" class="ch.qos.logback.classic.net.SMTPAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--error级别-->
<level>ERROR</level>
<!--onMatch="ACCEPT" 表示匹配该级别及以上
onMatch="DENY" 表示不匹配该级别及以上-->
<onMatch>ACCEPT</onMatch>
<!-- onMismatch="ACCEPT" 表示匹配该级别以下
onMismatch="DENY" 表示不匹配该级别以下的-->
<onMismatch>DENY</onMismatch>
</filter>
<smtpHost>smtp.163.com</smtpHost>
<To>[email protected]</To>
<username>18121419497</username>
<password>HCNWVDYOBDPTBYHN</password>
<From>[email protected]</From>
<asynchronousSending>false</asynchronousSending>
<Subject>财税金结算平台告警: %logger{20} - %m</Subject>
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger [%msg]%n</pattern>
</layout>
</appender>
<!--输出到数据库-->
<appender name="logInfoDb" class="ch.qos.logback.classic.db.DBAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--error级别-->
<level>ERROR</level>
<!--onMatch="ACCEPT" 表示匹配该级别及以上
onMatch="DENY" 表示不匹配该级别及以上-->
<onMatch>DENY</onMatch>
<!-- onMismatch="ACCEPT" 表示匹配该级别以下
onMismatch="DENY" 表示不匹配该级别以下的-->
<onMismatch>ACCEPT</onMismatch>
</filter>
<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
<driverClass>com.mysql.jdbc.Driver</driverClass>
<url>jdbc:mysql://localhost:3306/test</url>
<user>root</user>
<password>passw0rd</password>
</connectionSource>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
<appender-ref ref="logInfoFile" />
<appender-ref ref="logErrorFile" />
<appender-ref ref="logErrorEmail" />
<appender-ref ref="logInfoDb" />
</root>
</configuration>
需要注意的是:<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
这里使用的DriverManagerConnectionSource是ConnectionSource的一个实现,使用传统JDBC的方式与DB交互。
它在每次获取db连接的时候都会重新建立一条新连接,所以建议改为内置连接池,示例:
<connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource"> <dataSource class="com.alibaba.druid.pool.DruidDataSource"> <driverClassName>com.mysql.jdbc.Driver</driverClassName> <url>jdbc:mysql://localhost:3306/test</url> <username>root</username> <password>passw0rd</password> </dataSource> </connectionSource>
用阿里druid的话,记得加入maven
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency>
之后需要初始化一下数据库,创建表。logback不支持自动创建表,附带sql
/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Version : 50728
Source Host : localhost:3306
Source Database : test
Target Server Type : MYSQL
Target Server Version : 50728
File Encoding : 65001
Date: 2020-04-30 15:46:49
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for logging_event
-- ----------------------------
DROP TABLE IF EXISTS `logging_event`;
CREATE TABLE `logging_event` (
`timestmp` bigint(20) NOT NULL,
`formatted_message` text NOT NULL,
`logger_name` varchar(254) NOT NULL,
`level_string` varchar(254) NOT NULL,
`thread_name` varchar(254) DEFAULT NULL,
`reference_flag` smallint(6) DEFAULT NULL,
`arg0` varchar(254) DEFAULT NULL,
`arg1` varchar(254) DEFAULT NULL,
`arg2` varchar(254) DEFAULT NULL,
`arg3` varchar(254) DEFAULT NULL,
`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` bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`event_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for logging_event_exception
-- ----------------------------
DROP TABLE IF EXISTS `logging_event_exception`;
CREATE TABLE `logging_event_exception` (
`event_id` bigint(20) NOT NULL,
`i` smallint(6) NOT NULL,
`trace_line` varchar(254) NOT NULL,
PRIMARY KEY (`event_id`,`i`),
CONSTRAINT `logging_event_exception_ibfk_1` FOREIGN KEY (`event_id`) REFERENCES `logging_event` (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for logging_event_property
-- ----------------------------
DROP TABLE IF EXISTS `logging_event_property`;
CREATE TABLE `logging_event_property` (
`event_id` bigint(20) NOT NULL,
`mapped_key` varchar(254) NOT NULL,
`mapped_value` text,
PRIMARY KEY (`event_id`,`mapped_key`),
CONSTRAINT `logging_event_property_ibfk_1` FOREIGN KEY (`event_id`) REFERENCES `logging_event` (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
效果图: