链路追踪
从 Midway v4 开始,框架侧 tracing 能力已合并到 @midwayjs/core,不再需要安装和启用 @midwayjs/otel 组件。
使用须知
- Midway 会自动在入口/出口创建和传播 span。
tracing.enable是全局总开关(只控制“是否开启 tracing”)。- 协议级行为在各组件里配置(例如
koa.tracing、grpc.tracing、kafka.tracing),core不区分具体协议。 - 各组件可通过
<component>.tracing.enable单独开关,也可以配置meta、extractor、injector。 - 如果你需要在 Jaeger/Zipkin/OTLP 平台看到链路,仍需初始化 OpenTelemetry SDK 并配置 exporter。
OpenTelemetry 基础概念
- Trace:一次完整请求链路,包含多个 Span。
- Span:链路中的一个操作节点,记录开始/结束时间、状态和属性。
- Context Propagation:上下文传播,把上游 Trace 信息透传到下游(HTTP header、MQTT properties、gRPC metadata 等)。
- Attributes:Span 上的键值属性,用于检索和过滤。
- TraceId:Trace 的全局唯一 ID,用于关联整条链路。
快速开始
1) 开启框架 tracing(默认已开启)
// src/config/config.default.ts
export default {
tracing: {
enable: true,
onError: 'ignore', // 或 throw
logOnError: false,
},
};
2) 组件级开关
// src/config/config.default.ts
export default {
tracing: {
enable: true, // 全局总开关
},
koa: {
tracing: {
enable: true,
},
},
kafka: {
tracing: {
enable: false, // 单独关闭 kafka tracing
},
},
};
开关规则:
tracing.enable=false:全局关闭(所有组件都不产出 span)。tracing.enable=true:由各组件tracing.enable决定是否启用。
3) 导出到控制台(最简示例)
按本页的 bootstrap.js 初始化方式,你需要安装以下依赖:
$ npm install --save @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/sdk-trace-base
{
"dependencies": {
"@opentelemetry/api": "latest",
"@opentelemetry/sdk-trace-node": "latest",
"@opentelemetry/sdk-trace-base": "latest"
}
}
@opentelemetry/api@opentelemetry/sdk-trace-node@opentelemetry/sdk-trace-base
bootstrap.js 示例:
const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
const {
ConsoleSpanExporter,
SimpleSpanProcessor,
} = require('@opentelemetry/sdk-trace-base');
const { Bootstrap } = require('@midwayjs/bootstrap');
const provider = new NodeTracerProvider();
provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
provider.register();
Bootstrap.configure().run();
启动后你会看到应用正常启动日志。真正的 tracing 输出会在有请求/消息进入后打印。
例如请求一次接口后,控制台会出现类似内容(不同版本字段会略有差异):
Span: {
name: 'GET /api/user',
kind: 1,
traceId: '4bf92f3577b34da6a3ce929d0e0e4736',
parentId: undefined,
attributes: { 'midway.protocol': 'http' },
status: { code: 1 }
}
你可以重点看这几个字段,确认链路已接通:
traceId:存在且是 32 位十六进制字符串。name:能对应到你的请求/任务。attributes.midway.protocol:能看到http/grpc/kafka等协议标记。
如果没有看到 span 输出,优先检查:
provider.register()是否在Bootstrap.configure().run()之前执行。- 代码是否真的走到了被 tracing 覆盖的入口(例如发起 了一次 HTTP 请求)。
提示
在 dev 模式下,主进程控制台无法看到这些 span 输出(dev 不走这里的 bootstrap.js 初始化代码)。
4) 对接观测平台(按需)
常见 exporter:
- OTLP/HTTP:
@opentelemetry/exporter-trace-otlp-http - OTLP/gRPC:
@opentelemetry/exporter-trace-otlp-grpc - Jaeger:
@opentelemetry/exporter-jaeger - Zipkin:
@opentelemetry/exporter-zipkin
下面以 Jaeger 为例:
- 安装 Jaeger exporter 依赖(示例)
$ npm install --save @opentelemetry/exporter-jaeger
{
"dependencies": {
"@opentelemetry/exporter-jaeger": "latest"
}
}
- 修改
bootstrap.js,把 Console exporter 替换为 Jaeger exporter
const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { Bootstrap } = require('@midwayjs/bootstrap');
const exporter = new JaegerExporter({
host: process.env.JAEGER_AGENT_HOST || '127.0.0.1',
port: Number(process.env.JAEGER_AGENT_PORT || 6832),
});
const provider = new NodeTracerProvider();
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
provider.register();
Bootstrap.configure().run();
- 验证是否生效
- 启动应用后发起一次请求。
- 打开 Jaeger UI(通常是
http://127.0.0.1:16686)。 - 按服务名检索,确认能看到对应 span。
框架能力
ctx.traceId
@midwayjs/core 提供 ctx.traceId 字段。
所有使用 Midway 上下文的 framework 都可读取该字段(例如 web、koa、express、ws、grpc、faas 等)。
ctx.traceId => '4bf92f3577b34da6a3ce929d0e0e4736'
@Trace 装饰器
import { Trace } from '@midwayjs/core';
export class UserService {
@Trace('user.get')
async getUser() {
// ...
}
}
MidwayTraceService
import { Inject, MidwayTraceService } from '@midwayjs/core';
export class UserService {
@Inject()
traceService: MidwayTraceService;
}