{"id":11501,"library":"opentelemetry-instrumentation-fetch-node","title":"OpenTelemetry Node.js Fetch Instrumentation","description":"This package, `@gasbuddy/opentelemetry-instrumentation-fetch-node`, provides automatic OpenTelemetry instrumentation specifically for Node.js 18+ native `fetch` API calls. Unlike generic HTTP instrumentation, it is designed to work with the `undici`-based native `fetch` implementation in newer Node.js versions. The current stable version is 1.2.3, released in July 2024, with a consistent release cadence addressing bug fixes and features. A key differentiator is its use of Node.js's diagnostics channel for tracing and a unique workaround involving a 'phony fetch' to an unparseable URL, ensuring the instrumentation is active even with Node's lazy-loading behavior of the `fetch` API. It allows for advanced customization of spans and headers through an `onRequest` event. This is crucial for applications leveraging native `fetch` in modern Node environments that need comprehensive observability.","status":"active","version":"1.2.3","language":"javascript","source_language":"en","source_url":"https://github.com/gas-buddy/opentelemetry-instrumentation-fetch-node","tags":["javascript","typescript","gasbuddy","opentelemetry","fetch","undici"],"install":[{"cmd":"npm install opentelemetry-instrumentation-fetch-node","lang":"bash","label":"npm"},{"cmd":"yarn add opentelemetry-instrumentation-fetch-node","lang":"bash","label":"yarn"},{"cmd":"pnpm add opentelemetry-instrumentation-fetch-node","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency for OpenTelemetry API interfaces and types, required for all OpenTelemetry instrumentations.","package":"@opentelemetry/api","optional":false}],"imports":[{"note":"This is the primary class for initializing and configuring fetch instrumentation. While Node.js 18+ environments predominantly use ESM, CommonJS `require` is also supported.","wrong":"const { NodeFetchInstrumentation } = require('@gasbuddy/opentelemetry-instrumentation-fetch-node');","symbol":"NodeFetchInstrumentation","correct":"import { NodeFetchInstrumentation } from '@gasbuddy/opentelemetry-instrumentation-fetch-node';"},{"note":"This TypeScript type defines the configuration options available for `NodeFetchInstrumentation`, useful for detailed customization in TypeScript projects.","symbol":"NodeFetchInstrumentationConfig","correct":"import type { NodeFetchInstrumentationConfig } from '@gasbuddy/opentelemetry-instrumentation-fetch-node';"},{"note":"This is a generic OpenTelemetry utility from the core instrumentation package, essential for activating `NodeFetchInstrumentation` and any other instrumentations in your application.","symbol":"registerInstrumentations","correct":"import { registerInstrumentations } from '@opentelemetry/instrumentation';"}],"quickstart":{"code":"import { NodeSDK } from '@opentelemetry/sdk-node';\nimport { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-node';\nimport { Resource } from '@opentelemetry/resources';\nimport { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';\nimport { registerInstrumentations } from '@opentelemetry/instrumentation';\nimport { NodeFetchInstrumentation } from '@gasbuddy/opentelemetry-instrumentation-fetch-node';\n\nconst sdk = new NodeSDK({\n  resource: new Resource({\n    [SemanticResourceAttributes.SERVICE_NAME]: 'my-fetch-service',\n  }),\n  traceExporter: new ConsoleSpanExporter(),\n});\n\n// Initialize and register the fetch instrumentation\nregisterInstrumentations([\n  new NodeFetchInstrumentation({\n    propagateContext: true, // Propagate trace context in outgoing headers\n    ignoreMethods: ['OPTIONS'], // Do not instrument OPTIONS requests\n    onRequest: (span, request) => {\n      // Add custom attributes to the span before the request is made\n      span.setAttribute('http.request.method', request.method);\n      span.setAttribute('http.request.headers.host', request.headers.get('host') ?? '');\n      // Example: Add a custom header to the outgoing request\n      // request.headers.set('x-custom-trace-id', span.spanContext().traceId);\n    },\n    applyCustomAttributesOnSpan: (span, request, response) => {\n        // Add custom attributes to the span after the response is received\n        if (response) {\n            span.setAttribute('http.response.status_code', response.status);\n            span.setAttribute('http.response.status_text', response.statusText);\n        }\n    }\n  }),\n]);\n\nsdk.start();\n\nasync function makeFetchRequest() {\n  try {\n    console.log('Making a fetch request...');\n    const response = await fetch('https://httpbin.org/get', {\n      method: 'GET',\n      headers: {\n        'Content-Type': 'application/json',\n        'Accept': 'application/json'\n      },\n    });\n    const data = await response.json();\n    console.log('Fetch request completed (URL):', data.url);\n  } catch (error) {\n    console.error('Fetch request failed:', error);\n  }\n}\n\n// Execute the request and then shut down the SDK gracefully\nmakeFetchRequest().finally(() => {\n  console.log('Shutting down OpenTelemetry SDK...');\n  // A small delay to ensure all spans are processed before shutdown\n  setTimeout(() => sdk.shutdown().then(() => console.log('SDK shutdown complete.')), 500);\n});","lang":"typescript","description":"Demonstrates how to set up and register `NodeFetchInstrumentation` with a basic OpenTelemetry Node SDK, make a traced native `fetch` request, and customize span attributes and request headers using `onRequest` and `applyCustomAttributesOnSpan` callbacks."},"warnings":[{"fix":"Ensure your Node.js runtime environment is version 18.0.0 or later to use this package.","message":"This instrumentation specifically targets Node.js 18.0.0 or higher due to its reliance on native `fetch` (which uses `undici` internally) and Node's diagnostics channel features. It will not function on older Node.js versions.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"No user action is required; this is an internal mechanism. Be aware of this if you observe an unexpected, failed network event on application startup, which is harmless.","message":"Node.js's native `fetch` is lazily loaded. This instrumentation performs an internal 'phony fetch' to an unparseable URL at initialization to ensure the diagnostics channel is registered and no `fetch` events are missed.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Use `NodeFetchInstrumentation` for native `fetch` and `@opentelemetry/instrumentation-http` for other HTTP/HTTPS traffic if both types of requests are made in your application.","message":"Unlike generic HTTP instrumentations (e.g., `@opentelemetry/instrumentation-http`), this package is exclusively for Node.js native `fetch`. If your application uses both native `fetch` and Node's traditional `http`/`https` modules, you will need to register both instrumentations to cover all traffic.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"When accessing or manipulating headers (e.g., `request.headers.get('name')`), ensure your code accounts for the possibility of `string | string[]` return types or use `request.headers.raw()` for direct access to all header values as arrays.","message":"Since `undici` (Node's internal fetch implementation) and consequently this instrumentation (from v1.2.0) support array-based header values, your `onRequest` or `onResponse` callbacks should be prepared to handle headers as potentially being string arrays, not just single strings.","severity":"gotcha","affected_versions":">=1.2.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Upgrade your Node.js runtime to version 18.0.0 or higher to enable native `fetch` functionality.","cause":"The application is running on a Node.js version older than 18.0.0, where the global native `fetch` API is not available.","error":"TypeError: fetch is not a function"},{"fix":"Ensure `new NodeFetchInstrumentation()` is passed to `registerInstrumentations()` and that the `NodeSDK` is explicitly started *before* any native `fetch` requests are executed in your application's lifecycle.","cause":"The `NodeFetchInstrumentation` or the overall OpenTelemetry SDK was not correctly initialized and registered before `fetch` calls were made, preventing proper instrumentation.","error":"OpenTelemetry traces for native fetch calls are not appearing or seem incomplete."},{"fix":"Review the `Request` and `Response` interfaces provided by the DOM and Node's `undici` typings for correct property access. Use standard methods like `request.headers.get('header-name')` or `request.headers.raw()` for robust header manipulation.","cause":"The type definitions being used for `Request` or `Response` within the `onRequest` callback might not align with the `undici`-based native `fetch` types or you're attempting to access headers improperly.","error":"TypeScript compiler error: Property 'headers' does not exist on type 'Request' or 'Response' in `onRequest` callback."}],"ecosystem":"npm"}