spring boot內(nèi)部使用Commons Logging來記錄日志宣谈,但也保留外部接口可以讓一些日志框架來進(jìn)行實(shí)現(xiàn)瓮钥,例如Java Util Logging,Log4J2還有Logback探遵。如果你想用某一種日志框架來進(jìn)行實(shí)現(xiàn)的話番挺,就必須先配置姆坚,默認(rèn)情況下囱晴,Spring Boot會(huì)用Logback來記錄日志膏蚓,并用INFO級(jí)別輸出到控制臺(tái)。
1畸写、日志配置
1.1降允、默認(rèn)配置
依賴于開發(fā)者選擇的日志框架,這些對(duì)應(yīng)的配置文件會(huì)被加載艺糜;
日志框架 | 配置文件 |
---|---|
Logback | logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy |
Log4j | log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml |
Log4j2 | log4j2-spring.xml, log4j2.xml |
JDK(JAVA Util Logging) | logging.properties |
Spring Boot官方推薦優(yōu)先使用帶有-spring的文件名作為你的日志配置(如使用logback-spring.xml,而不是logback.xml)幢尚,命名為logback-spring.xml的日志配置文件破停,spring boot可以為它添加一些spring boot特有的配置項(xiàng),默認(rèn)的命名規(guī)則尉剩,并且放在 src/main/resources 下面即可真慢。
1.2、修改spring-boot日志配置
若不想使用spring-boot的默認(rèn)日志路徑及名稱理茎,可以在application.properties修改日志配置黑界,配置如下:
logging.config=classpath:spring/log4j2.xml
2管嬉、logback配置
Logback是log4j框架的作者開發(fā)的新一代日志框架,它效率更高朗鸠、能夠適應(yīng)諸多的運(yùn)行環(huán)境蚯撩,同時(shí)天然支持SLF4J。
2.1烛占、pom配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
若項(xiàng)目中添加以上依賴胎挎,則spring-boot將自動(dòng)使用logback作為應(yīng)用的日志框架;Spring Boot啟動(dòng)的時(shí)候忆家,由org.springframework.boot.logging.Logging-Application-Listener根據(jù)情況初始化并使用犹菇。但在實(shí)際的開發(fā)中無需直接添加此依賴,因?yàn)閟pring-boot-starter中已包含了此依賴芽卿。
2.2揭芍、配置文件位置
配置文件名稱為logback-spring.xml并放在classpath下,即項(xiàng)目的resources目錄下卸例;或自定義配置文件名稱和位置称杨,并在application.properties中配置,如下所示:
logging.config=classpath:config/logback-spring.xml
2.3币厕、配置文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--
說明:
1列另、日志級(jí)別及文件
日志記錄采用分級(jí)記錄,級(jí)別與日志文件名相對(duì)應(yīng)旦装,不同級(jí)別的日志信息記錄到不同的日志文件中
例如:error級(jí)別記錄到log_error_xxx.log或log_error.log(該文件為當(dāng)前記錄的日志文件)页衙,而log_error_xxx.log為歸檔日志,
日志文件按日期記錄阴绢,同一天內(nèi)店乐,若日志文件大小等于或大于100M,則按0呻袭、1眨八、2...順序分別命名
例如log-level-2013-12-21.0.log
其它級(jí)別的日志也是如此。
2左电、文件路徑
若開發(fā)廉侧、測(cè)試用,在Eclipse中運(yùn)行項(xiàng)目篓足,則到Eclipse的安裝路徑查找logs文件夾段誊,以相對(duì)路徑../logs。
若部署到Tomcat下栈拖,則在Tomcat下的logs文件中
3连舍、Appender
FILEERROR對(duì)應(yīng)error級(jí)別,文件名以log-error-xxx.log形式命名
FILEWARN對(duì)應(yīng)warn級(jí)別涩哟,文件名以log-warn-xxx.log形式命名
FILEINFO對(duì)應(yīng)info級(jí)別索赏,文件名以log-info-xxx.log形式命名
FILEDEBUG對(duì)應(yīng)debug級(jí)別盼玄,文件名以log-debug-xxx.log形式命名
FILEALL對(duì)應(yīng)所有級(jí)別,文件名以log-all-xxx.log形式命名
stdout將日志信息輸出到控制上潜腻,為方便開發(fā)測(cè)試使用
-->
<contextName>SpringBootDemo</contextName>
<property name="LOG_PATH" value="C:\Users\zhaozhou\Desktop\demo" />
<!--設(shè)置系統(tǒng)日志目錄-->
<property name="APPDIR" value="SpringBootDemo" />
<!-- 日志記錄器埃儿,日期滾動(dòng)記錄 -->
<appender name="FILEERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在記錄的日志文件的路徑及文件名 -->
<file>${LOG_PATH}/${APPDIR}/log_error.log</file>
<!-- 日志記錄器的滾動(dòng)策略,按日期砾赔,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 歸檔的日志文件的路徑蝌箍,例如今天是2013-12-21日志,當(dāng)前寫的日志文件路徑為file節(jié)點(diǎn)指定暴心,可以將此文件與file指定文件路徑設(shè)置為不同路徑妓盲,從而將當(dāng)前日志文件或歸檔日志文件置不同的目錄。
而2013-12-21的日志文件在由fileNamePattern指定专普。%d{yyyy-MM-dd}指定日期格式悯衬,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/${APPDIR}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日志記錄之外,還配置了日志文件不能超過2M檀夹,若超過2M筋粗,日志文件會(huì)以索引0開始,
命名日志文件炸渡,例如log-error-2013-12-21.0.log -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式記錄日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件只記錄error級(jí)別的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 日志記錄器娜亿,日期滾動(dòng)記錄 -->
<appender name="FILEWARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在記錄的日志文件的路徑及文件名 -->
<file>${LOG_PATH}/${APPDIR}/log_warn.log</file>
<!-- 日志記錄器的滾動(dòng)策略,按日期蚌堵,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 歸檔的日志文件的路徑买决,例如今天是2013-12-21日志,當(dāng)前寫的日志文件路徑為file節(jié)點(diǎn)指定吼畏,可以將此文件與file指定文件路徑設(shè)置為不同路徑督赤,從而將當(dāng)前日志文件或歸檔日志文件置不同的目錄。
而2013-12-21的日志文件在由fileNamePattern指定泻蚊。%d{yyyy-MM-dd}指定日期格式躲舌,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/${APPDIR}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日志記錄之外,還配置了日志文件不能超過2M性雄,若超過2M没卸,日志文件會(huì)以索引0開始,
命名日志文件秒旋,例如log-error-2013-12-21.0.log -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式記錄日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件只記錄warn級(jí)別的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 日志記錄器约计,日期滾動(dòng)記錄 -->
<appender name="FILEINFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在記錄的日志文件的路徑及文件名 -->
<file>${LOG_PATH}/${APPDIR}/log_info.log</file>
<!-- 日志記錄器的滾動(dòng)策略,按日期滩褥,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 歸檔的日志文件的路徑,例如今天是2013-12-21日志炫加,當(dāng)前寫的日志文件路徑為file節(jié)點(diǎn)指定瑰煎,可以將此文件與file指定文件路徑設(shè)置為不同路徑铺然,從而將當(dāng)前日志文件或歸檔日志文件置不同的目錄。
而2013-12-21的日志文件在由fileNamePattern指定酒甸。%d{yyyy-MM-dd}指定日期格式魄健,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/${APPDIR}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日志記錄之外,還配置了日志文件不能超過2M插勤,若超過2M沽瘦,日志文件會(huì)以索引0開始,
命名日志文件农尖,例如log-error-2013-12-21.0.log -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式記錄日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件只記錄info級(jí)別的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 日志記錄器析恋,日期滾動(dòng)記錄 -->
<appender name="FILEALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在記錄的日志文件的路徑及文件名 -->
<file>${LOG_PATH}/${APPDIR}/log_all.log</file>
<!-- 日志記錄器的滾動(dòng)策略,按日期盛卡,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 歸檔的日志文件的路徑助隧,例如今天是2013-12-21日志,當(dāng)前寫的日志文件路徑為file節(jié)點(diǎn)指定滑沧,可以將此文件與file指定文件路徑設(shè)置為不同路徑并村,從而將當(dāng)前日志文件或歸檔日志文件置不同的目錄。
而2013-12-21的日志文件在由fileNamePattern指定滓技。%d{yyyy-MM-dd}指定日期格式哩牍,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/${APPDIR}/all/log-all-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日志記錄之外,還配置了日志文件不能超過2M令漂,若超過2M膝昆,日志文件會(huì)以索引0開始,
命名日志文件洗显,例如log-error-2013-12-21.0.log -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式記錄日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件只記錄info級(jí)別的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>trace</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--encoder 默認(rèn)配置為PatternLayoutEncoder-->
<encoder>
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!--此日志appender是為開發(fā)使用外潜,只配置最底級(jí)別,控制臺(tái)輸出的日志級(jí)別是大于或等于此級(jí)別的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
</appender>
<logger name="org.springframework" level="WARN" />
<logger name="org.mybatis" level="DEBUG" />
<logger name="com.springboot" level="INFO"/>
<!-- 生產(chǎn)環(huán)境下挠唆,將此級(jí)別配置為適合的級(jí)別处窥,以免日志文件太多或影響程序性能 -->
<root level="DEBUG">
<appender-ref ref="FILEERROR" />
<appender-ref ref="FILEWARN" />
<appender-ref ref="FILEINFO" />
<appender-ref ref="FILEALL" />
<!-- 生產(chǎn)環(huán)境將請(qǐng)stdout,testfile去掉 -->
<appender-ref ref="STDOUT" />
</root>
</configuration>
2.3.1、設(shè)置上下文名稱<contextName>
每個(gè)logger都關(guān)聯(lián)到logger上下文玄组,默認(rèn)上下文名稱為“default”滔驾。但可以使用設(shè)置成其他名字,用于區(qū)分不同應(yīng)用程序的記錄俄讹。一旦設(shè)置哆致,不能修改,可以通過%contextName來打印日志上下文名稱。
<contextName>SpringBootDemo</contextName>
2.3.2患膛、設(shè)置變量<property>
用來定義變量值的標(biāo)簽摊阀, 有兩個(gè)屬性,name和value;其中name的值是變量的名稱胞此,value的值時(shí)變量定義的值臣咖。通過定義的值會(huì)被插入到logger上下文中。定義變量后漱牵,可以使“${}”來使用變量夺蛇。
<property name="LOG_PATH" value="C:\Users\zhaozhou\Desktop\demo" />
<!--設(shè)置系統(tǒng)日志目錄-->
<property name="APPDIR" value="SpringBootDemo" />
此處設(shè)置系統(tǒng)日志的path和應(yīng)用日志的目錄;
2.3.3酣胀、輸出到RollingFileAppender
隨著應(yīng)用的運(yùn)行時(shí)間越來越長(zhǎng)刁赦,日志也會(huì)增長(zhǎng)的越來越多,將他們輸出到同一個(gè)文件并非一個(gè)好辦法闻镶。RollingFileAppender用于切分文件日志甚脉,配置如下:
<!-- 日志記錄器,日期滾動(dòng)記錄 -->
<appender name="FILEERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在記錄的日志文件的路徑及文件名 -->
<file>${LOG_PATH}/${APPDIR}/log_error.log</file>
<!-- 日志記錄器的滾動(dòng)策略儒溉,按日期宦焦,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 歸檔的日志文件的路徑,例如今天是2013-12-21日志顿涣,當(dāng)前寫的日志文件路徑為file節(jié)點(diǎn)指定波闹,可以將此文件與file指定文件路徑設(shè)置為不同路徑,從而將當(dāng)前日志文件或歸檔日志文件置不同的目錄涛碑。
而2013-12-21的日志文件在由fileNamePattern指定精堕。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/${APPDIR}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日志記錄之外蒲障,還配置了日志文件不能超過2M歹篓,若超過2M,日志文件會(huì)以索引0開始揉阎,
命名日志文件庄撮,例如log-error-2013-12-21.0.log -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式記錄日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件只記錄error級(jí)別的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
- 此處配置日志類型為RollingFileAppender,<rollingPolicy>配置滾動(dòng)存儲(chǔ)的策略毙籽,一天一個(gè)文件洞斯,當(dāng)文件大于100M時(shí),按文件大小分文件存儲(chǔ)坑赡。
- <encoder>配置日志文件的格式烙如,<pattern>定義了格式;
- <filter>定義日志過濾器毅否,本文件的日志級(jí)別為error亚铁,當(dāng)日志級(jí)別為error時(shí)進(jìn)行存儲(chǔ),不符合時(shí)不處理螟加;
2.3.4徘溢、配置說明
本日志配置了五個(gè)處理器吞琐,分別處理error、warn然爆、info顽分、all及debug日志;
- error處理器只處理并存儲(chǔ)error級(jí)別的日志施蜜;
- warn處理器只處理并存儲(chǔ)warn級(jí)別的日志;
- info處理器只處理并存儲(chǔ)info級(jí)別的日志雌隅;
- all處理器處理所有級(jí)別的日志翻默;
- debug及以上的日志級(jí)別都會(huì)在標(biāo)準(zhǔn)輸出中輸出;
最終的日志文件會(huì)包含4個(gè):
- log_all.log:存儲(chǔ)所有debug及以上級(jí)別的日志恰起;
- log_error.log:存儲(chǔ)error級(jí)別的日志修械;
- log_warn.log:存儲(chǔ)warn級(jí)別的日志;
- log_info.log:存儲(chǔ)info級(jí)別的日志检盼;
3肯污、log4j2配置
由于spring-boot的所有starter的默認(rèn)日志框架為logback,所以在配置log4j2時(shí)吨枉,需要將logback的包給排除蹦渣,以免日志包沖突;
3.1貌亭、pom配置
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<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-test</artifactId>
<scope>test</scope>
<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-thymeleaf</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.25</version>
</dependency>-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.8</version>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
將所有會(huì)包含spring-boot-starter-logging的包給去除柬唯,并添加spring-boot-starter-log4j2的依賴包;
3.1圃庭、配置文件
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" name="defaultLogConfig"
packages="">
<properties>
<property name="LOG_HOME">C:\Users\zhaozhou\Desktop\demo</property>
<property name="patternlayout">%-d{yyyy-MM-dd HH:mm:ss}[ %t:%r ]- [%X{userName}] - [%X{reqId}] - [%-5p] %c-%M:%L - %m%n%throwable{full}</property>
</properties>
<Appenders>
<!--這個(gè)輸出控制臺(tái)的配置-->
<!--follow 不知道干嘛的-->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${patternlayout}" />
</Console>
<RollingFile name="LOGERROR" fileName="${LOG_HOME}/error_log.log" filePattern="${LOG_HOME}/error/log-error-%d{yyyy-MM-dd}.%i.log">
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${patternlayout}"/>
<SizeBasedTriggeringPolicy size="100MB"/>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
<RollingFile name="LOGWARN" fileName="${LOG_HOME}/warn_log.log" filePattern="${LOG_HOME}/warn/log-warn-%d{yyyy-MM-dd}.%i.log">
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${patternlayout}"/>
<SizeBasedTriggeringPolicy size="100MB"/>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
<RollingFile name="LOGALL" fileName="${LOG_HOME}/all_log.log" filePattern="${LOG_HOME}/all/log-all-%d{yyyy-MM-dd}.%i.log">
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="ACCEPT"/>
<PatternLayout pattern="${patternlayout}"/>
<SizeBasedTriggeringPolicy size="100MB"/>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
</Appenders>
<Loggers>
<!-- spring log -->
<AsyncLogger name="org.springframework" level="warn"/>
<!-- activiti log -->
<AsyncLogger name="org.activiti" level="info" />
<AsyncLogger name="org.mybatis" level="debug" />
<AsyncLogger name="org.apache" level="info" />
<AsyncLogger name="com.springboot.demo" level="debug"/>
<Root level="debug">
<AppenderRef ref="LOGERROR" />
<AppenderRef ref="LOGWARN"/>
<AppenderRef ref="LOGALL"/>
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
配置文件大體和上面logback的配置差不多锄奢,在此不多贅述;
4剧腻、MDC配置
4.1拘央、MDC簡(jiǎn)介
MDC 是 Mapped Diagnostic Context 的縮寫,“映射診斷上下文”看起來高大上的樣子书在,其實(shí)是非常簡(jiǎn)單的灰伟,就是一個(gè)臨時(shí)存放k-v對(duì)的容器。和普通Map的區(qū)別是它是基于ThreadLocal實(shí)現(xiàn)的蕊温,所以不存在資源競(jìng)爭(zhēng)問題袱箱,可以放心的往里面放東西。其主要用于打LOG時(shí)跟蹤一個(gè)“會(huì)話“义矛、一個(gè)”事務(wù)“发笔。舉例,有一個(gè)web controller凉翻,在同一時(shí)間可能收到來自多個(gè)客戶端的請(qǐng)求了讨,如果一個(gè)請(qǐng)求發(fā)生了錯(cuò)誤,我們要跟蹤這個(gè)請(qǐng)求從controller開始一步步都執(zhí)行到了哪些代碼、有哪些log的輸出前计。這時(shí)我們可以看log文件胞谭,但是log文件是多個(gè)請(qǐng)求同時(shí)記錄的,基本無法分辨哪行是哪個(gè)請(qǐng)求產(chǎn)生的男杈,雖然我們可以看線程丈屹,但線程可能被復(fù)用,也是很難分辨出伶棒,這時(shí)MDC就派上用場(chǎng)了旺垒。
4.2、主要api
public class MDC {
public static void put(String key, String val) //設(shè)置k-v
public static String get(String key) //獲取value
public static void remove(String key) //移除k-v
public static void clear() //clearMDC
public static Map<String, String> getCopyOfContextMap() //獲取MDC的備份map
public static void setContextMap(Map<String, String> contextMap) //設(shè)置MDC的map
}
- put()和setContextMap()主要進(jìn)行屬性設(shè)置肤无;
- get()和getCopyOfContextMap()主要進(jìn)行屬性獲认冉;
- remove()移除屬性信息宛渐,主要在線程結(jié)束時(shí)處理設(shè)置的屬性竞漾;
4.3、基于spring的HandlerInterceptorAdapter
此種方法主要適用場(chǎng)景為跟蹤http請(qǐng)求窥翩,通過攔截http請(qǐng)求业岁,設(shè)置MDC,并在日志中打印設(shè)置參數(shù)寇蚊,即可通過日志跟蹤請(qǐng)求鏈叨襟;
4.3.1、HandlerInterceptorAdapter攔截器配置
登錄攔截器:
public class LoginInterceptor extends HandlerInterceptorAdapter {
private static String MDC_KEY_USER_NAME = "userName";
private static String MDC_KEY_REQ_ID = "reqId";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
MDC.put(MDC_KEY_USER_NAME,"zhaozhou");
MDC.put(MDC_KEY_REQ_ID, UUID.randomUUID().toString());
return super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
MDC.remove(MDC_KEY_USER_NAME);
MDC.remove(MDC_KEY_REQ_ID);
super.afterCompletion(request, response, handler, ex);
}
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
super.afterConcurrentHandlingStarted(request, response, handler);
}
}
注冊(cè)攔截器:
@Component
public class MvcLoginInterceptor implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注冊(cè)攔截器
InterceptorRegistration ir = registry.addInterceptor(new LoginInterceptor());
// 配置攔截的路徑
ir.addPathPatterns("/**");
// 配置不攔截的路徑
ir.excludePathPatterns("/static/**","/templates/**");
}
}
4.3.2幔荒、log4j2的pattern配置
在log4j2-spring.xml的配置做如下修改:
<properties>
<property name="LOG_HOME">C:\Users\zhaozhou\Desktop\demo</property>
<property name="patternlayout">%-d{yyyy-MM-dd HH:mm:ss}[ %t:%r ]- [%X{userName}] - [%X{reqId}] - [%-5p] %c-%M:%L - %m%n%throwable{full}</property>
</properties>
在patternlayout屬性中添加userName和reqId的打雍觥;
對(duì)于logback日志的配置同此處一樣爹梁;
4.3.2右犹、輸出結(jié)果
瀏覽器請(qǐng)求:http://localhost:8888/
2018-10-31 12:11:06[ http-nio-8888-exec-8:17662 ]- [] - [] - [DEBUG] org.springframework.beans.factory.support.DefaultListableBeanFactory-doGetBean:254 - Returning cached instance of singleton bean 'testController'
2018-10-31 12:11:06[ http-nio-8888-exec-8:17662 ]- [] - [] - [DEBUG] org.springframework.web.servlet.DispatcherServlet-doDispatch:979 - Last-Modified value for [/] is: -1
2018-10-31 12:11:06[ http-nio-8888-exec-8:17663 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.mybatis.spring.SqlSessionUtils-getSqlSession:97 - Creating a new SqlSession
2018-10-31 12:11:06[ http-nio-8888-exec-8:17664 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.mybatis.spring.SqlSessionUtils-registerSessionHolder:148 - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1366610e] was not registered for synchronization because synchronization is not active
2018-10-31 12:11:06[ http-nio-8888-exec-8:17665 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.springframework.jdbc.datasource.DataSourceUtils-doGetConnection:114 - Fetching JDBC Connection from DataSource
2018-10-31 12:11:06[ http-nio-8888-exec-8:17665 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.mybatis.spring.transaction.SpringManagedTransaction-openConnection:87 - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@2c6224d7] will not be managed by Spring
2018-10-31 12:11:06[ http-nio-8888-exec-8:17666 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] com.springboot.demo.dao.UserDao.getUserById-debug:159 - ==> Preparing: select id, name, tel, email, create_time from t_user WHERE id = ?
2018-10-31 12:11:06[ http-nio-8888-exec-8:17667 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] com.springboot.demo.dao.UserDao.getUserById-debug:159 - ==> Parameters: 1(Long)
2018-10-31 12:11:06[ http-nio-8888-exec-8:17673 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] com.springboot.demo.dao.UserDao.getUserById-debug:159 - <== Total: 1
2018-10-31 12:11:06[ http-nio-8888-exec-8:17674 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.mybatis.spring.SqlSessionUtils-closeSqlSession:191 - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1366610e]
2018-10-31 12:11:06[ http-nio-8888-exec-8:17674 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.springframework.jdbc.datasource.DataSourceUtils-doReleaseConnection:340 - Returning JDBC Connection to DataSource
2018-10-31 12:11:06[ http-nio-8888-exec-8:17675 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.springframework.web.servlet.view.ContentNegotiatingViewResolver-getMediaTypes:269 - Requested media types are [text/html, application/xhtml+xml, image/webp, application/xml;q=0.9, */*;q=0.8] based on Accept header types and producible media types [*/*])
2018-10-31 12:11:06[ http-nio-8888-exec-8:17675 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.springframework.web.servlet.view.BeanNameViewResolver-resolveViewName:81 - No matching bean found for view name '/index.html'
2018-10-31 12:11:06[ http-nio-8888-exec-8:17675 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.springframework.web.servlet.view.ContentNegotiatingViewResolver-getBestView:348 - Returning [org.thymeleaf.spring5.view.ThymeleafView@199e0a7e] based on requested media type 'text/html'
2018-10-31 12:11:06[ http-nio-8888-exec-8:17675 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.springframework.web.servlet.DispatcherServlet-render:1319 - Rendering view [org.thymeleaf.spring5.view.ThymeleafView@199e0a7e] in DispatcherServlet with name 'dispatcherServlet'
2018-10-31 12:11:06[ http-nio-8888-exec-8:17678 ]- [] - [] - [DEBUG] org.springframework.web.servlet.DispatcherServlet-processRequest:1000 - Successfully completed request
2018-10-31 12:11:06[ http-nio-8888-exec-8:17678 ]- [] - [] - [DEBUG] org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter-doFilterInternal:104 - Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@4b2bca43
2018-10-31 12:11:06[ http-nio-8888-exec-1:17767 ]- [] - [] - [DEBUG] org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter-initContextHolders:114 - Bound request context to thread: org.apache.catalina.connector.RequestFacade@4b2bca43
2018-10-31 12:11:06[ http-nio-8888-exec-1:17767 ]- [] - [] - [DEBUG] org.springframework.web.servlet.DispatcherServlet-doService:891 - DispatcherServlet with name 'dispatcherServlet' processing GET request for [/favicon.ico]
可以看到,開始系統(tǒng)啟動(dòng)過程中是無userName喝reqId打印的姚垃,當(dāng)進(jìn)行http請(qǐng)求時(shí)念链,MDC配置的兩個(gè)參數(shù)都打印出來,且reqId一直不變积糯,通過此id即可追蹤調(diào)用鏈掂墓;
4.4、基于AOP設(shè)置MDC
此種方法所有類型的調(diào)用請(qǐng)求的調(diào)用跟蹤看成,例如http君编、基于tcp的RPC調(diào)用等;
4.4.1川慌、pom配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
4.4.2吃嘿、切面定義
@Aspect
@Component
public class LoginAop {
private static String MDC_KEY_USER_NAME = "userName";
private static String MDC_KEY_REQ_ID = "reqId";
@Pointcut("execution(public * com.springboot.demo.controller..*.*(..))")
public void webLog(){}
@Before("webLog()")
public void before(JoinPoint joinPoint){
MDC.put(MDC_KEY_USER_NAME,"zhaozhou");
MDC.put(MDC_KEY_REQ_ID, UUID.randomUUID().toString());
}
@AfterReturning(pointcut = "webLog()", returning = "ret")
public void afterReturning(Object ret){
MDC.remove(MDC_KEY_USER_NAME);
MDC.remove(MDC_KEY_REQ_ID);
}
}
MDC參數(shù)與4.3.1配置相同祠乃;
4.4.3、輸出結(jié)果
瀏覽器請(qǐng)求:http://localhost:8888/
2018-10-31 12:46:24[ http-nio-8888-exec-6:24774 ]- [] - [] - [DEBUG] org.springframework.beans.factory.support.DefaultListableBeanFactory-doGetBean:254 - Returning cached instance of singleton bean 'testController'
2018-10-31 12:46:24[ http-nio-8888-exec-6:24774 ]- [] - [] - [DEBUG] org.springframework.web.servlet.DispatcherServlet-doDispatch:979 - Last-Modified value for [/] is: -1
2018-10-31 12:46:24[ http-nio-8888-exec-6:24774 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] org.mybatis.spring.SqlSessionUtils-getSqlSession:97 - Creating a new SqlSession
2018-10-31 12:46:24[ http-nio-8888-exec-6:24774 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] org.mybatis.spring.SqlSessionUtils-registerSessionHolder:148 - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@675b44f3] was not registered for synchronization because synchronization is not active
2018-10-31 12:46:24[ http-nio-8888-exec-6:24775 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] org.springframework.jdbc.datasource.DataSourceUtils-doGetConnection:114 - Fetching JDBC Connection from DataSource
2018-10-31 12:46:24[ http-nio-8888-exec-6:24775 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] org.mybatis.spring.transaction.SpringManagedTransaction-openConnection:87 - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@121b39d5] will not be managed by Spring
2018-10-31 12:46:24[ http-nio-8888-exec-6:24776 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] com.springboot.demo.dao.UserDao.getUserById-debug:159 - ==> Preparing: select id, name, tel, email, create_time from t_user WHERE id = ?
2018-10-31 12:46:24[ http-nio-8888-exec-6:24776 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] com.springboot.demo.dao.UserDao.getUserById-debug:159 - ==> Parameters: 1(Long)
2018-10-31 12:46:24[ http-nio-8888-exec-6:24782 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] com.springboot.demo.dao.UserDao.getUserById-debug:159 - <== Total: 1
2018-10-31 12:46:24[ http-nio-8888-exec-6:24783 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] org.mybatis.spring.SqlSessionUtils-closeSqlSession:191 - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@675b44f3]
2018-10-31 12:46:24[ http-nio-8888-exec-6:24783 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] org.springframework.jdbc.datasource.DataSourceUtils-doReleaseConnection:340 - Returning JDBC Connection to DataSource
2018-10-31 12:46:24[ http-nio-8888-exec-6:24784 ]- [] - [] - [DEBUG] org.springframework.web.servlet.view.ContentNegotiatingViewResolver-getMediaTypes:269 - Requested media types are [text/html, application/xhtml+xml, image/webp, application/xml;q=0.9, */*;q=0.8] based on Accept header types and producible media types [*/*])
2018-10-31 12:46:24[ http-nio-8888-exec-6:24784 ]- [] - [] - [DEBUG] org.springframework.web.servlet.view.BeanNameViewResolver-resolveViewName:81 - No matching bean found for view name '/index.html'
可以看到兑燥,輸出與4.3.2基本相同亮瓷;
參考源碼:https://github.com/zhaozhou11/spring-boot-demo.git
相關(guān)閱讀:
spring-boot基礎(chǔ)環(huán)境搭建 【http://www.reibang.com/p/ee36bb9faa10】
spring-boot配置詳解【http://www.reibang.com/p/1d037ab638ef】
spring-boot+druid+mybatis環(huán)境搭建【http://www.reibang.com/p/e6c9e9945e45】
參考博客:
http://blog.51cto.com/11931236/2058708
http://tengj.top/2017/04/05/springboot7/
https://juejin.im/post/5a1f86f0f265da4326529c61
https://juejin.im/post/5b128f326fb9a01e8b7814c4
https://blog.csdn.net/Evankaka/article/details/50637994
https://blog.csdn.net/wohaqiyi/article/details/72853962
https://blog.csdn.net/wohaqiyi/article/details/72853962
https://my.oschina.net/gmd/blog/615849
http://www.reibang.com/p/44640b298c45
https://blog.csdn.net/u012050154/article/details/77370297