随着微服务架构的逐渐流行,在复杂且庞大的系统中准确地定位一个请求的完整生命周期,逐渐成为了研发人员面临的最大痛点之一。以研发自测过程为例,开发人员通常希望在发起 HTTP/RPC 测试请求后,能够以一个简单的方式获取整个测试请求的上下文信息。这其中通常包括相关的上下游链路、各个服务内部请求的方法堆栈,以及链路上打印的日志等数据,对于指标-链路-日志的一体化监控的需求已经迫在眉睫。
腾讯云应用性能监控(APM)作为本身包含指标-链路的全链路监控平台,已与 腾讯云日志服务(CLS) 联手打通,实现指标-链路-日志的一体化监控。在查看链路详情时,关联查看所对应的信息,完成从链路到日志的排查流程。
前提条件
说明:
为了保障您日志数据的可靠性以及更高效地使用日志服务,建议您使用 CLS 优化后的接口/Agent 上传结构化日志:
通过 API/SDK 上报,详情请参见 上传日志 中的 contents 部分。
通过 Agent 上报,详情请参见 使用 JSON 提取模式采集日志。
操作步骤
步骤1:将 TraceID 和 SpanID 打印到日志中
为了实现链路和日志的关联查询,您需要将 TraceID 和 SpanID 输出到日志中。对于通过如下方案接入的应用,可以在不修改代码的情况下,将 TraceID 和 SpanID 自动注入到日志中:
步骤2:在系统配置页面关联日志
1. 登录 腾讯云可观测平台。
2. 在左侧菜单栏选择应用性能监控 > 系统配置,进入业务系统配置页面。
3. 选择对应的业务系统,在日志关联中单击编辑。
4. 配置日志关联信息。
开启关联日志。
选择对应的日志地域、日志集、日志主题,并指定 TraceID 和 SpanID 所在的字段。
5. 配置完后单击确定即可。

步骤3:在链路查询页面查看日志信息
1. 登录 腾讯云可观测平台。
2. 在左侧菜单栏选择应用性能监控 > 链路追踪,进入链路追踪页面。
3. 选择对应的业务系统,找到对应的 TraceID,单击 TraceID 进入链路详情。
4. 在 Trace 日志和 Span 日志标签页中,可以查询该链路对应的日志信息。

