UNPKG

@ogcio/o11y-sdk-node

Version:

Opentelemetry standard instrumentation SDK for NodeJS based project

128 lines (127 loc) 5.57 kB
import { diag, DiagConsoleLogger, DiagLogLevel } from "@opentelemetry/api"; import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node"; import { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator, } from "@opentelemetry/core"; import { NodeSDK } from "@opentelemetry/sdk-node"; import { AlwaysOffSampler, ParentBasedSampler, TraceIdRatioBasedSampler, } from "@opentelemetry/sdk-trace-base"; import { setNodeSdkConfig } from "./config-manager.js"; import buildConsoleExporters from "./exporter/console.js"; import buildGrpcExporters from "./exporter/grpc.js"; import buildHttpExporters from "./exporter/http.js"; import { GeoBaggagePropagator } from "./geo/geo-baggage-propagator.js"; import { GeoEnrichLogProcessor } from "./processor/geo-enrich-log-processor.js"; import { GeoEnrichSpanProcessor } from "./processor/geo-enrich-span-processor.js"; import { _shutdownHook } from "./internals/hooks.js"; import { ObservabilityResourceDetector } from "./resource.js"; import { UrlSampler } from "./url-sampler.js"; export default async function buildNodeInstrumentation(config) { if (!config) { console.warn("observability config not set. Skipping NodeJS OpenTelemetry instrumentation."); return; } if (!config.collectorUrl) { console.warn("collectorUrl not set. Skipping NodeJS OpenTelemetry instrumentation."); return; } if (!isUrl(config.collectorUrl)) { console.error("collectorUrl does not use a valid format. Skipping NodeJS OpenTelemetry instrumentation."); return; } // Init configManager to make it available to all o11y utils. setNodeSdkConfig(config); // Build base sampler const urlSampler = new UrlSampler(config.ignoreUrls, new TraceIdRatioBasedSampler(config.traceRatio ?? 1)); const defaultSampler = new ParentBasedSampler({ root: urlSampler, remoteParentSampled: urlSampler, remoteParentNotSampled: new AlwaysOffSampler(), localParentSampled: urlSampler, localParentNotSampled: new AlwaysOffSampler(), }); // Allow sampler customization via config const finalSampler = config.samplerWrapper ? config.samplerWrapper(defaultSampler) : defaultSampler; diag.setLogger(new DiagConsoleLogger(), config.diagLogLevel ? DiagLogLevel[config.diagLogLevel] : DiagLogLevel.INFO); try { let exporter; if (config.protocol === "http") { exporter = buildHttpExporters(config); } else if (config.protocol === "console") { exporter = buildConsoleExporters(config); } else { exporter = await buildGrpcExporters(config); } const geoEnabled = config.geoEnrichment?.enabled === true; // Build span processors with custom processors from config const spanProcessors = [ ...(config.prependSpanProcessors ?? []), ...(geoEnabled ? [new GeoEnrichSpanProcessor()] : []), ...exporter.spans, ]; // Build log processors with custom processors from config const logProcessors = [ ...(config.prependLogProcessors ?? []), ...(geoEnabled ? [new GeoEnrichLogProcessor()] : []), ...exporter.logs, ]; const sdk = new NodeSDK({ resourceDetectors: [ new ObservabilityResourceDetector(config.resourceAttributes), ], spanProcessors, serviceName: config.serviceName, metricReaders: [exporter.metrics], logRecordProcessors: logProcessors, sampler: finalSampler, textMapPropagator: new CompositePropagator({ propagators: [ new W3CTraceContextPropagator(), ...(geoEnabled ? [ new W3CBaggagePropagator(), new GeoBaggagePropagator({ headerMap: config.geoEnrichment?.headerMap, precision: config.geoEnrichment?.precision, }), ] : []), ...(config.additionalPropagators ?? []), ], }), contextManager: config.contextManager, instrumentations: [ getNodeAutoInstrumentations(config.autoInstrumentationConfig ?? { "@opentelemetry/instrumentation-fs": { enabled: (() => { if (config.enableFS !== undefined) { console.warn("[o11y] 'enableFS' is deprecated and will be removed in the next major version. " + "Use 'autoInstrumentationConfig' instead."); } return config.enableFS ?? false; })(), }, }), ...(config.additionalInstrumentations ?? []), ], }); sdk.start(); console.log("NodeJS OpenTelemetry instrumentation started successfully."); _shutdownHook(sdk); config.onSdkStarted?.(sdk); return sdk; } catch (error) { console.error("Error starting NodeJS OpenTelemetry instrumentation:", error); } } function isUrl(url) { try { new URL(url); return true; } catch (_) /* NOSONAR */ { return false; } }