ThinkBridge的日志模块主要是收集了服务内的链路日志,包括访问日志、Feign日志、操作日志、JDBC日志和Messaging日志。日志支持通过Kafka、RabbitMQ或Pulsar进行收集。

模块引入后无需其他配置即可立即使用。

仓库坐标

Maven

<dependency>
    <groupId>com.luamas.thinkbridge</groupId>
    <artifactId>log-spring-boot-starter</artifactId>
</dependency>

Gradle

implementation("com.luamas.thinkbridge:log-spring-boot-starter")

架构概览

日志类型

日志类型

事件类

日志模型

说明

AccessLog

AccessEvent

AccessLog

HTTP访问日志,同时兼容MVC和WebFlux

FeignLog

RequestEvent

RequestLog

Feign调用日志,仅支持MVC

OperationLog

OperationEvent

OperationLog

操作日志,依赖AOP

JdbcLog

JdbcEvent

JdbcLog

SQL执行日志,依赖p6spy

MessageProducerLog

MessagingProducerEvent

ProducerMessagingLog

消息生产者日志,依赖Spring Integration

MessageConsumerLog

MessagingConsumerEvent

ConsumerMessagingLog

消息消费者日志,依赖Spring Integration

日志模型公共字段

所有日志模型均继承自 AbstractMessageLog,包含以下公共字段:

字段

说明

traceId

链路追踪ID

parentTraceId

父链路追踪ID

applicationName

来源应用名称

parentApplicationName

父来源应用名称

activeProfiles

来源应用激活环境

parentActiveProfiles

父来源应用激活环境

operator

操作人(需实现 AuditorAware 接口)

hostname

主机名称

threadName

线程名称

startTime

开始时间

time

执行时长(毫秒)

success

是否成功

stackTrace

异常堆栈追踪

extend

扩展数据(Map)

MDC机制

日志模块通过MDC(Mapped Diagnostic Context)传递链路信息,以下标签值会自动写入MDC:

MDC Key(可配置)

默认值

说明

logType

logType

当前日志类型

traceId

traceId

链路追踪ID

applicationName

applicationName

应用名称

activeProfiles

activeProfiles

应用环境

parentTraceId

parentTraceId

父链路追踪ID

parentApplicationName

parentApplicationName

父应用名称

parentActiveProfiles

parentActiveProfiles

父应用环境

在logback配置中可通过 %X{logType} 等方式引用MDC变量。

事件流

日志模块基于 Spring 事件机制,整体事件流如下:

环节

说明

日志采集

通过拦截器(如 AccessLogInterceptor)、注解(如 @OPLog)或扩展点(如 JdbcLogBuildHandler)采集原始日志数据

日志构建

采集的数据被封装为对应的日志模型(如 AccessLog、OperationLog),通过 LogEvent 发布到 Spring 事件总线

事件处理

ApplicationListener 或 EventService 接收事件,可进行过滤、转换、增强等处理

日志收集

通过标准收集(Spring 事件 → 消息中间件)或 logback 收集(Appender → 消息中间件)将日志发送到目标系统

各日志类型的采集方式:

日志类型

采集方式

访问日志

AccessLogInterceptor(MVC)或 AccessLogFilter(WebFlux)

Feign日志

FeignLogInterceptor(Feign)或 OkHttp3RequestLogInterceptor(OkHttp3)

操作日志

OperationLogAspect AOP 切面拦截

JDBC日志

JdbcLogBuildHandler 回调(基于 p6spy)

Messaging日志

ChannelInterceptor 消息通道拦截

自动配置

自动配置类为 ThinkBridgeLogAutoConfiguration,当 think.log.producer.enabled=true(默认为true)时自动生效。

该配置类会根据条件自动导入以下子配置:

配置类

说明

ThinkBridgeCommonLogConfiguration

公共日志配置,注册 EventService 和 MDCTaskHandlerInterceptor

ThinkBridgeMDCLogConfiguration

MDC日志配置,同时支持MVC和WebFlux

ThinkBridgeAccessLogConfiguration

访问日志配置,同时支持MVC和WebFlux

ThinkBridgeOperationLogConfiguration

操作日志配置,依赖AOP

ThinkBridgeJdbcLogConfiguration

JDBC日志配置,依赖p6spy

ThinkBridgeMessagingLogConfiguration

消息日志配置,依赖Spring Integration

ThinkBridgeFeignLogConfiguration

Feign日志配置,仅支持MVC

ThinkBridgeOkHttp3LogConfiguration

OkHttp3日志配置,自动为OkHttpClient注入日志拦截器(需引入okhttp3依赖)

扩展点

AuditorAware(操作人感知)

实现 AuditorAware 接口可自动为操作日志、JDBC日志、Messaging日志填充操作人信息:

@Bean
public AuditorAware auditorAware() {
    return () -> {
        // 从SecurityContext或其他地方获取当前用户
        return SecurityContextHolder.getContext().getAuthentication().getName();
    };
}

TraceAware(链路感知)

实现 TraceAware 接口可自定义链路追踪ID的生成策略:

@Bean
public TraceAware traceAware() {
    return () -> UUID.randomUUID().toString().replace("-", "");
}

全局配置

think:
  log:
    producer:
      # 是否启用全部日志,默认启用
      enabled: true
      # 日志类型标签,存储到MDC的key
      log-type-tag: logType
      # 链路ID标签,存储到MDC的key
      trace-id-tag: traceId
      # 应用名标签,存储到MDC的key
      application-name-tag: applicationName
      # 应用环境标签,存储到MDC的key
      active-profiles-tag: activeProfiles
      # 父链路ID标签,存储到MDC的key
      parent-trace-id-tag: parentTraceId
      # 父应用名标签,存储到MDC的key
      parent-application-name-tag: parentApplicationName
      # 父应用环境标签,存储到MDC的key
      parent-active-profiles-tag: parentActiveProfiles
      # 日志消费主题,用于kafka/rabbitmq/pulsar等订阅,为空则不发送
      topic: ""

配置属性一览

全局属性

属性

默认值

说明

think.log.producer.enabled

true

是否启用全部日志

think.log.producer.log-type-tag

logType

日志类型标签,存储到MDC的key

think.log.producer.trace-id-tag

traceId

链路ID标签,存储到MDC的key

think.log.producer.application-name-tag

applicationName

应用名标签,存储到MDC的key

think.log.producer.active-profiles-tag

activeProfiles

应用环境标签,存储到MDC的key

think.log.producer.parent-trace-id-tag

parentTraceId

父链路ID标签,存储到MDC的key

think.log.producer.parent-application-name-tag

parentApplicationName

父应用名标签,存储到MDC的key

think.log.producer.parent-active-profiles-tag

parentActiveProfiles

父应用环境标签,存储到MDC的key

think.log.producer.topic

""

日志消费主题,用于kafka/rabbitmq/pulsar等订阅

Access 日志属性

属性

默认值

说明

think.log.producer.access.enabled

true

是否启用访问日志

think.log.producer.access.name

AccessLog

日志类型名称

think.log.producer.access.ignore-urls

空

忽略的URL,支持AntPathMatcher

Access Origin 属性

属性

默认值

说明

think.log.producer.access.origin.prefix

X-

来源Header前缀

think.log.producer.access.origin.trace-id-tag

TRACE-ID

来源链路ID的Header标签

think.log.producer.access.origin.application-name-tag

APPLICATION-NAME

来源应用名的Header标签

think.log.producer.access.origin.active-profiles-tag

ACTIVE-PROFILES

来源应用环境的Header标签

Feign 日志属性

属性

默认值

说明

think.log.producer.feign.enabled

true

是否启用Feign日志

think.log.producer.feign.name

FeignLog

日志类型名称

think.log.producer.feign.ignore-urls

空

忽略的URL,支持AntPathMatcher

Feign Origin 属性

属性

默认值

说明

think.log.producer.feign.origin.prefix

X-

来源Header前缀

think.log.producer.feign.origin.trace-id-tag

TRACE-ID

来源链路ID的Header标签

think.log.producer.feign.origin.application-name-tag

APPLICATION-NAME

来源应用名的Header标签

think.log.producer.feign.origin.active-profiles-tag

ACTIVE-PROFILES

来源应用环境的Header标签

Operation 日志属性

属性

默认值

说明

think.log.producer.operation.enabled

true

是否启用操作日志

think.log.producer.operation.name

OperationLog

日志类型名称

JDBC 日志属性

属性

默认值

说明

think.log.producer.jdbc.enabled

true

是否启用JDBC日志

think.log.producer.jdbc.name

JdbcLog

日志类型名称

Messaging 日志属性

属性

默认值

说明

think.log.producer.messaging.enabled

true

是否启用Messaging日志

think.log.producer.messaging.producer.name

MessageProducerLog

生产者日志类型名称

think.log.producer.messaging.consumer.name

MessageConsumerLog

消费者日志类型名称

think.log.producer.messaging.patterns

*

过滤通道规则,默认拦截所有

Messaging Producer Origin 属性

属性

默认值

说明

think.log.producer.messaging.producer.origin.prefix

X-

生产者来源Header前缀

think.log.producer.messaging.producer.origin.trace-id-tag

TRACE-ID

生产者来源链路ID的Header标签

think.log.producer.messaging.producer.origin.application-name-tag

APPLICATION-NAME

