Logback 与 log4j2 性能哪个更强?

👉 这是一个或许对你有用的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料: 

23f8cf0079212ebede9c3b42441b59cc.gif

👉这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号等等功能:

  • Boot 仓库:https://gitee.com/zhijiantianya/ruoyi-vue-pro

  • Cloud 仓库:https://gitee.com/zhijiantianya/yudao-cloud

  • 视频教程:https://doc.iocoder.cn

【国内首批】支持 JDK 21 + SpringBoot 3.2.2、JDK 8 + Spring Boot 2.7.18 双版本 

来源:juejin.cn/post/
7327878308757520419

7c4d573b5a6232f07f1b6eeae5c28b7f.jpeg


一、简介

logback, log4j2 等都是非常优秀的日志框架, 在日常使用中,我们很少会关注去使用哪一个框架, 但其实这些日志框架在性能方面存在明显的差异。

尤其在生产环境中, 有时候日志的性能高低,很可能影响到机器的成本, 像一些大企业,如阿里、腾讯、字节等,一点点的性能优化,就能节省数百万的支出。

再次, 统一日志框架也是大厂常有的规范化的事情, 还可以便于后续的ETL流程, 因此,我们选一个日志框架,其实还是比较重要的。

浅谈与slfj4、log4j、logback的关系

笼统的讲就是slf4j是一系列的日志接口,而log4j logback是具体实现了这些接口的日志框架,也可以简单理解为 slf4j 是接口, logback 和log4j是slf4j的具体实现, slf4j 具备很高的易用性和很好的抽象性。

使用SLF4J编写日志消息非常简单。首先需要调用 LoggerFactory 上的 getLogger 方法来实例化一个新的 Logger 对象。一共有两种方法:

方法1:使用lombok (推荐)

直接在类上打上lombok的注解, 这个方法是最简单,代码量最小,编程效率最高的, 而且lombok组件在很多场景都很好用,

@Slf4j
public class Main {}
方法2:直接使用

使用 org.slf4j.LoggerFactory 的 getLogger 方法获取logger实例,注意推荐 private static final

private static final Logger LOG = LoggerFactory.getLogger(Main.class);

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

二、性能测试对比

性能对比图
b759002c0a5cf7f94928a7543bd7a533.jpeg

从上图可以得出两个结论:

  • log4j2 全面优于 logback, log4j2性能是 logback的两倍

  • 随着线程数量的增加, 日志输出能力并不会线性增加,在增加到约两倍于CPU核数的时候, 日志性能达到比较高的一个值。

tips:

已知的影响效率的是,打出方法名称和行号都会显著降低日志输出效率, 如我们单单去掉 行号,在单线程情况下, log4j2 的性能相差一倍多。

见下图:

34b3aa494287c17b345e0a6f07a976f3.jpeg
附:测试环境
1. 硬件环境:
CPU AMD Ryzen 5 3600 6-Core Processor  Base speed: 3.95 GHz
Memory 32.0 GB Speed: 2666 MHz
2. jvm 信息
  • JDK版本:semeru-11.0.20

  • JVM 参数:-Xms1000m -Xmx1000m

3. log4j2 和logback的版本
<log4j.version>2.22.1</log4j.version>
<logback.version>1.4.14</logback.version>
4. 测试线程数和测试方式
  • 线程数:  1 8 32 128

  • 测试方式: 统一预热,跑三次,取预热后的正式跑的平均值

5. 日志格式 日志格式对于log的效率会有非常大的影响, 有些时候则是天差地别。
<!-log4j2 的配置 -->
<Property name="log.pattern">[%d{yyyyMMdd HH:mm:ss.SSS}] [%t] [%level{length=4}] %c{1.}:%L %msg%n</Property>
<!-logback 的配置 -->
<pattern>[%date{yyyyMMdd HH:mm:ss.SSS}] [%thread] [%-4level] %logger{5}:%line %msg%n</pattern>
6. 日志长度

长度大约 129个字符,常见长度 输出到文件 app.log, 格式统一, 一模一样

[20240125 16:24:27.716] [thread-3] [INFO] c.w.d.Main:32 main - info level ...this is a demo script, pure string log will be used!
[20240125 16:24:27.716] [thread-1] [INFO] c.w.d.Main:32 main - info level ...this is a demo script, pure string log will be used!

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

三、 使用方法, 有需要的可以拿去.

1. logback在springboot项目中的使用

pom 文件, 不需要做任何事情, spring官方默认使用logback, 非spring项目可以直接引入下面的xml, 同时包含logback 和slf4j

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>${logback.version}</version>
</dependency>

配置文件放置位置: src/main/resource/logback.xml,样例如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

 <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  <encoder>
   <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
  </encoder>
 </appender>

 <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <encoder>
   <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
   <charset>utf-8</charset>
  </encoder>
  <file>log/output.log</file>
  <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
   <fileNamePattern>log/output.log.%i</fileNamePattern>
  </rollingPolicy>
  <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
   <MaxFileSize>1MB</MaxFileSize>
  </triggeringPolicy>
 </appender>

 <root level="INFO">
  <appender-ref ref="CONSOLE" />
  <appender-ref ref="FILE" />
 </root>
