1. 程式人生 > >日誌框架的瞭解與使用

日誌框架的瞭解與使用

什麼是日誌框架?

  • 是一套能實現日誌輸出的工具包
  • 能夠描述系統執行狀態的所有時間都可以算作日誌,比如:使用者下線、介面超時、資料庫崩潰以及Hello World等。

日誌框架的能力

  • 定製輸出目標:需要把日誌輸出到檔案,某些系統可能還需要定製日誌檔案的滾動策略,比如一天一個日誌檔案之類的。
  • 定製輸入格式:可以通過配置檔案修改日誌格式的具體內容,在不修改程式碼的前提下,可以自由的修改日誌格式,方便後期的加工和處理。
  • 攜帶上下文資訊:上下文資訊包括很多,比如時間戳、類路徑、執行緒等。
  • 執行時選擇性輸出:比如當前系統正常,那我只關注正常時的日誌。假如當前系統響應特別慢,那我可能就比較關心資料庫訪問層的問題,這時候如果能把這塊的細節通過日誌打印出來就顯得尤為重要了。
  • 靈活的配置:我們需要的各種能力,如果都需要編寫程式碼上線重啟才能實現,那永遠都做不出來牛逼系統。好的解決方案一定是可以通過靈活的配置來實現的。
  • 優異的效能:日誌終歸是正常業務之外的審計和運維需求,如果因為這個拖慢了整個系統的效能那就得不償失了。所以一款優秀的日誌一定具備優異的效能。

主流日誌框架Slf4j的使用

例項程式碼1
LoggerTest.java

@RunWith(SpringRunner.class)
@SpringBootTest
public class LoggerTest {

    private final Logger logger= LoggerFactory.getLogger(LoggerTest.class);

    @Test
    public void test1(){
        logger.debug("debug...");
        logger.info("info...");
        logger.error("error...");
    }
}

執行結果:

2018-11-27 20:04:48.222 INFO 10064 — [ main]
com.ft.LoggerTest : info… 2018-11-27
20:04:48.223 ERROR 10064 — [ main] com.ft.LoggerTest
: error…

結果分析:

可以看到執行結果裡面只是列印了info和error的記錄,debug並沒有打印出來。這是由於系統預設日誌級別是info,級別在info及以上的就能打印出來,而debug級別在info之下。

如何檢視日誌級別?
在專案裡搜尋Level類(位於org.slf4j.event包下),就能知道日誌級別。

ERROR(40, “ERROR”),
WARN(30, “WARN”),
INFO(20, “INFO”),
DEBUG(10, “DEBUG”),
TRACE(0, “TRACE”);

例項程式碼2

private final Logger logger= LoggerFactory.getLogger(LoggerTest.class);

以上這行程式碼引數是LoggerTest.class,表示我要告訴日誌框架這些日誌資訊都是來源於LoggerTest類,就好比我們使用IDEA控制檯報錯了,我們只要點選報錯類的超連結就能快速定位到目標類。但是,如果這個引數我寫成了LoggerTest1.class,然後列印了報錯資訊,那麼就會被定位到LoggerTest1這個類,其實真實的報錯資訊還是來源於LoggerTest類。
這裡有一種靈活的配置方式,不需要提前指定類,只需要標識@Slf4J註解即可。
LoggerTest.java

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class LoggerTest {

    @Test
    public void test1(){
        log.debug("debug...");
        log.info("info...");
        log.error("error...");
    }
}

結果分析:

這裡執行的結果跟例項程式碼1一致,值得注意的是,這裡的@Slf4j來源於lombok.extern.slf4j.Slf4j包,所以pom.xml檔案裡需要引入lombok包。此外,在標明@Slf4j之後,有些人log找不到,這是因為IDEA缺少lombok外掛,安裝下該外掛即可。

例項程式碼3(如何在日誌裡輸出變數)
LoggerTest.java

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class LoggerTest {

    @Test
    public void test1(){
        String name="taofut";
        String password="123456";
        log.debug("debug...");
        log.info("name: "+name+", password: "+password);
        //更優
        log.info("name: {}, password: {}",name,password);
        log.error("error...");
    }
}

執行結果:

2018-11-27 20:39:11.017 INFO 8128 — [ main]
com.ft.LoggerTest : name: taofut, password:
123456 2018-11-27 20:39:11.018 INFO 8128 — [ main]
com.ft.LoggerTest : name: taofut, password:
123456 2018-11-27 20:39:11.018 ERROR 8128 — [ main]
com.ft.LoggerTest : error…

結果分析:
以上的2行log.info程式碼都能正常輸出結果,但是更推薦後面那種採用佔位符的形式,因為前面那種在變數很多的情況下,拼接起來特別麻煩。

Logback的配置之application.yml的配置

這種配置方式相對比較簡單,只能配置一些日誌檔案的路徑、日誌輸出格式等。

例項程式碼1
LoggerTest.java

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class LoggerTest {

    @Test
    public void test1(){
        String name="taofut";
        String password="123456";
        log.debug("debug...");
        log.info("name: "+name+", password: "+password);
        //更優
        log.info("name: {}, password: {}",name,password);
        log.error("error...");
    }
}