生产者来源应用名的Header标签

think.log.producer.messaging.producer.origin.active-profiles-tag

ACTIVE-PROFILES

生产者来源应用环境的Header标签

Messaging Consumer Origin 属性

属性

默认值

说明

think.log.producer.messaging.consumer.origin.prefix

X-

消费者来源Header前缀

think.log.producer.messaging.consumer.origin.trace-id-tag

TRACE-ID

消费者来源链路ID的Header标签

think.log.producer.messaging.consumer.origin.application-name-tag

APPLICATION-NAME

消费者来源应用名的Header标签

think.log.producer.messaging.consumer.origin.active-profiles-tag

ACTIVE-PROFILES

消费者来源应用环境的Header标签

全局处理日志

如果引用了模块的收集装置,无需自定义接收消息的事件

使用spring的event来处理。可以统一接收 LogEvent,也可以单独接收各子事件。

package com.luamas.thinkbridge.integration.demo.log;

import com.luamas.thinkbridge.bootstarter.log.ThinkBridgeLogProperties;
import com.luamas.thinkbridge.common.log.event.LogEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.json.JsonMapper;

/**
 * 可以手动关闭各个日志模块,具体参考<br/>
 * {@link ThinkBridgeLogProperties}
 * 这里采用异步打印日志
 */
@Profile(("trace-log"))
@Component
@RequiredArgsConstructor
@Slf4j
public class LogApplicationListener implements ApplicationListener<LogEvent> {
    private final ObjectMapper objectMapper = JsonMapper.builder().build();
    private final ThinkBridgeLogProperties properties;
    @Override
    public void onApplicationEvent(LogEvent event) {
        // demo做的统一拦截,如果需要单独拦截,请单独接收相应的子事件,
        // AccessEvent JdbcEvent MessagingConsumerEvent MessagingProducerEvent OperationEvent RequestEvent(feign)
        // 也可以使用mdc变量来获取日志类型
        // 这里建议使用异步接收,这样可以让日志处理的后续在子线程中进行处理
//        if (event instanceof AccessEvent){
//            System.out.println("这是一条访问日志");
//        }
        System.out.println("打印了一个"+ MDC.get(properties.getLogTypeTag()) +"日志:" + objectMapper.writeValueAsString(event.getSource()));
    }
}

单独接收特定日志事件

// 单独接收访问日志
@Component
public class AccessLogListener implements ApplicationListener<AccessEvent> {
    @Override
    public void onApplicationEvent(AccessEvent event) {
        AccessLog log = event.getSource();
        // 处理访问日志
    }
}

// 单独接收操作日志
@Component
public class OperationLogListener implements ApplicationListener<OperationEvent> {
    @Override
    public void onApplicationEvent(OperationEvent event) {
        OperationLog log = event.getSource();
        // 处理操作日志
    }
}

// 其他事件:RequestEvent(Feign)、JdbcEvent、MessagingProducerEvent、MessagingConsumerEvent

访问日志

收集所有的HTTP访问日志,同时兼容Spring MVC和Spring WebFlux。

访问日志默认已开启,无需额外配置即可使用。

配置

think:
    log:
        producer:
            access:
                # 是否启用访问日志,默认启用
                enabled: true
                # 日志类型,logType的值
                name: AccessLog
                # 忽略url,默认为空,忽略支持AntPathMatcher方式,具体参考`org.springframework.util.AntPathMatcher`
                ignore-urls:
                    - /actuator/
                    - /error/
                origin:
                    # 来源Header前缀
                    prefix: X-
                    # 来源链路id的Header标签
                    trace-id-tag: TRACE-ID
                    # 来源应用名的Header标签
                    application-name-tag: APPLICATION-NAME
                    # 来源应用环境的Header标签
                    active-profiles-tag: ACTIVE-PROFILES

配置属性一览

属性

默认值

说明

think.log.producer.access.enabled

true

是否启用访问日志

think.log.producer.access.name

AccessLog

日志类型名称

think.log.producer.access.ignore-urls

空

忽略的URL,支持AntPathMatcher

think.log.producer.access.origin.prefix

X-

来源Header前缀

think.log.producer.access.origin.trace-id-tag

TRACE-ID

来源链路ID的Header标签

think.log.producer.access.origin.application-name-tag

APPLICATION-NAME

来源应用名的Header标签

think.log.producer.access.origin.active-profiles-tag

ACTIVE-PROFILES

来源应用环境的Header标签

AccessLog 模型字段

除公共字段外,AccessLog 还包含以下特有字段:

字段

说明

ip

访问IP地址

userAgent

用户代理

uri

请求URI

method

HTTP方法

queryParams

请求参数

requestBody

请求Body

requestContentType

请求ContentType

requestHeader

请求Header(Map)

code

业务状态码

responseContentType

响应ContentType

responseStatus

HTTP响应状态码

responseBody

响应Body

依赖

访问日志模块依赖 MVC 或 WebFlux 模块,根据项目类型选择对应的依赖:

MVC 仓库坐标

Maven
<dependency>
    <groupId>com.luamas.thinkbridge</groupId>
    <artifactId>web-spring-boot-starter</artifactId>
</dependency>
Gradle
implementation("com.luamas.thinkbridge:web-spring-boot-starter")

WebFlux 仓库坐标

Maven
<dependency>
    <groupId>com.luamas.thinkbridge</groupId>
    <artifactId>webflux-spring-boot-starter</artifactId>
</dependency>
Gradle
implementation("com.luamas.thinkbridge:webflux-spring-boot-starter")

处理日志

如果引用了模块的收集装置,无需手动编写事件监听器。

如果需要在代码中手动处理日志事件,可以通过 Spring 的 ApplicationListener 机制实现:

@Slf4j
public class AccessLogApplicationListener implements ApplicationListener<AccessEvent> {
    @Override
    public void onApplicationEvent(AccessEvent event) {
        log.info(JsonUtil.toJSONString(event.getSource()));
    }
}

日志扩展

MVC 环境扩展

实现 ServletAccessLogBuildHandler 接口,解析来源放入扩展字段

public class CustomServletAccessLogBuildHandler implements ServletAccessLogBuildHandler {
    @Override
    public AccessLog buildLog(AccessLog accessLog, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        String token = httpServletRequest.getHeader("CUSTOM_INFO");
        if (!StringUtils.hasText(token)) return accessLog;
        Map<String, Object> extend = accessLog.getExtend();
        if (extend != null) {
            extend.put("custom_info", token);
        }
        return accessLog;
    }
}

WebFlux 环境扩展

实现 ReactiveAccessLogBuildHandler 接口

public class CustomReactiveAccessLogBuildHandler implements ReactiveAccessLogBuildHandler {
    @Override
    public AccessLog buildLog(AccessLog accessLog, ServerWebExchange exchange) {
        ServerHttpRequest request = exchange.getRequest();
        String token = request.getHeaders().getFirst("CUSTOM_INFO");
        if (!StringUtils.hasText(token)) return accessLog;
        Map<String, Object> extend = accessLog.getExtend();
        if (extend != null) {
            extend.put("custom_info", token);
        }
        return accessLog;
    }
}

Feign日志

收集Feign调用的请求和响应日志。目前仅支持MVC环境。

配置