将 TraceID 和 SpanID 打印到日志中
腾讯云增强版 OpenTelemetry Java 探针
对于满足要求的日志组件,通过修改日志配置文件中的 pattern,即可实现对 TraceID 和 SpanID 的注入。在日志配置文件中,TraceID 和 SpanID 分别使用
%X{trace_id}和 %X{span_id}字段注入。日志框架 | 支持的版本范围 |
Log4j | 1.2+ |
Log4j2 | 2.7+ |
Logback | 1.0+ |
Log4j
log4j.properties 文件修改示例:
log4j.appender.warn.layout=org.apache.log4j.PatternLayoutlog4j.appender.warn.layout.ConversionPattern=trace_id: %X{trace_id} span_id: %X{span_id} - %m%n
Log4j2
Log4j2支持多种格式的配置文件,包括 XML、JSON、YAML、Properties 等。以 XML 格式为例,Pattern 有多种写法,请根据已有的写法参考其中一种:
<PatternLayout pattern="trace_id: %X{trace_id} span_id: %X{span_id} - %m%n"/>
<PatternLayout><Pattern>trace_id: %X{trace_id} span_id: %X{span_id} - %m%n</Pattern></PatternLayout>
<Layout type="PatternLayout" pattern="trace_id: %X{trace_id} span_id: %X{span_id} - %m%n"/>
Logback
logback.xml 文件修改示例:
<encoder><pattern>trace_id: %X{trace_id} span_id: %X{span_id} %msg%n</pattern></encoder>
SkyWalking Java 探针
请根据日志组件的类型,从 SkyWalking 官网获取在日志中注入 TraceID 和 SpanID 的操作指引。
Log4j
Log4j2
Logback
腾讯云 OpenTelemetry-Go 探针
对于满足要求的日志组件,无需额外的任何操作,即可实现对 TraceID 和 SpanID 的注入。如果探针检测到活跃 Span 的存在,会分别以
trace_id和span_id作为标记,向日志中注入 TraceID 和 SpanID。日志框架 | 包路径 | 支持的版本范围 |
Zap | go.uber.org/zap/zapcore | 1.20.0+ |
Logrus | github.com/sirupsen/logrus | 1.5.0+ |
Zerolog | github.com/rs/zerolog | 1.10.0+ |
go-kit/log | github.com/go-kit/log | 0.1.0+ |
Go 标准库 log | log | 无限制 |
Go 标准库 slog | log/slog | 无限制 |
以 Zap 为例,注入 TraceID 和 SpanID 后生成的日志内容如下所示:
{"level":"info","msg":"this is info message","trace_id":"38e6910973e1c0c11351e502329d2d72","span_id":"6f4efff78445ea61"}OpenTelemetry-Python
对于内置 logging 库,以及底层调用内置 logging 库的日志组件,通过添加
OTEL_PYTHON_LOG_CORRELATION环境变量,即可实现对 TraceID 和 SpanID 的注入。# Enable Log CorrelationOTEL_PYTHON_LOG_CORRELATION=truetapm-instrument \\--traces_exporter otlp \\--metrics_exporter otlp \\--logs_exporter none \\--service_name python-web-test \\--resource_attributes "token=xxxxx" \\--exporter_otlp_endpoint xxxxxx \\python main.py
开启日志关联后,生成的日志内容如下所示:
2026-02-25 19:51:25,069 INFO [__main__] [main.py:19] [trace_id=c20f528fa45eebc2cbdae9e341ced39a span_id=fa84ffb16a978ab6 resource.service.name=python-web-test trace_sampled=True]
OpenTelemetry-JS
对于满足要求的日志组件,无需额外的任何操作,即可实现对 TraceID 和 SpanID 的注入。如果探针检测到活跃 Span 的存在,会分别以
trace_id和span_id作为标记,向日志中注入 TraceID 和 SpanID。日志框架 | 包路径 | 支持的版本范围 |
Winston | github.com/winstonjs/winston | 1.0.0+ |
Pino | github.com/pinojs/pino | 5.14.0+ |
Bunyan | trentm/node-bunyan | 1.0.0+ |
以 Bunyan 为例,注入 TraceID 和 SpanID 后生成的日志内容如下所示:
INFO: this is info message: GET /|trace_id="e793e3edafb93f98a8a395c13096a26f"span_id="9564de488477c6a8"trace_flags="01"
需要注意的是,如果在 Winston 框架中对日志进行自定义格式化,需要参考如下代码,手动将 TraceID 和 SpanID 附加到日志内容中:
const logger = winston.createLogger({level: "info",format: winston.format.combine(winston.format.timestamp(),winston.format.printf(({ timestamp, level, message, trace_id, span_id }) => {return `${timestamp} [${level.toUpperCase()}] [trace_id=${trace_id} span_id=${span_id}]: ${message}`;})),transports: [new winston.transports.Console()],});
OpenTelemetry-dotnet
对于满足要求的日志组件,通过修改日志配置文件中的 pattern,即可实现对 TraceID 和 SpanID 的注入。
日志框架 | 支持的版本范围 |
Log4Net | 2.0.13+ |
NLog | 5.0.0+ |
Log4Net
在日志配置文件中,TraceID 和 SpanID 分别使用
%property{trace_id}和%property{span_id}字段注入。<layout type="log4net.Layout.PatternLayout"><conversionPattern value="%date [%level] %logger - %message trace_id=%property{trace_id} span_id=%property{span_id} %newline" /></layout>
NLog
在日志配置文件中,TraceID 和 SpanID 分别使用
${event-properties:TraceId}和span_id=${event-properties:SpanId}字段注入。<target xsi:type="File" name="file" fileName="logs/app.log"layout="${longdate} [${level:uppercase=true}] ${logger} - ${message} trace_id=${event-properties:TraceId} span_id=${event-properties:SpanId}" />
其他方案
对于其他方案,请使用 OpenTelemetry SDK 从链路上下文中获取 TraceID 和 SpanID,并附加到日志内容中。例如,通过 OpenTelemetry-Go SDK 接入的应用,可以参考如下代码片段将 TraceID 和 SpanID 打印到日志中:
func logWithTrace(ctx context.Context, format string, args ...interface{}) {span := trace.SpanFromContext(ctx)sc := span.SpanContext()traceID := sc.TraceID().String()spanID := sc.SpanID().String()msg := fmt.Sprintf(format, args...)log.Printf("[trace_id: %s span_id: %s] %s", traceID, spanID, msg)}