腾讯云应用性能监控(APM)作为本身包含指标-链路的全链路监控平台,已与 腾讯云日志服务(CLS) 联手打通,实现指标-链路-日志的一体化监控。在查看链路详情时,关联查看所对应的信息,完成从链路到日志的排查流程。
一、前提条件
请确保应用已经接入应用性能监控(APM),并参考日志服务(CLS)入门指南 将业务日志上报到腾讯云日志服务(CLS)。
注意:说明:
注意:为了保障你日志数据的可靠性以及更高效地使用日志服务,建议你使用 CLS 优化后的接口/Agent 上传结构化日志:
二、步骤1:将 TraceID 和 SpanID 打印到日志中
为了实现链路和日志的关联查询,你需要将 TraceID 和 SpanID 输出到日志中。对于通过如下方案接入的应用,可以在不修改代码的情况下,将 TraceID 和 SpanID 自动注入到日志中:
·腾讯云增强版 OpenTelemetry Java 探针
·SkyWalking Java 探针
·腾讯云 OpenTelemetry-Go 探针
·OpenTelemetry-Python
·OpenTelemetry-JS
·OpenTelemetry-dotnet
对于通过其他方式接入的应用,请参考 其他方案,从链路上下文中获取 TraceID 和 SpanID,并附加到日志内容中。
三、步骤2:在系统配置页面关联日志
1. 登录 腾讯云可观测平台。
2. 在左侧菜单栏选择应用性能监控 > 系统配置,进入业务系统配置页面。
3. 选择对应的业务系统,在日志关联中单击编辑。
4. 配置日志关联信息。
·开启关联日志。
·选择对应的日志地域、日志集、日志主题,并指定 TraceID 和 SpanID 所在的字段。
5. 配置完后单击确定即可。
除了可以在业务系统级别配置日志关联以外,也可以在应用级别配置日志关联,请到 应用性能监控 > 系统配置 > 应用配置 中进行操作,具体的配置方式与业务系统级别相同。
四、步骤3:在链路查询页面查看日志信息
1. 登录 腾讯云可观测平台。
2. 在左侧菜单栏选择应用性能监控 > 链路追踪,进入链路追踪页面。
3. 选择对应的业务系统,找到对应的 TraceID,单击 TraceID 进入链路详情。
4. 在 Trace 日志和 Span 日志标签页中,可以查询该链路对应的日志信息。
五、腾讯云增强版 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 Correlation OTEL_PYTHON_LOG_CORRELATION=true tapm-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)}