install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/otel-sdk-setup" ~/.claude/skills/intense-visions-harness-engineering-otel-sdk-setup && rm -rf "$T"
manifest:
agents/skills/claude-code/otel-sdk-setup/SKILL.mdsource content
OpenTelemetry SDK Setup
Initialize the OpenTelemetry Node.js SDK with resource attributes, exporters, and auto-instrumentation
When to Use
- Setting up OpenTelemetry in a new Node.js application
- Migrating from vendor-specific SDKs (Datadog, New Relic) to OpenTelemetry
- Configuring auto-instrumentation for HTTP, database, and framework libraries
- Establishing the telemetry foundation before adding custom spans and metrics
Instructions
- Install the core SDK and auto-instrumentation packages.
- Create the instrumentation file (
) — it must run before any other application code.instrumentation.ts - Define the resource with service name, version, and environment.
- Configure exporters for traces, metrics, and logs (OTLP is the standard protocol).
- Register auto-instrumentations for libraries your application uses.
- Load the instrumentation file first:
ornode --require ./instrumentation.ts
at the top of your entry point.import './instrumentation'
npm install @opentelemetry/sdk-node \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/exporter-trace-otlp-http \ @opentelemetry/exporter-metrics-otlp-http \ @opentelemetry/resources \ @opentelemetry/semantic-conventions
// instrumentation.ts — must be loaded before application code import { NodeSDK } from '@opentelemetry/sdk-node'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'; import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'; import { Resource } from '@opentelemetry/resources'; import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION, ATTR_DEPLOYMENT_ENVIRONMENT, } from '@opentelemetry/semantic-conventions'; const resource = new Resource({ [ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME || 'my-service', [ATTR_SERVICE_VERSION]: process.env.npm_package_version || '0.0.0', [ATTR_DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV || 'development', }); const sdk = new NodeSDK({ resource, traceExporter: new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318/v1/traces', }), metricReader: new PeriodicExportingMetricReader({ exporter: new OTLPMetricExporter({ url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318/v1/metrics', }), exportIntervalMillis: 15000, }), instrumentations: [ getNodeAutoInstrumentations({ // Disable noisy instrumentations '@opentelemetry/instrumentation-fs': { enabled: false }, '@opentelemetry/instrumentation-dns': { enabled: false }, }), ], }); sdk.start(); // Graceful shutdown process.on('SIGTERM', () => { sdk.shutdown().then( () => console.log('Telemetry shut down'), (err) => console.error('Telemetry shutdown error', err) ); });
// package.json — load instrumentation first { "scripts": { "start": "node --require ./dist/instrumentation.js ./dist/index.js", "dev": "tsx --require ./src/instrumentation.ts ./src/index.ts" } }
Details
Load order is critical. OpenTelemetry hooks into library internals (HTTP, pg, express) by monkey-patching. If you import
express before OpenTelemetry initializes, the instrumentation will not work. Always load instrumentation.ts first.
Auto-instrumentations included:
— HTTP/HTTPS client and server@opentelemetry/instrumentation-http
— Express routes and middleware@opentelemetry/instrumentation-express
— PostgreSQL queries@opentelemetry/instrumentation-pg
— Redis commands@opentelemetry/instrumentation-redis
— MongoDB operations@opentelemetry/instrumentation-mongodb
— gRPC calls@opentelemetry/instrumentation-grpc- And many more via
auto-instrumentations-node
Environment variables (standard):
— service name (overrides code)OTEL_SERVICE_NAME
— collector URLOTEL_EXPORTER_OTLP_ENDPOINT
—OTEL_EXPORTER_OTLP_PROTOCOL
orgrpchttp/protobuf
—OTEL_TRACES_SAMPLER
,always_on
,always_offtraceidratio
— sampler argument (e.g.,OTEL_TRACES_SAMPLER_ARG
for 10%)0.1
Local development: Run the OpenTelemetry Collector and Jaeger locally:
docker run -d -p 4318:4318 -p 16686:16686 jaegertracing/all-in-one:latest
Then view traces at
http://localhost:16686.
Common mistakes:
- Importing the instrumentation file after application modules
- Not calling
on process exit (traces may be lost)sdk.shutdown() - Configuring the exporter URL without the path suffix (
)/v1/traces
Source
https://opentelemetry.io/docs/languages/js/getting-started/nodejs/
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.