logback自定義Appender和Layout
logback自定義Appender和Layout
@Date 2017.05.09
- Appender是logback中最重要的元件之一,它委託encoder元件來完成LoggingEvent的格式化和記錄,具體原始碼分析網上有很多, 本文主要是應用實踐.
- Layout元件來將LoggingEvent進行格式化,返回一個String,然後通過OutputStream.write()方法,把格式化之後的日誌資訊寫到目的地.
繼承RollingFileAppender,重寫輸出檔案格式
- 場景
工程中期望輸出到日誌中的是JSON格式, 但是在業務中log.info(變數),此變數會有帶引號的情況下, 會影響最終輸出結構,因為重寫file appender.
- logback.xml
<encoder>--> <charset>UTF-8</charset> <pattern>{"time":"${bySecond}","level":"%-5level","msg":"%msg"} %n</pattern>--> </encoder>
%msg是logback輸出的日誌內容,此字串如果本身帶引號,則造成輸出到日誌檔案裡的JSON格式無法解析.
- 解決辦法
- 整合logback預設的RollingFileAppender,獲取msg內容並做格式化替換
- 在logback.xml中<appender class="替換自定義的Appender"/>
public class UserFileAppender extends RollingFileAppender<ILoggingEvent> { @Override protected void subAppend(ILoggingEvent event){ // 獲取event中的message內容 event.getFormattedMessage().replace("\"","\\\""); start(); super.subAppend(event); } }
進階:非同步處理log.xxxx()日誌
- 場景
當在程式中輸出了一些日誌,並期望對這些日誌內容做特定處理(儲存DB/解析傳送訊息等)
- 整合UnsynchronizedAppenderBase
public class TransportDBLoggerAppender extends UnsynchronizedAppenderBase<ILoggingEvent> { @Override public void append(ILoggingEvent event) { try { String content = event.getFormattedMessage(); Map<String, String> map = new HashMap<>(); map.put("LOG_LEVEL", event.getLevel().levelStr); map.put("CONTENT", content.replace("'", "''")); // 處理邏輯 } catch (Exception e) { System.err.println(e); } } }
- 上述程式碼繼承了UnsynchronizedAppenderBase,重寫了append方法,裡面可以根據event物件獲取log中的內容和預設的系統提供的引數(level等),可以在此做各種業務邏輯, 此內容是非同步操作,節省我們在工程上自己構建非同步日誌收集等工作量,適合小應用的場景.
Layout:自定義日誌輸出格式
- 場景
在上述場景中發現只輸出msg還不夠滿足業務的需求,業務裡有需要把MDC儲存的上下文也加到輸出的JSON日誌中,因此使用了layout自定義輸出.
- logback.xml
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="自定義layout類" /> </encoder>
public class LoggingConsoleLayout extends LayoutBase<ILoggingEvent> { @Override public String doLayout(ILoggingEvent event) { StringBuilder sbuf = new StringBuilder(); if (null != event && null != event.getMDCPropertyMap()) { sbuf.append("{"); sbuf.append("\"time\":\""); sbuf.append(System.currentTimeMillis()); sbuf.append("\","); sbuf.append("\"level\":\""); sbuf.append(event.getLevel()); sbuf.append("\","); sbuf.append("\"tag\":\""); sbuf.append(event.getMDCPropertyMap().get("tag")); sbuf.append("\","); sbuf.append("\"msg\":\""); sbuf.append(event.getFormattedMessage().replace("\"", "\\\"")); sbuf.append("\","); sbuf.append("\"source\":\"dialog\"} \n"); } return sbuf.toString(); } }
- 利用自定義的encoder layout,輸出程式中存在的各種變數,輸出不同需求自定義的日誌格式