You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Spring Cloud Sleuth日志消息发送至Zipkin?

实现SLF4J日志内容上报到Zipkin的方案

当然可行!你已经通过Spring Cloud Sleuth让日志带上了TraceId/SpanId,现在只需要把日志内容附加到Zipkin的Span中,或者生成独立Span来记录日志。下面给你几个实用的实现方式:

方式一:封装日志工具类,手动添加日志到当前Span

如果你愿意少量修改现有日志调用,可以封装一个自定义的日志工具,在打印日志的同时把内容添加到当前Span的Tag中:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import brave.Tracer;
import brave.Span;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TraceLogger {
    private final Logger LOG = LoggerFactory.getLogger(TraceLogger.class);
    private final Tracer tracer;

    @Autowired
    public TraceLogger(Tracer tracer) {
        this.tracer = tracer;
    }

    public void info(String message) {
        LOG.info(message);
        addLogToSpan("info", message);
    }

    public void error(String message, Throwable throwable) {
        LOG.error(message, throwable);
        addLogToSpan("error", message);
        // 可以额外添加异常信息到Span
        addLogToSpan("error.stack", throwable.getMessage());
    }

    private void addLogToSpan(String level, String message) {
        Span currentSpan = tracer.currentSpan();
        if (currentSpan != null) {
            // 用log.{level}作为Tag键,避免和其他Tag冲突
            currentSpan.tag(String.format("log.%s", level), message);
        }
    }
}

之后在业务代码中用traceLogger.info("something")替代原来的LOG.info,就能在Zipkin的Span详情里看到对应的日志Tag了。

方式二:监听日志事件,自动注入Span(无需修改现有代码)

如果不想改动现有日志调用,可以通过Spring的事件监听机制,自动捕获SLF4J日志并添加到当前Span:

import brave.Tracer;
import brave.Span;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.LoggingEvent;
import org.springframework.stereotype.Component;
import ch.qos.logback.classic.Level;

@Component
public class LogToSpanInjector implements ApplicationListener<LoggingEvent> {
    private final Tracer tracer;

    public LogToSpanInjector(Tracer tracer) {
        this.tracer = tracer;
    }

    @Override
    public void onApplicationEvent(LoggingEvent event) {
        // 只处理INFO及以上级别的日志,避免日志量过大
        if (event.getLevel().isGreaterOrEqual(Level.INFO)) {
            Span currentSpan = tracer.currentSpan();
            if (currentSpan != null) {
                // 把日志级别作为Tag的一部分,方便在Zipkin中筛选
                String tagKey = String.format("log.%s", event.getLevel().name().toLowerCase());
                currentSpan.tag(tagKey, event.getFormattedMessage());
            }
        }
    }
}

这个类会自动监听应用内的所有日志事件,只要当前存在活跃的Span,就会把日志内容添加为Span的Tag。完全不用修改你原来的LOG.info()调用,非常便捷。

方式三:将单条日志作为独立Span上报(按需使用)

如果需要把每条日志作为独立的子Span上报到Zipkin(适合需要单独追踪日志场景),可以这样实现:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import brave.Tracer;
import brave.Span;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class LogAsSpanLogger {
    private final Logger LOG = LoggerFactory.getLogger(LogAsSpanLogger.class);
    private final Tracer tracer;

    @Autowired
    public LogAsSpanLogger(Tracer tracer) {
        this.tracer = tracer;
    }

    public void info(String message) {
        LOG.info(message);
        // 启动一个子Span,命名为log.info
        try (Span logSpan = tracer.nextSpan().name("log.info").start()) {
            logSpan.tag("message", message);
            // 可以添加更多自定义Tag,比如日志来源类
            logSpan.tag("logger.class", LOG.getName());
        }
    }
}

这种方式会在原有请求Span下生成一个子Span,专门记录这条日志,不过会增加Zipkin中的Span数量,建议根据实际需求选择。

注意事项

  1. 确保你的spring.sleuth.sampler.probability已经设置为1.0(100%采样),你已经配置过这点,没问题。
  2. 如果日志量很大,建议限制上报的日志级别(比如只上报ERROR和INFO,忽略DEBUG),避免Zipkin存储压力过大。
  3. Tag的长度在Zipkin中有默认限制,如果日志内容过长,可能会被截断,必要时可以配置Zipkin的存储参数调整长度。

内容的提问来源于stack exchange,提问作者cmatsuoka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:51:27