以下配置中的 标签 指的是传递给日志系统 MDC 中的 key 值。
think:
    log:
        producer:
            feign:
                # 是否启用Feign日志,默认启用
                enabled: true
                # 日志类型,logType的值
                name: FeignLog
                # 忽略url,默认为空,忽略支持AntPathMatcher方式
                ignore-urls:
                    - /actuator/**
                # 来源配置
                origin:
                    # 来源Header前缀
                    prefix: X-
                    # 来源链路id的Header标签
                    trace-id-tag: TRACE-ID
                    # 来源应用名的Header标签
                    application-name-tag: APPLICATION-NAME
                    # 来源应用环境的Header标签
                    active-profiles-tag: ACTIVE-PROFILES

配置属性一览

属性

默认值

说明

think.log.producer.feign.enabled

true

是否启用Feign日志

think.log.producer.feign.name

FeignLog

日志类型名称

think.log.producer.feign.ignore-urls

空

忽略的URL,支持AntPathMatcher

think.log.producer.feign.origin.prefix

X-

来源Header前缀

think.log.producer.feign.origin.trace-id-tag

TRACE-ID

来源链路ID的Header标签

think.log.producer.feign.origin.application-name-tag

APPLICATION-NAME

来源应用名的Header标签

think.log.producer.feign.origin.active-profiles-tag

ACTIVE-PROFILES

来源应用环境的Header标签

RequestLog 模型字段

除公共字段外,RequestLog 还包含以下特有字段:

字段

说明

url

请求URL

method

HTTP方法

host

主机名称

requestBody

请求Body

requestHeader

请求Header(Map<String, Collection<String>>)

requestContentType

请求ContentType

responseContentType

响应ContentType

responseStatus

HTTP响应状态码

responseBody

响应Body

依赖

Feign 日志模块需要依赖 OpenFeign,请确保项目中已引入:

Maven

<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

Gradle

implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

OkHttp3 支持

除了 Feign 调用外,框架还提供了 OkHttp3RequestLogInterceptor 用于拦截 OkHttp3 的 HTTP 请求,生成 RequestLog 日志。

com.luamas.thinkbridge.common.log.request.okhttp.OkHttp3RequestLogInterceptor

自动生效(推荐)

如果项目中使用了 log-spring-boot-starter,当容器中存在 OkHttpClient Bean 时,框架通过 OkHttp3LogBeanPostProcessor(BeanPostProcessor 机制)自动为已有的 OkHttpClient 实例注入日志拦截器,无需任何手动配置。

原理说明:

  • 拦截 OkHttpClient Bean 的初始化过程

  • 通过 OkHttpClient.newBuilder() 克隆原实例,保留原所有配置

  • 追加 OkHttp3RequestLogInterceptor 后生成新的 OkHttpClient 实例

  • 对已注入到其他 Bean 的引用透明

即使你自行创建了 OkHttpClient Bean(配置了自定义超时、代理等),BeanPostProcessor 也会自动包装该 Bean 追加拦截器,无需手动添加 OkHttp3RequestLogInterceptor。所有请求只会被记录一次,不会重复。

功能说明

  • 自动记录请求 URL、方法、Header、Body

  • 自动记录响应状态码、ContentType、Body

  • 支持 GZip 解压后的响应体记录

  • 支持异常链路追踪(记录异常堆栈)

  • 生成的 RequestLog 事件与 Feign 日志共用同一事件模型,可通过 RequestEvent 统一处理

处理日志

如果引用了模块的收集装置,无需手动编写事件监听器。

如果需要在代码中手动处理日志事件,可以通过 Spring 的 ApplicationListener 机制实现:

@Slf4j
public class FeignLogApplicationListener implements ApplicationListener<RequestEvent> {
    @Override
    public void onApplicationEvent(RequestEvent event) {
        log.info(JsonUtil.toJSONString(event.getSource()));
    }
}

Jdbc日志

通过p6spy拦截SQL执行,收集SQL语句及执行时长等日志信息。

配置

think:
    log:
        producer:
            jdbc:
                # 是否启用Jdbc日志,默认启用
                enabled: true
                # 日志类型,logType的值
                name: JdbcLog

配置属性一览

属性

默认值

说明

think.log.producer.jdbc.enabled

true

是否启用JDBC日志

think.log.producer.jdbc.name

JdbcLog

日志类型名称

JdbcLog 模型字段

除公共字段外,JdbcLog 还包含以下特有字段:

字段

说明

url

数据库连接URL

sourceSql

编译语句(预编译SQL)

sqlWithValue

执行语句(带参数值的完整SQL)

依赖

JDBC 日志模块依赖 P6Spy 包。关于 P6Spy 的配置属性请参考 P6Spy 文档。

Maven

<dependency>
    <groupId>com.luamas.thinkbridge</groupId>
    <artifactId>p6spy-spring-boot-starter</artifactId>
</dependency>

Gradle

implementation("com.luamas.thinkbridge:p6spy-spring-boot-starter")

日志扩展

框架提供了 JdbcLogBuildHandler 接口,支持在 JDBC 日志构建阶段对日志进行自定义扩展,例如对 SQL 语句进行脱敏处理或添加自定义业务字段。

com.luamas.thinkbridge.common.log.jdbc.handler.JdbcLogBuildHandler

public class CustomJdbcLogBuildHandler implements JdbcLogBuildHandler {
    @Override
    public JdbcLog buildLog(JdbcLog jdbcLog) {
        // 对SQL中的敏感信息进行脱敏
        String sql = jdbcLog.getSourceSql();
        if (sql != null && sql.contains("password")) {
            jdbcLog.getExtend().put("hasSensitiveData", true);
        }
        return jdbcLog;
    }
}

在 Spring 配置中将自定义 Handler 注册为 Bean 即可生效:

@Configuration
public class JdbcLogConfig {

    @Bean
    public JdbcLogBuildHandler customJdbcLogBuildHandler() {
        return new CustomJdbcLogBuildHandler();
    }
}

处理日志

如果引用了模块的收集装置,无需手动编写事件监听器。

如果需要在代码中手动处理日志事件,可以通过 Spring 的 ApplicationListener 机制实现:

@Slf4j
public class JdbcLogApplicationListener implements ApplicationListener<JdbcEvent> {
    @Override
    public void onApplicationEvent(JdbcEvent event) {
        log.info(JsonUtil.toJSONString(event.getSource()));
    }
}

Messaging日志

Messaging日志 是基于 Spring Cloud Stream 的 Kafka、RabbitMQ 或 Pulsar 消息拦截进行日志收集,分别记录消息的生产者和消费者日志。

配置

以下配置中的 标签 指的是传递给日志系统 MDC 中的 key 值。
think:
    log:
        producer:
            messaging:
                # 是否启用Messaging日志,默认启用
                enabled: true
                # 消息生产者日志类型,logType的值
                name: MessageProducerLog
                # 消息生产者来源配置
                origin:
                    # 来源Header前缀
                    prefix: X-
                    # 来源链路id的Header标签
                    trace-id-tag: TRACE-ID
                    # 来源应用名的Header标签
                    application-name-tag: APPLICATION-NAME
                    # 来源应用环境的Header标签
                    active-profiles-tag: ACTIVE-PROFILES
                # 消息消费者配置
                consumer:
                    # 消息消费者日志类型,logType的值
                    name: MessageConsumerLog
                    # 消息消费者来源配置
                    origin:
                        # 来源Header前缀
                        prefix: X-
                        # 来源链路id的Header标签
                        trace-id-tag: TRACE-ID
                        # 来源应用名的Header标签
                        application-name-tag: APPLICATION-NAME
                        # 来源应用环境的Header标签
                        active-profiles-tag: ACTIVE-PROFILES
                # 过滤通道规则,默认拦截所有,具体如何书写规则参考org.springframework.integration.support.utils.PatternMatchUtils#smartMatch(String, String...)
                patterns: "*"

配置属性一览

属性

默认值

说明

think.log.producer.messaging.enabled

true

是否启用Messaging日志

think.log.producer.messaging.producer.name

MessageProducerLog

生产者日志类型名称

think.log.producer.messaging.consumer.name

MessageConsumerLog

消费者日志类型名称

think.log.producer.messaging.patterns

*

过滤通道规则

Producer Origin 属性

属性

默认值

说明

think.log.producer.messaging.producer.origin.prefix

X-

生产者来源Header前缀

think.log.producer.messaging.producer.origin.trace-id-tag

TRACE-ID

生产者来源链路ID的Header标签

think.log.producer.messaging.producer.origin.application-name-tag

APPLICATION-NAME

生产者来源应用名的Header标签

think.log.producer.messaging.producer.origin.active-profiles-tag

ACTIVE-PROFILES

生产者来源应用环境的Header标签

Consumer Origin 属性

属性

默认值

说明

think.log.producer.messaging.consumer.origin.prefix

X-

消费者来源Header前缀

think.log.producer.messaging.consumer.origin.trace-id-tag

TRACE-ID

消费者来源链路ID的Header标签

think.log.producer.messaging.consumer.origin.application-name-tag

APPLICATION-NAME

消费者来源应用名的Header标签

think.log.producer.messaging.consumer.origin.active-profiles-tag

ACTIVE-PROFILES

消费者来源应用环境的Header标签

日志模型字段

ProducerMessagingLog 和 ConsumerMessagingLog 均继承自 AbstractMessagingLog,除公共字段外还包含以下特有字段:

字段

说明

topic

消息主题

body

消息体

headers

消息头信息(Map<String, String>)

MessagingJudge 日志判断机制

框架提供了 MessagingJudge 接口,用于选择性开启或关闭特定消息通道的日志记录,避免不必要的日志收集。

com.luamas.thinkbridge.common.log.messaging.judge.MessagingJudge

内置实现

默认提供 DefaultMessagingJudge 实现,根据配置属性决定是否记录日志:

@Component
public class DefaultMessagingJudge implements MessagingJudge {

    @Override
    public boolean judgeProducer(String channel) {
        return true; // 默认记录所有生产者日志
    }

    @Override
    public boolean judgeConsumer(String channel) {
        return true; // 默认记录所有消费者日志
    }
}

自定义实现

如需对特定消息通道进行过滤,实现 MessagingJudge 接口并注册为 Spring Bean 即可覆盖默认行为:

@Component
public class CustomMessagingJudge implements MessagingJudge {

    / 某些通道不需要记录生产者日志 */
    @Override
    public boolean judgeProducer(String channel) {
        // 忽略 health-check 通道的生产者日志
        return !"health-check".equals(channel);
    }

    / 某些通道不需要记录消费者日志 */
    @Override
    public boolean judgeConsumer(String channel) {
        // 只记录 business 通道的消费者日志
        return channel != null && channel.startsWith("business");
    }
}

应用场景

  • 屏蔽内部系统心跳/健康检查消息的日志

  • 只记录核心业务消息通道的日志

  • 按环境动态决定是否记录(例如开发环境全量记录,生产环境选择性记录)

依赖

使用消息日志收集功能需要额外引入 Spring Cloud Stream 及相关 Binder 依赖,根据使用的消息中间件选择对应的依赖:

Maven

