ELK-traceId实现跨服务日志追踪
目录
ELK traceId实现跨服务日志追踪
在使用ELK(Elasticsearch, Logstash, Kibana)进行日志管理时,通过
traceId
实现日志跟踪是一种常见的做法。
traceId
可以帮助我们在分布式系统中追踪请求的完整链路。通过Spring的
HandlerInterceptor
,我们可以在请求进入时生成
traceId
,并将其传递到日志中。
实现思路
- 生成
traceId
:在请求进入时生成一个唯一的traceId
,并将其存储在MDC
(Mapped Diagnostic Context)中。 - 传递
traceId
:在请求处理过程中,确保traceId
能够传递到各个组件和日志中。 - 清理
traceId
:在请求处理完成后,清理MDC
中的traceId
,避免内存泄漏。
代码实现
1. 创建 TraceIdInterceptor
首先,我们需要创建一个
HandlerInterceptor
实现类,用于在请求进入时生成
traceId
,并在请求完成后清理
traceId
。
java
复制
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
@Component
public class TraceIdInterceptor implements HandlerInterceptor {
private static final String TRACE_ID = "traceId";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 生成唯一的traceId
String traceId = UUID.randomUUID().toString();
// 将traceId放入MDC
MDC.put(TRACE_ID, traceId);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 请求完成后清理MDC中的traceId
MDC.remove(TRACE_ID);
}
}
2. 注册 TraceIdInterceptor
接下来,我们需要将
TraceIdInterceptor
注册到Spring的拦截器链中。
java
复制
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private TraceIdInterceptor traceIdInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(traceIdInterceptor);
}
}
3. 配置日志输出 traceId
在日志配置文件中,配置日志输出格式,确保
traceId
能够被打印出来。以
logback.xml
为例:
xml
复制
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - [%X{traceId}] %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>
运行 HTML
在这个配置中,
%X{traceId}
会从
MDC
中获取
traceId
并输出到日志中。
4. 在代码中使用 traceId
在业务代码中,你可以通过
MDC
获取
traceId
,并将其传递到其他服务或日志中。
java
复制
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
private static final Logger logger = LoggerFactory.getLogger(MyController.class);
@GetMapping("/test")
public String test() {
// 获取traceId
String traceId = MDC.get("traceId");
logger.info("Processing request with traceId: {}", traceId);
return "Hello, World!";
}
}
总结
通过上述步骤,我们实现了一个简单的
traceId
日志跟踪系统。
HandlerInterceptor
在请求进入时生成
traceId
并将其放入
MDC
,在请求完成后清理
MDC
。日志配置确保
traceId
能够被输出到日志中,从而方便我们在ELK中追踪请求的完整链路。
扩展
- 分布式系统中的
traceId
传递 :在微服务架构中,traceId
需要在服务之间传递。可以通过HTTP头、消息队列等方式传递traceId
。 - 异步任务中的
traceId
:在异步任务中,traceId
可能会丢失。可以通过自定义线程池或使用TaskDecorator
来确保traceId
在异步任务中传递。
通过这些扩展,你可以在更复杂的系统中实现全链路的日志跟踪。