今天講講Java中的日誌—logging、logback

擁抱心中的夢想發表於2019-03-02

今天中午就不休息了,把剩餘的草稿寫完~

一、Java API 中自帶的日誌系統

Java自帶的日誌處理api位於java.util.logging包下,該包下只有少數的一些類,如下圖:

今天講講Java中的日誌—logging、logback

其實結構非常地簡單,主要由以下三個元件組成:

  • Logger元件:logger元件定義了一些日誌的基本操作,如log輸出日誌,getName獲取該日誌物件的名稱,setLevel()設定日誌級別等等,就是一些基本的操作啦!
  • Handler元件:Handler就是定義一些日誌處理嘛!比如你想將日誌輸出到檔案,可使用FileHandler,想將日誌輸出到控制檯,可使用ConsoleHandler
  • Formatter元件:很顯然就是對日誌輸出的格式進行定義嘛!
  • Level元件:日誌的級別,最基本的級別INFOWARNING
  • filter元件:過濾器,允許你對輸出日誌的一個過濾

對於Java api的日誌體系,下面我寫了一個小栗子進行總結:

package com.wokao66.logger;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.logging.FileHandler;
import java.util.logging.Filter;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

public class JavaLogger {

  static Logger logger = Logger.getLogger(JavaLogger.class.getName());

  public static void HandlerFilter() throws SecurityException, IOException {
    //首先我宣告一個檔案處理器,因為我打算將日誌輸出到一個檔案當中,即儲存在E盤的a.txt檔案
    FileHandler handler = new FileHandler("E://a.txt");
    //我自定義一個Formatter,用於對每條輸出日誌進行格式化,你也可以不指定,則預設使用SimpleFormatter
    handler.setFormatter(new Formatter() {

    @Override
    public String format(LogRecord record) {
      //這就是我自定義的格式
      return "[" + new SimpleDateFormat().format(record.getMillis()) + "]-[" + record.getLevel()
    + "]-" + record.getSourceClassName() + "-" + "[" + record.getMessage() + "]
";
    
    }
 });
    //當然,我也可以設定一個過濾器
    handler.setFilter(new Filter() {

    @Override
    public boolean isLoggable(LogRecord record) {
      //當日志內容與"this is a unloged message!"相同時,則不輸出該日誌,當然這裡只是測試,實際專案這個規則是不存在的
      return !record.getMessage().equals("this is a unloged message!");

    }
 });
    //給Logger設定Handler
    logger.addHandler(handler);
    //預設是ConsoleHandler,禁用之後才不會輸出到控制檯,而是輸出到檔案中
    logger.setUseParentHandlers(false);
}

public static void main(String[] args) throws SecurityException, IOException {
  HandlerFilter();
  logger.log(Level.INFO, "this is a info message!");
  logger.log(Level.OFF, "this is a OFF message!");
  logger.log(Level.SEVERE, "this is a SEVERE message!");
  logger.log(Level.WARNING, "this is a WARNING message!");
  logger.log(Level.INFO, "this is a unloged message!");//這一句將不會被記錄到檔案中
	}
}

複製程式碼

二、說一說Logback咯!

logback這個傢伙在企業中的使用很頻繁。我先講下logback的一些常用的元件和配置,然後再來個栗子作為演示。

  • logback由三大基本模組組成,分別是logback-core,logback-access,logback-classic.其中core是核心模組,是其他兩模組的基礎。

  • logback由三大元件組成,分別是Logger,Appender,Layout.其中logger屬於classic模組,appender,layout屬於core模組,core模組沒有logger的概念!Appender其實就是表示一個日誌輸出的目的地,可以是控制檯,也可以是檔案。

  • logback擁有自己的命名規範,一般logger是按照層次命名的,具有繼承關係,以.來作為分割,擁有祖先和父節點的概念,比如一個logger被命名為com.wokao666.www,那麼com就是wokao666的父節點,comwww的祖先節點。

  • root屬於所有logger的根節點,以org.slf4j.Logger.ROOT_LOGGER_NAME作為root的名字。

  • logback會預設在類路徑下查詢名為logback-test.xmllogback.groovy或者是logback.xml的配置檔案。

  • 日誌的列印是向上傳遞的,什麼意思呢?比如你列印了一個info級別的日誌(輸出到控制檯),同時也列印了一個error的日誌,那麼控制檯會同時輸出info和error兩條日誌,因為error的級別比info高。

很簡單吧!所以說你要使用logback,主要有以下三大步驟:

  • 1、在類路徑下建立你相應的配置檔案,如logback.xml,並做好相關配置。
  • 2、通過呼叫LoggerFactory.getLogger()方法並傳遞一個名稱或類進去獲得一個Logger物件
  • 3、通過第二步獲得的Logger物件,呼叫相應的日誌級別方法,如info(),error()

好了,我不多說了,基本的就這些,下面我通過問題和栗子來演示一波:

先看看我的配置檔案logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- 表示啟動配置檔案掃描,每隔30秒掃描一次,什麼意思?就是說它會去檢查你的配置檔案在執行過程中配置是否有變化 -->
<configuration scan="true" scanPeriod="30 seconds">
    <!-- 配置一個存放日誌檔案的地方,注意這裡是一個變數來著,以後可以通過${變數名}來獲取變數的值 -->
	<property name="log.base" value="/logs" />
	<!-- 這裡又定義一個變數 -->
	<property name="log.controller" value="${log.base}/controller" />
	<!-- 輸出到控制檯 -->
	<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
			<pattern>${log.pattern}</pattern>
		</encoder>
	</appender>
	<!-- 宣告瞭一個存放info訊息的appender -->
	<!-- 啟動日誌回滾appender,就是說有一些規則,比如說規定一個檔案大小達到10M之後輸出到一個新的檔案中去 -->
	<appender name="controller-info"
		class="ch.qos.logback.core.rolling.RollingFileAppender">
		<File>${log.controller}/current-info.log</File>
		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<fileNamePattern>${log.controller}/controller_info_%d{yyyyMMdd_HH}.%i.log
			</fileNamePattern>
			<timeBasedFileNamingAndTriggeringPolicy
				class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
				<maxFileSize>10MB</maxFileSize>
			</timeBasedFileNamingAndTriggeringPolicy>
		</rollingPolicy>
		<encoder charset="UTF-8">
			<pattern>%msg%n</pattern>
		</encoder>
	</appender>
	<!-- 宣告瞭一個存放error訊息的appender -->
	<appender name="controller-error"
		class="ch.qos.logback.core.rolling.RollingFileAppender">
		<File>${log.controller}/current-error.log</File>
		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<fileNamePattern>${log.controller}/controller_error_%d{yyyyMMdd_HH}.%i.log
			</fileNamePattern>
			<timeBasedFileNamingAndTriggeringPolicy
				class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
				<maxFileSize>10MB</maxFileSize>
			</timeBasedFileNamingAndTriggeringPolicy>
		</rollingPolicy>
		<encoder charset="UTF-8">
			<pattern>%msg%n</pattern>
		</encoder>
	</appender>
    <!-- 這裡我定義一個logger,該logger會跟蹤club.wokao666包下的日誌列印語句,但是它不會對日誌進行輸出,因為你沒有關聯任何的appender,雖然沒有關聯,但是預設會繼承自父logger的相應配置,即club包下的配置,由於我們也沒有對club進行相應的配置,所以它預設會繼承自下面的 root logger -->
	<logger name="club.wokoa666" level="info"></logger>
	
	<logger name="club.wokao666.controller" additivity="false" level="WARN">
		<appender-ref ref="controller-error" /><!-- 關聯我們的Appender,表示日誌輸出的地址 -->
	</logger>
    <!-- 這就是我們的根logger -->
	<root level="info">
		<appender-ref ref="controller-info" />
	</root>
</configuration>
複製程式碼

日誌分類例項,新增相應的過濾器

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
	<property name="log.base" value="/logs" />
	<property name="log.controller" value="${log.base}/controller" />
	<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
			<pattern>${log.pattern}</pattern>
		</encoder>
	</appender>
	<appender name="controller-info"
		class="ch.qos.logback.core.rolling.RollingFileAppender">
		<File>${log.controller}/current-info.log</File>
		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<fileNamePattern>${log.controller}/controller_info_%d{yyyyMMdd_HH}.%i.log
			</fileNamePattern>
			<timeBasedFileNamingAndTriggeringPolicy
				class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
				<maxFileSize>10MB</maxFileSize>
			</timeBasedFileNamingAndTriggeringPolicy>
		</rollingPolicy>
		<encoder charset="UTF-8">
			<pattern>%msg%n</pattern>
		</encoder>
		<!-- 過濾器配置 -->
		<filter class="ch.qos.logback.classic.filter.LevelFilter">
			<level>INFO</level>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
	</appender>
	<appender name="controller-debug"
		class="ch.qos.logback.core.rolling.RollingFileAppender">
		<File>${log.controller}/current-debug.log</File>
		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<fileNamePattern>${log.controller}/controller_debug_%d{yyyyMMdd_HH}.%i.log
			</fileNamePattern>
			<timeBasedFileNamingAndTriggeringPolicy
				class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
				<maxFileSize>10MB</maxFileSize>
			</timeBasedFileNamingAndTriggeringPolicy>
		</rollingPolicy>
		<encoder charset="UTF-8">
			<pattern>%msg%n</pattern>
		</encoder>
		<!-- 過濾器配置 -->
		<filter class="ch.qos.logback.classic.filter.LevelFilter">
			<level>DEBUG</level>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
	</appender>
	<appender name="controller-error"
		class="ch.qos.logback.core.rolling.RollingFileAppender">
		<File>${log.controller}/current-error.log</File>
		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<fileNamePattern>${log.controller}/controller_error_%d{yyyyMMdd_HH}.%i.log
			</fileNamePattern>
			<timeBasedFileNamingAndTriggeringPolicy
				class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
				<maxFileSize>10MB</maxFileSize>
			</timeBasedFileNamingAndTriggeringPolicy>
		</rollingPolicy>
		<encoder charset="UTF-8">
			<pattern>%msg%n</pattern>
		</encoder>
	   	<!-- 過濾器配置 -->
		<filter class="ch.qos.logback.classic.filter.LevelFilter">
			<level>ERROR</level>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
	</appender>
	<root level="trace">
		<appender-ref ref="controller-error" />
		<appender-ref ref="controller-info" />
		<appender-ref ref="controller-debug" />
	</root>
</configuration>
複製程式碼

最後,更多高階內容可以查閱官網文件進行學習,我有一點感想,就是說如果我大學四年的空閒時間都花在學習英文技術文件的話,可能,或許現在的我會不那麼一樣,一首《我們不一樣》送給大家,謝謝閱讀!

相關文章