最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Spring Boot下使用logback 記錄多個(gè)文件日志

 更新時(shí)間:2018年08月21日 14:41:21   作者:weidwonder  
這篇文章主要介紹了詳解Spring Boot下使用logback 記錄多個(gè)文件日志,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

背景

這兩天遇到一個(gè)比較有意思的日志問(wèn)題.

近期對(duì)我之前的python代碼進(jìn)行java的重構(gòu), 一方面是因?yàn)閖ava使用的醫(yī)療庫(kù)非常健全穩(wěn)定, 可以商用. 另一方面是因?yàn)閖ava速度快, 這個(gè)庫(kù)的實(shí)現(xiàn)的效率也高, 性能是Python版本的好幾倍.

但是作為這個(gè)項(xiàng)目的唯一作者, 我的癖好也成為這個(gè)項(xiàng)目的風(fēng)格. 這個(gè)項(xiàng)目會(huì)給很多部署工程師使用. 當(dāng)然項(xiàng)目的可用性和性能作為第一考慮的因素, 但是作為一個(gè)懶人, 對(duì)使用軟件時(shí)候的復(fù)雜部署過(guò)程和混亂調(diào)試信息深?lèi)和唇^. 所以我在項(xiàng)目中使用了高度可配置/易用和多文件日志.

說(shuō)道多文件日志, 它的優(yōu)點(diǎn)是每個(gè)日志只容納自身的邏輯, 所以對(duì)于一般的入門(mén)開(kāi)發(fā)者或者是初級(jí)運(yùn)維工程師查看起來(lái)非常方便.

初步嘗試

因?yàn)閟pring boot的配置一般來(lái)講是application.properties, 但是同時(shí)開(kāi)發(fā)者可以使用yml格式的配置, 二者相比, yml文件更為簡(jiǎn)潔. 熟讀python之禪的我當(dāng)然是簡(jiǎn)潔勝于冗余選擇了yml.

發(fā)現(xiàn)spring-boot可以通過(guò)application.yml配置日志. 高興的配置一番之后發(fā)現(xiàn)沒(méi)法配置多個(gè)logger, 棄用! 改用logback-spring.xml(為什么不用logback.xml? 因?yàn)?spring這種文件可以獲取到spring配置中的變量.下面再說(shuō))

第一次實(shí)現(xiàn)

我有好幾個(gè)服務(wù)需要打日志. 一般來(lái)講我的日志風(fēng)格是 *.log 保存 INFO以上級(jí)別日志. *.err.log保存ERROR以上級(jí)別日志. 我如果每個(gè)文件日志都使用一個(gè)Appender的話, 配置文件太長(zhǎng)了. 而且很難看, 不是我的風(fēng)格.

Google了一下, 發(fā)現(xiàn)了這種方案:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  # 下面這一行的意思是使用application.yml中的global.log-dir變量
  <springProperty scope="context" name="LOG_DIR" source="global.log-dir" defaultValue="./log/"/>
  <!-- 追加器開(kāi)始 -->
  # 這個(gè)是一個(gè)可以定義變量的Appender
  <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
    # 使用 LoggerNameBasedDiscriminator 這個(gè)類(lèi)根據(jù)當(dāng)前Logger獲取變量
    <discriminator class="com.utils.loggers.LoggerNameBasedDiscriminator">
      <defaultValue>general</defaultValue>
    </discriminator>
    <sift>
      # 根據(jù)變量loggerName名字生成根據(jù)日期滾動(dòng)的Appender
      <appender name="FILE-${loggerName}" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>
          ${LOG_DIR}/${loggerName}.log
        </file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
          <fileNamePattern>
            ${LOG_DIR}/${loggerName}.%d{yyyy-MM-dd}.log.gz
          </fileNamePattern>
          <maxHistory>15</maxHistory>
        </rollingPolicy>

        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
          <level>INFO</level>
        </filter>

        <encoder>
          <pattern>%d{HH:mm:ss.SSS} %-5level - %msg%n
          </pattern>
        </encoder>
      </appender>

      <appender name="FILE-ERROR-${loggerName}" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_DIR}/${loggerName}.err.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
          <fileNamePattern>
            ${LOG_DIR}/${loggerName}.%d{yyyy-MM-dd}.err.log.gz
          </fileNamePattern>
          <maxHistory>15</maxHistory>
        </rollingPolicy>

        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
          <level>ERROR</level>
        </filter>

        <encoder>
          <pattern>%d{HH:mm:ss.SSS} %-5level - %msg%n
          </pattern>
        </encoder>
      </appender>
    </sift>
  </appender>
  <!-- 追加器結(jié)束 -->

  <!-- 日志開(kāi)始 -->
  <logger name="com.some.service" level="INFO" additivity="false">
    <appender-ref ref="SIFT"/>
  </logger>
  <!-- 日志結(jié)束 -->

