用SLF4j/Logback打印日志-3
在 用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
MDC 是 Mapped Diagnostic Context 的缩写,“映射诊断上下文”看起来高大上的样子,其实是非常简单的,就是一个临时存放k-v对的容器。和普通Map的区别是它是基于ThreadLocal实现的,所以不存在资源竞争问题,可以放心的往里面放东西。
假如我们有一个类似网关的应用,同一时间有很多的请求会发送到本系统。一般情况下,为了追踪每个请求的处理情况我们会在请求中加一个字段叫“TraceId” - 一个普通的UID用来区别每一个请求。那么怎么在日志中打印出TraceId呢,一般可以在打印消息的时候,把TraceId作为参数拼凑到日志消息中,这样有两个不好的地方:
- 需要写额外的代码拼凑消息
- 需要在每个打印消息的地方维护一个全局的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的更多相关文章
- 用SLF4j/Logback打印日志-1
在 浅谈后端日志系统 中已经写了很多日志方面的零散的非技术的东西.本篇更像一份入门说明,讲解一下SLF4j/Logback.SLF4J是一套抽象的日志API接口,logback它是的底层实现,所以在这 ...
- 用SLF4j/Logback打印日志-2
本篇主要介绍logback的输出源配置,logback默认提供了很多输出源,但是用的最多的是这几种: OutputStreamAppender 日志输出到一个二进制流,可以通过 <encoder ...
- 日志框架之2 slf4j+logback实现日志架构 · 远观钱途
如何从缤纷复杂的日志系统世界筛选出适合自己的日志框架以及slf4j+logback的组合美妙之处?此文可能有帮助 logback介绍 Logback是由log4j创始人设计的另一个开源日志组件,官方网 ...
- slf4j/logback: logging日志的配置
slf4j/logback: logging日志的配置 import依赖: import org.slf4j.Logger;import org.slf4j.LoggerFactory;private ...
- 使用 SLF4J + LogBack 构建日志系统(转)
转载自:http://www.cnblogs.com/mailingfeng/p/3499436.html 上次我们讨论了如何选择一个好的开源日志系统方案,其中的结论是:使用 SLF4J + LogB ...
- Spring Boot(三):logback打印日志
springboot对logback的支持是非常好的,不需要任何配置,只需要在resource下加logback.xml就可以实现功能直接贴代码: <?xml version="1.0 ...
- springboot中logback打印日志(转)
springboot对logback的支持是非常好的,不需要任何配置,只需要在resource下加logback.xml就可以实现功能 直接贴代码: <?xml version="1. ...
- java IDE 中安装 lombok plugin 插件,并使用 @Slf4j 注解打印日志初体验
lombok 插件介绍: IntelliJ IDEA官方插件页面:https://plugins.jetbrains.com/plugin/6317-lombok-plugin 使用lombok之后, ...
- logback打印日志时添加上下文
尝试上述特性, 配置如下: 效果:
随机推荐
- CSS选择器优先级(转)
原文:http://www.cnblogs.com/wangfupeng1988/p/4285251.html 另外,w3c有文章介绍了CSS选择器的特定性,见https://www.w3.org/T ...
- 小成就之解决调用spring中FileSystemXmlApplicationContext路径问题
此文写下调用spring过程中遇到的一个问题!或许对于入行的人一看觉得我很傻逼吧,这问题谁都会了!但我觉得对于新手(自已)来说,算是一个好思路与好办法! 问题: 对于 test_aa ta = (te ...
- Windows密码破解工具ophcrack
Windows密码破解工具ophcrack Windows用户密码都采用哈希算法加密进行保存.Kali Linux内置了专用破解工具ophcrack.该工具是一个图形化界面工具,支持Windows ...
- 五校联考R1 Day2T2 矩阵matrix(容斥)
题目链接 容易想到容斥,但是很恶心,因为要对行和列都容斥,然后行+列又要容斥.. 于是得到\(O(nm\log)\)的做法. 就有70分了: #include <cstdio> #incl ...
- Javascript:10天设计一门语言
演进和使用的JavaScript是早在1995年开发的一种语言,真的是刚刚起步. 网景公司在1995年四月聘请Brendan Eich ,他被告知,他有10天时间创造并制作了一种将在Netscape的 ...
- PS小技巧之完美抠图
具体详细步骤如下01.打开图片,ctrl+j复制一层得到图层1,点击红圈处新建图层2,放于图层1与背景层之间,填充你喜欢的颜色,作为检查效果和新的背景图层. 02.点击图层1,用“快速选择工具”大致做 ...
- CentOS的epel源rpm最新下载地址获取技巧
最近发现以前的的脚本上安装epel不起作用,最后发现是官方更新了,且每次更新都会把以前旧的删除. 鉴于上面这种情况,不建议安装rpm包,直接转投阿里云的镜像站点,下载文件替换,阿里云的好处是不改文件名 ...
- spring cloud 学习(11) - 用fastson替换jackson及用gb2312码输出
前几天遇到一个需求,因为要兼容旧项目的编码格式,需要spring-cloud的rest接口,输出gb2312编码,本以为是一个很容易的事情,比如下面这样: @RequestMapping(method ...
- 飘逸的python - 中文编码长度有趣的现象
最近在做验证用户姓名的功能时发现这样一个现象. >>len(u'打怪者') #unicode 3 >>len(u'打怪者'.encode('gbk')) #gbk 6 &g ...
- Java 微服务实践 - Spring Boot 系列
https://segmentfault.com/l/1500000009515571