</configuration>
2. log4j2 在spring项目中的使用

由于spring官方默认使用logback,因此我们需要对spring默认的依赖进行排除然后再引入以下依赖:

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>${log4j.version}</version>
</dependency>

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>${log4j.version}</version>
</dependency>

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j2-impl</artifactId>
    <version>${log4j.version}</version>
</dependency>

配置文件放置位置: src/main/resource/log4j2.xml, 样例如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
 <Properties>
        <!-- 定义日志格式 -->
  <Property name="log.pattern">%d{MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}%n%msg%n%n</Property>
        <!-- 定义文件名变量 -->
  <Property name="file.err.filename">log/err.log</Property>
  <Property name="file.err.pattern">log/err.%i.log.gz</Property>
 </Properties>
    <!-- 定义Appender,即目的地 -->
 <Appenders>
        <!-- 定义输出到屏幕 -->
  <Console name="console" target="SYSTEM_OUT">
            <!-- 日志格式引用上面定义的log.pattern -->
   <PatternLayout pattern="${log.pattern}" />
  </Console>
        <!-- 定义输出到文件,文件名引用上面定义的file.err.filename -->
  <RollingFile name="err" bufferedIO="true" fileName="${file.err.filename}" filePattern="${file.err.pattern}">
   <PatternLayout pattern="${log.pattern}" />
   <Policies>
                <!-- 根据文件大小自动切割日志 -->
    <SizeBasedTriggeringPolicy size="1 MB" />
   </Policies>
            <!-- 保留最近10份 -->
   <DefaultRolloverStrategy max="10" />
  </RollingFile>
 </Appenders>
 <Loggers>
  <Root level="info">
            <!-- 对info级别的日志,输出到console -->
   <AppenderRef ref="console" level="info" />
            <!-- 对error级别的日志,输出到err,即上面定义的RollingFile -->
   <AppenderRef ref="err" level="error" />
  </Root>
 </Loggers>
</Configuration>
最佳实践:

滚动日志,永远不让磁盘满

  • 根据运行环境要求, 配置最大日志数量

  • 根据运行环境要求, 配置日志文件最大大小

日志如何使用才方便统计和定位问题

  • 统一日志格式,比如统一先打印方法名称,再打印参数列表

  • 写好要打印参数的 toString方法

日志如何配置性能才比较高

  • 日志配置应该遵循结构清晰,尽量简化的原则,能不让框架计算的,尽量不让框架计算, 比如方法名,行号等

全公司,或者个人使用习惯统一,这样有助于后续的日志收集、分析和统计

四、 附录

1. 测试代码:
package com.winjeg.demo;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

@Slf4j
public class Main {

    private static final Logger LOG = LoggerFactory.getLogger(Main.class);

    private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(128, 256, 1L,
            TimeUnit.MINUTES, new ArrayBlockingQueue<>(512),
            new BasicThreadFactory.Builder().namingPattern("thread-%d").daemon(true).build());

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        execute(8, 160_000);
        long first = System.currentTimeMillis();
        execute(8, 160_000);
        System.out.printf("time cost, preheat:%d\t, formal:%d\n", first - start, System.currentTimeMillis() - first);
    }

    private static void execute(int threadNum, int times) {
        List<Future<?>> futures = new ArrayList<>();
        for (int i = 0; i < threadNum; i++) {
            Future<?> f = EXECUTOR.submit(() -> {
                for (long j = 0; j < times; j++) {
                    log.info("main - info level ...this is a demo script, pure string log will be used!");
                }
            });
            futures.add(f);
        }
        futures.forEach(f -> {
            try {
                f.get();
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        });
    }
}
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.winjeg.spring</groupId>
    <artifactId>demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <log4j.version>2.22.1</log4j.version>
        <logback.version>1.4.14</logback.version>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j2-impl</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <!--        <dependency>-->
        <!--            <groupId>ch.qos.logback</groupId>-->
        <!--            <artifactId>logback-classic</artifactId>-->
        <!--            <version>${logback.version}</version>-->
        <!--        </dependency>-->
    </dependencies>
</project>
2. 更多参考

这些参考资料有可能不太对, 但是为了方便大家查阅, 我还是给出了一些官方的和比较受欢迎的资料

  • logback官方测试结果 [1]

  • log4j2官方测试结果 [2]

  • Java日志框架:log4j vs logback vs log4j2 [3]

参考资料

[1]logback官方测试结果: https://logback.qos.ch/performance.html

[2]log4j2官方测试结果: https://logging.apache.org/log4j/2.x/performance.html

[3]Java日志框架:log4j vs logback vs log4j2: https://zhuanlan.zhihu.com/p/472941897


欢迎加入我的知识星球,全面提升技术能力。

👉 加入方式,长按”或“扫描”下方二维码噢

9ce057db57b6093d8d85630c24f91acb.png

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。

ad811daed195ee7e72f120d977dea066.png

5473e93b02fe0cb8e4b94ccb313df596.pngee65de2cf81470afd7cd735d502d6f49.png6a2d0d0b982937f2b2acacfc74d7f111.png29e42f40ddb599beed6d7d991565eab2.png

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值