</configuration>

下的是對(duì)應(yīng)的 LoggerNameBasedDiscriminator 類(lèi)

package com.utils.loggers;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.sift.AbstractDiscriminator;

public class LoggerNameBasedDiscriminator extends AbstractDiscriminator<ILoggingEvent> {
  private static final String KEY = "loggerName";
  private String defaultValue;

  public String getDefaultValue() {
    return defaultValue;
  }

  public void setDefaultValue(String defaultValue) {
    this.defaultValue = defaultValue;
  }
  # 這就是之所以xml里面可以引用loggerName變量的原因
  public String getKey() {
    return KEY;
  }

  public void setKey() {
    throw new UnsupportedOperationException("Key not settable. Using " + KEY);
  }

  public String getDiscriminatingValue(ILoggingEvent e) {
    String loggerName = e.getLoggerName();

    if (loggerName == null)
      return defaultValue;
    else {
      String[] split = loggerName.split("\\.");
      return split[split.length - 1];
    }
  }
}

最開(kāi)始我的日志里面沒(méi)有報(bào)錯(cuò)信息, 正常的生成INFO日志. 但是后來(lái)發(fā)現(xiàn)事情好像不是想象的那樣

問(wèn)題出現(xiàn)

后來(lái)我把程序改成多線程. 發(fā)現(xiàn)所有涉及到多線程的服務(wù)日志里面都沒(méi)信息了. Google半天, 發(fā)現(xiàn)幾個(gè)令我震驚的真相:

  • 真相1: 所有滾動(dòng)Appender都不支持異步追加 (其實(shí)也不是, 但是那種方式需要寫(xiě)死日志文件名, 不推薦, 不講)
  • 真相2: SiftingAppender 內(nèi)部最多嵌套一個(gè)Appender. 所以理論上我的ERROR的日志里面應(yīng)該永遠(yuǎn)不會(huì)有內(nèi)容.

問(wèn)題解決

對(duì)于之前的兩個(gè)問(wèn)題, 分而治之.

不支持異步

再次谷歌(到這里讀者基本上發(fā)現(xiàn)了我搬磚的本質(zhì)), 發(fā)現(xiàn)有個(gè)Appender名字叫AsyncAppender, 這玩意是一個(gè)其他Appender的Wrapper. 說(shuō)白了, 就是你打日志的命令是異步的, 放到隊(duì)列里面, 而它真正的打日志的動(dòng)作是一個(gè)單獨(dú)的同步線程. 這就牛逼了, 使用這玩意收集我所有日志, 然后再轉(zhuǎn)發(fā)給SiftingAppender 進(jìn)行分發(fā)即可.

SiftingAppender 內(nèi)部最多嵌套一個(gè)Appender

這個(gè)好辦, 把INFO的Appender和ERROR的Appender拆開(kāi)放到兩個(gè)SiftingAppender里面就行了, 不過(guò)這樣的話, 前面提到的的AsyncAppender 也要寫(xiě)兩個(gè).

