iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >基于slf4j日志MDC输出格式的问题
  • 798
分享到

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

2024-04-02 19:04:59 798人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录slf4j日志MDC输出格式配置使用原因分析slf4j输出日志的语法slf4j输出log的语法1. 直接拼接字符串2. 使用SLF4J的格式化功能3. 格式化占位符的转义4. l

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,内部通过PatternSelector匹配选择器根据Pattern匹配选择对应的转换器进行格式化

默认使用MarkerPatternSelector实现,选择器构造器中解析获取各个匹配模式对应的格式化实现列表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 = false;
        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;
        } 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()
    // 如果没有附加的属性,我们输出每一个单独的MDC配置的key/value对,类似与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扩展即存在附加属性配置


// 按照配置的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('}');
}

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


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

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

slf4j输出日志的语法

slf4j输出log的语法

1. 直接拼接字符串

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


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

输出结果:

1

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;i
logger.info("这是第{}条数据",index1);
logger.info("这是第{}、{}条数据",index1,index2);

输出:

2

3. 格式化占位符的转义

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

例:


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

输出:

3

用”\”转义{}占位符

例:



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

logger.info("\\\\{} 这是第{}条数据 ",index3); 

输出:

4

4. log前做条件判断

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

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

例:


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

输出:

5

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);//slf4j
log.debug("Found " + records + " records matching filter: '" + filter + "'");//log4j

可以看出SLF4J的优点有:

更简略易读;

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

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

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

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

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: 基于slf4j日志MDC输出格式的问题

本文链接: https://www.lsjlt.com/news/160917.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 基于slf4j日志MDC输出格式的问题
    目录slf4j日志MDC输出格式配置使用原因分析slf4j输出日志的语法slf4j输出log的语法1. 直接拼接字符串2. 使用SLF4J的格式化功能3. 格式化占位符的转义4. l...
    99+
    2024-04-02
  • Slf4j+logback实现JSON格式日志输出方式
    目录Slf4j+logback实现JSON格式日志输出依赖logback 记录JSON日志Slf4j+logback实现JSON格式日志输出 依赖 <dependency&...
    99+
    2024-04-02
  • Slf4j+logback实现JSON格式日志输出方式是什么
    Slf4j+logback实现JSON格式日志输出方式是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Slf4j+logback实现JSON格式日志输出依赖<de...
    99+
    2023-06-22
  • logback 日志输出格式
      前言  日志对一个系统的重要性不言而喻;日志通常是在排查问题时给人看,一个友好的输出样式让人看到后赏心悦目,排查效率通常也会随之提高;下面为大家共享一下通过设置logback日志输出格式,打印出令人欣喜的日志样式。  一、未指定日志格式...
    99+
    2023-06-02
  • logback日志输出格式设置方式
    目录部分标签解释内置转换器部分特殊字符串解释更多内置特殊字符如何自定义输出样式字符颜色定义内置的一些样式代码示例使用内置模板使用自定义模板总结部分标签解释 withJansi: 是否...
    99+
    2023-05-14
    logback日志输出 logback日志格式设置 logback日志
  • logback日志输出格式怎么设置
    本篇内容介绍了“logback日志输出格式怎么设置”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!部分标签解释withJansi: 是否配合j...
    99+
    2023-07-05
  • 关于log4j2的异步日志输出方式
    目录log4j2的异步日志输出方式第一种实现异步方式AsyncAppender第二种实现异步方式AsyncLoggerlog4j2异步注意事项log4j2异步类型小提示log4j2的...
    99+
    2024-04-02
  • JAVA中使用log4j及slf4j进行日志输出的方法
    JAVA中输出日志比较常用的是log4j,这里讲下log4j的配置和使用方法,以及slf4j的使用方法。 一、下载log4j的架包,并导入项目中,如下: 二、创建log4j.properties配置文件 1、log4j配置文件的位置...
    99+
    2023-10-06
    java log4j 单元测试
  • 怎么在Python自定义日志输出格式
    今天就跟大家聊聊有关怎么在Python自定义日志输出格式,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。python有哪些常用库python常用的库:1.requesuts;2.scr...
    99+
    2023-06-14
  • python中print格式化输出的问题
    前言 福宝们,下午好啊。改版后的第4.5章阅读量有点少呀,不知道是不是拖更了一天的缘故。呜呜呜,以后一定要做个不拖更的好熊,所以今天继续爆肝第五章:print格式化输出。在写第三章的...
    99+
    2024-04-02
  • 解决springmvc整合Mybatis的Log4j日志输出问题
    springmvc整合Mybatis的Log4j日志输出 当我们进行web开发的时候总是看到配置的log4j日志在控制台无法显示mybatis的主要是指sql、参数、结果,出现这种问...
    99+
    2024-04-02
  • 关于Thinkphp6的日志问题
    目录Thinkphp6的日志问题设置日志记录级别单一日志独立日志日志的写入时机日志通道Thinkphp6异常处理与日志异常处理日志手动记录日志关闭日志总结Thinkphp6的日志问题...
    99+
    2023-03-23
    Thinkphp6的日志 Thinkphp6日志 关于Thinkphp6日志
  • Golang如何将日志以Json格式输出到Kafka
    目录格式化接口普通文本格式化器Json文本格式化器写日志接口写日志到文件写日志到Kafka接口的组装如何提高日志处理的吞吐量在上一篇文章中我实现了一个支持Debug、Info、Err...
    99+
    2024-04-02
  • logback输出日志屏蔽quartz的debug等级日志方式
    目录logback输出日志屏蔽quartz的debug等级日志解决方法quartz关闭DBUG日志把他的log级别改成 ERROR或者索性logback输出日志屏蔽quartz的de...
    99+
    2024-04-02
  • 解决 K8s 中日志输出问题的技巧有哪些
    解决 K8s 中日志输出问题的技巧有哪些,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。前言我们将从实践角度出发来一步步构建 K8s 中的日志监控体系。构建日志系...
    99+
    2023-06-04
  • Tomcat的支持log4j及日志输出为json格式是怎样的
    今天就跟大家聊聊有关Tomcat的支持log4j及日志输出为json格式是怎样的,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1.下载apache-tomcat-7.0.42及解压[...
    99+
    2023-06-03
  • Golang GinWeb之自定义日志格式和输出方式/启禁日志颜色的方法是什么
    这篇文章主要介绍“Golang GinWeb之自定义日志格式和输出方式/启禁日志颜色的方法是什么”,在日常操作中,相信很多人在Golang GinWeb之自定义日志格式和输出方式/启禁日志颜色的方法是什么问...
    99+
    2024-04-02
  • 源码分析SpringMvc日志打印被忽略输出问题
    目录1.写在前面2.问题引出3.截取源码分析4.截取问题处理1.写在前面 在java的开发过程中,涉及到java web的开发,基本上都是走spring这一套了。 我们之前一般来说,...
    99+
    2024-04-02
  • Springboot异常日志输出方式的示例分析
    小编给大家分享一下Springboot异常日志输出方式的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!lombok插件使用引入依赖,在项目中使用Lombok可以减少很多重复代码的书写。比如说getter/sette...
    99+
    2023-06-22
  • rocketmq client 日志的问题处理方式
    目录rocketmq client 日志的问题处理方式一: rocketmq启用slf4j【推荐】方式二: 更改默认rocketmq路劲和级别RocketMQ 自己加载日志,以及特性...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作