<dependencies>
      <!-- 必须依赖 -->
      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-stream</artifactId>
      </dependency>
      <!-- kafka使用 -->
      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-kafka</artifactId>
      </dependency>
      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-stream-binder-kafka-streams</artifactId>
      </dependency>
      <!-- rabbitmq使用 -->
      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
      </dependency>
      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
      </dependency>
      <!-- pulsar使用 -->
      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-pulsar</artifactId>
      </dependency>
      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-stream-binder-pulsar</artifactId>
      </dependency>
</dependencies>

Gradle

// 必须依赖
implementation 'org.springframework.cloud:spring-cloud-stream'
// kafka使用
implementation 'org.springframework.boot:spring-boot-starter-kafka'
implementation 'org.springframework.cloud:spring-cloud-stream-binder-kafka-streams'
// rabbitmq使用
implementation 'org.springframework.boot:spring-boot-starter-amqp'
implementation 'org.springframework.cloud:spring-cloud-stream-binder-rabbit'
// pulsar使用
implementation 'org.springframework.boot:spring-boot-starter-pulsar'
implementation 'org.springframework.cloud:spring-cloud-stream-binder-pulsar'

处理日志

如果引用了模块的收集装置(如 log-logback-kafka-spring-boot-starter),无需手动编写事件监听器。

如果需要在代码中手动处理日志事件,可以通过 Spring 的 ApplicationListener 机制实现:

消息消费者日志监听

@Slf4j
public class MessagingConsumerLogApplicationListener implements ApplicationListener<MessagingConsumerEvent> {
    @Override
    public void onApplicationEvent(MessagingConsumerEvent event) {
        log.info(JsonUtil.toJSONString(event.getSource()));
    }
}

消息生产者日志监听

@Slf4j
public class MessagingProducerLogApplicationListener implements ApplicationListener<MessagingProducerEvent> {
    @Override
    public void onApplicationEvent(MessagingProducerEvent event) {
        log.info(JsonUtil.toJSONString(event.getSource()));
    }
}

操作日志

操作日志通过 @OPLog 等注解进行打点,用于标注链路日志。依赖 AOP,未引入 AOP 则不会生效。

配置

think:
    log:
        producer:
            operation:
                # 是否启用Operation日志,默认启用
                enabled: true
                # 日志类型,logType的值
                name: OperationLog

配置属性一览

属性

默认值

说明

think.log.producer.operation.enabled

true

是否启用操作日志

think.log.producer.operation.name

OperationLog

日志类型名称

OperationLog 模型字段

除公共字段外,OperationLog 还包含以下特有字段:

字段

说明

msg

日志描述信息

psi

日志标识,用于唯一标识某个操作

className

方法所在类名

methodName

方法名称

params

操作提交的数据(Map<String, String>)

returnResult

返回结果

type

操作类型(见OperationType枚举)

@OPLog 注解

com.luamas.thinkbridge.common.log.operation.annotation.OPLog

属性

默认值

说明

type

无(必填)

操作类型,见 OperationType 枚举

msg

""

日志描述信息

psi

""

日志标识,用于唯一标识某个操作

OperationType 枚举

枚举值

值

说明

OTHER

0

其他操作

IMPORT

1

导入操作

EXPORT

2

导出操作

READ

3

查看操作,主要用于敏感数据查询记录

CREATE

4

新建操作

UPDATE

5

修改操作

DELETE

6

删除操作

使用

基本用法

@Service
public class HomeService {
    @OPLog(type = OperationType.OTHER, msg = "首页")
    public void home(String p) {
        System.out.println("访问");
    }
}

快捷注解

框架提供了基于 @OPLog 的快捷注解,无需手动指定 type:

快捷注解

对应 OperationType

说明

@CreateOPLog

CREATE

新建操作

@ReadOPLog

READ

查看操作

@UpdateOPLog

UPDATE

修改操作

@DeleteOPLog

DELETE

删除操作

@Service
public class UserService {
    @CreateOPLog(msg = "创建用户")
    public void createUser(UserDto userDto) { ... }

    @ReadOPLog(msg = "查询用户")
    public UserVo getUser(Long id) { ... }

    @UpdateOPLog(msg = "更新用户")
    public void updateUser(UserDto userDto) { ... }

    @DeleteOPLog(msg = "删除用户")
    public void deleteUser(Long id) { ... }
}

处理日志

如果引用了模块的收集装置,无需手动编写事件监听器。

如果需要在代码中手动处理日志事件,可以通过 Spring 的 ApplicationListener 机制实现:

@Slf4j
public class OperationLogApplicationListener implements ApplicationListener<OperationEvent> {
    @Override
    public void onApplicationEvent(OperationEvent event) {
        log.info(JsonUtil.toJSONString(event.getSource()));
    }
}

日志收集

日志收集支持两种方式:

  • 标准收集:通过Spring事件机制,将日志事件发送到Kafka、RabbitMQ或Pulsar

  • logback收集:通过logback appender方式,直接将日志发送到Kafka、RabbitMQ或Pulsar,无需经过Spring事件机制

标准收集

标准收集方式通过Spring事件机制,监听日志事件并将其发送到消息中间件。支持Kafka、RabbitMQ和Pulsar三种消息中间件。

kafka

通过Kafka标准方式收集日志事件,将日志事件发送到Kafka主题。

仓库坐标
Maven
<dependency>
    <groupId>com.luamas.thinkbridge</groupId>
    <artifactId>log-kafka-spring-boot-starter</artifactId>
</dependency>
Gradle
implementation("com.luamas.thinkbridge:log-kafka-spring-boot-starter")
配置
think:
  log:
    receive:
      standard:
        kafka:
          # 是否启用,默认启用
          enabled: true
          # 是否异步发送,默认true
          async: true
          trace:
            # 主题
            topic: thinkBridge-log
            # 指定分区,默认不指定
            partition:
            # Kafka Producer配置,参考org.apache.kafka.clients.producer.ProducerConfig
            properties:
              bootstrap.servers: localhost:9092
              key.serializer: org.apache.kafka.common.serialization.ByteArraySerializer
              value.serializer: org.apache.kafka.common.serialization.ByteArraySerializer
配置属性一览

属性

默认值

说明

think.log.receive.standard.kafka.enabled

true

是否启用

think.log.receive.standard.kafka.async

true

是否异步发送

think.log.receive.standard.kafka.trace.topic

thinkBridge-log

Kafka主题

think.log.receive.standard.kafka.trace.partition

空

指定分区,不指定则由Kafka决定

think.log.receive.standard.kafka.trace.properties

空

Kafka Producer配置(Map)

rabbitmq

通过RabbitMQ标准方式收集日志事件,将日志事件发送到RabbitMQ交换机。

仓库坐标
Maven
<dependency>
    <groupId>com.luamas.thinkbridge</groupId>
    <artifactId>log-amqp-spring-boot-starter</artifactId>
</dependency>
Gradle
implementation("com.luamas.thinkbridge:log-amqp-spring-boot-starter")
配置
think:
  log:
    receive:
      standard:
        amqp:
          # 是否启用,默认启用
          enabled: true
          # 是否异步发送,默认true
          async: true
          trace:
            # 主机,默认localhost
            host: localhost
            # 端口,默认5672
            port: 5672
            # 用户名,默认guest
            username: guest
            # 密码,默认guest
            password: guest
            # 虚拟主机,默认/
            virtual-host: /
            # 交换机,默认thinkbridge.log(必填)
            exchange: thinkbridge.log
            # 交换机类型:topic,direct,fanout,headers,默认topic
            exchange-type: topic
            # 路由key,默认thinkbridge.log.trace.common
            routing-key: thinkbridge.log.trace.common
            # 消费者队列,默认thinkbridge.log.logstash
            consumer-queue: thinkbridge.log.logstash
            # 给队列绑定的路由key,默认thinkbridge.log.trace.*
            consumer-queue-routing-key: thinkbridge.log.trace.*
            # 是否初始化exchange,默认false
            init-exchange: true
            # 是否初始化消费者queue,默认false
            init-consumer-queue-declare: true
            # 是否初始化绑定关系,默认false
            init-consumer-queue-bind: true
            # 是否持久化,默认true
            durable: true
            # 是否排他,默认false
            exclusive: false
            # 是否自动删除,默认false
            auto-delete: false
配置属性一览

属性

默认值

说明

think.log.receive.standard.amqp.enabled

true

是否启用

think.log.receive.standard.amqp.async

true

是否异步发送

think.log.receive.standard.amqp.trace.host

localhost

RabbitMQ主机

think.log.receive.standard.amqp.trace.port

5672

RabbitMQ端口

think.log.receive.standard.amqp.trace.username

guest

用户名

think.log.receive.standard.amqp.trace.password

guest

密码

think.log.receive.standard.amqp.trace.virtual-host

/

虚拟主机

think.log.receive.standard.amqp.trace.exchange

thinkbridge.log

交换机名称

think.log.receive.standard.amqp.trace.exchange-type

topic

交换机类型

think.log.receive.standard.amqp.trace.routing-key

thinkbridge.log.trace.common

路由key

think.log.receive.standard.amqp.trace.consumer-queue

thinkbridge.log.logstash

消费者队列

think.log.receive.standard.amqp.trace.consumer-queue-routing-key

thinkbridge.log.trace.*

消费者队列路由key

think.log.receive.standard.amqp.trace.init-exchange

false

是否初始化exchange

think.log.receive.standard.amqp.trace.init-consumer-queue-declare

false

是否初始化消费者queue