application.yml配置內容:

logging:
  pattern:
    console: "%d - %msg%n"

執行結果:

2018-11-27 21:07:44,068 - name: taofut, password: 123456 2018-11-27
21:07:44,069 - name: taofut, password: 123456 2018-11-27 21:07:44,069

  • error…

結果分析:

例項程式碼跟前面的一樣,但是執行結果內容明顯比之前的短了很多,這是因為在application.yml指定了日誌的輸出格式只包括時間和內容。

例項程式碼2
application.yml配置內容裡新增日誌的輸出路徑path:

logging:
  pattern:
    console: "%d - %msg%n"
  path: d:/log/

再次執行LoggerTest.java,在d:/log/下可以找到一個spring.log的日誌檔案。檔案裡面的內容就是我們控制檯輸出的所有日誌,但是會比控制檯的日誌資訊更加全面。

例項程式碼3
application.yml配置內容裡新增日誌的輸出路徑file:

logging:
  pattern:
    console: "%d - %msg%n"
  path: d:/log/
  file: d:/log/taofut.log

再次執行LoggerTest.java,在d:/log/下可以找到一個taofut.log的日誌檔案。檔案裡面的內容就是我們控制檯輸出的所有日誌,但是會比控制檯的日誌資訊更加全面。也就是說file不指定的話,輸出日誌的檔名預設為spring.log,file指定的話,輸出日誌的檔名就是指定的。

Logback的配置之logback-spring.xml的配置

這種配置方式可以進行比較複雜的配置。

例項程式碼1(配置控制檯日誌內容的輸出)
專案resources目錄下新增logback-spring.xml檔案,配置檔案內容為:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>
    <!--配置項-->
    <appender name="consolelog" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>
                %d - %msg%n
            </pattern>
        </layout>
    </appender>

    <root level="info">
        <appender-ref ref="consolelog" />
    </root>
</configuration>

執行LoggerTest.java,結果跟之前的一致。

例項程式碼2(配置日誌內容輸出到磁碟檔案)
logback-spring.xml檔案內容:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>
    <!--配置控制檯日誌輸出格式-->
    <appender name="consolelog" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>
                %d - %msg%n
            </pattern>
        </layout>
    </appender>

    <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>
                %msg%n
            </pattern>
        </encoder>
        <!--滾動策略-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--路徑-->
            <fileNamePattern>
                d:/log/taofut/info.%d.log
            </fileNamePattern>
        </rollingPolicy>
    </appender>

    <!--指定在root info級別下使用該配置-->
    <root level="info">
        <appender-ref ref="consolelog" />
        <appender-ref ref="fileInfoLog" />
    </root>
</configuration>

執行LoggerTest.java,可以發現在 d:/log/taofut/目錄下有了一個info.2018-11-27.log的檔案,這個時間是當前時間。

例項程式碼3
例項程式碼2執行完的info.2018-11-27.log檔案內容為:
在這裡插入圖片描述
既然是info日誌檔案,但是error日誌也被包含到裡面去了,所以下面需要將info日誌與error日誌分開。
logback-spring.xml檔案內容:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>
    <!--配置控制檯日誌輸出格式-->
    <appender name="consolelog" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>
                %d - %msg%n
            </pattern>
        </layout>
    </appender>

    <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>
                %msg%n
            </pattern>
        </encoder>
        <!--滾動策略:每天建立一個檔案-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--路徑-->
            <fileNamePattern>
                d:/log/taofut/info.%d.log
            </fileNamePattern>
        </rollingPolicy>
    </appender>

    <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--攔截器,控制只輸出error日誌-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <encoder>
            <pattern>
                %msg%n
            </pattern>
        </encoder>
        <!--滾動策略:每天建立一個檔案-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--路徑-->
            <fileNamePattern>
                d:/log/taofut/error.%d.log
            </fileNamePattern>
        </rollingPolicy>
    </appender>

    <!--指定在root info級別下使用該配置-->
    <root level="info">
        <appender-ref ref="consolelog" />
        <appender-ref ref="fileInfoLog" />
        <appender-ref ref="fileErrorLog" />
    </root>
</configuration>

同理,執行LoggerTest.java,可以發現在 d:/log/taofut/目錄下有了一個error.2018-11-27.log的檔案,這個時間是當前時間。檔案裡的內容就只輸出了error日誌。

例項程式碼4
現在error.2018-11-27.log裡只輸出了error日誌,但是info.2018-11-27.log還是存在error日誌,出現的原因還是因為配置的info日誌,但是error日誌級別高於info,所以也會被打印出來。那非要過濾掉error日誌怎麼做?
只需要更改logback-spring.xml檔案內容:

   <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <!--如果匹配,就禁止掉-->
            <onMatch>DENY</onMatch>
            <!--反之,則使用該規則-->
            <onMismatch>ACCEPT</onMismatch>
        </filter>
        <encoder>
            <pattern>
                %msg%n
            </pattern>
        </encoder>
        <!--滾動策略:每天建立一個檔案-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--路徑-->
            <fileNamePattern>
                d:/log/taofut/info.%d.log
            </fileNamePattern>
        </rollingPolicy>
   </appender>