一、重點問題整理
1.1 關於logback.xml中的路徑設置問題
准備金系統的logback.xml中設置的路徑是:
<!-- 定義日志文件 輸出位置 --> <property name="log_dir" value="E:\logs" />
在Windows環境下,會識別E:為系統的E盤,默認在E盤下創建logs文件夾。但是正在Linux環境下,不存在E盤,會將E:\logs識別為E:logs文件夾。此時為相對路徑,而tomcat在創建文件時:會從程序啟動的地方去創建這個文件(Java項目中也是如此),那么web應用是從有tomcat來執行的,tomcat這個程序是從哪里啟動文件是startup.bat?位置是tomcat/bin。會在bin目錄下創建E:logs文件夾,而不是在tomcat的默認根路徑故tomcat文件夾下創建E:logs文件夾。(驗證:若是用sh bin/startup.sh命令,在tomcat目錄下啟動tomcat,則會在tomcat路徑下創建E:logs文件夾。)
所以為了使日志文件在我們指定的目錄下,有兩只方式:
【1】我們可以使用絕對路徑: /
【2】也可以使用相對路徑:
./ 當前目錄。
../ 父級目錄。
/ 根目錄。
但是並不及建議用E:這種寫死的路徑。可以用以下方式創建日志文件的路徑:
方式一:
value="${catalina.home}/logs":
本地:會在tomcat目錄下創建logs文件。
Linux:Linux上會在tomcat目錄下創建logs文件。
方式二:
value="${catalina.base}/logs":
本地:會在C:\Users\Administrator\.IntelliJIdea2017.2\system\tomcat\Unnamed_reserve_10目錄下創建logs文件。(因為
本地tomcat為每個idea項目在這里創建了一個副本,項目是在這里啟動的)
Linux:會在tomcat目錄下創建logs文件。
方式三:
value="logs":會在tomcat/bin目錄下創建logs文件。
../webapps/工程名:會在工程名目錄下創建logs文件。
注意:我上次本地啟動項目是在E盤創建的logs文件夾,這次可能是改啥東西了?我也不知道,反正本地的logs文件夾又跑tomcat/bin目錄下了。奇怪。
這個是用tomcat啟動的web項目。我在這個項目里建了個main主方法,創建的logs文件又跑項目的根路徑下了:
邪了門了,本地啟動項目,好像配置的路徑不起作用了。。。
1.2 查看日志是輸出的格式,及在不同級別文件中都是怎么記錄日志信息的?是否與控制台的輸出內容一致?
答:一致。
本地文件:
控制台:
1.3 為什么要用日志框架來進行日志管理?
日志框架對日志的管理能力非常強大,可以根據自定義的日志等級輸出日志到指定位置,還可以對日志文件進行切分。Java自帶的功能滿足不了需要。
1.4 tomcat - catalina.out 日志過大處理方法
解決方案:
1.4.1 修改tomcat的日志配置,配置輸出日志級別
修改conf/logging.properties日志配置文件來屏蔽掉這部分的日志信息。
將level級別設置成WARNING就可以大量減少日志的輸出,當然也可以設置成OFF,直接禁用掉。
1.4.2 修改工程的日志配置:輸出在控制台的級別
刪除log4j中的輸出控制台的日志配置,catalina.out中不再記錄應用的日志。 日志輸出級別:ALL、DEBUG、INFO、WARN、ERROR 這下它不會漲的那么快了。設置工程項目輸出至控制台catalina.out日志的級別: WARN
1.4.3 對catalina.out 啟動定時清空
編寫清空腳本腳本:(默認目錄tomcat 根目錄)
1.4.4 tomcat不輸出到catalina.out
由於最近項目需要部署到外網環境,之前在內網測試看日志都是在catalina.out,但是現在修改了一下,不需要看這個了,而且如果項目在外網環境部
署,這個文件一直會增大,浪費空間,所有墨跡了半天,才重網上找到一個比較好的方法,不輸出到catalina.out. 找到tomcat下的 bin/catalina.sh; 找到下面這一段, 把#CATALINA_OUT="$CATALINA_HOME"/logs/catalina.out 注釋掉,改為CATALINA_OUT=/dev/null, if [ -z "$CATALINA_OUT" ] ; then #CATALINA_OUT="$CATALINA_HOME"/logs/catalina.out CATALINA_OUT=/dev/null fi 對於/dev/null,我在網上了解是,它相當於垃圾桶一樣,輸出什么到它哪里,它直接丟了.所有我們在/dev/null,看到null這個文件,大小是空的,所有並不會占用空間大小了.
1.4.4 禁止日志輸出到catalina.out
1、修改tomcat/conf/logging.properties中的日志輸出級別
把 catalina.org.apache.juli.AsyncFileHandler.level = FINE 更改為 catalina.org.apache.juli.AsyncFileHandler.level = OFF
OFF為禁止
改后效果如圖:
2、關閉localhost_access_log日志
注釋tomcat/conf/server.xml中最下方AccessLogValue
3、修改tomcat/bin/catalina.sh中 185行左右
把
if [ -z "$CATALINA_OUT" ] ; then CATALINA_OUT="$CATALINA_BASE"/logs/catalina.out fi
改為
null作為垃圾桶,因此大小為0
原文鏈接:https://blog.csdn.net/su1573/article/details/87883126
1.5 Windows下生成calalina.out 日志文件
之前我們在linux系統下查看日志的時候,總有個習慣,啟動項目后會進入logs/下,敲擊類似
tail -fn500 catalina.out tail -f catalina.out
的命令,便可以進入到catalina.out中實時的顯示出最新的500行信息,但是有個問題,在windows系統中我們卻沒發現這個catalina.out,難道是只有在linux系統下才有catalina.out文件嗎?其實不是這樣的,首先說下為什么在linux下是叫catalina.out,這是由於catalina_home/bin/catalina.sh文件指定的,參看下面部分源碼:
shift touch "$CATALINA_BASE"/logs/catalina.out if [ "$1" = "-security" ] ; then echo "Using Security Manager" shift "$_RUNJAVA" $JAVA_OPTS "$LOGGING_CONFIG" $CATALINA_OPTS \ -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ -Djava.security.manager \ -Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy \ -Dcatalina.base="$CATALINA_BASE" \ -Dcatalina.home="$CATALINA_HOME" \ -Djava.io.tmpdir="$CATALINA_TMPDIR" \ org.apache.catalina.startup.Bootstrap "$@" start \ >> "$CATALINA_BASE"/logs/catalina.out 2>&1 & if [ ! -z "$CATALINA_PID" ]; then echo $! > $CATALINA_PID fi
注:touch命令可以創建一個不存在的文件。
那么同理可以想象在windows下也可以存在catalina.out文件(只是默認建的文件不叫這個名而已),那么可不可以在windows系統下也看的見,或者說創建出catalina.out呢?答案是肯定的,參考如下:
由於tomcat本身是可以跨平台的,故既然有linux下的catalina.sh,就會對應有windows下的catalina.bat。
問題:windows下的tomcat的日志只輸出在控制台下,且日志文件輸出只有一些基本信息。如何把所有日志都輸出到catalina.out?
解決方案
需要修改兩個地方:
1、修改startup.bat
把call “%EXECUTABLE%” start %CMD_LINE_ARGS%修改為call “%EXECUTABLE%” run %CMD_LINE_ARGS%.
2、修改catalina.bat
查找catalina.bat含有%ACTION%的4行內容(在文件末),在后面添加 >> %CATALINA_HOME%\logs\catalina.out 或者 >> %CATALINA_BASE%\logs\catalina.out
修改之后如下圖(沒有顯示完全):
重啟tomcat后,發現在logs文件下會生成catalina.out的文件,內容為tomcat的日志。
3、不過有個弊端就是日志在命令行不輸出了。
二、應用實例
2.1、maven依賴
<!-- logback begin--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.7</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-access</artifactId> <version>1.1.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.3</version> </dependency> <!-- logback end-->
2.2、完整的logback.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <!-- 級別從高到低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL --> <!-- 日志輸出規則 根據當前ROOT 級別,日志輸出時,級別高於root默認的級別時 會輸出 --> <!-- 以下 每個配置的 filter 是過濾掉輸出文件里面,會出現高級別文件,依然出現低級別的日志信息,通過filter 過濾只記錄本級別的日志 --> <!-- scan 當此屬性設置為true時,配置文件如果發生改變,將會被重新加載,默認值為true。 --> <!-- scanPeriod 設置監測配置文件是否有修改的時間間隔,如果沒有給出時間單位,默認單位是毫秒。當scan為true時,此屬性生效。默認的時間間隔為1分鍾。 --> <!-- debug 當此屬性設置為true時,將打印出logback內部日志信息,實時查看logback運行狀態。默認值為false。 --> <configuration scan="true" scanPeriod="60 seconds" debug="false"> <!-- 動態日志級別 --> <jmxConfigurator /> <!-- 定義日志文件 輸出位置 --> <property name="log_dir" value="E:\logs" /> <!-- 日志最大的歷史 30天 --> <property name="maxHistory" value="30" /> <!-- ConsoleAppender 控制台輸出日志 --> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern> <!-- 設置日志輸出格式 --> %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n </pattern> </encoder> </appender> <!-- ERROR級別日志 --> <!-- 滾動記錄文件,先將日志記錄到指定文件,當符合某個條件時,將日志記錄到其他文件 RollingFileAppender --> <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 過濾器,只記錄WARN級別的日志 --> <!-- 果日志級別等於配置級別,過濾器會根據onMath 和 onMismatch接收或拒絕日志。 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <!-- 設置過濾級別 --> <level>ERROR</level> <!-- 用於配置符合過濾條件的操作 --> <onMatch>ACCEPT</onMatch> <!-- 用於配置不符合過濾條件的操作 --> <onMismatch>DENY</onMismatch> </filter> <!-- 最常用的滾動策略,它根據時間來制定滾動策略.既負責滾動也負責出發滾動 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--日志輸出位置 可相對、和絕對路徑 --> <fileNamePattern> ${log_dir}/error/%d{yyyy-MM-dd}/error-log.log </fileNamePattern> <!-- 可選節點,控制保留的歸檔文件的最大數量,超出數量就刪除舊文件假設設置每個月滾動,且<maxHistory>是6, 則只保存最近6個月的文件,刪除之前的舊文件。注意,刪除舊文件是,那些為了歸檔而創建的目錄也會被刪除 --> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <encoder> <pattern> <!-- 設置日志輸出格式 --> %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n </pattern> </encoder> </appender> <!-- WARN級別日志 appender --> <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 過濾器,只記錄WARN級別的日志 --> <!-- 果日志級別等於配置級別,過濾器會根據onMath 和 onMismatch接收或拒絕日志。 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <!-- 設置過濾級別 --> <level>WARN</level> <!-- 用於配置符合過濾條件的操作 --> <onMatch>ACCEPT</onMatch> <!-- 用於配置不符合過濾條件的操作 --> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--日志輸出位置 可相對、和絕對路徑 --> <fileNamePattern>${log_dir}/warn/%d{yyyy-MM-dd}/warn-log.log</fileNamePattern> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern> </encoder> </appender> <!-- INFO級別日志 appender --> <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender"> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log_dir}/info/%d{yyyy-MM-dd}/info-log.log</fileNamePattern> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern> </encoder> </appender> <!-- DEBUG級別日志 appender --> <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender"> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUG</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log_dir}/debug/%d{yyyy-MM-dd}/debug-log.log</fileNamePattern> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern> </encoder> </appender> <!-- TRACE級別日志 appender --> <appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>TRACE</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log_dir}/trace/%d{yyyy-MM-dd}/trace-log.log</fileNamePattern> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern> </encoder> </appender> <!-- root級別 DEBUG --> <root> <!-- 打印info級別日志及以上級別日志 --> <level value="INFO" /> <!-- 控制台輸出 --> <appender-ref ref="console" /> <!-- 文件輸出 --> <appender-ref ref="ERROR" /> <appender-ref ref="INFO" /> <appender-ref ref="WARN" /> <appender-ref ref="DEBUG" /> <appender-ref ref="TRACE" /> </root> </configuration>
我這里定義的路徑為:
<!-- 定義日志文件 輸出位置 --> <property name="log_dir" value="E:\logs" />
2.3 自定義異常
package com.asd.common.utils;
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
public BusinessException(){
}
public BusinessException(String message){
super(message);
}
}
2.4、應用
2.4.1 main方法
public static final Logger log = LoggerFactory.getLogger(DWSHttpServletServiceImpl.class);
public static void main(String[] args) {
int a = 0;
log.info("驗證logback記錄日志");
try{
//
a = testException();
} catch (BusinessException be) {
String exceptionMessge = be.getMessage();
//在日志里記錄自定義異常信息
log.error(exceptionMessge);
} catch (Exception e){
e.printStackTrace();
}
System.out.println(a);
}
public static int testException(){
int a = 0;
try {
a = 1/0;
}
catch (Exception e){
throw new BusinessException("除數不能為0");//拋出自定義異常
}
return a;
}
控制台輸出:
刪除配置文件后:
說明配置文件是起作用的。
我這里是直接在一個web項目里(准備金系統)創建的一個main方法進行測試的,可見logback並不需要使用容器。
在web項目中的使用方式也一樣。
三、logback等日志框架
3.1 概念
Log Java日志:(slf4j、log4j、logback、common-logging )
- slf4j 是規范/接口
- 日志實現:log4j、logback、common-logging
簡單地說,Logback 是一個 Java 領域的日志框架。它被認為是 Log4J 的繼承人。
Logback 主要由三個模塊組成:
- logback-core
- logback-classic
- logback-access
logback-core 是其它模塊的基礎設施,其它模塊基於它構建,顯然,logback-core 提供了一些關鍵的通用機制。
logback-classic 的地位和作用等同於 Log4J,它也被認為是 Log4J 的一個改進版,並且它實現了簡單日志門面 SLF4J。
logback-access 主要作為一個與 Servlet 容器交互的模塊,比如說 tomcat 或者 jetty,提供一些與 HTTP 訪問相關的功能。
根據不同的日志系統,你可以按如下規則組織配置文件名,就能被正確加載:
- 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
Logback 與 Log4J
實際上,這兩個日志框架都出自同一個開發者之手,Logback 相對於 Log4J 有更多的優點:
- 同樣的代碼路徑,Logback 執行更快
- 更充分的測試
- 原生實現了 SLF4J API(Log4J 還需要有一個中間轉換層)
- 內容更豐富的文檔
- 支持 XML 或者 Groovy 方式配置
- 配置文件自動熱加載
- 從 IO 錯誤中優雅恢復
- 自動刪除日志歸檔
- 自動壓縮日志成為歸檔文件
- 支持 Prudent 模式,使多個 JVM 進程能記錄同一個日志文件
- 支持配置文件中加入條件判斷來適應不同的環境
- 更強大的過濾器
- 支持 SiftingAppender(可篩選 Appender)
- 異常棧信息帶有包信息
logback是java的日志開源組件,是log4j創始人寫的,性能比log4j要好,目前主要分為3個模塊。
- logback-core:核心代碼模塊
- logback-classic:log4j的一個改良版本,同時實現了
slf4j
的接口,這樣你如果之后要切換其他日志組件也是一件很容易的事 - logback-access:訪問模塊與Servlet容器集成提供通過Http來訪問日志的功能。
3.2 實現原理:slf4j是什么
slf4j只是一套標准,通俗來講,就是定義了一系列接口,它並不提供任何的具體實現。所以,我們使用這套接口進行開發,可以任意的切換底層的實現框架。比如,一開始項目用的是log4j的實現,后來發現log4j的性能太差了,想換成logback,由於我們代碼中都是面向slf4j接口的,這樣我們只要吧log4j的依賴換成logback就可以了。
3.3 總結
日志組件的使用一般都非常簡單,幾乎所有的項目中都會用到各種各樣的日志組件。但是可能就是由於太簡單了,比較少的人會願意深入系統的去了解。本人也只是對logback的配置以及一些簡單的原理做了一些了解,並沒有很深入的去看logback的具體實現。
因此,本文的內容大部分都是基於官網的文檔以及網上一些其他關於logback的博客,雖然也做了一些簡單的測試,但並不保證全部都是正確的。
參看鏈接:
logback介紹和配置詳解:https://www.jianshu.com/p/04065d8cb2a9
Logback配置使用:https://www.jianshu.com/p/638b4e2c4068
tomcat 日志詳解:https://www.cnblogs.com/operationhome/p/9680040.html
Java日志框架:slf4j作用及其實現原理:https://www.cnblogs.com/xrq730/p/8619156.html