think.log.receive.standard.amqp.trace.init-consumer-queue-bind

false

是否初始化绑定关系

think.log.receive.standard.amqp.trace.durable

true

是否持久化

think.log.receive.standard.amqp.trace.exclusive

false

是否排他

think.log.receive.standard.amqp.trace.auto-delete

false

是否自动删除

pulsar

通过Pulsar标准方式收集日志事件,将日志事件发送到Pulsar主题。

仓库坐标
Maven
<dependency>
    <groupId>com.luamas.thinkbridge</groupId>
    <artifactId>log-pulsar-spring-boot-starter</artifactId>
</dependency>
Gradle
implementation("com.luamas.thinkbridge:log-pulsar-spring-boot-starter")
配置
think:
  log:
    receive:
      standard:
        pulsar:
          # 是否启用,默认启用
          enabled: true
          # 是否异步发送,默认true
          async: true
          trace:
            # 主题
            topic: thinkBridge-log
            # Pulsar服务地址
            service-url: pulsar://localhost:6650
            # Pulsar Producer配置
            properties:
              # 可自定义 Pulsar Producer 属性,如:
              # send-timeout-ms: 30000
              # max-pending-messages: 1000
配置属性一览

属性

默认值

说明

think.log.receive.standard.pulsar.enabled

true

是否启用

think.log.receive.standard.pulsar.async

true

是否异步发送

think.log.receive.standard.pulsar.trace.topic

thinkBridge-log

Pulsar主题

think.log.receive.standard.pulsar.trace.service-url

pulsar://localhost:6650

Pulsar服务地址

think.log.receive.standard.pulsar.trace.properties

空

Pulsar Producer配置(Map)

手动发送日志

标准收集方式除了由框架自动产生日志事件外,还支持通过 EventService 手动发送日志事件。EventService 已由 log-spring-boot-starter 自动注册为 Spring Bean,可直接注入使用。

EventService 接口

com.luamas.thinkbridge.common.log.event.EventService

方法

说明

void publishEvent(LogEvent event)

发布日志事件,日志类型取自 MessageLog 的类名

void publishEvent(LogEvent event, String logType)

发布日志事件,并指定日志类型

发送事件时,框架会自动补全 hostname、traceId、applicationName、activeProfiles 等公共字段(仅当 MDC 中不存在时才补全)。

内置事件类型

LogEvent 是抽象类,不能直接实例化,需使用以下内置子类:

事件类

模型类

说明

OperationEvent

OperationLog

操作日志

AccessEvent

AccessLog

访问日志

JdbcEvent

JdbcLog

JDBC 日志

MessagingProducerEvent

ProducerMessagingLog

消息生产者日志

MessagingConsumerEvent

ConsumerMessagingLog

消息消费者日志

RequestEvent

RequestLog

请求日志

使用

注入 EventService
@Service
public class ManualLogService {
    @Autowired
    private EventService eventService;
}
发送操作日志
public void sendOperationLog() {
    OperationLog operationLog = new OperationLog();
    operationLog.setMsg("手动发送的操作日志");
    operationLog.setClassName(this.getClass().getName());
    operationLog.setMethodName("sendOperationLog");
    operationLog.setSuccess(true);
    operationLog.setStartTime(new Date());
    operationLog.setTime(0L);

    // 日志类型默认为 OperationLog(模型类名)
    eventService.publishEvent(new OperationEvent(operationLog));

    // 指定自定义日志类型
    eventService.publishEvent(new OperationEvent(operationLog), "MyOperationLog");
}
发送访问日志
public void sendAccessLog() {
    AccessLog accessLog = new AccessLog();
    accessLog.setUri("/manual/test");
    accessLog.setMethod("GET");
    accessLog.setSuccess(true);
    accessLog.setStartTime(new Date());
    accessLog.setTime(10L);

    eventService.publishEvent(new AccessEvent(accessLog));
}
携带异常信息

所有事件构造方法均支持传入 Throwable,异常堆栈会被记录到日志的 stackTrace 字段:

public void sendErrorLog() {
    try {
        // 业务逻辑
    } catch (Exception e) {
        OperationLog operationLog = new OperationLog();
        operationLog.setMsg("执行失败");
        operationLog.setSuccess(false);
        operationLog.setStartTime(new Date());
        operationLog.setTime(0L);
        eventService.publishEvent(new OperationEvent(operationLog, e));
    }
}

存储自定义字段

所有日志模型均继承自 AbstractMessageLog,内置 extend 字段(Map<String, Object> 类型)用于存储自定义业务字段。该字段在 AbstractMessageLog 中已默认初始化为 HashMap,可直接使用,无需手动创建。

extend 字段定义于 MessageLog 接口,所有内置日志模型(OperationLog、AccessLog、JdbcLog 等)及自定义日志模型均支持。

手动发送时存储自定义字段
public void sendLogWithExtend() {
    OperationLog operationLog = new OperationLog();
    operationLog.setMsg("手动发送的操作日志");
    operationLog.setSuccess(true);
    operationLog.setStartTime(new Date());
    operationLog.setTime(0L);

    // 存储自定义业务字段
    operationLog.getExtend().put("userId", "1001");
    operationLog.getExtend().put("tenantId", "thinkbridge");
    operationLog.getExtend().put("amount", 99.9);

    eventService.publishEvent(new OperationEvent(operationLog));
}

序列化后日志中 extend 字段输出示例:

{
  "msg": "手动发送的操作日志",
  "success": true,
  "extend": {
    "userId": "1001",
    "tenantId": "thinkbridge",
    "amount": 99.9
  }
}
替换整个扩展字段

如需一次性设置多个字段,也可直接替换 extend:

Map<String, Object> extend = new HashMap<>();
extend.put("userId", "1001");
extend.put("tenantId", "thinkbridge");
operationLog.setExtend(extend);
自动收集时存储自定义字段

对于框架自动收集的日志(如访问日志),可通过实现对应的 BuildHandler 接口,在日志构建阶段将自定义信息写入 extend 字段。具体用法参考「访问日志」文档的「日志扩展」章节。

自定义日志类型

如需发送完全自定义的日志,可自行实现 MessageLog(或继承 AbstractMessageLog)并定义对应的 LogEvent 子类。

自定义模型
@Getter
@Setter
public class CustomLog extends AbstractMessageLog {
    private String content;
}
自定义事件
public class CustomEvent extends LogEvent<CustomLog> {
    public CustomEvent(CustomLog source) {
        super(source);
    }

    public CustomEvent(CustomLog source, Throwable throwable) {
        super(source, throwable);
    }
}
发送自定义日志
public void sendCustomLog() {
    CustomLog customLog = new CustomLog();
    customLog.setContent("自定义日志内容");
    customLog.setSuccess(true);
    customLog.setStartTime(new Date());
    customLog.setTime(0L);
    eventService.publishEvent(new CustomEvent(customLog));
}

注意事项

  1. 手动发送走的是 Spring 事件机制,需引入标准收集模块(log-kafka-spring-boot-starter、log-amqp-spring-boot-starter 或 log-pulsar-spring-boot-starter)才会有监听器将事件转发到消息中间件。若仅引入 log-logback-* 模块(logback appender 方式),手动发送的日志不会被转发。

  2. LogEvent 是抽象类,不能直接 new LogEvent(),需使用内置子类或自定义子类。

  3. 默认日志类型为模型类的简单类名(由 MessageLog.getLogType() 返回),可通过 publishEvent(event, logType) 覆盖。

  4. 手动发送的日志不经过框架的 BuildHandler,因此 operator(操作人)等字段不会被自动填充,如需记录请在发送前手动设置。

logback

logback收集方式通过自定义logback appender,直接将日志发送到消息中间件,无需经过Spring事件机制。支持Kafka(含Kafka Producer API v4)、Pulsar和RabbitMQ三种消息中间件。

kafka

通过logback appender方式将日志直接发送到Kafka,无需经过Spring事件机制。

仓库坐标
Maven
<dependency>
    <groupId>com.luamas.thinkbridge</groupId>
    <artifactId>log-logback-kafka-spring-boot-starter</artifactId>
</dependency>
Gradle
implementation("com.luamas.thinkbridge:log-logback-kafka-spring-boot-starter")
配置
think:
  log:
    receive:
      logback:
        kafka:
          # 是否启用,默认启用
          enabled: true
          # 是否异步发送,默认true
          async: true
          trace:
            # Kafka服务器地址
            bootstrap: localhost:9092
            # 主题
            topic: thinkbridge-kafka-trace-log
            # ack配置,默认1
            ack: 1
            # 重试次数,默认3
            retries: 3
            # 发送大小限制,默认10MB
            size: 10485760
bootstrap 和 topic 无默认值,需在配置中显式指定。
配置属性一览

属性

默认值

说明

think.log.receive.logback.kafka.enabled

true

是否启用

think.log.receive.logback.kafka.async

true

是否异步发送

think.log.receive.logback.kafka.trace.bootstrap

无

Kafka服务器地址(必填)

think.log.receive.logback.kafka.trace.topic

无

主题(必填)

think.log.receive.logback.kafka.trace.ack

1

Producer ack配置

think.log.receive.logback.kafka.trace.retries

3

重试次数

think.log.receive.logback.kafka.trace.size

10485760

发送大小限制(10MB)

