欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于slf4j日志MDC輸出格式的問(wèn)題

 更新時(shí)間:2021年12月27日 08:53:39   作者:會(huì)灰翔的灰機(jī)  
這篇文章主要介紹了基于slf4j日志MDC輸出格式的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

slf4j日志MDC輸出格式

配置使用

// 自動(dòng)配置模板
...
<Property name="layout">%d %p %X{traceId} [%t] %c{10}:%M:%L %m%n</Property>
...
<PatternLayout pattern="${layout}"/>
...
// 具體項(xiàng)目覆蓋配置的格式
<Property name="layout">%d %p [%t] %c{1.}:%M:%L %X{myTraceId} %m%n</Property>
MDC.put("myTraceId", myTraceId);
try {
    ...
} catch (Exception e) {
    ...
} finally {
    MDC.clear();
}

日志輸出效果發(fā)現(xiàn)是直接打印了myTraceId所對(duì)應(yīng)的的值,而我們期望是這樣的格式{myTraceId=123}。

原因分析

查看格式化的實(shí)現(xiàn)類PatternLayout,內(nèi)部通過(guò)PatternSelector匹配選擇器根據(jù)Pattern匹配選擇對(duì)應(yīng)的轉(zhuǎn)換器進(jìn)行格式化

默認(rèn)使用MarkerPatternSelector實(shí)現(xiàn),選擇器構(gòu)造器中解析獲取各個(gè)匹配模式對(duì)應(yīng)的格式化實(shí)現(xiàn)列表PatternFormatter

PatternFormatter實(shí)現(xiàn)的實(shí)例屬性LogEventPatternConverter抽象類對(duì)具體的日志內(nèi)容進(jìn)行格式化轉(zhuǎn)換,查看其實(shí)現(xiàn)類

直接查看MdcPatternConverter實(shí)現(xiàn)

構(gòu)造器中按照逗號(hào)“,”切分MDC的key配置

// options, 對(duì)應(yīng)配置中的key列表
private MdcPatternConverter(final String[] options) {
    super(options != null && options.length > 0 ? "MDC{" + options[0] + '}' : "MDC", "mdc");
    if (options != null && options.length > 0) {
        full = false;
        if (options[0].indexOf(',') > 0) {
            // 按照逗號(hào)切分key
            keys = options[0].split(",");
            for (int i = 0; i < keys.length; i++) {
                keys[i] = keys[i].trim();
            }
            key = null;
        } else {
            keys = null;
            key = options[0];
        }
    } else {
        full = true;
        key = null;
        keys = null;
    }
}
// 格式化
public void format(final LogEvent event, final StringBuilder toAppendTo) {
    final ReadOnlyStringMap contextData = event.getContextData();
    // if there is no additional options, we output every single
    // Key/Value pair for the MDC in a similar format to Hashtable.toString()
    // 如果沒(méi)有附加的屬性,我們輸出每一個(gè)單獨(dú)的MDC配置的key/value對(duì),類似與Hashtable.toString()的格式
    if (full) {
        if (contextData == null || contextData.size() == 0) {
            toAppendTo.append("{}");
            return;
        }
        appendFully(contextData, toAppendTo);
    } else {
        if (keys != null) {
            if (contextData == null || contextData.size() == 0) {
                toAppendTo.append("{}");
                return;
            }
            // 存在附加屬性配置
            appendSelectedKeys(keys, contextData, toAppendTo);
        } else if (contextData != null){
            // otherwise they just want a single key output
            final Object value = contextData.getValue(key);
            if (value != null) {
                StringBuilders.appendValue(toAppendTo, value);
            }
        }
    }
}

我們配置了%X擴(kuò)展即存在附加屬性配置

// 按照配置的MDC keys輸出,輸出格式為{key=value,key2=value2}
private static void appendSelectedKeys(final String[] keys, final ReadOnlyStringMap contextData, final StringBuilder sb) {
    // Print all the keys in the array that have a value.
    final int start = sb.length();
    sb.append('{');
    for (int i = 0; i < keys.length; i++) {
        final String theKey = keys[i];
        final Object value = contextData.getValue(theKey);
        if (value != null) { // !contextData.containskey(theKey)
            if (sb.length() - start > 1) {
                sb.append(", ");
            }
            sb.append(theKey).append('=');
            StringBuilders.appendValue(sb, value);
        }
    }
    sb.append('}');
}

問(wèn)題定位后修改配置即可,修改配置后驗(yàn)證格式符合我們的期望

<Property name="layout">%d %p [%t] %c{1.}:%M:%L %X{myTraceId,} %m%n</Property>

