惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
N
News and Events Feed by Topic
Latest news
Latest news
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Threatpost
The Hacker News
The Hacker News
T
The Exploit Database - CXSecurity.com
S
Schneier on Security
Cisco Talos Blog
Cisco Talos Blog
Hacker News: Ask HN
Hacker News: Ask HN
Simon Willison's Weblog
Simon Willison's Weblog
W
WeLiveSecurity
H
Hacker News: Front Page
L
LINUX DO - 热门话题
T
Tor Project blog
N
News | PayPal Newsroom
S
Secure Thoughts
小众软件
小众软件
Recent Commits to openclaw:main
Recent Commits to openclaw:main
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
AWS News Blog
AWS News Blog
Security Latest
Security Latest
MyScale Blog
MyScale Blog
Webroot Blog
Webroot Blog
Cyberwarzone
Cyberwarzone
Engineering at Meta
Engineering at Meta
腾讯CDC
T
Tailwind CSS Blog
SecWiki News
SecWiki News
博客园 - 司徒正美
Microsoft Azure Blog
Microsoft Azure Blog
P
Palo Alto Networks Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
B
Blog RSS Feed
大猫的无限游戏
大猫的无限游戏
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Martin Fowler
Martin Fowler
P
Proofpoint News Feed
GbyAI
GbyAI
C
Check Point Blog
博客园_首页
PCI Perspectives
PCI Perspectives
月光博客
月光博客
TaoSecurity Blog
TaoSecurity Blog
aimingoo的专栏
aimingoo的专栏
酷 壳 – CoolShell
酷 壳 – CoolShell
IT之家
IT之家

博客园 - wastonl

Spring异步任务和定时任务 Spring ResolvableType说明 Jvm内存以及垃圾回收相关知识 RocketMQ如何保证消息可靠性 RocketMQ整体架构 mybatis-plus易忘点笔记 SpringMVC使用Resource实现二进制传输(下载) Spring事件异步执行设计与实现 Spring Bean销毁机制 Spring Lifecycle组件 Zipkin Brave使用 Spring Boot日志系统简要介绍 Spring懒加载与@Lazy注解 tomcat自动刷新响应输出流缓冲区 https碎碎念 ES脚本使用 SpringMVC静态资源处理 Maven插件运行方式 如何使用Maven将项目中的依赖打进jar包 时区以及时区对于Java时间类格式化的影响 SpringMVC处理请求头、响应头、编码行为 tomcat连接处理机制和线程模型 树组件实现 JWT示例与原理 方法句柄API使用
spring cloud sleuth基本使用
wastonl · 2026-01-12 · via 博客园 - wastonl

概述

Spring Cloud Sleuth是Spring Boot 2.x的分布式链路追踪组件,不适用于Spring Boot 3。它的底层是zipkin的brave。

基本使用

只需要在pom中引入spring-cloud-sleuth-starter,你便可以获得链路追踪能力。

  • 默认的日志打印格式,包含traceId、spanId
# 其中service-producer为service name, 取值spring.application.name
# ba3ca79a343923b7为traceId
# 761f1e8c321706bb为spanId
2026-01-12 21:12:50.321  INFO [service-producer,ba3ca79a343923b7,761f1e8c321706bb] 89772 --- [nio-9081-exec-1] c.w.producer.controller.UserController   : =============get=============
  • 自动整合Spring cloud open feign、RestTemplate,使用它们发送请求时会携带traceId、spanId等头部,用于给链路的下一环节使用。

  • 自动装饰Executor(JDK)、TaskExecutor(Spring)线程池,线程池必须注册到容器中才能被代理。

  • spring cloud gateway中使用有局限性

@Slf4j
@Component
public class LogFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String requestUrl = exchange.getRequest().getURI().getPath();
        log.info("request url: {}", requestUrl);
        return chain.filter(exchange);
    }

    /**
     * 必须放在ReactiveLoadBalancerClientFilter之前执行
     * 从nacos注册中心获取实例时会切换线程到boundedElastic-1
     * 导致traceContext丢失
     */
    @Override
    public int getOrder() {
        return ReactiveLoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER - 1;
    }
}

底层原理

自动配置类

BraveAutoConfiguration,会自动配置一些Brave的对象,比如Tracing、Tracer等

默认日志实现

TraceEnvironmentPostProcessor

@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
    Map<String, Object> map = new HashMap<String, Object>();
    // This doesn't work with all logging systems but it's a useful default so you see
    // traces in logs without having to configure it.
    if (Boolean.parseBoolean(environment.getProperty("spring.sleuth.enabled", "true"))) {
        if (Boolean
                .parseBoolean(environment.getProperty("spring.sleuth.default-logging-pattern-enabled", "true"))) {
            map.put("logging.pattern.level", "%5p [${spring.zipkin.service.name:"
                    + "${spring.application.name:}},%X{traceId:-},%X{spanId:-}]");
        }
        String neverRefereshables = environment.getProperty("spring.cloud.refresh.never-refreshable",
                "com.zaxxer.hikari.HikariDataSource");
        map.put("spring.cloud.refresh.never-refreshable",
                neverRefereshables + ",org.springframework.cloud.sleuth.instrument.jdbc.DataSourceWrapper");
    }
    addOrReplace(environment.getPropertySources(), map);
}

可以看到它改写了logging.pattern.level属性,在日志等级后面拼接了serveName、traceId、spanId。

而对于logging.pattern.level属性,Spring Boot会把环境中的这个属性写到Jvm系统属性中LOG_LEVEL_PATTERN(注意这里${}还是spring取变量的语法,不是logback的,会进行变量替换再写到Jvm系统属性中),这样logback日志配置文件可以直接使用这个变量了,Spring Boot默认的日志配置文件为defaults.xml,该文件就用到了这个系统属性变量。

异步线程池包装

ExecutorBeanPostProcessor

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (!ExecutorInstrumentor.isApplicableForInstrumentation(bean)) {
        return bean;
    }
    return new ExecutorInstrumentor(() -> sleuthAsyncProperties().getIgnoredBeans(), this.beanFactory)
            .instrument(bean, beanName);
}

/**
 * 只要是Executor的子类(去掉包装后的类型)都会进行包装
 */
public static boolean isApplicableForInstrumentation(Object bean) {
    return bean instanceof Executor && !(bean instanceof LazyTraceThreadPoolTaskExecutor
            || bean instanceof TraceableScheduledExecutorService || bean instanceof TraceableExecutorService
            || bean instanceof LazyTraceAsyncTaskExecutor || bean instanceof LazyTraceExecutor);
}

Open feign或者RestTemplate

调用下游时会自动添加相关头部

x-b3-parentspanid: [64dbb232e0c0ce25]
x-b3-sampled: [0]
x-b3-spanid: [c212e696bd8d5a56]
x-b3-traceid: [042125a08fb299ad]

高级使用

传递业务逻辑字段

在当前jvm内部传递,可以使用baggage local fields,不同进程之间传递,使用baggage remote fields

baggage意为行李。

remote fields需要上下游两个服务都配置

spring:
  sleuth:
    baggage:
      remote-fields:
        - userId
        - userName

上游服务传递值

// 往下游传递userId
BaggageField.getByName("userId").updateValue("123456");
// 往下游传递userName
BaggageField.getByName("userName").updateValue("zhangsan");
// 使用open feign调用下游服务

下游服务自动接收值

String userId = BaggageField.getByName("userId").getValue();
String userName = BaggageField.getByName("userName").getValue();

代码示例

https://github.com/wangtaoj/spring-cloud-sleuth-learning