默认不需要自定义 logback-spring.xml,开箱即用即可。如果有自定义需求,按照如下方式配置:
自定义logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="1 seconds">
    <contextName>logback</contextName>
    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
        <resetJUL>true</resetJUL>
    </contextListener>
	<!-- 这里一定要引入此配置,否则无法使用 -->
    <include resource="thinkbridge/logback-kafka-trace-log.xml" />

    <!-- 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %highlight(%-5p) [%thread] %logger.%M\(%F:%L\) :[%X\{logType}]
                %msg%n
            </pattern>
        </encoder>
    </appender>
    <!-- 关闭apache包信息-->
    <logger name="org.apache.catalina.core" level="OFF">
        <appender-ref ref="CONSOLE"/>
    </logger>
    <!-- 默认级别 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

kafka4

基于 Kafka Producer API 的日志收集模块,通过自定义 logback appender 将应用日志异步发送到 Kafka。支持 JSON 编码、MDC 上下文传递、敏感数据过滤、失败重试和 Actuator 监控端点。

仓库坐标
Maven
<dependency>
    <groupId>com.luamas.thinkbridge</groupId>
    <artifactId>log-logback-kafka4-spring-boot-starter</artifactId>
</dependency>
Gradle
implementation("com.luamas.thinkbridge:log-logback-kafka4-spring-boot-starter")
架构说明

该模块通过 KafkaAppender(继承 UnsynchronizedAppenderBase)拦截 logback 日志事件,经 JsonLogEncoder 编码为 JSON 格式后,由 KafkaLogProducer 异步发送到 Kafka。

核心组件

组件

说明

KafkaAppender

logback appender,负责日志事件的队列缓冲和批量发送

JsonLogEncoder

JSON 编码器,将日志事件转为结构化 JSON,支持敏感数据过滤

KafkaLogProducer

Kafka 生产者,封装 KafkaTemplate,支持失败重试和指数退避

ThinkBridgeKafkaAppenderConfigurer

动态配置器,实现 SmartLifecycle,启动时将 appender 挂载到 root logger

ThinkBridgeLoggingMetricsEndpoint

Actuator 端点,暴露重试线程池状态和失败日志数量

发送流程
logback 日志事件
  → KafkaAppender.append() 写入队列
  → 后台线程批量取出(最多 100 条/批)
  → JsonLogEncoder 编码为 JSON
  → KafkaLogProducer.send() 发送到 Kafka
  → 发送失败? → 加入失败队列 → 指数退避重试(最多 3 次)
配置
think:
  logging:
    kafka:
      enabled: true
      bootstrap-servers: localhost:9092
      topic: app-logs
      app-name: my-app
      environment: default

      acks: "1"
      retries: 3
      batch-size: 16384
      linger-ms: 5
      buffer-memory: 33554432
      compression-type: none
      idempotence: false
      max-in-flight-requests: 5

      max-retries: 3
      retry-backoff-ms: 100
      max-retry-backoff-ms: 5000

      queue-size: 10000
      max-failed-logs-per-topic: 1000
      failed-logs-ttl-hours: 24

      include-mdc: true
      include-caller-data: false
      exclude-fields:
        - password
        - token
        - secret
        - key
      exclude-loggers:
        - org.apache.kafka
        - org.springframework
      min-level: INFO
配置属性一览
基础配置

属性

默认值

说明

think.logging.kafka.enabled

false

是否启用 Kafka 日志收集

think.logging.kafka.bootstrap-servers

localhost:9092

Kafka 服务器地址

think.logging.kafka.topic

app-logs

日志 Topic

think.logging.kafka.app-name

thinkBridge-app

应用名称

think.logging.kafka.environment

default

环境标识

Kafka Producer 配置

属性

默认值

说明

think.logging.kafka.acks

1

Producer acks 配置

think.logging.kafka.retries

3

Kafka Producer 内置重试次数

think.logging.kafka.batch-size

16384

批量发送大小(字节)

think.logging.kafka.linger-ms

5

延迟发送时间(ms)

think.logging.kafka.buffer-memory

33554432

缓冲区大小(字节)

think.logging.kafka.compression-type

none

压缩类型(none/gzip/snappy/lz4/zstd)

think.logging.kafka.idempotence

false

是否启用幂等性

think.logging.kafka.max-in-flight-requests

5

最大在途请求数

重试配置

属性

默认值

说明

think.logging.kafka.max-retries

3

应用层最大重试次数

think.logging.kafka.retry-backoff-ms

100

初始重试间隔(ms)

think.logging.kafka.max-retry-backoff-ms

5000

最大重试间隔(ms),重试采用指数退避 + 随机抖动

队列配置

属性

默认值

说明

think.logging.kafka.queue-size

10000

内部日志事件队列大小,队列满时丢弃新日志

think.logging.kafka.max-failed-logs-per-topic

1000

每个 Topic 最大失败日志缓存数

think.logging.kafka.failed-logs-ttl-hours

24

失败日志缓存过期时间(小时)

编码器配置

属性

默认值

说明

think.logging.kafka.include-mdc

true

是否在 JSON 中包含 MDC 上下文

think.logging.kafka.include-caller-data

false

是否包含调用者信息(类名、方法名、文件、行号)

think.logging.kafka.exclude-fields

password, token, secret, key

敏感字段列表,匹配的值会被替换为 [FILTERED]

过滤配置

属性

默认值

说明

think.logging.kafka.exclude-loggers

org.apache.kafka, org.springframework

排除的 logger 名称列表,避免循环发送

think.logging.kafka.min-level

INFO

最低日志级别,低于此级别的日志不发送

Actuator 监控端点

引入 spring-boot-actuator 后,自动暴露 /actuator/thinkbridge-logging-metrics 端点。

端点信息

HTTP 方法

路径

说明

GET

/actuator/thinkbridge-logging-metrics

查询日志系统状态

POST

/actuator/thinkbridge-logging-metrics

手动触发 flush

响应示例
{
  "timestamp": "2026-08-13T10:30:00Z",
  "kafkaEnabled": true,
  "retryExecutor": {
    "activeThreads": 0,
    "poolSize": 1,
    "completedTasks": 1523,
    "failedLogsCount": 0
  }
}
敏感数据过滤

JsonLogEncoder 内置正则表达式过滤机制,对 excludeFields 中配置的字段进行匹配替换。

过滤规则
  • 对日志消息体中的 field: "value" 或 field=value 模式进行匹配

  • 匹配到的值替换为 [FILTERED]

  • 对 MDC 中的 key 做包含匹配,命中则替换 MDC value

  • 正则模式缓存,避免重复编译

过滤示例
原始日志: {"password": "abc123", "token": "eyJhbG..."}
过滤后:   {"password": "[FILTERED]", "token": "[FILTERED]"}
失败重试机制

发送失败时,KafkaLogProducer 会将失败消息加入内存队列,通过 ScheduledExecutorService 定时重试。

重试策略
  • 指数退避:delay = retryBackoffMs * 2^(attempt - 1),上限为 maxRetryBackoffMs

  • 随机抖动:延迟乘以 0.8~1.2 的随机因子,避免重试风暴

  • 最大重试次数:达到 maxRetries 后丢弃

  • 可重试异常:RetriableException、IOException、SocketException 等网络异常

优雅关闭

应用关闭时,ThinkBridgeKafkaAppenderConfigurer.stop() 会: . 停止接收新日志 . 等待队列中剩余日志发送完毕(最多 5 秒) . 关闭 Kafka producer . 关闭重试线程池

日志输出格式
JSON 格式示例
{
  "@timestamp": 1723536000000,
  "timestamp": "2026-08-13T10:30:00.000+00:00",
  "level": "INFO",
  "logger": "com.example.MyService",
  "message": "User login success",
  "thread": "http-nio-8080-exec-1",
  "app": "my-app",
  "env": "production",
  "host": "my-hostname",
  "ip": "192.168.1.100",
  "mdc": {
    "traceId": "abc123",
    "userId": "[FILTERED]"
  },
  "exception": {
    "class": "java.lang.RuntimeException",
    "message": "Something went wrong",
    "stacktrace": "java.lang.RuntimeException: Something went wrong\n    at ..."
  },
  "extra": {
    "pid": "12345",
    "instanceId": "i-abc123",
    "logTime": "2026-08-13T10:30:00.000Z"
  }
}
自定义 logback-spring.xml

默认无需自定义 logback-spring.xml,开箱即用。如需自定义:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="1 seconds">
    <contextName>logback</contextName>

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %highlight(%-5p) [%thread] %logger.%M\(%F:%L\) :[%X\{logType}] %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>
Kafka Appender 由 ThinkBridgeKafkaAppenderConfigurer 动态添加到 root logger,无需在 XML 中手动配置。通过 enabled 属性控制开关即可。

pulsar

基于 Apache Pulsar Client API 的日志收集模块,通过自定义 logback appender 将应用日志异步发送到 Pulsar。支持 JSON 编码、MDC 上下文传递、敏感数据过滤、失败重试和 Actuator 监控端点。

仓库坐标
Maven
<dependency>
    <groupId>com.luamas.thinkbridge</groupId>
    <artifactId>log-logback-pulsar-spring-boot-starter</artifactId>
</dependency>
Gradle
implementation("com.luamas.thinkbridge:log-logback-pulsar-spring-boot-starter")
架构说明

