fix(server): duplicate registered otel providers (#11513)

This commit is contained in:
liuyi
2025-04-08 10:25:36 +08:00
committed by GitHub
parent e927d02c96
commit 646182ea2a
3 changed files with 44 additions and 34 deletions

View File

@@ -2,14 +2,18 @@ import './config';
import { Global, Module } from '@nestjs/common';
import { OpentelemetryFactory } from './opentelemetry';
import {
OpentelemetryOptionsFactory,
OpentelemetryProvider,
} from './opentelemetry';
@Global()
@Module({
providers: [OpentelemetryFactory],
providers: [OpentelemetryOptionsFactory, OpentelemetryProvider],
exports: [OpentelemetryOptionsFactory],
})
export class MetricsModule {}
export * from './metrics';
export * from './utils';
export { OpentelemetryFactory };
export { OpentelemetryOptionsFactory };

View File

@@ -1,4 +1,5 @@
import { Injectable, Logger, OnModuleDestroy } from '@nestjs/common';
import { Injectable, Logger } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import {
CompositePropagator,
W3CBaggagePropagator,
@@ -14,7 +15,7 @@ import { NestInstrumentation } from '@opentelemetry/instrumentation-nestjs-core'
import { SocketIoInstrumentation } from '@opentelemetry/instrumentation-socket.io';
import { Resource } from '@opentelemetry/resources';
import { MetricProducer, MetricReader } from '@opentelemetry/sdk-metrics';
import { NodeSDK } from '@opentelemetry/sdk-node';
import { NodeSDK, NodeSDKConfiguration } from '@opentelemetry/sdk-node';
import {
BatchSpanProcessor,
SpanExporter,
@@ -34,7 +35,7 @@ import { PrismaMetricProducer } from './prisma';
const { PrismaInstrumentation } = prismaInstrument;
export abstract class BaseOpentelemetryFactory {
export abstract class BaseOpentelemetryOptionsFactory {
abstract getMetricReader(): MetricReader;
abstract getSpanExporter(): SpanExporter;
@@ -61,9 +62,9 @@ export abstract class BaseOpentelemetryFactory {
});
}
create() {
create(): Partial<NodeSDKConfiguration> {
const traceExporter = this.getSpanExporter();
return new NodeSDK({
return {
resource: this.getResource(),
sampler: new TraceIdRatioBasedSampler(0.1),
traceExporter,
@@ -77,21 +78,32 @@ export abstract class BaseOpentelemetryFactory {
}),
instrumentations: this.getInstractions(),
serviceName: 'affine-cloud',
});
};
}
}
@Injectable()
export class OpentelemetryFactory
extends BaseOpentelemetryFactory
implements OnModuleDestroy
{
private readonly logger = new Logger(OpentelemetryFactory.name);
export class OpentelemetryOptionsFactory extends BaseOpentelemetryOptionsFactory {
override getMetricReader(): MetricReader {
return new PrometheusExporter({
metricProducers: this.getMetricsProducers(),
});
}
override getSpanExporter(): SpanExporter {
return new ZipkinExporter();
}
}
@Injectable()
export class OpentelemetryProvider {
readonly #logger = new Logger(OpentelemetryProvider.name);
#sdk: NodeSDK | null = null;
constructor(private readonly config: Config) {
super();
}
constructor(
private readonly config: Config,
private readonly ref: ModuleRef
) {}
@OnEvent('config.init')
async init(event: Events['config.init']) {
@@ -112,27 +124,21 @@ export class OpentelemetryFactory
await this.#sdk?.shutdown();
}
override getMetricReader(): MetricReader {
return new PrometheusExporter({
metricProducers: this.getMetricsProducers(),
});
}
override getSpanExporter(): SpanExporter {
return new ZipkinExporter();
}
private async setup() {
if (this.config.metrics.enabled) {
if (!this.#sdk) {
this.#sdk = this.create();
const factory = this.ref.get(OpentelemetryOptionsFactory, {
strict: false,
});
this.#sdk = new NodeSDK(factory.create());
}
this.#sdk.start();
this.logger.log('OpenTelemetry SDK started');
this.#logger.log('OpenTelemetry SDK started');
} else {
await this.#sdk?.shutdown();
this.#sdk = null;
this.logger.log('OpenTelemetry SDK stopped');
this.#logger.log('OpenTelemetry SDK stopped');
}
}
}

View File

@@ -14,10 +14,10 @@ import {
SEMRESATTRS_K8S_POD_NAME,
} from '@opentelemetry/semantic-conventions';
import { OpentelemetryFactory } from '../../base/metrics';
import { OpentelemetryOptionsFactory } from '../../base/metrics';
@Injectable()
export class GCloudOpentelemetryFactory extends OpentelemetryFactory {
export class GCloudOpentelemetryOptionsFactory extends OpentelemetryOptionsFactory {
override getResource(): Resource {
const env = getEnv();
return super
@@ -48,8 +48,8 @@ export class GCloudOpentelemetryFactory extends OpentelemetryFactory {
}
const FactorProvider: Provider = {
provide: OpentelemetryFactory,
useClass: GCloudOpentelemetryFactory,
provide: OpentelemetryOptionsFactory,
useClass: GCloudOpentelemetryOptionsFactory,
};
@Global()