NestJS集成OpenTelemetry Metrics报错:MetricReader无法重复绑定MeterProvider
NestJS中OpenTelemetry Metrics报错:MetricReader can not be bound to a MeterProvider again
错误信息
MetricReader can not be bound to a MeterProvider again. at PeriodicExportingMetricReader.setMetricProducer (/Users//metrics-otel/node_modules/@opentelemetry/sdk-metrics/src/export/MetricReader.ts:93:13) at MeterProvider.addMetricReader (/Users/metrics-otel/node_modules/@opentelemetry/sdk-metrics/src/MeterProvider.ts:97:18) at new MeterProvider (/Users/metrics-otel/node_modules/@opentelemetry/sdk-metrics/src/MeterProvider.ts:61:14) at NodeSDK.start (/Users/metrics-otel/node_modules/@opentelemetry/sdk-node/src/sdk.ts:279:29) at bootstrap (/Users/metrics-otel/src/main.ts:6:17) at Object.<anonymous> (/Users/metrics-otel/src/main.ts:10:1) at Module._compile (node:internal/modules/cjs/loader:1256:14) at Object.Module._extensions..js (node:internal/modules/cjs/loader:1310:10) at Module.load (node:internal/modules/cjs/loader:1119:32) at Function.Module._load (node:internal/modules/cjs/loader:960:12)
复现步骤
- 执行命令
nest new project-name创建项目 - 在src目录下创建metrics.ts文件
相关代码
metrics.ts
/*instrumentation.ts*/ import { NodeSDK } from '@opentelemetry/sdk-node'; import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-node'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; import { PeriodicExportingMetricReader, ConsoleMetricExporter, } from '@opentelemetry/sdk-metrics'; export const otelSDK = new NodeSDK({ traceExporter: new ConsoleSpanExporter(), metricReader: new PeriodicExportingMetricReader({ exporter: new ConsoleMetricExporter(), }), instrumentations: [getNodeAutoInstrumentations()], }); otelSDK.start();
main.ts
import { otelSDK } from './metrics'; import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { await otelSDK.start(); const app = await NestFactory.create(AppModule); await app.listen(3000); } bootstrap();
依赖版本
"dependencies": { "@opentelemetry/api": "^1.8.0", "@opentelemetry/auto-instrumentations-node": "^0.46.1", "@opentelemetry/sdk-metrics": "^1.24.1", "@opentelemetry/sdk-node": "^0.51.1", "@opentelemetry/sdk-trace-node": "^1.24.1" }
错误原因
问题核心是重复调用了otelSDK.start():
- 在metrics.ts中,创建完
otelSDK实例后直接执行了otelSDK.start() - 在main.ts的bootstrap函数里,又再次调用
await otelSDK.start()
第一次启动SDK时,PeriodicExportingMetricReader已经绑定到对应的MeterProvider;第二次调用start()会尝试重复绑定同一个MetricReader,触发OpenTelemetry的重复绑定校验逻辑,从而抛出错误。
解决方案
只保留一次otelSDK.start()调用即可,两种可选方式:
方式1:移除metrics.ts中的启动代码
修改后的metrics.ts:
/*instrumentation.ts*/ import { NodeSDK } from '@opentelemetry/sdk-node'; import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-node'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; import { PeriodicExportingMetricReader, ConsoleMetricExporter, } from '@opentelemetry/sdk-metrics'; export const otelSDK = new NodeSDK({ traceExporter: new ConsoleSpanExporter(), metricReader: new PeriodicExportingMetricReader({ exporter: new ConsoleMetricExporter(), }), instrumentations: [getNodeAutoInstrumentations()], }); // 移除这一行:otelSDK.start();
main.ts保持不变,由bootstrap函数统一启动SDK。
方式2:移除main.ts中的启动代码
修改后的main.ts:
import { otelSDK } from './metrics'; import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { // 移除这一行:await otelSDK.start(); const app = await NestFactory.create(AppModule); await app.listen(3000); } bootstrap();
metrics.ts保持不变,由模块导入时自动执行启动逻辑。
内容的提问来源于stack exchange,提问作者Krish909
相关产品推荐
相关产品推荐

