ollygarden-otel-js-setup
JS/Node.js SDK Setup Conventions
Status decision: declarative vs programmatic
The @opentelemetry/configuration package is experimental. Default to declarative config
for new projects. Use the programmatic NodeSDK fallback below if stability is critical or
the project needs runtime configuration that YAML cannot express.
Dependencies
npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/configuration
npm install @opentelemetry/auto-instrumentations-node
npm install @opentelemetry/semantic-conventions
Fetch the latest versions of these packages (see the otel-js skill's Sources of Truth)
and pin them in package.json as appropriate for your project.
Project Structure
src/
├── telemetry/
│ ├── constants.ts # Service scope and telemetry constants
│ ├── setup.ts # SDK initialization
│ └── index.ts # Re-exports
├── index.ts # App entry point (imports telemetry first)
configs/
└── otel.yaml # Declarative configuration
Instrumentation File (src/telemetry/setup.ts)
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
// When OTEL_CONFIG_FILE is set, NodeSDK reads config from that file.
// Exporters, processors, samplers, and resource are all configured via YAML.
export const sdk = new NodeSDK({
instrumentations: [
getNodeAutoInstrumentations({
'@opentelemetry/instrumentation-fs': { enabled: false },
'@opentelemetry/instrumentation-dns': { enabled: false },
'@opentelemetry/instrumentation-net': { enabled: false },
}),
],
});
Entry Point (src/index.ts)
// IMPORTANT: Import and start telemetry BEFORE any other imports
import { sdk } from './telemetry/setup';
sdk.start();
import { app } from './app';
const PORT = process.env.PORT ?? 3000;
const server = app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
});
process.on('SIGTERM', () => {
server.close(async () => {
await sdk.shutdown();
process.exit(0);
});
});
Fallback: Programmatic NodeSDK Setup
If declarative config is not suitable (e.g., need dynamic runtime config or older SDK version), use programmatic setup:
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { resourceFromAttributes } from '@opentelemetry/resources';
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
const resource = resourceFromAttributes({
[ATTR_SERVICE_NAME]: 'my-service',
[ATTR_SERVICE_VERSION]: process.env.SERVICE_VERSION ?? '0.0.0',
});
export const sdk = new NodeSDK({
resource,
traceExporter: new OTLPTraceExporter(),
metricReader: new PeriodicExportingMetricReader({
exporter: new OTLPMetricExporter(),
exportIntervalMillis: 30_000,
}),
logRecordProcessors: [
new BatchLogRecordProcessor(new OTLPLogExporter()),
],
instrumentations: [
getNodeAutoInstrumentations({
'@opentelemetry/instrumentation-fs': { enabled: false },
'@opentelemetry/instrumentation-dns': { enabled: false },
'@opentelemetry/instrumentation-net': { enabled: false },
}),
],
});
Key Details
- Disable noisy instrumentations:
fs,dns, andnetinstrumentations generate high volumes of low-value spans. Disable them unless specifically needed. - SIGTERM handler: Always register a shutdown handler to flush buffered telemetry before the process exits.
Cross-References
- Reference:
otel-jsskill —references/declarative-setup.mdfor the package version fetch table, activation, ESM/CJS rules, v2.0 migration facts. - General conventions:
ollygarden-otel-declarative-config— anti-patterns and common YAML patterns.
More from ollygarden/skills
ollygarden-otel-declarative-config
Ollygarden's recommended patterns and anti-patterns for OpenTelemetry declarative configuration. Use when reviewing or authoring otel.yaml files, when deciding whether declarative config is right for a project, or when the user asks for "the right way" to configure OpenTelemetry. Triggers on "otel best practices", "otel anti-patterns", "is this otel config correct", "should I use declarative config".
1ollygarden-otel-sdk-setup
OpenTelemetry SDK initialization and configuration. Use when setting up or reviewing TracerProvider, MeterProvider, or LoggerProvider; choosing exporters, processors, or propagators; configuring OTLP transport; or extending an existing SDK setup for new signals. Use this skill whenever the task involves wiring up the OpenTelemetry SDK, even if the user only mentions "add tracing" or "set up metrics" without saying "SDK.
1