小結(jié)一下:MDC配置的key,日志會(huì)按照逗號(hào)切分出keys列表,如果keys列表小于等于1則直接輸出一個(gè)單獨(dú)的value值。如果大于1則按照map的格式輸出,即:{key1=value1,key2=value2}

slf4j輸出日志的語(yǔ)法

slf4j輸出log的語(yǔ)法

1. 直接拼接字符串

用字符串拼接的構(gòu)造方式輸出log,字符串消息還是會(huì)被求值,存在類型轉(zhuǎn)換和字符串連接的性能消耗。例:

int index = 1;
logger.info("這是第"+index+"條數(shù)據(jù)");
logger.info("這是第"+String.valueOf(index)+"條數(shù)據(jù)");

輸出結(jié)果:

1

2. 使用SLF4J的格式化功能

這種用法不存在上面提到的缺點(diǎn)。SLF4J使用自己的格式化語(yǔ)法{},同時(shí)提供了適合不同參數(shù)個(gè)數(shù)的方法重載:

logger.debug(String format, Object param); //支持一個(gè)參數(shù)
logger.debug(String format, Object param1, Object param2); //支持兩個(gè)參數(shù)
logger.debug(String format, Object… param); //任意數(shù)量參數(shù),構(gòu)造參數(shù)數(shù)組具有一定的性能損耗

例:

int index1=1;int index2=2;i
logger.info("這是第{}條數(shù)據(jù)",index1);
logger.info("這是第{}、{}條數(shù)據(jù)",index1,index2);

輸出:

2

3. 格式化占位符的轉(zhuǎn)義

連續(xù)的{}才被認(rèn)為是格式化占位符

例:

logger.info("{1,2} 這是第{}條數(shù)據(jù)",index2);
logger.info("{1,2} 這是第{{}}條數(shù)據(jù)",index2);

輸出:

3

用”\”轉(zhuǎn)義{}占位符

例:

/**用”\”轉(zhuǎn)義{}占位符*/
logger.info("\\{} 這是第{}條數(shù)據(jù) ",index2);
/**用“\”本身轉(zhuǎn)義“{}”中的”\”*/
logger.info("\\\\{} 這是第{}條數(shù)據(jù) ",index3); 

輸出:

4

4. log前做條件判斷

isDebugEnabled()的方法在debug disabled的情況下不存在構(gòu)造字符串參數(shù)的性能消耗,但是如果debug enabled,debug是否被enabled將會(huì)被求值兩次:

  • 一次是isDebugEnabled(),
  • 一次是debug()本身(該影響較小,因?yàn)榍笾祃ogger狀態(tài)花費(fèi)的時(shí)間比真正log一條語(yǔ)句花費(fèi)的時(shí)間的1%都還要小)。

例:

if(logger.isDebugEnabled()){
			logger.info("這是第{}條數(shù)據(jù) ",index2);
}

輸出:

5

5、打印異常堆棧

logger.error("Failed to format {}", s, e);

slf4j總結(jié)

slf4j是Java的一種Log Api,類似Apache Commons Logging 。

官網(wǎng)介紹:http://www.slf4j.org/.

在SLF4J中,不需要進(jìn)行字符串拼接,不會(huì)導(dǎo)致使用臨時(shí)字符串帶來(lái)的消耗。

相反,我們使用帶占位符的模板消息來(lái)記錄日志信息,并提供實(shí)際值作為參數(shù)??梢允褂脦?shù)版的日志方法,也可以通過(guò)Object數(shù)組傳入。在為日志信息產(chǎn)生最終的字符串之前,該方法會(huì)檢查是否開(kāi)啟了特定的日志級(jí)別,這不僅降低了內(nèi)存占用,而且預(yù)先減少了執(zhí)行字符串拼接所消耗的CPU時(shí)間。

log.debug("Found {} records matching filter: '{}'", records, filter);//slf4j
log.debug("Found " + records + " records matching filter: '" + filter + "'");//log4j

可以看出SLF4J的優(yōu)點(diǎn)有:

更簡(jiǎn)略易讀;

在日志級(jí)別不夠時(shí),少了字符串拼接的開(kāi)銷,不會(huì)調(diào)用對(duì)象(records/filter)的toString方法。通過(guò)使用日志記錄方法,直到你使用到的時(shí)候,才會(huì)去構(gòu)造日志信息(字符串),這就同時(shí)提高了內(nèi)存和CPU的使用率。

Slf4j在1.6.0之后,更是支持了異常堆棧的打印,作為最后一個(gè)參數(shù)傳入即可,基本滿足了日志的常見(jiàn)打印場(chǎng)景。

