// OpenTelemetry tracing and logging initialization for the gibbz backend. // Loaded before HTTP / network modules start serving traffic. import process from 'node:process'; import { NodeSDK } from '@opentelemetry/sdk-node'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http'; import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs'; import { resourceFromAttributes } from '@opentelemetry/resources'; import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions'; export class Tracing { private sdk: NodeSDK | undefined; start( env: Record = process.env, onFatal?: (err: unknown) => void, ): void { const serviceName = env.OTEL_SERVICE_NAME || 'gibbz'; const serviceRelease = env.SERVICE_RELEASE || env.OTEL_SERVICE_RELEASE || env.APP_RELEASE || 'dev'; const environment = env.ENVIRONMENT || env.NODE_ENV || 'production'; const otelUrl = (env.OTEL_EXPORTER_OTLP_ENDPOINT || env.OTEL_URL || 'https://otel.k6n.net').replace(/\/+$/, ''); const ingestKey = env.OTEL_INGEST_KEY || ''; const headers: Record = {}; if (ingestKey) headers['X-Otel-Ingest-Key'] = ingestKey; const resource = resourceFromAttributes({ [ATTR_SERVICE_NAME]: serviceName, [ATTR_SERVICE_VERSION]: serviceRelease, 'service.release': serviceRelease, 'service.environment': environment, }); const sdk = new NodeSDK({ resource, traceExporter: new OTLPTraceExporter({ url: `${otelUrl}/v1/traces`, headers }), logRecordProcessor: new BatchLogRecordProcessor({ exporter: new OTLPLogExporter({ url: `${otelUrl}/v1/logs`, headers }), }), instrumentations: [ getNodeAutoInstrumentations({ '@opentelemetry/instrumentation-fs': { enabled: false }, }), ], }); this.sdk = sdk; try { sdk.start(); console.log( `[otel] Initialized OpenTelemetry for ${serviceName} (release: ${serviceRelease}, env: ${environment}) -> ${otelUrl}`, ); } catch (err) { console.error('[otel] Failed to start OpenTelemetry SDK:', err); onFatal?.(err); } process.on('SIGTERM', () => { this.shutdown() .then(() => { console.log('[otel] SDK shut down successfully'); process.exit(0); }) .catch((err) => { console.error('[otel] Error shutting down SDK', err); process.exit(0); }); }); } async shutdown(): Promise { await this.sdk?.shutdown(); } }