首页 > 作文

基于slf4j日志MDC输出格式的问题

更新时间:2023-04-04 07:27:47 阅读: 评论:0

目录
slf4j日志mdc输出格式配置使用原因分析slf4j输出日志的语法一、slf4j输出log的语法1. 直接拼接字符串2. 使用slf4j的格式化功能3. 格式化占位符的转义4. log前做条件判断5、打印异常堆栈二、slf4j总结

slf4j日志mdc输出格式

配置使用

// 自动配置模板...<property name="layout">%d %p %x{traceid} [%t] %c{10}:%m:%l %m%n</property>...<patternlayout pattern="${layout}"/>...// 具体项目覆盖配置的格式<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();}

日志输出效果发现是直接打印了mytraceid所对应的的值,而我们期望是这样的格式{mytraceid=123}。

原因分析

查看格式化的实现类patternlayout,内部通过patternlector匹配选择器根据pattern匹配选百家讲坛辛弃疾择对应的转换器进行格式化

默认使用markerpatternlector实现,选择器构造器中解析获取各个匹配模式对应的格式化实现列表patternformatter

patternformatter实现的实例属性logeventpatternconverter抽象类对具体的日志内容进行格式化转换,查看其实现类

直接查看mdcpatternconverter实现

构造器中按照逗号“,”切分mdc的key配置

// options, 对应配置中的key列表private mdcpatternconverter(final string[] options) {    super(options != null && options.length > 0 ? "mdc{" + options[0] + '}' : "mdc", "mdc");    if (options != null && options.length > 0) {        full = fal;        if (options[0].indexof(',') > 0) {            // 按照逗号切分key            keys = options[0].split(",");            for (int i = 0; i < keys.length; i++) {                keys[i] = keys[i].trim();            }            key = null;        } el {            keys = null;            key = options[0];        }    } el {        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()    // 如果没有附加的属性,我们输出年终述职每一个单独的mdc配置的key/value对,类似与hashtable.tostring()的格式    if (full) {        if (contextdata == null || contextdata.size() == 0) {            toappendto.append("{}");            return;        }        appendfully(contextdata, toappendto);    } el {        if (keys != null) {            if (contextdata == null || contextdata.size() == 0) {  双方代理              toappendto.append("{}");                return;            }            // 存在附加属插画师需要学什么性配置            appendlectedkeys(keys, contextdata, toappendto);        } el if (contextdata != null){            // otherwi they just want a single key output            final object value = contextdata.getvalue(key);            if (value != null) {                stringbuilders.appendvalue(toappendto, value);            }        }    }}

我们配置了%x扩展即存在附加属性配置

// 按照配置的mdc keys输出,输出格式为{key=value,key2=value2}private static void appendlectedkeys(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('}');}

问题定位后修改配置即可,修改配置后验证格式符合我们的期望

<property name="layout">%d %p [%t] %c{1.}:%m:%l %x{mytraceid,} %m%n</property>

小结一下:mdc配置的key,日志会按照逗号切分出keys列表,如果keys列表小于等于1则直接输出一个单独的vadnf进不了游戏lue值。如果大于1则按照map的格式输出,即:{key1=value1,key2=value2}

slf4j输出日志的语法

一、slf4j输出log的语法

1. 直接拼接字符串

用字符串拼接的构造方式输出log,字符串消息还是会被求值,存在类型转换和字符串连接的性能消耗。例:

int index = 1;logger.info("这是第"+index+"条数据");logger.info("这是第"+string.valueof(index)+"条数据");

输出结果:

2. 使用slf4j的格式化功能

这种用法不存在上面提到的缺点。slf4j使用自己的格式化语法{},同时提供了适合不同参数个数的方法重载:

logger.debug(string format, object param); //支持一个参数logger.debug(string format, object param1, object param2); //支持两个参数logger.debug(string format, object… param); //任意数量参数,构造参数数组具有一定的性能损耗

例:

int index1=1;int index2=2;ilogger.info("这是第{}条数据",index1);logger.info("这是第{}、{}条数据",index1,index2);

输出:

3. 格式化占位符的转义

连续的{}才被认为是格式化占位符

例:

logger.info("{1,2} 这是第{}条数据",index2);logger.info("{1,2} 这是第{{}}条数据",index2);

输出:

用”\”转义{}占位符

例:

/**用”\”转义{}占位符*/logger.info("\\{} 这是第{}条数据 ",index2);/**用“\”本身转义“{}”中的”\”*/logger.info("\\\\{} 这是第{}条数据 ",index3); 

输出:

4. log前做条件判断

isdebugenabled()的方法在debug disabled的情况下不存在构造字符串参数的性能消耗,但是如果debug enabled,debug是否被enabled将会被求值两次:

一次是isdebugenabled(),一次是debug()本身(该影响较小,因为求值logger状态花费的时间比真正log一条语句花费的时间的1%都还要小)。

例:

if(logger.isdebugenabled()){logger.info("这是第{}条数据 ",index2);}

输出:

5、打印异常堆栈

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

二、slf4j总结

slf4j是java的一种log api,类似apache commons logging 。

官网介绍:http://www.slf4j.org/.

在slf4j中,不需要进行字符串拼接,不会导致使用临时字符串带来的消耗。

相反,我们使用带占位符的模板消息来记录日志信息,并提供实际值作为参数。可以使用带参数版的日志方法,也可以通过object数组传入。在为日志信息产生最终的字符串之前,该方法会检查是否开启了特定的日志级别,这不仅降低了内存占用,而且预先减少了执行字符串拼接所消耗的cpu时间。

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

可以看出slf4j的优点有:

更简略易读;

在日志级别不够时,少了字符串拼接的开销,不会调用对象(records/filter)的tostring方法。通过使用日志记录方法,直到你使用到的时候,才会去构造日志信息(字符串),这就同时提高了内存和cpu的使用率。

slf4j在1.6.0之后,更是支持了异常堆栈的打印,作为最后一个参数传入即可,基本满足了日志的常见打印场景。

在你的开源库或者私有库中使用slf4j,可以使它独立于任何的日志实现,这就意味着不需要管理多个库和多个日志文件。

slf4j提供了占位日志记录,通过移除对isdebugenabled(), isinfoenabled()等等的检查提高了代码的可读性。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持www.887551.com。

本文发布于:2023-04-04 07:27:42,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/1786b3ab4cf195ede4a88b38b9b59fb4.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:基于slf4j日志MDC输出格式的问题.doc

本文 PDF 下载地址:基于slf4j日志MDC输出格式的问题.pdf

下一篇:返回列表
标签:这是   字符串   日志   参数
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图