在你的開(kāi)源庫(kù)或者私有庫(kù)中使用SLF4J,可以使它獨(dú)立于任何的日志實(shí)現(xiàn),這就意味著不需要管理多個(gè)庫(kù)和多個(gè)日志文件。

SLF4J提供了占位日志記錄,通過(guò)移除對(duì)isDebugEnabled(), isInfoEnabled()等等的檢查提高了代碼的可讀性。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java深度優(yōu)先遍歷解決排列組合問(wèn)題詳解

    Java深度優(yōu)先遍歷解決排列組合問(wèn)題詳解

    這篇文章主要介紹了Java深度優(yōu)先遍歷解決排列組合問(wèn)題詳解,深度優(yōu)先搜索是遞歸過(guò)程,帶有回退操作,因此需要使用棧存儲(chǔ)訪問(wèn)的路徑信息,當(dāng)訪問(wèn)到的當(dāng)前頂點(diǎn)沒(méi)有可以前進(jìn)的鄰接頂點(diǎn)時(shí),需要進(jìn)行出棧操作,將當(dāng)前位置回退至出棧元素位置,需要的朋友可以參考下
    2024-01-01
  • Java數(shù)據(jù)結(jié)構(gòu)中堆的向下和向上調(diào)整解析

    Java數(shù)據(jù)結(jié)構(gòu)中堆的向下和向上調(diào)整解析

    堆是一顆完全二叉樹(shù),在這棵樹(shù)中,所有父節(jié)點(diǎn)都滿足大于等于其子節(jié)點(diǎn)的堆叫大根堆,所有父節(jié)點(diǎn)都滿足小于等于其子節(jié)點(diǎn)的堆叫小根堆。堆雖然是一顆樹(shù),但是通常存放在一個(gè)數(shù)組中,父節(jié)點(diǎn)和孩子節(jié)點(diǎn)的父子關(guān)系通過(guò)數(shù)組下標(biāo)來(lái)確定
    2021-11-11
  • easycode配置成mybatis-plus模板的實(shí)現(xiàn)方法

    easycode配置成mybatis-plus模板的實(shí)現(xiàn)方法

    本文主要介紹了easycode配置成mybatis-plus模板的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Java編程之雙重循環(huán)打印圖形

    Java編程之雙重循環(huán)打印圖形

    這篇文章主要介紹了Java編程之雙重循環(huán)打印圖形,屬于Java編程基礎(chǔ)練習(xí)部分,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • Matplotlib可視化之自定義顏色繪制精美統(tǒng)計(jì)圖

    Matplotlib可視化之自定義顏色繪制精美統(tǒng)計(jì)圖

    matplotlib提供的所有繪圖都帶有默認(rèn)樣式.雖然這可以進(jìn)行快速繪圖,但有時(shí)可能需要自定義繪圖的顏色和樣式,以對(duì)繪制更加精美、符合審美要求的圖像.matplotlib的設(shè)計(jì)考慮到了此需求靈活性,很容易調(diào)整matplotlib圖形的樣式,需要的朋友可以參考下
    2021-06-06
  • 解決方法A調(diào)用方法B的事務(wù)控制問(wèn)題

    解決方法A調(diào)用方法B的事務(wù)控制問(wèn)題

    這篇文章主要介紹了解決方法A調(diào)用方法B的事務(wù)控制問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 詳解java各種集合的線程安全

    詳解java各種集合的線程安全

    這篇文章主要介紹了詳解java各種集合的線程安全,小編覺(jué)得挺不錯(cuò)的,這里分享給大家,供需要的朋友參考。
    2017-10-10
  • spring事務(wù)@Transactional失效原因及解決辦法小結(jié)

    spring事務(wù)@Transactional失效原因及解決辦法小結(jié)

    今天就跟大家聊聊有關(guān)spring中@Transactional失效原因及解決辦法小結(jié),主要從三個(gè)方面考慮,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • SpringBoot集成Kafka的步驟

    SpringBoot集成Kafka的步驟

    這篇文章主要介紹了SpringBoot集成Kafka的步驟,幫助大家更好的理解和使用SpringBoot,感興趣的朋友可以了解下
    2021-01-01
  • SpringBoot整合Sa-Token實(shí)現(xiàn)登錄認(rèn)證的示例代碼

    SpringBoot整合Sa-Token實(shí)現(xiàn)登錄認(rèn)證的示例代碼

    本文主要介紹了SpringBoot整合Sa-Token實(shí)現(xiàn)登錄認(rèn)證的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01

最新評(píng)論