Java-Logback-使用Logback輸出日志為JSON

前提

  • 使用者需要知道如何配置 logback-spring.xml

解決方案

  • 覆蓋Encoder類
package io.wetoo.streaming.common.customlog;

import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.LoggerContextVO;
import ch.qos.logback.classic.spi.StackTraceElementProxy;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ESEncoder extends PatternLayoutEncoder {

    @Override
    public byte[] encode(ILoggingEvent event) {
        return convertEventWithError(event).getBytes();
    }

    private String convertEventWithError(ILoggingEvent event) {
        try {
            // 檢查-------------------------------------------------------
            if (event == null)
                return "";
            if (StringUtils.isBlank(event.getMessage()))
                return "";
            // 獲取源Msg替換結(jié)果-------------------------------------------
            String msg = printReplace(event.getMessage(), event.getArgumentArray());
            // 嘗試獲取錯誤日志--------------------------------------------
            IThrowableProxy err = event.getThrowableProxy();
            StringBuilder errStr = null;
            if (err != null) {
                errStr = new StringBuilder();
                errStr.append(err.getClassName());
                errStr.append(" : ");
                errStr.append(err.getMessage());
                errStr.append(" \n ");
                StackTraceElementProxy[] errTrack = err.getStackTraceElementProxyArray();
                for (StackTraceElementProxy stackTraceElementProxy : errTrack) {
                    errStr.append(stackTraceElementProxy.getStackTraceElement());
                    errStr.append(" \n ");
                }
                errStr.delete(errStr.length() - 3, errStr.length());
            }
            // 構(gòu)建Json--------------------------------------------------
            LinkedHashMap<String, String> result = new LinkedHashMap();
            LoggerContextVO context = event.getLoggerContextVO();
            result.put("serverName", context == null ? "default" : context.getName());
            result.put("logTime", LocalDateTime.now().toString() + "Z");
            result.put("level", event.getLevel().levelStr);
            result.put("thread", event.getThreadName());
            result.put("logger", event.getLoggerName());
            result.put("msg", msg);
            if (errStr != null && errStr.length() != 0)
                result.put("err", errStr.toString());
            // 返回--------------------------------------------------
            return (new ObjectMapper()).writeValueAsString(result) + "\n";
        } catch (Throwable e) {
            try {
                return (new ObjectMapper()).writeValueAsString(ImmutableMap.of("err", "ESEncoder日志工具錯誤:" + e.toString())) + "\n";
            } catch (Throwable e2) {
                return "{\"err\":\"ESEncoder日志工具錯誤\"}\n";
            }
        }
    }

    public static String printReplace(String first, Object... replaces) {
        try {
            int replaceLen = 0;
            if (StringUtils.isBlank(first))
                return first;
            if (replaces == null || (replaceLen = replaces.length) == 0)
                return first;

            StringBuilder result = new StringBuilder();
            int replaceIdx = 0;
            int curCpIdx = 0;

            Matcher m = Pattern.compile("\\{\\}").matcher(first);
            boolean tailed = false;
            while (m.find()) {
                if (replaceIdx < replaceLen) {
                    result.append(first.substring(curCpIdx, m.start()));
                    result.append(replaces[replaceIdx] == null ? "null" : replaces[replaceIdx].toString());
                    curCpIdx = m.end();
                } else {
                    result.append(first.substring(curCpIdx, first.length()));
                    tailed = true;
                    break;
                }
                replaceIdx++;
            }
            if (!tailed) result.append(first.substring(curCpIdx, first.length()));

            return result.toString();
        } catch (Throwable e) {
            return first;
        }
    }

}
  • 在配置文件中引入Encoder類
<encoder class="com.common.customlog.ESEncoder" >
    <pattern>   balabalabala  </pattern>
</encoder>
  • 可能依賴的Maven庫
          <!-- json數(shù)據(jù) -->
          <dependency>
                <artifactId>jackson-core</artifactId>
                <groupId>com.fasterxml.jackson.core</groupId>
                <version>${jackson.version}</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-annotations</artifactId>
                <version>${jackson.version}</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>${jackson.version}</version>
            </dependency>
            <!-- 好用的Google工具庫 -->
            <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
                <version>18.0</version>
            </dependency>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纯赎,一起剝皮案震驚了整個濱河市逞盆,隨后出現(xiàn)的幾起案子决摧,更是在濱河造成了極大的恐慌齿桃,老刑警劉巖挎狸,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寺擂,死亡現(xiàn)場離奇詭異,居然都是意外死亡劣针,警方通過查閱死者的電腦和手機(jī)俩檬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門夷家,熙熙樓的掌柜王于貴愁眉苦臉地迎上來橙喘,“玉大人态秧,你說我怎么就攤上這事搓扯⊙妫” “怎么了探赫?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵厦画,是天一觀的道長牍陌。 經(jīng)常有香客問我擎浴,道長,這世上最難降的妖魔是什么毒涧? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任贮预,我火速辦了婚禮,結(jié)果婚禮上契讲,老公的妹妹穿的比我還像新娘萌狂。我一直安慰自己,他們只是感情好怀泊,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布茫藏。 她就那樣靜靜地躺著,像睡著了一般霹琼。 火紅的嫁衣襯著肌膚如雪务傲。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天枣申,我揣著相機(jī)與錄音售葡,去河邊找鬼。 笑死忠藤,一個胖子當(dāng)著我的面吹牛挟伙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播模孩,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼尖阔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了榨咐?” 一聲冷哼從身側(cè)響起介却,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎块茁,沒想到半個月后齿坷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體桂肌,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年永淌,在試婚紗的時候發(fā)現(xiàn)自己被綠了崎场。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡遂蛀,死狀恐怖照雁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情答恶,我是刑警寧澤饺蚊,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站悬嗓,受9級特大地震影響污呼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜包竹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一燕酷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧周瞎,春花似錦苗缩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至彼乌,卻和暖如春泻肯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背慰照。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工灶挟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人毒租。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓稚铣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親墅垮。 傳聞我的和親對象是個殘疾皇子惕医,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)噩斟,斷路器曹锨,智...
    卡卡羅2017閱讀 134,628評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,773評論 6 342
  • 1.1 Spring IoC容器和bean簡介 本章介紹了Spring Framework實(shí)現(xiàn)的控制反轉(zhuǎn)(IoC)...
    起名真是難閱讀 2,577評論 0 8
  • 若羽飄飄閱讀 192評論 0 1
  • 你指給的路充滿荊棘泥濘斥废,我還是含著笑走著椒楣,有時懷疑那是條無盡頭的路,可還是不愿意回頭牡肉。 那么相信你的我捧灰,卻才發(fā)現(xiàn)你...
    大臉歡閱讀 117評論 0 2