ThinkBridge的日志模块主要是收集了服务内的链路日志,包括访问日志、Feign日志、操作日志、JDBC日志和Messaging日志。日志支持通过Kafka、RabbitMQ或Pulsar进行收集。
| 模块引入后无需其他配置即可立即使用。 |
架构概览
日志类型
日志类型 |
事件类 |
日志模型 |
说明 |
AccessLog |
|
|
HTTP访问日志,同时兼容MVC和WebFlux |
FeignLog |
|
|
Feign调用日志,仅支持MVC |
OperationLog |
|
|
操作日志,依赖AOP |
JdbcLog |
|
|
SQL执行日志,依赖p6spy |
MessageProducerLog |
|
|
消息生产者日志,依赖Spring Integration |
MessageConsumerLog |
|
|
消息消费者日志,依赖Spring Integration |
日志模型公共字段
所有日志模型均继承自 AbstractMessageLog,包含以下公共字段:
字段 |
说明 |
|
链路追踪ID |
|
父链路追踪ID |
|
来源应用名称 |
|
父来源应用名称 |
|
来源应用激活环境 |
|
父来源应用激活环境 |
|
操作人(需实现 |
|
主机名称 |
|
线程名称 |
|
开始时间 |
|
执行时长(毫秒) |
|
是否成功 |
|
异常堆栈追踪 |
|
扩展数据(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 事件机制,整体事件流如下:
环节 |
说明 |
日志采集 |
通过拦截器(如 |
日志构建 |
采集的数据被封装为对应的日志模型(如 |
事件处理 |
|
日志收集 |
通过标准收集(Spring 事件 → 消息中间件)或 logback 收集(Appender → 消息中间件)将日志发送到目标系统 |
各日志类型的采集方式:
日志类型 |
采集方式 |
访问日志 |
|
Feign日志 |
|
操作日志 |
|
JDBC日志 |
|
Messaging日志 |
|
自动配置
自动配置类为 ThinkBridgeLogAutoConfiguration,当 think.log.producer.enabled=true(默认为true)时自动生效。
该配置类会根据条件自动导入以下子配置:
配置类 |
说明 |
|
公共日志配置,注册 |
|
MDC日志配置,同时支持MVC和WebFlux |
|
访问日志配置,同时支持MVC和WebFlux |
|
操作日志配置,依赖AOP |
|
JDBC日志配置,依赖p6spy |
|
消息日志配置,依赖Spring Integration |
|
Feign日志配置,仅支持MVC |
|
OkHttp3日志配置,自动为OkHttpClient注入日志拦截器(需引入okhttp3依赖) |
扩展点
全局配置
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地址 |
|
用户代理 |
|
请求URI |
|
HTTP方法 |
|
请求参数 |
|
请求Body |
|
请求ContentType |
|
请求Header(Map) |
|
业务状态码 |
|
响应ContentType |
|
HTTP响应状态码 |
|
响应Body |
依赖
访问日志模块依赖 MVC 或 WebFlux 模块,根据项目类型选择对应的依赖:
处理日志
| 如果引用了模块的收集装置,无需手动编写事件监听器。 |
如果需要在代码中手动处理日志事件,可以通过 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 |
|
HTTP方法 |
|
主机名称 |
|
请求Body |
|
请求Header(Map<String, Collection<String>>) |
|
请求ContentType |
|
响应ContentType |
|
HTTP响应状态码 |
|
响应Body |
依赖
Feign 日志模块需要依赖 OpenFeign,请确保项目中已引入:
OkHttp3 支持
除了 Feign 调用外,框架还提供了 OkHttp3RequestLogInterceptor 用于拦截 OkHttp3 的 HTTP 请求,生成 RequestLog 日志。
com.luamas.thinkbridge.common.log.request.okhttp.OkHttp3RequestLogInterceptor
自动生效(推荐)
如果项目中使用了 log-spring-boot-starter,当容器中存在 OkHttpClient Bean 时,框架通过 OkHttp3LogBeanPostProcessor(BeanPostProcessor 机制)自动为已有的 OkHttpClient 实例注入日志拦截器,无需任何手动配置。
原理说明:
-
拦截
OkHttpClientBean 的初始化过程 -
通过
OkHttpClient.newBuilder()克隆原实例,保留原所有配置 -
追加
OkHttp3RequestLogInterceptor后生成新的 OkHttpClient 实例 -
对已注入到其他 Bean 的引用透明
| 即使你自行创建了 OkHttpClient Bean(配置了自定义超时、代理等),BeanPostProcessor 也会自动包装该 Bean 追加拦截器,无需手动添加 OkHttp3RequestLogInterceptor。所有请求只会被记录一次,不会重复。 |
处理日志
| 如果引用了模块的收集装置,无需手动编写事件监听器。 |
如果需要在代码中手动处理日志事件,可以通过 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.enabled |
true |
是否启用JDBC日志 |
think.log.producer.jdbc.name |
JdbcLog |
日志类型名称 |
JdbcLog 模型字段
除公共字段外,JdbcLog 还包含以下特有字段:
字段 |
说明 |
|
数据库连接URL |
|
编译语句(预编译SQL) |
|
执行语句(带参数值的完整SQL) |
依赖
JDBC 日志模块依赖 P6Spy 包。关于 P6Spy 的配置属性请参考 P6Spy 文档。
日志扩展
框架提供了 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();
}
}
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,除公共字段外还包含以下特有字段:
字段 |
说明 |
|
消息主题 |
|
消息体 |
|
消息头信息(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 机制实现:
操作日志
操作日志通过 @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 还包含以下特有字段:
字段 |
说明 |
|
日志描述信息 |
|
日志标识,用于唯一标识某个操作 |
|
方法所在类名 |
|
方法名称 |
|
操作提交的数据(Map<String, String>) |
|
返回结果 |
|
操作类型(见OperationType枚举) |
@OPLog 注解
com.luamas.thinkbridge.common.log.operation.annotation.OPLog
属性 |
默认值 |
说明 |
type |
无(必填) |
操作类型,见 OperationType 枚举 |
msg |
"" |
日志描述信息 |
psi |
"" |
日志标识,用于唯一标识某个操作 |
使用
基本用法
@Service
public class HomeService {
@OPLog(type = OperationType.OTHER, msg = "首页")
public void home(String p) {
System.out.println("访问");
}
}
快捷注解
框架提供了基于 @OPLog 的快捷注解,无需手动指定 type:
快捷注解 |
对应 OperationType |
说明 |
|
CREATE |
新建操作 |
|
READ |
查看操作 |
|
UPDATE |
修改操作 |
|
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主题。
仓库坐标
配置
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交换机。
仓库坐标
配置
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主题。
仓库坐标
配置
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
方法 |
说明 |
|
发布日志事件,日志类型取自 |
|
发布日志事件,并指定日志类型 |
发送事件时,框架会自动补全 hostname、traceId、applicationName、activeProfiles 等公共字段(仅当 MDC 中不存在时才补全)。
|
内置事件类型
LogEvent 是抽象类,不能直接实例化,需使用以下内置子类:
事件类 |
模型类 |
说明 |
|
|
操作日志 |
|
|
访问日志 |
|
|
JDBC 日志 |
|
|
消息生产者日志 |
|
|
消息消费者日志 |
|
|
请求日志 |
使用
注入 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
}
}
自定义日志类型
如需发送完全自定义的日志,可自行实现 MessageLog(或继承 AbstractMessageLog)并定义对应的 LogEvent 子类。
注意事项
-
手动发送走的是 Spring 事件机制,需引入标准收集模块(
log-kafka-spring-boot-starter、log-amqp-spring-boot-starter或log-pulsar-spring-boot-starter)才会有监听器将事件转发到消息中间件。若仅引入log-logback-*模块(logback appender 方式),手动发送的日志不会被转发。 -
LogEvent是抽象类,不能直接new LogEvent(),需使用内置子类或自定义子类。 -
默认日志类型为模型类的简单类名(由
MessageLog.getLogType()返回),可通过publishEvent(event, logType)覆盖。 -
手动发送的日志不经过框架的
BuildHandler,因此operator(操作人)等字段不会被自动填充,如需记录请在发送前手动设置。
logback
logback收集方式通过自定义logback appender,直接将日志发送到消息中间件,无需经过Spring事件机制。支持Kafka(含Kafka Producer API v4)、Pulsar和RabbitMQ三种消息中间件。
kafka
通过logback appender方式将日志直接发送到Kafka,无需经过Spring事件机制。
仓库坐标
配置
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 监控端点。
仓库坐标
架构说明
该模块通过 KafkaAppender(继承 UnsynchronizedAppenderBase)拦截 logback 日志事件,经 JsonLogEncoder 编码为 JSON 格式后,由 KafkaLogProducer 异步发送到 Kafka。
核心组件
组件 |
说明 |
|
logback appender,负责日志事件的队列缓冲和批量发送 |
|
JSON 编码器,将日志事件转为结构化 JSON,支持敏感数据过滤 |
|
Kafka 生产者,封装 KafkaTemplate,支持失败重试和指数退避 |
|
动态配置器,实现 SmartLifecycle,启动时将 appender 挂载到 root logger |
|
Actuator 端点,暴露重试线程池状态和失败日志数量 |
配置
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 |
失败日志缓存过期时间(小时) |
Actuator 监控端点
引入 spring-boot-actuator 后,自动暴露 /actuator/thinkbridge-logging-metrics 端点。
敏感数据过滤
JsonLogEncoder 内置正则表达式过滤机制,对 excludeFields 中配置的字段进行匹配替换。
失败重试机制
发送失败时,KafkaLogProducer 会将失败消息加入内存队列,通过 ScheduledExecutorService 定时重试。
日志输出格式
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 监控端点。
仓库坐标
架构说明
该模块通过 PulsarAppender(继承 UnsynchronizedAppenderBase)拦截 logback 日志事件,经 JsonLogEncoder 编码为 JSON 格式后,由 PulsarLogProducer 异步发送到 Pulsar。
核心组件
组件 |
说明 |
|
logback appender,负责日志事件的队列缓冲和批量发送 |
|
JSON 编码器,将日志事件转为结构化 JSON,支持敏感数据过滤 |
|
Pulsar 生产者,封装 PulsarClient/Producer,支持失败重试和指数退避 |
|
动态配置器,实现 SmartLifecycle,启动时将 appender 挂载到 root logger |
|
Actuator 端点,暴露重试线程池状态和失败日志数量 |
配置
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 |
失败日志存活时间(小时) |
自定义 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"
}
}
rabbitmq
通过logback appender方式将日志直接发送到RabbitMQ,无需经过Spring事件机制。
仓库坐标
配置
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>"