Harness-engineering otel-sdk-setup

OpenTelemetry SDK Setup

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.md
source 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

  1. Install the core SDK and auto-instrumentation packages.
  2. Create the instrumentation file (
    instrumentation.ts
    ) — it must run before any other application code.
  3. Define the resource with service name, version, and environment.
  4. Configure exporters for traces, metrics, and logs (OTLP is the standard protocol).
  5. Register auto-instrumentations for libraries your application uses.
  6. Load the instrumentation file first:
    node --require ./instrumentation.ts
    or
    import './instrumentation'
    at the top of your entry point.
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:

  • @opentelemetry/instrumentation-http
    — HTTP/HTTPS client and server
  • @opentelemetry/instrumentation-express
    — Express routes and middleware
  • @opentelemetry/instrumentation-pg
    — PostgreSQL queries
  • @opentelemetry/instrumentation-redis
    — Redis commands
  • @opentelemetry/instrumentation-mongodb
    — MongoDB operations
  • @opentelemetry/instrumentation-grpc
    — gRPC calls
  • And many more via
    auto-instrumentations-node

Environment variables (standard):

  • OTEL_SERVICE_NAME
    — service name (overrides code)
  • OTEL_EXPORTER_OTLP_ENDPOINT
    — collector URL
  • OTEL_EXPORTER_OTLP_PROTOCOL
    grpc
    or
    http/protobuf
  • OTEL_TRACES_SAMPLER
    always_on
    ,
    always_off
    ,
    traceidratio
  • OTEL_TRACES_SAMPLER_ARG
    — sampler argument (e.g.,
    0.1
    for 10%)

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
    sdk.shutdown()
    on process exit (traces may be lost)
  • Configuring the exporter URL without the path suffix (
    /v1/traces
    )

Source

https://opentelemetry.io/docs/languages/js/getting-started/nodejs/

Process

  1. Read the instructions and examples in this document.
  2. Apply the patterns to your implementation, adapting to your specific context.
  3. 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.