最后, logback-spring.xml文件如下

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <springProperty scope="context" name="LOG_DIR" source="global.log-dir" defaultValue="./log/"/>

  <!-- 追加器開(kāi)始 -->
  <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
    <discriminator class="com.utils.loggers.LoggerNameBasedDiscriminator">
    </discriminator>
    <sift>
      <appender name="FILE-${loggerName}"
           class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_DIR}/${loggerName}.log</file>
        <rollingPolicy
            class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
          <fileNamePattern>
            ${LOG_DIR}/${loggerName}.%d{yyyy-MM-dd}.log
          </fileNamePattern>
          <maxHistory>15</maxHistory>
        </rollingPolicy>

        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
          <level>INFO</level>
        </filter>

        <encoder>
          <pattern>%d{HH:mm:ss.SSS} %-5level - %msg%n
          </pattern>
        </encoder>
      </appender>
    </sift>
  </appender>
  <appender name="SIFT-ERR" class="ch.qos.logback.classic.sift.SiftingAppender">
    <discriminator class="com.infervision.utils.loggers.LoggerNameBasedDiscriminator">
    </discriminator>
    <sift>
      <appender name="FILE-ERROR-${loggerName}" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_DIR}/${loggerName}.err.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
          <fileNamePattern>
            ${LOG_DIR}/${loggerName}.%d{yyyy-MM-dd}.err.log
          </fileNamePattern>
          <maxHistory>15</maxHistory>
          <totalSizeCap>50MB</totalSizeCap>
        </rollingPolicy>

        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
          <level>ERROR</level>
        </filter>

        <encoder>
          <pattern>%d{HH:mm:ss.SSS} %-5level - %msg%n
          </pattern>
        </encoder>
      </appender>
    </sift>
  </appender>

  <!-- 異步輸出 -->
  <appender name ="ASYNC" class= "ch.qos.logback.classic.AsyncAppender">
    <!-- 不丟失日志.默認(rèn)的,如果隊(duì)列的80%已滿(mǎn),則會(huì)丟棄TRACT、DEBUG、INFO級(jí)別的日志 -->
    <discardingThreshold >0</discardingThreshold>
    <!-- 更改默認(rèn)的隊(duì)列的深度,該值會(huì)影響性能.默認(rèn)值為256 -->
    <queueSize>512</queueSize>
    <!-- 添加附加的appender,最多只能添加一個(gè) -->
    <appender-ref ref ="SIFT"/>
  </appender>

  <!-- 異步輸出 -->
  <appender name ="ASYNC-ERR" class= "ch.qos.logback.classic.AsyncAppender">
    <!-- 不丟失日志.默認(rèn)的,如果隊(duì)列的80%已滿(mǎn),則會(huì)丟棄TRACT、DEBUG、INFO級(jí)別的日志 -->
    <discardingThreshold >0</discardingThreshold>
    <!-- 更改默認(rèn)的隊(duì)列的深度,該值會(huì)影響性能.默認(rèn)值為256 -->
    <queueSize>512</queueSize>
    <!-- 添加附加的appender,最多只能添加一個(gè) -->
    <appender-ref ref ="SIFT-ERR"/>
  </appender>
  <!-- 追加器結(jié)束 -->

  <!-- 日志開(kāi)始 -->

  <logger name="com.some.service" level="INFO" additivity="false">
    <appender-ref ref="ASYNC"/>
  </logger>
  <!-- 日志結(jié)束 -->

