文章

SpringBoot + Log4j2 + TLog 实现日志追踪

前言

随着微服务盛行,很多公司都把系统按照业务边界拆成了很多微服务,在排错查日志的时候。因为业务链路贯穿着很多微服务节点,导致定位某个请求的日志以及上下游业务的日志会变得有些困难。
TLog 轻量级的分布式日志标记追踪神器 提供了一种最简单的方式来解决日志追踪问题,它不收集日志,也不需要另外的存储空间,它只是自动的对你的日志进行打标签,自动生成 TraceId 贯穿你微服务的一整条链路。并且提供上下游节点信息。适合中小型企业以及想快速解决日志追踪问题的公司项目使用。
TLog 适配了三大日志框架,支持自动检测适配。支持 dubbo,dubbox,spring cloud 三大 RPC 框架,更重要的是,项目接入 TLog,异常简单。下面来介绍基于 Log4j2 日志框架的 SpringBoot 如何快速接入 TLog。

引入 Maven 依赖

Maven 核心依赖

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-log4j2</artifactId>
	</dependency>
	<!-- TLog 日志工具  https://tlog.yomahub.com/pages/8d5538/-->
	<dependency>
		<groupId>com.yomahub</groupId>
		<artifactId>tlog-web-spring-boot-starter</artifactId>
		<version>1.5.2</version>
	</dependency>

工程使用的完整 Maven 依赖

<?xml version="1.0" encoding="UTF-8"?>
<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>cn.phixlin</groupId>
    <artifactId>trace-log-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.1</version>
        <relativePath/>
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-logging</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-logging</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        <!-- TLog 日志工具  https://tlog.yomahub.com/pages/8d5538/-->
        <dependency>
            <groupId>com.yomahub</groupId>
            <artifactId>tlog-web-spring-boot-starter</artifactId>
            <version>1.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

log4j2-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
    status : 这个用于设置 log4j2 自身内部的信息输出, 可以不设置, 当设置成 trace 时, 会看到 log4j2 内部各种详细输出
    monitorInterval : Log4j 能够自动检测修改配置文件和重新配置本身, 设置间隔秒数。
-->
<Configuration status="INFO" monitorInterval="30">
    <Properties>
        <Property name="log-directory" value="./logs"/>
        <Property name="history-log-directory" value="./logs/history"/>
        <Property name="split-size">100MB</Property>
        <Property name="file-count">5</Property>
    </Properties>
    <Appenders>
        <!-- 这个输出控制台的配置 -->
        <Console name="Console" target="SYSTEM_OUT">
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <!-- 输出日志的格式 -->
            <PatternLayout pattern="[%TX{tl}][%d{yyyy-MM-dd HH:mm:ss}][%p][%t][%c] %m%n"/>
        </Console>

        <!-- 这个会打印出所有的 info 及以下级别的信息,每次大小超过 size,则这 size 大小的日志会自动存入按年份 - 月份建立的文件夹下面并进行压缩,作为存档 -->
        <RollingFile name="RollingFileInfo" fileName="${log-directory}/trace.log"
                     filePattern="${history-log-directory}/info.%d{yyyy-MM-dd}-%i.log">
            <!-- 控制台只输出 level 及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%TX{tl}][%d{yyyy-MM-dd HH:mm:ss}][%p][%t][%c.%M] %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="${split-size}"/>
            </Policies>
        </RollingFile>

        <RollingFile name="RollingFileError" fileName="${log-directory}/error.log"
                     filePattern="${history-log-directory}/error.%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%TX{tl}][%d{yyyy-MM-dd HH:mm:ss}][%p][%t][%c.%M] %m%n"/>
            <!-- 日志文件切分策略 -->
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="${split-size}"/>
            </Policies>
            <!-- 日志滚动策略,如不设置,则默认为最多同一文件夹下 7 个文件 -->
            <DefaultRolloverStrategy max="${file-count}"/>
        </RollingFile>

    </Appenders>
    <!-- 然后定义 logger,只有定义了 logger 并引入的 appender,appender 才会生效 -->
    <Loggers>
        <!-- 过滤掉 spring 和 mybatis 的一些无用的 DEBUG 信息 -->
        <logger name="org.springframework" level="INFO"/>
        <logger name="org.mybatis" level="INFO"/>
        <root level="all">
            <appender-ref ref="Console"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileError"/>
        </root>
    </Loggers>
</Configuration>

测试接口

package cn.phixlin.controllers;

import cn.phixlin.config.CommonThreadTaskExecutorConfig;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

/**
 * @author phixlin
 * @description
 * @date 2024/8/29 13:56
 */

@RestController
@Slf4j
public class TestController {

    @Autowired
    @Qualifier(CommonThreadTaskExecutorConfig.COMMON_THREAD_TASK_EXECUTOR_NAME)
    private ThreadPoolTaskExecutor executor;
    @RequestMapping(value = "about")
    public String about() throws InterruptedException {
        //MDC.put("TRACE_ID",UUID.randomUUID().toString().replace("-",""));
        log.info("MDC: {}", MDC.getCopyOfContextMap());
        log.info("打印日志,开始测试");
        for (int i = 0; i < 6; i++){executor.submit(() ->{
                log.info("子线程打印日志,时间: {}", System.currentTimeMillis());});
        }
        Thread.sleep(3000);
        log.info("打印日志,结束测试");
        return "version 1.0";
    }
}

日志结果输出

[<0><6586981214566311567360>][2024-08-29 15:16:23][INFO][http-nio-9216-exec-2][cn.phixlin.controllers.TestController] MDC: {tlogSpanId=0, preIp=NONE, tl=<0><6586981214566311567360>, preIvkApp=NONE, preIvkHost=NONE, tlogTraceId=6586981214566311567360, currIp=192.168.255.10}
[<0><6586981214566311567360>][2024-08-29 15:16:23][INFO][http-nio-9216-exec-2][cn.phixlin.controllers.TestController] 打印日志,开始测试
[<0><6586981214566311567360>][2024-08-29 15:16:23][INFO][common_thread_task_executor3][cn.phixlin.controllers.TestController] 子线程打印日志,时间: 1724915783328 
[<0><6586981214566311567360>][2024-08-29 15:16:23][INFO][common_thread_task_executor2][cn.phixlin.controllers.TestController] 子线程打印日志,时间: 1724915783328 
[<0><6586981214566311567360>][2024-08-29 15:16:23][INFO][common_thread_task_executor1][cn.phixlin.controllers.TestController] 子线程打印日志,时间: 1724915783328 
[<0><6586981214566311567360>][2024-08-29 15:16:23][INFO][common_thread_task_executor4][cn.phixlin.controllers.TestController] 子线程打印日志,时间: 1724915783336 
[<0><6586981214566311567360>][2024-08-29 15:16:23][INFO][common_thread_task_executor1][cn.phixlin.controllers.TestController] 子线程打印日志,时间: 1724915783336 
[<0><6586981214566311567360>][2024-08-29 15:16:23][INFO][common_thread_task_executor3][cn.phixlin.controllers.TestController] 子线程打印日志,时间: 1724915783336 
[<0><6586981214566311567360>][2024-08-29 15:16:26][INFO][http-nio-9216-exec-2][cn.phixlin.controllers.TestController] 打印日志,结束测试
License:  CC BY 4.0