在 用SLF4j/Logback打印日志-1 和 用SLF4j/Logback打印日志-2 中分别介绍了Logback记录日志的基本原理并重点介绍了输出源配置。本篇介绍一些性能和技巧性的东西。

性能


在查看线上业务代码的时候有时候会发现类似这样的代码:

logger.debug("This " + this + " and " + that);

在对性能有要求的系统中,这种写法是非常不利的,虽然在配置线上系统的时候不会打印 DEBUG 级别的日志,但是在进入函数之前会先计算 "This " + this + " and " + that 这个字符串造成无畏的资源浪费。

在Logback中可以采用类似这样的API来解决拼字符串问题:

logger.debug("This {} and {}", this, that);

这种语法可以解决绝大部分由于拼字符串造成的性能问题,但是在某些情况下,比如还要计算一些数值,这样方案就不行了。

logger.debug("This {} and {} with {} ", this, that, compute());

这段代码虽然解决了拼字符的问题,但是调用 compute() 方法依然会造成资源浪费。在Java8之前大多数的解决方案是这样的:

if (logger.isDebugEnabled()) {
logger.debug("This {} and {} with {} ", this, that, compute());
}

在打印日志之前先判断是否需要打印相应级别的日志,这种写法可以解决任何由于日志打印造成的性能问题。但是代码却变得不够优雅,几乎需要在每个调用logger.debug(..) 方法之前掉一次 if (logger.isDebugEnabled()) {.. ,在Java8之后可以用lambda表达式完美解决这个问题。

logger.debug("I am logging that {} happened.", () -> compute());

这种写法把compute() 封装到一个匿名类里面传递给了debug方法,只有Debug方法内部执行的时候才会执行 compute() 。但是如果函数有多个参数,这种写法就变得有些怪异,因为它要求每个参数都要是lambda表达式,而写出来的代码就会变成这样:

logger.debug("This {} and {} with {} ", () -> this, () -> that, () -> compute());

Java8的lambda是非常低效的,如果方法参数较多这种写法会在每次调用的时候创建3个匿名类,反而会降低程序的性能。综合考虑,一般参数较少并且有耗时计算任务的时候考虑用java8的特性。

日志分析


通常情况下,我们会约定日志的打印格式,以便日后的分析。默认情况下,logback是用空格分隔不同的日志字段的。

%d %-5p %t %c{2} %m%n

这种约定不利于日志的机器分析,如果被打印的消息里面也包含空格,那么解析就会出错。简单的方案是重新约定日志的格式,比如用,号分隔日志,并保证打印的消息里面不再包含,号,类似这样 - %d, %-5p, %t, %c{2}, %m%n。逗号分隔只是比空格分隔略好一点,毕竟逗号出现在消息体里面的机会少一些。延续这种思路可能会进入一个误区,我们需要寻找一种尽可能稀有的分隔符来分隔日志的字段。

其实我们完全可以直接约定一种协议格式来打印日志,比如JSON。这样就不会担心消息和协议冲突的问题,但是也会带来新的新能问题。综合考虑,如果需要日志比较简单,那么可以采用简单的分隔符分隔日志,如果日志较多比较复杂,那么可以封装一些API来打印特有协议的日志,而性能问题可以考虑上一节的方案。

MDC


MDCMapped Diagnostic Context 的缩写,“映射诊断上下文”看起来高大上的样子,其实是非常简单的,就是一个临时存放k-v对的容器。和普通Map的区别是它是基于ThreadLocal实现的,所以不存在资源竞争问题,可以放心的往里面放东西。

假如我们有一个类似网关的应用,同一时间有很多的请求会发送到本系统。一般情况下,为了追踪每个请求的处理情况我们会在请求中加一个字段叫“TraceId” - 一个普通的UID用来区别每一个请求。那么怎么在日志中打印出TraceId呢,一般可以在打印消息的时候,把TraceId作为参数拼凑到日志消息中,这样有两个不好的地方:

  1. 需要写额外的代码拼凑消息
  2. 需要在每个打印消息的地方维护一个全局的TraceId变量

如果使用MDC问题就可以简化很多,在接收到请求后,解析出TraceId然后放入MDC,在配置文件中配置打印MDC,之后所有调用打印消息的日志都会自动包含TraceId了。

// 解析请求,取出TraceId放入MDC
MDC.put("traceid", xxxxx);
//配置XML
%d, %-5p, %t, %c{2}, %X{traceid}, %m%n

非常的简单而且自然有没有!!!

PS:如果使用的是log4j需要1.2版本以上。

用SLF4j/Logback打印日志-3的更多相关文章

  1. 用SLF4j/Logback打印日志-1

    在 浅谈后端日志系统 中已经写了很多日志方面的零散的非技术的东西.本篇更像一份入门说明,讲解一下SLF4j/Logback.SLF4J是一套抽象的日志API接口,logback它是的底层实现,所以在这 ...

  2. 用SLF4j/Logback打印日志-2

    本篇主要介绍logback的输出源配置,logback默认提供了很多输出源,但是用的最多的是这几种: OutputStreamAppender 日志输出到一个二进制流,可以通过 <encoder ...

  3. 日志框架之2 slf4j+logback实现日志架构 · 远观钱途

    如何从缤纷复杂的日志系统世界筛选出适合自己的日志框架以及slf4j+logback的组合美妙之处?此文可能有帮助 logback介绍 Logback是由log4j创始人设计的另一个开源日志组件,官方网 ...

  4. slf4j/logback: logging日志的配置

    slf4j/logback: logging日志的配置 import依赖: import org.slf4j.Logger;import org.slf4j.LoggerFactory;private ...

  5. 使用 SLF4J + LogBack 构建日志系统(转)

    转载自:http://www.cnblogs.com/mailingfeng/p/3499436.html 上次我们讨论了如何选择一个好的开源日志系统方案,其中的结论是:使用 SLF4J + LogB ...

  6. Spring Boot(三):logback打印日志

    springboot对logback的支持是非常好的,不需要任何配置,只需要在resource下加logback.xml就可以实现功能直接贴代码: <?xml version="1.0 ...

  7. springboot中logback打印日志(转)

    springboot对logback的支持是非常好的,不需要任何配置,只需要在resource下加logback.xml就可以实现功能 直接贴代码: <?xml version="1. ...

  8. java IDE 中安装 lombok plugin 插件,并使用 @Slf4j 注解打印日志初体验

    lombok 插件介绍: IntelliJ IDEA官方插件页面:https://plugins.jetbrains.com/plugin/6317-lombok-plugin 使用lombok之后, ...

  9. logback打印日志时添加上下文

    尝试上述特性, 配置如下: 效果:

随机推荐

  1. linux timer operate

    1.gettimeofday()    ---->   http://www.linuxidc.com/Linux/2012-06/61903.htm   (一般)

  2. 002.iSCSI服务端配置

    一 iSCSI target的磁盘种类 大型文件 单一分区(partition) 磁盘 数组 RAID LVM 二 iSCSI创建步骤 建立用于共享的磁盘设备(分区/磁盘/文件) 创建后备磁盘 创建相 ...

  3. 谈 JavaScript 中的强制类型转换 (2. 应用篇)

    这一部分内容是承接上一篇的, 建议先阅读谈 JavaScript 中的强制类型转换 (1. 基础篇) 前两章讨论了基本数据类型和基本包装类型的关系, 以及两个在类型转换中十分重要的方法: valueO ...

  4. 【Vue实战之路】一、Vue-cli入门及Vue工程目录全解。

    全面的Vue-cli学习,这一篇就够了! 一.下载 使用vue-cli前,需先安装node.js,node的安装就不赘述,不过在此需要注意: 1. node版本需在4.x以上,首推6.x以上版本(no ...

  5. 【教程】使用gitee搭建免费的图床

    前几天七牛云的免费图床测试域名回收,导致我上传的图片都不能访问!要配置自定义域名,域名还要绑定主机.没有云主机的我开始想你们搞一个免费的图床,并且数据也不会丢失呢 ? ​ 想到之前自己在GitHub上 ...

  6. Nmap扫描教程之网络基础服务DHCP服务类

    Nmap扫描教程之网络基础服务DHCP服务类 Nmap网络基础服务 网络基础服务是网络正常工作的基石,常见的网络基础服务包括DHCP服务和DNS服务.其中,DHCP服务用来为计算机动态分配IP地址:D ...

  7. Bzoj2149拆迁队:cdq分治 凸包

    国际惯例的题面:我们考虑大力DP.首先重新定义代价为:1e13*选择数量-(总高度+总补偿).这样我们只需要一个long long就能维护.然后重新定义高度为heighti - i,这样我们能选择高度 ...

  8. [USACO07JAN]Balanced Lineup

    OJ题号:洛谷2880 思路1: 线段树维护区间最大最小值. #include<cstdio> #include<cctype> #include<utility> ...

  9. CentOS添加环境变量的三种方式

    CentOS添加环境变量的三种方式,以添加php环境变量为例,假定php的安装目录为 /usr/local/php5 一.仅对当前会话临时生效 [root@bogon ~]# export PATH= ...

  10. redis主从集群搭建及容灾部署(哨兵sentinel)

    Redis也用了一段时间了,记录一下相关集群搭建及配置详解,方便后续使用查阅. 提纲 Redis安装 整体架构 Redis主从结构搭建 Redis容灾部署(哨兵sentinel) Redis常见问题 ...