阿里巴巴开发手册强制使用SLF4J作为门面担当的秘密,被我发现了(3)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 阿里巴巴开发手册强制使用SLF4J作为门面担当的秘密,被我发现了

第四步,在 resources 目录下创建 log4j.properties 文件,内容如下所示:


### 设置###

log4j.rootLogger = debug,stdout,D


### 输出信息到控制台 ###

log4j.appender.stdout = org.apache.log4j.ConsoleAppender

log4j.appender.stdout.Target = System.out

log4j.appender.stdout.layout = org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n


### 输出DEBUG 级别以上的日志到=debug.log ###

log4j.appender.D = org.apache.log4j.DailyRollingFileAppender

log4j.appender.D.File = debug.log

log4j.appender.D.Append = true

log4j.appender.D.Threshold = DEBUG

log4j.appender.D.layout = org.apache.log4j.PatternLayout

log4j.appender.D.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n


再次运行 Demo 类,你会发现 target 目录下会生成一个名叫 debug.log 的文件,内容如下所示:


2020-10-21 15:32:06  [ main:0 ] - [ INFO ]  jcl

1

并且可以在控制台看到以下信息:


[INFO ] 2020-10-21 15:32:06,192 method:com.itwanger.Demo.main(Demo.java:12)

jcl

1

2

仔细对比一下,你就会发现,这次输出的格式和之前不一样,这就是因为 Log4j 和 JUL 的日志格式不同导致的。


另外,你有没有发现?我们并没有改动测试类 Demo,它里面使用的仍然是 JCL 获取 Log 的方式:


private static Log logger = LogFactory.getLog(Demo.class);

1

但输出的格式已经切换到 Log4j 了!


SLF4J 除了提供这种解决方案,绑定 Log4j 替换 JUL 和 JCL;还提供了绑定 Logback 替换 JUL、JCL、Log4j 的方案:


image.png


还有绑定 JUL 替换 JCL 和 Log4j 的方案:


image.png


太强了,有木有?有的话请在留言区敲出 666。



03、SLF4J 比 Log4J 强在哪


SLF4J 除了解决掉以上的痛点,帮助我们的应用程序独立于任何特定的日志系统,还有一个非常牛逼的功能,那就是 SLF4J 在打印日志的时候使用了占位符 {},它有点类似于 String 类的 format() 方法(使用 %s 等填充参数),但更加便捷,这在很大程度上提高了程序的性能。


众所周知,字符串是不可变的,字符串拼接会创建很多不必要的字符串对象,极大的消耗了内存空间。但 Log4J 在打印带参数的日志时,只能使用字符串拼接的方式:


String name = "沉默王二";

int age = 18;

logger.debug(name + ",年纪:" + age + ",是个非常不要脸的程序员");



非常笨重,但加入了 SLF4J 后,这个问题迎刃而解。我们来看一下在 Log4j 项目中加入 SLF4J 的详细的步骤。


第一步,把 log4j 的依赖替换为 slf4j-log4j12(Maven 会自动引入 slf4j-api.jar 和 log4j.jar):


<dependency>

   <groupId>org.slf4j</groupId>

   <artifactId>slf4j-log4j12</artifactId>

   <version>1.7.25</version>

</dependency>



第二步,在 resources 目录下创建 log4j.properties 文件,内容和 Log4j 那一篇完全相同:


### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=debug.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = debug.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
### 输出ERROR 级别以上的日志到=error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =error.log 
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n



第三步,新建测试类:


package com.itwanger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * @author 微信搜「沉默王二」,回复关键字 PDF
 */
public class Log4jSLF4JDemo {
    private static final Logger logger = LoggerFactory.getLogger(Log4jSLF4JDemo.class);
    public static void main(String[] args) {
        logger.debug("{},是个非常不要脸的程序员","沉默王二");
    }
}



看到了吧,使用占位符要比“+”操作符方便的多。并且此时不再需要 isDebugEnabled() 先进行判断,debug() 方法会在字符串拼接之前执行。




如果只是 Log4J 的话,会先进行字符串拼接,再执行 debug() 方法,来看示例代码:


String name = "沉默王二";

int age = 18;

logger.debug(name + ",年纪:" + age + ",是个非常不要脸的程序员");



在调试这段代码的时候,你会发现的,如下图所示:


image.png


这也就意味着,如果日志系统的级别不是 DEBUG,就会多执行了字符串拼接的操作,白白浪费了性能。


