Spring Cloud 下的分布式日志追踪
程序员文章站
2022-07-03 12:34:49
...
概要
本文是《基于 ELK6.6 + Filebeat 的 Spring Cloud 日志收集》的续集(文末有链接),是在该篇文章的基础上进行的。
分布式环境下,我看查看一条日志,希望同时能看到与之相关的上下文关系,比如上一步是哪一个服务过来的,都有些什么参数。在ELK的基础上其实也能实现,就找对应时间前后很短时间内的日志,基本都是相关的,但还是得筛选,当日志的量越来越大,筛选就会变得越来越难。
本文会介绍作者当前正使用的一种方式,大概思路如下:
- 请求到达网关时,添加 traceId 到 Header 中
- 服务收到请求时,取出 traceId ,并生成一个 requestId ,然后把它们都加到 MDC(Logback中用于追踪记录日志的,后面会介绍) 中
- 服务在需要调用其他服务时,保证 traceId 添加到 Header 中。
- 配置 logback,将 MDC 中添加的两个键输出到 json 日志中。
- Kibana 中刷新对应的索引配置。
实现过程
处理网关
本人使用 Spring Cloud Gateway
在全局过滤器 GlobalFilter 中,添加 Header 信息:
@Bean
@Order(-1)
public GlobalFilter a() {
return (exchange, chain) -> {
/* 其他处理代码 */
val traceId = UUID.randomUUID().toString().replace("-", "");
return chain.filter(exchange.mutate().request(exchange.getRequest().mutate().header("X-TraceId", traceId).build()).build());
};
}
服务处理请求
这里使用一个切面就可以实现了:
/**
* 基础接口切面
*/
@Slf4j
@Aspect
@Configuration
public class ApiHelperAutoConfigure {
// API接口调用切面配置 注意:这里配置要切的Controller方法
@Pointcut("execution(com.*(..))")
public void executeForAPI() {
}
/**
* 环绕通知
*/
@Around("executeForAPI()")
public Object aroundExecuteForAPI(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
val requestAttributes = RequestContextHolder.getRequestAttributes();
val request = (HttpServletRequest) (requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST));
MDC.put("traceId", request.getHeader("X-TraceId"));
MDC.put("requestId", UUID.randomUUID().toString().replace("-", ""));
/* 其他处理 */
Object body = proceedingJoinPoint.proceed(args);
/* 其他处理 */
return body;
}
}
上面代码只贴出了核心部分,直接复制粘贴可能会出问题。
服务间的调用
Spring Cloud 中的服务调用默认是使用的 Feign,对其配置即可:
@Configuration
public class FeignConfig implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("X-TraceId", MDC.get("traceId"));
}
}
配置Logback
相关的核心配置如下:
<property name="app.name" value="service-myService"/>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/home/logs/${app.name}.json</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/home/logs/${app.name}/%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>90</maxHistory>
<totalSizeCap>200GB</totalSizeCap>
</rollingPolicy>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"app":"${app.name}"}}</customFields>
<includeMdcKeyName>traceId</includeMdcKeyName>
<includeMdcKeyName>requestId</includeMdcKeyName>
</encoder>
</appender>
includeMdcKeyName 是用于包含 MDC 中的内容的
customFields 用于添加自定义字段
处理 Kibana
位置:主页 -> Management -> Kibana(Index Patterns) -> 对应的 Index Patterns -> 刷新。
也可以找到对应的字段,增加 Popularity 值,这样就能更快的找到该值。
扩展
MDC
MDC 是日志框架下用于线程日志追踪的工具,使用 ThreadLocal 实现:
final ThreadLocal<Map<String, String>> copyOnThreadLocal = new ThreadLocal<Map<String, String>>();
MDC 使用起来类似一个 Map,核心方法为 put、 get、 clear等。
在 logback 配置文件中可以直接引用。
链接
推荐阅读
-
Spring Cloud分布式微服务实战,养成应对复杂业务的综合技术能力
-
利用Spring Cloud Config结合Bus实现分布式配置中心的步骤
-
详解spring cloud config整合gitlab搭建分布式的配置中心
-
Spring Cloud微服务架构的构建:分布式配置中心(加密解密功能)
-
利用Spring Cloud Config结合Bus实现分布式配置中心的步骤
-
详解spring cloud config整合gitlab搭建分布式的配置中心
-
spring cloud config分布式配置中心的高可用问题
-
Spring Cloud微服务架构的构建:分布式配置中心(加密解密功能)
-
Spring Cloud下使用Feign Form实现微服务之间的文件上传
-
spring cloud 入门系列七:基于Git存储的分布式配置中心--Spring Cloud Config