@ogcio/o11y-sdk-node
Version:
Opentelemetry standard instrumentation SDK for NodeJS based project
128 lines (127 loc) • 5.57 kB
JavaScript
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;
}
}