</configuration>

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • JAVA入門(mén)教學(xué)之快速搭建基本的springboot(從spring boot到spring cloud)

    JAVA入門(mén)教學(xué)之快速搭建基本的springboot(從spring boot到spring cloud)

    本文主要入門(mén)者介紹怎么搭建一個(gè)基礎(chǔ)的springboot環(huán)境,本文通過(guò)圖文并茂的形式給大家介紹從spring boot到spring cloud的完美搭建過(guò)程,適用java入門(mén)教學(xué),需要的朋友可以參考下
    2021-02-02
  • 基于Cookie與Session的Servlet?API會(huì)話管理操作

    基于Cookie與Session的Servlet?API會(huì)話管理操作

    這篇文章主要為大家介紹了基于Cookie與Session的Servlet?API會(huì)話管理操作詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Java獲取視頻時(shí)長(zhǎng)、大小的示例

    Java獲取視頻時(shí)長(zhǎng)、大小的示例

    這篇文章主要介紹了Java獲取視頻時(shí)長(zhǎng)、大小的示例,幫助大家利用Java處理視頻,完成需求,感興趣的朋友可以了解下
    2020-11-11
  • Java中Dom4j的配置與使用示例詳解

    Java中Dom4j的配置與使用示例詳解

    Dom4j是一個(gè)強(qiáng)大的Java庫(kù),用于處理XML數(shù)據(jù),結(jié)合了DOM、SAX、JDOM的優(yōu)點(diǎn),它可以解析、生成、修改和序列化XML文檔,適用于數(shù)據(jù)交換、配置文件管理、日志記錄、數(shù)據(jù)持久化和Web服務(wù)等場(chǎng)景,Dom4j提供了簡(jiǎn)單易用的API,便于開(kāi)發(fā)者進(jìn)行高效的XML操作
    2024-10-10
  • Java數(shù)據(jù)結(jié)構(gòu)之優(yōu)先級(jí)隊(duì)列(堆)圖文詳解

    Java數(shù)據(jù)結(jié)構(gòu)之優(yōu)先級(jí)隊(duì)列(堆)圖文詳解

    優(yōu)先級(jí)隊(duì)列是比棧和隊(duì)列更專(zhuān)用的結(jié)構(gòu),在多數(shù)情況下都非常有用,下面這篇文章主要給大家介紹了關(guān)于Java數(shù)據(jù)結(jié)構(gòu)之優(yōu)先級(jí)隊(duì)列(堆)的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • Java檢查日期字符串是否合法的方法總結(jié)

    Java檢查日期字符串是否合法的方法總結(jié)

    后端接口在接收數(shù)據(jù)的時(shí)候,都需要進(jìn)行檢查。檢查全部通過(guò)后,才能夠執(zhí)行業(yè)務(wù)邏輯。本文總結(jié)了四個(gè)Java檢查日期字符串是否合法的方法,感興趣的可以了解一下
    2022-10-10
  • Java面向?qū)ο蟮姆庋b你了解嗎

    Java面向?qū)ο蟮姆庋b你了解嗎

    這篇文章主要為大家詳細(xì)介紹了Java面向?qū)ο蟮姆庋b,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • Java concurrency集合之ConcurrentSkipListSet_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java concurrency集合之ConcurrentSkipListSet_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要為大家詳細(xì)介紹了Java concurrency集合之ConcurrentSkipListSet的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • Java中char[]輸出不是內(nèi)存地址的原因詳解

    Java中char[]輸出不是內(nèi)存地址的原因詳解

    這篇文章主要介紹了關(guān)于Java中char[]輸出為什么不是內(nèi)存地址的原因,文中通過(guò)示例代碼介紹的很詳細(xì),需要的朋友們可以參考學(xué)習(xí)。
    2017-03-03
  • Spring Cloud Gateway 如何修改HTTP響應(yīng)信息

    Spring Cloud Gateway 如何修改HTTP響應(yīng)信息

    這篇文章主要介紹了Spring Cloud Gateway 修改HTTP響應(yīng)信息的方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07

最新評(píng)論

霍邱县| 乌拉特中旗| 汝阳县| 醴陵市| 凤山县| 武邑县| 曲周县| 枣阳市| 巴东县| 大石桥市| 东安县| 仪陇县| 新巴尔虎右旗| 晴隆县| 永平县| 通化市| 巴林右旗| 化州市| 长治市| 通化县| 浑源县| 陆丰市| 衡南县| 郑州市| 德惠市| 麻阳| 华宁县| 将乐县| 肃北| 大埔县| 织金县| 额济纳旗| 鹤壁市| 鹤壁市| 常德市| 皋兰县| 定结县| 深水埗区| 行唐县| 泰和县| 临清市|