该模块通过 PulsarAppender(继承 UnsynchronizedAppenderBase)拦截 logback 日志事件,经 JsonLogEncoder 编码为 JSON 格式后,由 PulsarLogProducer 异步发送到 Pulsar。

核心组件

组件

说明

PulsarAppender

logback appender,负责日志事件的队列缓冲和批量发送

JsonLogEncoder

JSON 编码器,将日志事件转为结构化 JSON,支持敏感数据过滤

PulsarLogProducer

Pulsar 生产者,封装 PulsarClient/Producer,支持失败重试和指数退避

ThinkBridgePulsarAppenderConfigurer

动态配置器,实现 SmartLifecycle,启动时将 appender 挂载到 root logger

ThinkBridgeLoggingMetricsEndpoint

Actuator 端点,暴露重试线程池状态和失败日志数量

发送流程
logback 日志事件
  → PulsarAppender.append() 写入队列
  → 后台线程批量取出(最多 100 条/批)
  → JsonLogEncoder 编码为 JSON
  → PulsarLogProducer.send() 发送到 Pulsar
  → 发送失败? → 加入失败队列 → 指数退避重试(最多 3 次)
配置
think:
  logging:
    pulsar:
      enabled: true
      service-url: pulsar://localhost:6650
      topic: app-logs
      app-name: my-application
      environment: production
      send-timeout-ms: 30000
      max-pending-messages: 1000
      block-if-queue-full: false
      enable-batching: true
      batching-max-messages: 1000
      batching-max-publish-delay-ms: 10
      batching-max-bytes: 131072
      max-retries: 3
      retry-backoff-ms: 100
      max-retry-backoff-ms: 5000
      queue-size: 10000
      max-failed-logs-per-topic: 1000
      failed-logs-ttl-hours: 24
      include-mdc: true
      include-caller-data: false
      exclude-fields:
        - password
        - token
        - secret
        - key
      exclude-loggers:
        - org.apache.pulsar
        - org.springframework
      min-level: INFO
配置属性一览
基础配置

属性

默认值

说明

think.logging.pulsar.enabled

false

是否启用

think.logging.pulsar.service-url

pulsar://localhost:6650

Pulsar 服务地址

think.logging.pulsar.topic

app-logs

目标 topic

think.logging.pulsar.app-name

thinkBridge-app

应用名称

think.logging.pulsar.environment

default

运行环境

think.logging.pulsar.min-level

INFO

最低日志级别

Pulsar Producer 配置

属性

默认值

说明

think.logging.pulsar.send-timeout-ms

30000

发送超时(毫秒)

think.logging.pulsar.max-pending-messages

1000

最大待发送消息数

think.logging.pulsar.block-if-queue-full

false

队列满时是否阻塞

think.logging.pulsar.enable-batching

true

是否启用批量发送

think.logging.pulsar.batching-max-messages

1000

批量最大消息数

think.logging.pulsar.batching-max-publish-delay-ms

10

批量发送最大延迟(毫秒)

think.logging.pulsar.batching-max-bytes

131072

批量最大字节数(128KB)

重试配置

属性

默认值

说明

think.logging.pulsar.max-retries

3

最大重试次数

think.logging.pulsar.retry-backoff-ms

100

重试退避基准时间(毫秒)

think.logging.pulsar.max-retry-backoff-ms

5000

最大退避时间(毫秒)

队列配置

属性

默认值

说明

think.logging.pulsar.queue-size

10000

日志事件队列大小

think.logging.pulsar.max-failed-logs-per-topic

1000

每个 topic 最大失败日志缓存数

think.logging.pulsar.failed-logs-ttl-hours

24

失败日志存活时间(小时)

编码器配置

属性

默认值

说明

think.logging.pulsar.include-mdc

true

是否包含 MDC 上下文

think.logging.pulsar.include-caller-data

false

是否包含调用者信息

过滤配置

属性

默认值

说明

think.logging.pulsar.exclude-fields

password, token, secret, key

敏感字段过滤列表

think.logging.pulsar.exclude-loggers

org.apache.pulsar, org.springframework

排除的 logger 名称

自定义 logback-spring.xml
默认不需要自定义 logback-spring.xml,开箱即用即可。如果有自定义需求,按照如下配置。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>

    <appender name="PULSAR" class="com.luamas.thinkbridge.bootstarter.log.logback.pulsar.appender.PulsarAppender">
        <enabled>true</enabled>
        <topic>app-logs</topic>
        <serviceUrl>pulsar://localhost:6650</serviceUrl>
        <appName>my-application</appName>
        <environment>production</environment>
        <includeMdc>true</includeMdc>
        <includeCallerData>false</includeCallerData>
        <maxRetries>3</maxRetries>
        <queueSize>10000</queueSize>
    </appender>

    <root level="INFO">
        <appender-ref ref="PULSAR"/>
    </root>
</configuration>
日志输出格式(JSON)
{
  "@timestamp": 1692000000000,
  "timestamp": "2023-08-14T08:00:00.000Z",
  "level": "INFO",
  "logger": "com.example.MyService",
  "message": "User login successful",
  "thread": "http-nio-8080-exec-1",
  "app": "my-application",
  "env": "production",
  "host": "my-server",
  "ip": "192.168.1.100",
  "mdc": {
    "userId": "12345",
    "traceId": "abc-def-ghi"
  },
  "exception": null,
  "extra": {
    "pid": "1234",
    "logTime": "2023-08-14T08:00:00.123Z"
  }
}
敏感数据过滤

模块内置敏感数据过滤机制,默认过滤 password、token、secret、key 字段。

过滤前
User login: username=admin, password=123456, token=abc123
过滤后
User login: username=admin, password: "[FILTERED]", token: "[FILTERED]"
失败重试机制

发送失败时采用指数退避 + 随机抖动策略:

延迟 = min(baseDelay * 2^(attempt-1), maxDelay) * jitter(0.8~1.2)
重试 1: ~100ms
重试 2: ~200ms
重试 3: ~400ms

可重试的异常类型:PulsarClientException、TimeoutException、IOException、SocketException。

Actuator 监控端点
GET /actuator/thinkbridge-logging-metrics
{
  "timestamp": "2023-08-14T08:00:00.123Z",
  "pulsarEnabled": true,
  "retryExecutor": {
    "activeThreads": 0,
    "poolSize": 1,
    "completedTasks": 5,
    "failedLogsCount": 0
  }
}
POST /actuator/thinkbridge-logging-metrics

手动触发日志刷新,确保所有缓冲日志被发送。

rabbitmq

通过logback appender方式将日志直接发送到RabbitMQ,无需经过Spring事件机制。

仓库坐标
Maven
<dependency>
    <groupId>com.luamas.thinkbridge</groupId>
    <artifactId>log-logback-amqp-spring-boot-starter</artifactId>
</dependency>
Gradle
implementation("com.luamas.thinkbridge:log-logback-amqp-spring-boot-starter")
配置
think:
  log:
    receive:
      logback:
        amqp:
          # 是否启用,默认启用
          enabled: true
          # 是否异步发送,默认true
          async: true
          trace:
            # RabbitMQ主机
            host: 127.0.0.1
            # RabbitMQ端口
            port: 5672
            # 用户名
            username: guest
            # 密码
            password: guest
            # 虚拟主机
            virtual-host: /
            # 交换机名称
            exchange-name: thinkBridge-log
            # 交换机类型,默认topic
            exchange-type: topic
            # 交换机不存在时自动创建
            declare-exchange: true
            # 是否持久化
            durable: true
            # 是否自动删除
            auto-delete: false
配置属性一览

属性

默认值

说明

think.log.receive.logback.amqp.enabled

true

是否启用

think.log.receive.logback.amqp.async

true

是否异步发送

think.log.receive.logback.amqp.trace.host

空

RabbitMQ主机

think.log.receive.logback.amqp.trace.port

空

RabbitMQ端口

think.log.receive.logback.amqp.trace.username

空

用户名

think.log.receive.logback.amqp.trace.password

空

密码

think.log.receive.logback.amqp.trace.virtual-host

空

虚拟主机

think.log.receive.logback.amqp.trace.exchange-name

thinkBridge-log

交换机名称

think.log.receive.logback.amqp.trace.exchange-type

topic

交换机类型

think.log.receive.logback.amqp.trace.declare-exchange

true

交换机不存在时自动创建

think.log.receive.logback.amqp.trace.durable

true

是否持久化

think.log.receive.logback.amqp.trace.auto-delete

false

是否自动删除

默认不需要自定义 logback-spring.xml,开箱即用即可。如果有自定义需求,按照如下方式配置:
自定义logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="1 seconds">
    <contextName>logback</contextName>
    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
        <resetJUL>true</resetJUL>
    </contextListener>
	<!-- 这里一定要引入此配置,否则无法使用 -->
    <include resource="thinkbridge/logback-amqp-trace-log.xml" />

    <!-- 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %highlight(%-5p) [%thread] %logger.%M\(%F:%L\) :[%X\{logType}]
                %msg%n
            </pattern>
        </encoder>
    </appender>
    <!-- 关闭apache包信息-->
    <logger name="org.apache.catalina.core" level="OFF">
        <appender-ref ref="CONSOLE"/>
    </logger>
    <!-- 默认级别 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

最佳实践

logstash配置

以下配置示例中,<…​> 占位符需要替换为实际环境的值。

