Skip to main content

opentelemetry-instrumentation

Instruments Node.js/TypeScript applications with OpenTelemetry spans following best practices. Use when adding distributed tracing, instrumenting HTTP requests, database operations, or when implementing observability with OpenTelemetry in Node.js applications.

Zur Installation springen

Quellinformationen

Repository
whitebeardit/.cursor
Letzte Quellaktivität
31. Januar 2026 um 23:09
Erkannte Sprache von SKILL.md
Englisch
Sterne
12
Forks
6

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
opentelemetry-instrumentation
description
Instruments Node.js/TypeScript applications with OpenTelemetry spans following best practices. Use when adding distributed tracing, instrumenting HTTP requests, database operations, or when implementing observability with OpenTelemetry in Node.js applications.
# OpenTelemetry Instrumentation for Node.js This skill guides you through instrumenting Node.js/TypeScript applications with OpenTelemetry spans, following best practices for distributed tracing. ## When to Instrument **✅ DO Instrument:** - External service calls (HTTP, gRPC) - Database operations (queries, transactions) - Critical business operations (order processing, payment flows) - Long-running operations (file processing, batch jobs) - Integration points (third-party APIs, message queues) **❌ DON'T Instrument:** - Simple property getters/setters - In-memory operations (object lookups, array operations) - Trivial calculations - Operations that complete in <1ms consistently ## Installation ```bash npm install @opentelemetry/api @opentelemetry/sdk-trace-base @opentelemetry/sdk-trace-node npm install @opentelemetry/instrumentation-http @opentelemetry/instrumentation-express npm install @opentelemetry/exporter-otlp-http ``` ## Core Concepts ### Tracer and Span OpenTelemetry uses `Tracer` and `Span` for creating traces: ```typescript import { trace } from '@opentelemetry/api'; const tracer = trace.getTracer('MyService'); // Create a span const span = tracer.startSpan('operation.name'); try { // Your code here span.setAttributes({ 'key': 'value', }); span.setStatus({ code: SpanStatusCode.OK }); } catch (error) { span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }); span.recordException(error); throw error; } finally { span.end(); } ``` ### Span Kinds ```typescript import { SpanKind } from '@opentelemetry/api'; SpanKind.SERVER // Incoming HTTP request SpanKind.CLIENT // Outgoing HTTP/gRPC call SpanKind.INTERNAL // Internal operation SpanKind.PRODUCER // Message queue producer SpanKind.CONSUMER // Message queue consumer ``` ## Instrumentation Patterns ### Pattern 1: HTTP Server (Express) **Automatic instrumentation:** ```typescript import { NodeSDK } from '@opentelemetry/sdk-node'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; import { OTLPTraceExporter } from '@opentelemetry/exporter-otlp-http'; const sdk = new NodeSDK({ traceExporter: new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318/v1/traces', }), instrumentations: [getNodeAutoInstrumentations()], }); sdk.start(); ``` **Manual instrumentation:** ```typescript import { trace, SpanKind, SpanStatusCode } from '@opentelemetry/api'; import express, { Request, Response, NextFunction } from 'express'; const tracer = trace.getTracer('MyService'); export function tracingMiddleware( req: Request, res: Response, next: NextFunction ): void { const span = tracer.startSpan(`HTTP ${req.method} ${req.path}`, { kind: SpanKind.SERVER, attributes: { 'http.method': req.method, 'http.url': req.url, 'http.route': req.route?.path || req.path, }, }); res.on('finish', () => { span.setAttributes({ 'http.status_code': res.statusCode, }); if (res.statusCode >= 400) { span.setStatus({ code: SpanStatusCode.ERROR, message: `HTTP ${res.statusCode}`, }); } else { span.setStatus({ code: SpanStatusCode.OK }); } span.end(); }); trace.setSpan(trace.active(), span); next(); } ``` ### Pattern 2: HTTP Client Calls ```typescript import { trace, SpanKind, SpanStatusCode } from '@opentelemetry/api'; import axios, { AxiosRequestConfig } from 'axios'; const tracer = trace.getTracer('MyService'); export async function callExternalApi( url: string, config?: AxiosRequestConfig ) { const span = tracer.startSpan('http.client.call', { kind: SpanKind.CLIENT, attributes: { 'http.method': config?.method?.toUpperCase() || 'GET', 'http.url': url, }, }); try { const response = await axios(url, config); span.setAttributes({ 'http.status_code': response.status, }); span.setStatus({ code: SpanStatusCode.OK }); return response; } catch (error: any) { span.recordException(error); span.setStatus({ code: SpanStatusCode.ERROR, message: error.message, }); throw error; } finally { span.end(); } } ``` ### Pattern 3: Database Operations ```typescript import { trace, SpanKind, SpanStatusCode } from '@opentelemetry/api'; const tracer = trace.getTracer('MyService'); export async function queryDatabase<T>( query: string, params?: any[] ): Promise<T[]> { const span = tracer.startSpan('db.query', { kind: SpanKind.INTERNAL, attributes: { 'db.system': 'postgresql', 'db.name': databaseName, 'db.operation': 'SELECT', // Note: Sanitize db.statement if contains sensitive data }, }); try { const result = await db.query(query, params); span.setAttributes({ 'db.rows_affected': result.rowCount || 0, }); span.setStatus({ code: SpanStatusCode.OK }); return result.rows; } catch (error: any) { span.recordException(error); span.setStatus({ code: SpanStatusCode.ERROR, message: error.message, }); throw error; } finally { span.end(); } } ``` ### Pattern 4: Business Operations ```typescript export async function processOrder(orderId: string, amount: number) { const span = tracer.startSpan('order.process', { kind: SpanKind.INTERNAL, attributes: { 'order.id': orderId, 'order.amount': amount, }, }); try { // Child spans for sub-operations const paymentSpan = tracer.startSpan('payment.process', { kind: SpanKind.INTERNAL, }); try { await processPayment(orderId, amount); paymentSpan.setStatus({ code: SpanStatusCode.OK }); } catch (error: any) { paymentSpan.recordException(error); paymentSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.message, }); throw error; } finally { paymentSpan.end(); } span.setStatus({ code: SpanStatusCode.OK }); return { success: true }; } catch (error: any) { span.recordException(error); span.setStatus({ code: SpanStatusCode.ERROR, message: error.message, }); throw error; } finally { span.end(); } } ``` ## Configuration ### Bootstrap TracerProvider ```typescript import { NodeSDK } from '@opentelemetry/sdk-node'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; import { OTLPTraceExporter } from '@opentelemetry/exporter-otlp-http'; import { Resource } from '@opentelemetry/resources'; import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; const sdk = new NodeSDK({ resource: new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: process.env.SERVICE_NAME || 'MyService', }), traceExporter: new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318/v1/traces', }), instrumentations: [getNodeAutoInstrumentations()], }); // Start SDK sdk.start(); // Graceful shutdown process.on('SIGTERM', () => { sdk.shutdown() .then(() => console.log('Tracing terminated')) .catch((error) => console.error('Error terminating tracing', error)) .finally(() => process.exit(0)); }); ``` ## Environment Variables ```bash # Enable/disable OpenTelemetry OTEL_ENABLED=true # OTLP endpoint OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318/v1/traces # Service name SERVICE_NAME=MyService # Sampling configuration OTEL_TRACES_SAMPLER=traceidratio OTEL_TRACES_SAMPLER_ARG=1.0 # 1.0 = 100%, 0.1 = 10% ``` ## Semantic Tags (Best Practices) Follow OpenTelemetry semantic conventions: **HTTP:** `http.method`, `http.url`, `http.status_code`, `http.route`, `net.peer.name` **Database:** `db.system`, `db.name`, `db.operation`, `db.statement` (sanitized!), `db.rows_affected` **RPC:** `rpc.system`, `rpc.service`, `rpc.method`, `rpc.status_code` **Custom Business:** `order.id`, `user.id`, `payment.amount`, etc. **Never include:** Passwords, tokens, API keys, credit cards, full request/response bodies ## Helper Pattern (Recommended) Create a centralized helper for consistent instrumentation: ```typescript import { trace, SpanKind, SpanStatusCode, Span } from '@opentelemetry/api'; export class TraceabilityHelper { private static tracer = trace.getTracer('MyService'); static startSpan( name: string, kind: SpanKind = SpanKind.INTERNAL ): Span | undefined { if (!this.isOtelEnabled()) return undefined; return this.tracer.startSpan(name, { kind }); } static setHttpTags( span: Span | undefined, method?: string, url?: string, statusCode?: number ): void { if (!span) return; if (method) span.setAttribute('http.method', method); if (url) span.setAttribute('http.url', url); if (statusCode !== undefined) { span.setAttribute('http.status_code', statusCode); } } static setDbTags( span: Span | undefined, system: string, name: string, operation: string ): void { if (!span) return; span.setAttribute('db.system', system); span.setAttribute('db.name', name); span.setAttribute('db.operation', operation); } static setSuccessStatus(span: Span | undefined): void { span?.setStatus({ code: SpanStatusCode.OK }); } static setErrorStatus( span: Span | undefined, errorMessage?: string ): void { span?.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage, }); } static recordException(span: Span | undefined, error: Error): void { if (!span || !error) return; span.recordException(error); } private static isOtelEnabled(): boolean { const env = process.env.OTEL_ENABLED; return env === 'true' || env === '1'; } } ``` ## Best Practices 1. **Feature Flag**: Use `OTEL_ENABLED` to disable without code changes 2. **Never Crash**: Wrap initialization in try/catch - misconfiguration shouldn't bring down the app 3. **Null Checks**: Always check if span exists (may be null if disabled or sampled out) 4. **Semantic Conventions**: Use standard attribute names (`http.*`, `db.*`, `rpc.*`, `error.*`) 5. **Sensitive Data**: Never include passwords, tokens, credit cards, full payloads 6. **Span Hierarchy**: Create logical parent-child relationships (Server → Internal → Client) 7. **Error Handling**: Always record exceptions and set error status 8. **Sampling**: Dev 100% (`SAMPLER_ARG=1.0`), Production 10% or less (`0.1` or `0.01`) ## Common Issues **Spans Not Appearing:** - Check `OTEL_ENABLED=true`, OTLP endpoint reachable, sampling rate, tracer registered **Memory Leaks:** - Ensure spans are properly ended in finally blocks - Use automatic instrumentation when possible **Performance Impact:** - Use sampling in production (10% or less) - Avoid instrumenting high-frequency operations ## Key Principles
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen