diff --git a/packages/backend/server/src/base/metrics/index.ts b/packages/backend/server/src/base/metrics/index.ts index b774930be3..4029c472e3 100644 --- a/packages/backend/server/src/base/metrics/index.ts +++ b/packages/backend/server/src/base/metrics/index.ts @@ -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 }; diff --git a/packages/backend/server/src/base/metrics/opentelemetry.ts b/packages/backend/server/src/base/metrics/opentelemetry.ts index d22bdb736d..601b46864a 100644 --- a/packages/backend/server/src/base/metrics/opentelemetry.ts +++ b/packages/backend/server/src/base/metrics/opentelemetry.ts @@ -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 { 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'); } } } diff --git a/packages/backend/server/src/plugins/gcloud/metrics.ts b/packages/backend/server/src/plugins/gcloud/metrics.ts index ad06b6314c..b59cc5df6e 100644 --- a/packages/backend/server/src/plugins/gcloud/metrics.ts +++ b/packages/backend/server/src/plugins/gcloud/metrics.ts @@ -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()