如何在Spring Cloud Sleuth中新增client_ip等自定义标签并透传至下游微服务
实现步骤
1. API网关(Spring Cloud Gateway)侧配置
1.1 新增Sleuth Baggage配置
在网关的application.yml中添加如下配置,声明要传递的自定义字段:
spring: sleuth: baggage: # 允许跨服务传递的自定义字段 remote-fields: client_ip # 自动将该字段加入MDC,输出到日志标签 tag-fields: client_ip
注:如果使用Sleuth 2.x版本,配置改为spring.sleuth.propagation-keys: client_ip即可
1.2 编写全局过滤器采集客户端IP
实现优先级高于路由转发的全局过滤器,获取真实客户端IP后注入Sleuth链路上下文:
@Component @Order(Ordered.HIGHEST_PRECEDENCE + 1) // 优先级低于Sleuth链路创建过滤器,高于路由转发 public class ClientIpInjectFilter implements GlobalFilter { private final Tracer tracer; public ClientIpInjectFilter(Tracer tracer) { this.tracer = tracer; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 获取真实客户端IP,处理反向代理场景 String clientIp = exchange.getRequest().getHeaders().getFirst("X-Forwarded-For"); if (clientIp == null || clientIp.isEmpty() || "unknown".equalsIgnoreCase(clientIp)) { clientIp = exchange.getRequest().getHeaders().getFirst("Proxy-Client-IP"); } if (clientIp == null || clientIp.isEmpty() || "unknown".equalsIgnoreCase(clientIp)) { clientIp = exchange.getRequest().getHeaders().getFirst("WL-Proxy-Client-IP"); } if (clientIp == null || clientIp.isEmpty() || "unknown".equalsIgnoreCase(clientIp)) { clientIp = Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getAddress().getHostAddress(); } // 多个代理场景取第一个IP为真实客户端IP if (clientIp != null && clientIp.contains(",")) { clientIp = clientIp.split(",")[0].trim(); } // 将client_ip注入Sleuth Baggage上下文 tracer.createBaggageInScope(tracer.currentSpan().context(), "client_ip", clientIp); return chain.filter(exchange); } }
2. 下游微服务配置
所有需要获取client_ip标签的下游微服务,都需要添加和网关一致的Baggage配置:
spring: sleuth: baggage: remote-fields: client_ip tag-fields: client_ip
配置完成后Sleuth会自动从请求头中解析上游传递的client_ip,自动注入MDC上下文,不需要额外编码。
3. 日志格式适配
在你的日志输出pattern中添加%X{client_ip}占位符即可将client_ip输出到日志中,示例logback pattern:
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} [%X{traceId},%X{spanId},%X{client_ip}] - %msg%n</pattern>
注意事项
- Feign、Spring管理的RestTemplate默认会自动携带Baggage字段传递到下游,不需要额外配置
- 如果你的网关是Zuul,逻辑和上述方案一致,只需要将全局过滤器替换为Zuul的前置过滤器即可
- 生产环境建议对采集到的client_ip做合法性校验,避免恶意构造的请求头导致IP异常
内容的提问来源于stack exchange,提问作者chuanguojinbo
相关产品推荐
相关产品推荐

