@ogcio/o11y-sdk-node
Version:
Opentelemetry standard instrumentation SDK for NodeJS based project
126 lines (109 loc) • 3.53 kB
text/typescript
import { diag, DiagConsoleLogger, DiagLogLevel } from "@opentelemetry/api";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
import { 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 type { Exporters } from "./exporter/index.js";
import type { NodeSDKConfig } from "./index.js";
import { _shutdownHook } from "./internals/hooks.js";
import { ObservabilityResourceDetector } from "./resource.js";
import { UrlSampler } from "./url-sampler.js";
export default async function buildNodeInstrumentation(
config?: NodeSDKConfig,
): Promise<NodeSDK | undefined> {
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;
}
if (!config.detection) {
config.detection = {
email: true,
};
}
if (config.detection.email === undefined) {
config.detection.email = true;
}
// Init configManager to make it available to all o11y utils.
setNodeSdkConfig(config);
const urlSampler = new UrlSampler(
config.ignoreUrls,
new TraceIdRatioBasedSampler(config.traceRatio ?? 1),
);
const mainSampler = new ParentBasedSampler({
root: urlSampler,
remoteParentSampled: urlSampler,
remoteParentNotSampled: new AlwaysOffSampler(),
localParentSampled: urlSampler,
localParentNotSampled: new AlwaysOffSampler(),
});
diag.setLogger(
new DiagConsoleLogger(),
config.diagLogLevel ? DiagLogLevel[config.diagLogLevel] : DiagLogLevel.INFO,
);
try {
const nodeSdkInstrumentation = getNodeAutoInstrumentations({
"@opentelemetry/instrumentation-fs": {
enabled: config.enableFS ?? false,
},
});
let exporter: Exporters;
if (config.protocol === "http") {
exporter = buildHttpExporters(config);
} else if (config.protocol === "console") {
exporter = buildConsoleExporters(config);
} else {
exporter = await buildGrpcExporters(config);
}
const sdk = new NodeSDK({
resourceDetectors: [
new ObservabilityResourceDetector(config.resourceAttributes),
],
spanProcessors: exporter.spans,
serviceName: config.serviceName,
metricReader: exporter.metrics,
logRecordProcessors: exporter.logs,
sampler: mainSampler,
textMapPropagator: new W3CTraceContextPropagator(),
instrumentations: [nodeSdkInstrumentation],
});
sdk.start();
console.log("NodeJS OpenTelemetry instrumentation started successfully.");
_shutdownHook(sdk);
return sdk;
} catch (error) {
console.error(
"Error starting NodeJS OpenTelemetry instrumentation:",
error,
);
}
}
function isUrl(url: string): boolean {
try {
new URL(url);
return true;
} catch (_) {
return false;
}
}