注意,阿里巴巴开发手册上还有一条「强制」级别的规约:


image.png


这是因为如果参数是基本数据类型的话,会先进行自动装箱(Integer.valueOf())。测试代码如下所示:


logger.debug("沉默王二,{}岁", 18);

1

通过反编译工具就可以看得到:


logger.debug("\u6C89\u9ED8\u738B\u4E8C\uFF0C{}\u5C81", Integer.valueOf(18));

1

如果参数需要调用其他方法的话,debug() 方法会随后调用。


image.png


也就是说,如果不 isDebugEnabled() 的话,在不是 DEBUG 级别的情况下,会多执行自动装箱和调用其他方法的操作——程序的性能就下降了!


测试类运行的结果和之前 Log4J 的一样,小伙伴们可以点击链接跳转到 Log4j 那篇对比下。


04、总结


简单总结一下这篇文章哈。


1)在使用日志系统的时候,一定要使用 SLF4J 作为门面担当。


2)SLF4J 可以统一日志系统,作为上层的抽象接口,不需要关注底层的日志实现,可以是 Log4j,也可以是 Logback,或者 JUL、JCL。


3)SLF4J 在打印日志的时候可以使用占位符,既提高了程序性能(临时字符串少了,垃圾回收的工作量就小),又让代码变得美观统一。


4)小伙伴们如果知道更多秘密的话,建议在留言区贴出来哦。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2月前
|
JSON Java fastjson
Java日志通关(五) - 最佳实践
作者日常在与其他同学合作时,经常发现不合理的日志配置以及五花八门的日志记录方式,后续作者打算在团队内做一次Java日志的分享,本文是整理出的系列文章第五篇。
|
4月前
|
监控 Java API
Java日志框架的纷争演进与传奇故事
Java日志框架的纷争演进与传奇故事
|
4月前
|
Java API Apache
【JAVA日志框架大全】一文快速讲透JAVA日志体系
【JAVA日志框架大全】一文快速讲透JAVA日志体系
180 0
|
5月前
|
Java API Apache
Java日志体系
Java日志体系
55 0
|
5月前
|
消息中间件 Java 关系型数据库
又一里程碑!阿里首推Java技术成长笔记,业内评级“钻石级”
根据数据表明,阿里巴巴已经连续3年获评最受欢迎的中国互联网公司,实际上阿里巴巴无论在科技创新力还是社会创造价值这几个方面,都是具有一定代表里的。在行业内,很多互联网企业也将阿里作为自己的标杆,越来越多的“打工人”也希望能够进到阿里工作。
|
5月前
|
SQL 安全 前端开发
这部SpringBoot实战派早已刷爆国内外一线大厂!面试稳了!
近年来,Spring Boot 是整个Java社区中最有影响力的项目之一,常常被人看作是Java EE( Java Platform Enterprise Edition )开发的颠覆者,它将逐渐替代传统SSM ( Java EE互联网轻量级框架整合开发——Spring MvC+Spring+MyBatis)架构。
|
安全 Java 编译器
阿里巴巴面试题- - -Java体系最新面试题(2022内部资料)
阿里巴巴面试题- - -Java体系最新面试题(2022内部资料)
|
设计模式 监控 IDE
探析Java日志框架
        目前,几乎所有的应用程序中,都会用到日志框架来记录程序的运行信息。日志虽然不影响应用程序的运行结果,但是没有日志的应用程序是不健全,不完整的。良好的日志系统可以帮助我们快速的定位到程序问题,包括近几年火起来的日志分析系统,比如ELK,日志在我们系统中被重视起来,也起到了举足轻重的作用
131 0
|
存储 安全 Java
全网最全、最细致的Java日志框架以及门面技术(一)。
对于一个应用程序来说日志记录是必不可少的一部分。线上问题追踪,基于日志的业务逻辑统计分析等都离不日志。java领域存在多种日志框架,目前常用的日志框架包括Log4j 1,Log4j 2,Commons Logging,Slf4j,Logback,Jul。
全网最全、最细致的Java日志框架以及门面技术(一)。
|
XML 设计模式 Java
全网最全、最细致的Java日志框架以及门面技术(二)。
对于一个应用程序来说日志记录是必不可少的一部分。线上问题追踪,基于日志的业务逻辑统计分析等都离不日志。java领域存在多种日志框架,目前常用的日志框架包括Log4j 1,Log4j 2,Commons Logging,Slf4j,Logback,Jul。
全网最全、最细致的Java日志框架以及门面技术(二)。