以下示例配置文件路径为 log-logback-kafka 模块下 thinkbridge/thinkbridge_trace_log_kafka-logstash.conf 。 rabbit具有同样的示例配置 thinkbridge/thinkbridge_trace_log_amqp-logstash.conf

logstash从kafka中收集链路日志

thinkbridge_trace_log_kafka-logstash.conf

input {
  kafka {
    bootstrap_servers => "<kafka-bootstrap-servers>"
    topics => ["<kafka-topic>"] # 订阅主题
    auto_offset_reset => "earliest" #从最早的偏移量开始消费
    group_id => "<consumer-group-id>" # 组id
    consumer_threads => 5
  }
}

filter {
  # 解析kafka message
  json {
    source => "message"
    remove_field => ["event","@version"]
  }

  mutate {
      add_field => { "messagetmp" => "%{message}" }
  }
  json {
      source => "messagetmp"
      remove_field => ["messagetmp", "message"]
  }

  mutate {
    rename => { "logType" => "log_type" }
  }

  mutate {
    add_field => { "[@metadata][log_type]" => "%{log_type}" }
    add_field => { "[@metadata][application_name]" => "%{application_name}" }
  }

  mutate {
    lowercase => ["[@metadata][log_type]", "[@metadata][application_name]"]
  }
  mutate {
    remove_field => ["@timestamp"]
    rename => { "start_time" => "@timestamp" }
  }
}

output {
  elasticsearch {
    hosts => ["<elasticsearch-host>"]
    index => "thinkbridge-trace-%{[@metadata][application_name]}-%{[@metadata][log_type]}"
    user => "<elasticsearch-username>" #用户名
    password => "<elasticsearch-password>" #密码
    # for data stream
    # action => "create" #这里如果使用es的 stream滚动收集需要打开此注释
  }
}
logstash从rabbitmq中收集链路日志

thinkbridge_trace_log_amqp-logstash.conf

input {
  rabbitmq{
      host=>"<rabbitmq-host>"                # 这里填写Rabbitmq的地址,确保可以ping通
      port=> 15672                            # 这里填写Rabbitmq的端口
      user=>"<rabbitmq-username>"                          # 这里填写Rabbitmq的用户名
      password=>"<rabbitmq-password>"                      # 这里填写Rabbitmq的密码
      exchange => "<rabbitmq-exchange>"      # 这里填写Rabbitmq的交换机的名称
      key => "<routing-key>"                   #路由键
      queue=>"<rabbitmq-queue>"                     # 这里填写Rabbitmq的队列的名称
      durable=> true                         # 这里填写Rabbitmq的队列的durable属性
      codec=>json                            # 这里填写Rabbitmq的队列的内容是什么格式
     }
}

filter {
  # 解析rabbitmq message
  json {
    source => "message"
    remove_field => ["event","@version"]
  }

  mutate {
      add_field => { "messagetmp" => "%{message}" }
  }
  json {
      source => "messagetmp"
      remove_field => ["messagetmp", "message"]
  }

  mutate {
    rename => { "logType" => "log_type" }
  }

  mutate {
    add_field => { "[@metadata][log_type]" => "%{log_type}" }
    add_field => { "[@metadata][application_name]" => "%{application_name}" }
  }

  mutate {
    lowercase => ["[@metadata][log_type]", "[@metadata][application_name]"]
  }
  mutate {
    remove_field => ["@timestamp"]
    rename => { "start_time" => "@timestamp" }
  }
}

output {
  elasticsearch {
    hosts => ["<elasticsearch-host>"]
    index => "thinkbridge-trace-%{[@metadata][application_name]}-%{[@metadata][log_type]}"
    user => "<elasticsearch-username>"
    password => "<elasticsearch-password>"
    # for data stream
    # action => "create"
  }
}

OpenSearch接入(Data Prepper)

Data Prepper 是 OpenSearch 官方推荐的服务器端数据采集工具,用于替代 Logstash 将日志数据注入 OpenSearch。它使用声明式 YAML pipeline 配置,更加轻量和高效。

以下示例配置文件路径为 log-logback-kafka 模块下 thinkbridge/thinkbridge_trace_log_kafka-data-prepper.yaml 。

Data Prepper从kafka中收集链路日志到OpenSearch

thinkbridge_trace_log_kafka-data-prepper.yaml

entry-pipeline:
  source:
    kafka:
      bootstrap_servers: "<kafka-bootstrap-servers>" # Kafka服务器地址
      topics:
        - name: "<kafka-topic>" # 订阅主题
      group_id: "<consumer-group-id>" # 组id
      auto_offset_reset: earliest # 从最早的偏移量开始消费
  processor:
    - parse_json:
        source: message # 解析kafka原始消息
    - delete_entries:
        with_keys:
          - event
          - "@version"
    - parse_json:
        source: message # 二次解析message字段
    - delete_entries:
        with_keys:
          - message
    - rename_keys:
        entries:
          - from_key: logType # 重命名logType为log_type
            to_key: log_type
    - lowercase_string:
        with_keys:
          - log_type
          - application_name
    - date:
        from_time_received: false
        destination: "@timestamp"
        source: start_time
        date_when: null
  sink:
    - opensearch:
        hosts:
          - "<opensearch-host>" # OpenSearch地址,例如 https://localhost:9200
        index: thinkbridge-trace-${application_name}-${log_type}
        username: "<opensearch-username>" # 用户名
        password: "<opensearch-password>" # 密码
Data Prepper从rabbitmq中收集链路日志到OpenSearch

thinkbridge_trace_log_amqp-data-prepper.yaml

entry-pipeline:
  source:
    rabbitmq:
      host: "<rabbitmq-host>" # Rabbitmq地址
      port: 5672 # Rabbitmq端口
      username: "<rabbitmq-username>" # Rabbitmq用户名
      password: "<rabbitmq-password>" # Rabbitmq密码
      exchange: "<rabbitmq-exchange>" # 交换机名称
      routing_key: "<routing-key>" # 路由键
      queue: "<rabbitmq-queue>" # 队列名称
      durable: true # 队列持久化
  processor:
    - parse_json:
        source: message # 解析rabbitmq原始消息
    - delete_entries:
        with_keys:
          - event
          - "@version"
    - parse_json:
        source: message # 二次解析message字段
    - delete_entries:
        with_keys:
          - message
    - rename_keys:
        entries:
          - from_key: logType # 重命名logType为log_type
            to_key: log_type
    - lowercase_string:
        with_keys:
          - log_type
          - application_name
    - date:
        from_time_received: false
        destination: "@timestamp"
        source: start_time
        date_when: null
  sink:
    - opensearch:
        hosts:
          - "<opensearch-host>" # OpenSearch地址,例如 https://localhost:9200
        index: thinkbridge-trace-${application_name}-${log_type}
        username: "<opensearch-username>" # 用户名
        password: "<opensearch-password>" # 密码
logstash从pulsar中收集链路日志
input {
  pulsar {
    service_url => "<pulsar-service-url>" # Pulsar服务地址,例如 pulsar://localhost:6650
    topics => ["<pulsar-topic>"] # 订阅主题
    subscription_name => "<subscription-name>" # 订阅名称
    consumer_name => "logstash-consumer"
    ack_timeout => "30000"
  }
}

filter {
  json {
    source => "message"
    remove_field => ["event","@version"]
  }

  mutate {
      add_field => { "messagetmp" => "%{message}" }
  }
  json {
      source => "messagetmp"
      remove_field => ["messagetmp", "message"]
  }

  mutate {
    rename => { "logType" => "log_type" }
  }

  mutate {
    add_field => { "[@metadata][log_type]" => "%{log_type}" }
    add_field => { "[@metadata][application_name]" => "%{application_name}" }
  }

  mutate {
    lowercase => ["[@metadata][log_type]", "[@metadata][application_name]"]
  }
  mutate {
    remove_field => ["@timestamp"]
    rename => { "start_time" => "@timestamp" }
  }
}

output {
  elasticsearch {
    hosts => ["<elasticsearch-host>"]
    index => "thinkbridge-trace-%{[@metadata][application_name]}-%{[@metadata][log_type]}"
    user => "<elasticsearch-username>"
    password => "<elasticsearch-password>"
  }
}
Data Prepper从pulsar中收集链路日志到OpenSearch
entry-pipeline:
  source:
    pulsar:
      service_url: "<pulsar-service-url>" # Pulsar服务地址
      topics:
        - name: "<pulsar-topic>" # 订阅主题
      subscription_name: "<subscription-name>" # 订阅名称
  processor:
    - parse_json:
        source: message # 解析pulsar原始消息
    - delete_entries:
        with_keys:
          - event
          - "@version"
    - parse_json:
        source: message # 二次解析message字段
    - delete_entries:
        with_keys:
          - message
    - rename_keys:
        entries:
          - from_key: logType # 重命名logType为log_type
            to_key: log_type
    - lowercase_string:
        with_keys:
          - log_type
          - application_name
    - date:
        from_time_received: false
        destination: "@timestamp"
        source: start_time
        date_when: null
  sink:
    - opensearch:
        hosts:
          - "<opensearch-host>" # OpenSearch地址
        index: thinkbridge-trace-${application_name}-${log_type}
        username: "<opensearch-username>"
        password: "<opensearch-password>"