### Context Manager Setup Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of setting up and enabling the AsyncHooksContextManager for context propagation. ```javascript const { AsyncHooksContextManager } = require('@opentelemetry/context-async-hooks'); const contextManager = new AsyncHooksContextManager(); context.setGlobalContextManager(contextManager); contextManager.enable(); ``` -------------------------------- ### OpenTelemetry SDK Setup Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of setting up the NodeTracerProvider and adding a span processor. ```javascript const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); const provider = new NodeTracerProvider({ resource: new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: 'my-service' }) }); // Add span processor for exporting provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); // Set as global context.setGlobalContextManager(new AsyncHooksContextManager()); ``` -------------------------------- ### Exporter Setup Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of setting up the JaegerExporter and adding it to the provider. ```javascript const { JaegerExporter } = require('@opentelemetry/exporter-trace-jaeger-http'); const exporter = new JaegerExporter({ endpoint: 'http://localhost:14268/api/traces', serviceName: 'my-service' }); provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); ``` -------------------------------- ### Minimal Configuration Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Demonstrates a basic setup with Fastify and OpenTelemetry instrumentation, configuring Jaeger exporter. ```javascript const Fastify = require('fastify'); const FastifyOtelInstrumentation = require('@fastify/otel'); const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); const { JaegerExporter } = require('@opentelemetry/exporter-trace-jaeger-http'); // Create tracer provider const jaegerExporter = new JaegerExporter({ serviceName: 'my-api', }); const provider = new NodeTracerProvider(); provider.addSpanProcessor(new SimpleSpanProcessor(jaegerExporter)); // Create instrumentation const instrumentation = new FastifyOtelInstrumentation(); instrumentation.setTracerProvider(provider); // Create Fastify app const app = Fastify(); // Register instrumentation await app.register(instrumentation.plugin()); // Define routes (automatically instrumented) app.get('/', (request, reply) => { return { message: 'hello world' }; }); app.listen({ port: 3000 }); ``` -------------------------------- ### Recommended Propagator Setup Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Sets up W3C Trace Context and Jaeger propagators for distributed tracing. ```javascript const { W3CTraceContextPropagator } = require('@opentelemetry/core'); const { JaegerPropagator } = require('@opentelemetry/propagator-jaeger'); propagation.setGlobalPropagator( new CompositePropagator({ propagators: [ new W3CTraceContextPropagator(), new JagerPropagator() ] }) ); ``` -------------------------------- ### Minimal Setup Source: https://github.com/fastify/otel/blob/main/_autodocs/README.md Basic setup and minimal configuration for FastifyOtelInstrumentation. ```javascript const FastifyOtelInstrumentation = require('@fastify/otel'); const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); const instrumentation = new FastifyOtelInstrumentation(); const provider = new NodeTracerProvider(); instrumentation.setTracerProvider(provider); const app = require('fastify')(); await app.register(instrumentation.plugin()); app.get('/', (request, reply) => { const otel = request.opentelemetry(); return 'hello world'; }); ``` -------------------------------- ### Adding Metrics Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of how to add metrics using OpenTelemetry API and SDK. ```javascript const { metrics } = require('@opentelemetry/api'); const MeterProvider = require('@opentelemetry/sdk-metrics').MeterProvider; const meterProvider = new MeterProvider(); metrics.setGlobalMeterProvider(meterProvider); const meter = metrics.getMeter('my-app'); const requestCounter = meter.createCounter('http.requests.total'); app.addHook('onResponse', (request, reply, done) => { requestCounter.add(1, { 'http.method': request.method, 'http.status_code': reply.statusCode }); done(); }); ``` -------------------------------- ### With Authentication Plugin Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Example of integrating an authentication plugin and adding user information to the trace. ```javascript const authPlugin = async (app, opts) => { app.addHook('preHandler', async (request, reply) => { const otel = request.opentelemetry(); try { const user = await authenticate(request); request.user = user; // Add user to trace if (otel.span) { otel.span.setAttribute('user.id', user.id); otel.span.setAttribute('user.role', user.role); } } catch (error) { if (otel.span) { otel.span.setAttribute('auth.failed', true); otel.span.setAttribute('auth.error', error.message); } reply.code(401).send({ error: 'Unauthorized' }); } }); }; const app = Fastify(); // Register auth plugin BEFORE instrumentation for better trace context await app.register(authPlugin); const instrumentation = new FastifyOtelInstrumentation(); instrumentation.setTracerProvider(provider); await app.register(instrumentation.plugin()); app.get('/profile', (request, reply) => { // User info is in the trace context return { user: request.user }; }); ``` -------------------------------- ### FastifyOtelInstrumentationOptions examples Source: https://github.com/fastify/otel/blob/main/README.md Example of initializing FastifyOtelInstrumentation with options to register on initialization and ignore specific paths. ```typescript import { FastifyOtelInstrumentation } from '@fastify/otel'; const fastifyOtelInstrumentation = new FastifyOtelInstrumentation({ registerOnInitialization: true, ignorePaths: (opts) => { // Ignore all paths that start with /ignore return opts.url.startsWith('/ignore'); }, }); // Service name should be set via environment variable: // export OTEL_SERVICE_NAME=my-server // or via NodeSDK resource configuration ``` -------------------------------- ### OTEL_FASTIFY_IGNORE_PATHS Environment Variable Examples Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md Examples of setting the OTEL_FASTIFY_IGNORE_PATHS environment variable. ```bash export OTEL_FASTIFY_IGNORE_PATHS='/health/*' export OTEL_FASTIFY_IGNORE_PATHS='/metrics' export OTEL_FASTIFY_IGNORE_PATHS='/**/*.json' ``` -------------------------------- ### Auto-Registration with Node SDK Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Example of auto-registering Fastify OpenTelemetry instrumentation when initializing the OpenTelemetry Node SDK. ```javascript const { NodeSDK } = require('@opentelemetry/sdk-node'); const FastifyOtelInstrumentation = require('@fastify/otel'); const sdk = new NodeSDK({ traceExporter: new JaegerExporter({ serviceName: 'my-service' }), instrumentations: [ new FastifyOtelInstrumentation({ registerOnInitialization: true // Auto-register on Fastify creation }) ] }); sdk.start(); // No need to manually register the plugin const app = Fastify(); app.get('/', (request, reply) => { // Automatically instrumented return 'hello'; }); ``` -------------------------------- ### Constructor Usage Example Source: https://github.com/fastify/otel/blob/main/_autodocs/api-reference/FastifyOtelInstrumentation.md Example of creating a new FastifyOtelInstrumentation instance with various configuration options. ```javascript const FastifyOtelInstrumentation = require('@fastify/otel'); const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); // Create instrumentation instance const instrumentation = new FastifyOtelInstrumentation({ registerOnInitialization: false, ignorePaths: '/health/*', recordExceptions: true, requestHook: (span, request) => { span.setAttribute('user.id', request.headers['x-user-id'] ?? 'anonymous'); span.updateName(`${request.method} ${request.routeOptions.url}`); }, lifecycleHook: (span, info) => { span.setAttribute('handler.name', info.handler ?? 'anonymous'); } }); // Set the tracer provider const provider = new NodeTracerProvider(); instrumentation.setTracerProvider(provider); ``` -------------------------------- ### Install Source: https://github.com/fastify/otel/blob/main/README.md Install the @fastify/otel package using npm. ```sh npm i @fastify/otel ``` -------------------------------- ### Complete Configuration Example Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md A comprehensive example showing the initialization of Fastify OpenTelemetry Instrumentation with various options, including ignoring paths, custom request and lifecycle hooks, and setting a specific tracer provider. ```javascript const FastifyOtelInstrumentation = require('@fastify/otel'); const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); const { JaegerExporter } = require('@opentelemetry/exporter-trace-jaeger-http'); // Create tracer provider const jaegerExporter = new JaegerExporter({ serviceName: process.env.OTEL_SERVICE_NAME || 'my-service', }); const provider = new NodeTracerProvider(); provider.addSpanProcessor(new SimpleSpanProcessor(jaegerExporter)); // Create instrumentation with all options const instrumentation = new FastifyOtelInstrumentation({ registerOnInitialization: false, ignorePaths: (route) => { if (route.url.startsWith('/health')) return true; if (route.url.startsWith('/metrics')) return true; if (route.method === 'OPTIONS') return true; return false; }, requestHook: (span, request) => { span.setAttribute('service.version', '1.0.0'); span.setAttribute('http.client_ip', request.ip); const userId = request.headers['x-user-id']; if (userId) span.setAttribute('user.id', userId); }, lifecycleHook: (span, info) => { span.setAttribute('fastify.hook', info.hookName); if (info.handler) { span.setAttribute('handler.name', info.handler); } }, recordExceptions: true }); // Set tracer provider instrumentation.setTracerProvider(provider); // Enable instrumentation instrumentation.enable(); // Register with Fastify app.register(instrumentation.plugin()); ``` -------------------------------- ### Debugging and Logging Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of enabling diagnostic logging for debugging OpenTelemetry integration. ```javascript const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api'); // Enable debug logging diag.setLogger( new DiagConsoleLogger(), { logLevel: DiagLogLevel.DEBUG } ); // Now you'll see debug messages from instrumentation ``` -------------------------------- ### Message Propagation Example (Incoming) Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of extracting trace context from message context on the receiving end. ```javascript const parentContext = otel.extract(message.context); const span = otel.tracer.startSpan('process_message', {}, parentContext); ``` -------------------------------- ### enable() Usage Example Source: https://github.com/fastify/otel/blob/main/_autodocs/api-reference/FastifyOtelInstrumentation.md Example of enabling instrumentation with registerOnInitialization set to true. ```javascript const instrumentation = new FastifyOtelInstrumentation({ registerOnInitialization: true }); instrumentation.setTracerProvider(provider); instrumentation.enable(); // Fastify instance will be automatically instrumented on creation const app = Fastify(); ``` -------------------------------- ### Exception Recording Example Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of manually recording an exception to the current span. ```javascript span.recordException(error) // Records the error ``` -------------------------------- ### Resource Attributes Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of setting service resource attributes using the SDK. ```javascript const { Resource } = require('@opentelemetry/resources'); const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions'); const resource = Resource.default().merge( new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: 'my-api', [SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0', [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: 'production', 'custom.attribute': 'custom-value' }) ); const provider = new NodeTracerProvider({ resource }); ``` -------------------------------- ### Incoming Header Propagation Example Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of extracting trace context from incoming request headers using the OpenTelemetry API. ```javascript // From OpenTelemetry API const parentContext = propagation.extract(ctx, request.headers) ``` -------------------------------- ### Recording All Exceptions Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Example showing the default behavior of recording all exceptions in Fastify OpenTelemetry instrumentation. ```javascript // Default behavior - record all exceptions const instrumentation = new FastifyOtelInstrumentation({ recordExceptions: true }); app.get('/operation', (request, reply) => { throw new Error('Operation failed'); // This exception is recorded in the span }); ``` -------------------------------- ### Latency Tracking Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md This example demonstrates how to track request latency using Fastify OpenTelemetry, including starting a timing event and adding response time attributes to spans. ```javascript const instrumentation = new FastifyOtelInstrumentation({ lifecycleHook: (span, info) => { // Record timing information const startTime = process.hrtime.bigint(); // Use an event to mark timing span.addEvent('timing_start', { 'timing.start_ns': Number(startTime) }); } }); // At request level app.addHook('onResponse', (request, reply, done) => { const otel = request.opentelemetry(); if (otel.span) { // Add response timing otel.span.setAttribute('http.response_time_ms', reply.getResponseTime?.()); } done(); }); ``` -------------------------------- ### Real-Time Export (SimpleSpanProcessor) Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of configuring immediate span export using SimpleSpanProcessor. ```javascript // Export immediately when span is ended provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); ``` -------------------------------- ### OTEL_SERVICE_NAME Environment Variable Example Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md Example of setting the OTEL_SERVICE_NAME environment variable. ```bash export OTEL_SERVICE_NAME=my-api-service ``` -------------------------------- ### Usage Example Source: https://github.com/fastify/otel/blob/main/README.md Example of how to use @fastify/otel in a Fastify application, including setting up the tracer provider and registering the plugin. ```js // ... in your OTEL setup const FastifyOtelInstrumentation = require('@fastify/otel'); // Service name comes from OpenTelemetry resources (via NodeSDK or OTEL_SERVICE_NAME) // as per https://opentelemetry.io/docs/languages/sdk-configuration/general/. const fastifyOtelInstrumentation = new FastifyOtelInstrumentation(); fastifyOtelInstrumentation.setTracerProvider(provider) module.exports = { fastifyOtelInstrumentation } // ... in your Fastify definition const { fastifyOtelInstrumentation } = require('./otel.js'); const Fastify = require('fastify'); const app = fastify(); // It is necessary to await for its register as it requires to be able // to intercept all route definitions await app.register(fastifyOtelInstrumentation.plugin()); // automatically all your routes will be instrumented app.get('/', () => 'hello world') // as well as your instance level hooks. app.addHook('onError', () => /* do something */) // Manually skip telemetry for a specific route app.get('/healthcheck', { config: { otel: false } }, () => 'Up!') // you can also scope your instrumentation to only be enabled on a sub context // of your application app.register((instance, opts, done) => { instance.register(fastifyOtelInstrumentation.plugin()); // If only enabled in your encapsulated context // the parent context won't be instrumented app.get('/', () => 'hello world') done() }, { prefix: '/nested' }) ``` -------------------------------- ### plugin() Usage Example Source: https://github.com/fastify/otel/blob/main/_autodocs/api-reference/FastifyOtelInstrumentation.md Example of registering the FastifyOtelInstrumentation plugin with a Fastify instance. ```javascript const Fastify = require('fastify'); const FastifyOtelInstrumentation = require('@fastify/otel'); const app = Fastify(); const instrumentation = new FastifyOtelInstrumentation(); instrumentation.setTracerProvider(provider); // Register the plugin - must be done before routes await app.register(instrumentation.plugin()); // Routes defined after registration are automatically instrumented app.get('/', (request, reply) => { const otel = request.opentelemetry(); return 'hello world'; }); ``` -------------------------------- ### Sampling Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of configuring a probability sampler to control which spans are exported. ```javascript const { ProbabilitySampler } = require('@opentelemetry/core'); const sampler = new ProbabilitySampler(0.1); // Sample 10% of requests const provider = new NodeTracerProvider({ sampler }); ``` -------------------------------- ### Business Logic Tracing Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Shows how to add custom events to spans within business logic, such as user lookup start, success, or failure. ```javascript app.get('/users/:id', async (request, reply) => { const otel = request.opentelemetry(); if (otel.span) { otel.span.addEvent('user_lookup_started', { 'user.id': request.params.id }); } try { const user = await db.users.findById(request.params.id); otel.span?.addEvent('user_lookup_succeeded', { 'user.exists': !!user }); return user; } catch (error) { otel.span?.addEvent('user_lookup_failed', { 'error.message': error.message }); throw error; } }); ``` -------------------------------- ### Outgoing Header Propagation Example Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of injecting trace context into outgoing request headers for calling external services. ```javascript const otel = request.opentelemetry(); const headers = {}; otel.inject(headers); // Adds trace headers fetch('https://external-service', { headers: { ...headers } }); ``` -------------------------------- ### Integration with HTTP Instrumentation Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of integrating Fastify with OpenTelemetry HTTP instrumentation for full HTTP tracing. ```javascript const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http'); const FastifyOtelInstrumentation = require('@fastify/otel'); const httpInstrumentation = new HttpInstrumentation(); const fastifyInstrumentation = new FastifyOtelInstrumentation(); httpInstrumentation.setTracerProvider(provider); fastifyInstrumentation.setTracerProvider(provider); httpInstrumentation.enable(); fastifyInstrumentation.enable(); ``` -------------------------------- ### Encapsulation Example Source: https://github.com/fastify/otel/blob/main/_autodocs/integration-architecture.md An example demonstrating how to register the @fastify/otel instrumentation within an encapsulated Fastify instance, ensuring that instrumentation only applies to routes within that scope. ```javascript app.register(async (instance) => { await instance.register(instrumentation.plugin()) // Routes here use instrumentation instance.get('/', handler) }, { prefix: '/api' }) // Routes here do NOT use instrumentation app.get('/health', handler) ``` -------------------------------- ### Message Propagation Example (Outgoing) Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of injecting trace context into message context for message queues or event systems. ```javascript const message = { data: payload, context: {} }; otel.inject(message.context); // Embed trace context await queue.send(message); ``` -------------------------------- ### FastifyOtelInstrumentation Usage Example Source: https://github.com/fastify/otel/blob/main/_autodocs/module-exports.md An example demonstrating how to instantiate and use the `FastifyOtelInstrumentation` class. ```javascript const instrumentation = new FastifyOtelInstrumentation({ ignorePaths: '/health/*' }); console.log(instrumentation.isEnabled()); // false initially instrumentation.setTracerProvider(provider); instrumentation.enable(); console.log(instrumentation.isEnabled()); // true const plugin = instrumentation.plugin(); await app.register(plugin); ``` -------------------------------- ### With Configuration Source: https://github.com/fastify/otel/blob/main/_autodocs/README.md FastifyOtelInstrumentation setup with custom configuration options. ```javascript const instrumentation = new FastifyOtelInstrumentation({ ignorePaths: '/health/*', requestHook: (span, request) => { span.setAttribute('user.id', request.headers['x-user-id']); }, lifecycleHook: (span, info) => { span.setAttribute('hook.name', info.hookName); }, recordExceptions: true }); ``` -------------------------------- ### Tracer Provider Configuration Example Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md Example of explicitly configuring the OpenTelemetry tracer provider for the instrumentation using the `setTracerProvider()` method. ```javascript const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); const provider = new NodeTracerProvider(); instrumentation.setTracerProvider(provider); ``` -------------------------------- ### Function-Based Filtering Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Example demonstrating how to use a function for more granular path filtering in Fastify OpenTelemetry instrumentation. ```javascript const instrumentation = new FastifyOtelInstrumentation({ ignorePaths: (route) => { // Skip health checks if (route.url.startsWith('/health')) return true; // Skip metrics if (route.url.startsWith('/metrics')) return true; // Skip preflight requests if (route.method === 'OPTIONS') return true; // Skip static files if (route.url.startsWith('/static')) return true; return false; } }); ``` -------------------------------- ### Message Queue Integration Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Example showing how to integrate OpenTelemetry with message queue operations, such as sending a message to RabbitMQ and injecting trace context. ```javascript const amqp = require('amqplib'); app.post('/queue-job', async (request, reply) => { const otel = request.opentelemetry(); // Create span for queue operation const queueSpan = otel.tracer.startSpan('enqueue_job', { attributes: { 'messaging.system': 'rabbitmq', 'messaging.destination': 'job_queue' } }, otel.context); try { const message = { data: request.body, traceContext: {} }; // Inject trace context into message otel.inject(message.traceContext); const channel = await getAmqpChannel(); channel.sendToQueue('job_queue', Buffer.from(JSON.stringify(message))); queueSpan.end(); return { queued: true }; } catch (error) { queueSpan.recordException(error); queueSpan.end(); throw error; } }); ``` -------------------------------- ### Scoped Instrumentation Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Example of applying different instrumentation configurations to different route groups using nested Fastify instances. ```javascript const app = Fastify(); // Main app routes (instrumented with root config) const rootInstrumentation = new FastifyOtelInstrumentation({ ignorePaths: '/health/*' }); await app.register(rootInstrumentation.plugin()); app.get('/', (request, reply) => 'Main app'); // Scoped /api routes with different instrumentation await app.register( async (apiInstance, opts) => { const apiInstrumentation = new FastifyOtelInstrumentation({ requestHook: (span, request) => { span.setAttribute('api.version', 'v1'); } }); await apiInstance.register(apiInstrumentation.plugin()); apiInstance.get('/data', (request, reply) => 'API data'); }, { prefix: '/api' } ); ``` -------------------------------- ### Glob Pattern Ignore Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Example of configuring Fastify OpenTelemetry instrumentation to ignore specific paths using a glob pattern. ```javascript const instrumentation = new FastifyOtelInstrumentation({ // Ignore health check and metrics endpoints ignorePaths: '/{health,metrics}/**' }); ``` -------------------------------- ### Exception Recording Control Examples Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md Examples demonstrating how to control exception recording. Setting `recordExceptions` to `false` disables recording, while `true` (the default) enables it. ```javascript const instrumentation = new FastifyOtelInstrumentation({ recordExceptions: false }); // Exceptions will not be recorded, reducing noise in error tracking ``` ```javascript const instrumentation = new FastifyOtelInstrumentation({ recordExceptions: true // default, records all exceptions }); ``` -------------------------------- ### Database Operations Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Example showing how to instrument database queries, including capturing statement, duration, and rows affected. ```javascript app.get('/users', async (request, reply) => { const otel = request.opentelemetry(); const dbSpan = otel.tracer.startSpan('db.query', { attributes: { 'db.system': 'postgresql', 'db.operation': 'select', 'db.statement': 'SELECT * FROM users WHERE active = $1' } }, otel.context); try { const startTime = process.hrtime.bigint(); const users = await db.query('SELECT * FROM users WHERE active = $1', [true]); const duration = Number(process.hrtime.bigint() - startTime) / 1000000; // ms dbSpan.setAttribute('db.duration_ms', duration); dbSpan.setAttribute('db.rows', users.length); return users; } catch (error) { dbSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.message }); dbSpan.recordException(error); throw error; } finally { dbSpan.end(); } }); ``` -------------------------------- ### Nested Spans Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Example demonstrating how to create nested spans for batch operations and individual item processing. ```javascript app.get('/process-batch', async (request, reply) => { const otel = request.opentelemetry(); // Create a parent span for the batch operation const batchSpan = otel.tracer.startSpan('batch_processing', { attributes: { 'batch.count': request.body.items.length } }, otel.context); try { const results = await Promise.all( request.body.items.map((item, index) => { // Create child spans for each item const itemSpan = otel.tracer.startSpan(`process_item`, { attributes: { 'item.index': index, 'item.id': item.id } }, otel.context); return processItem(item) .then(result => { itemSpan.end(); return result; }) .catch(error => { itemSpan.recordException(error); itemSpan.end(); throw error; }); }) ); batchSpan.addEvent('batch_completed', { 'results.count': results.length }); return results; } catch (error) { batchSpan.recordException(error); throw error; } finally { batchSpan.end(); } }); ``` -------------------------------- ### Memory Tracking Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md This example shows how to track process memory usage (heap and external) and add these metrics as attributes to spans using a request hook. ```javascript const instrumentation = new FastifyOtelInstrumentation({ requestHook: (span, request) => { const memUsage = process.memoryUsage(); span.setAttribute('process.memory.heap_mb', Math.round(memUsage.heapUsed / 1024 / 1024)); span.setAttribute('process.memory.external_mb', Math.round(memUsage.external / 1024 / 1024)); } }); ``` -------------------------------- ### FastifyOtelInstrumentationOptions requestHook example Source: https://github.com/fastify/otel/blob/main/README.md Example of using the requestHook to add custom attributes and rename spans based on request information. ```javascript const otel = new FastifyOtelInstrumentation({ requestHook: (span, request) => { // attach user info span.setAttribute('user.id', request.headers['x-user-id'] ?? 'anonymous') // optional: give the span a cleaner name span.updateName(`${request.method} ${request.routeOptions.url}`) } }) ``` -------------------------------- ### Node SDK Integration Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Sets up the OpenTelemetry Node SDK with Fastify auto-instrumentation. ```javascript const { NodeSDK } = require('@opentelemetry/sdk-node'); const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); const FastifyOtelInstrumentation = require('@fastify/otel'); const sdk = new NodeSDK({ resource: { attributes: { 'service.name': 'my-service', 'service.version': '1.0.0' } }, traceExporter: new JaegerExporter({ endpoint: 'http://localhost:14268/api/traces' }), instrumentations: [ new FastifyOtelInstrumentation({ registerOnInitialization: true // Auto-register }), ...getNodeAutoInstrumentations() // Other instrumentations ] }); sdk.start(); ``` -------------------------------- ### Usage Example for enabled property Source: https://github.com/fastify/otel/blob/main/_autodocs/api-reference/request-context.md This example demonstrates how to check if OpenTelemetry instrumentation is enabled for the current route and add custom tracing logic if it is. ```javascript app.get('/', (request, reply) => { const otel = request.opentelemetry(); if (otel.enabled) { // Add custom tracing logic otel.span.addEvent('Processing started'); } return 'hello world'; }); ``` -------------------------------- ### Route-Level Disabling Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Example of disabling OpenTelemetry instrumentation for specific routes by setting `otel: false` in the route configuration. ```javascript // Disable instrumentation for specific routes app.get('/healthcheck', { config: { otel: false } }, (request, reply) => { return { status: 'ok' }; }); app.get('/metrics', { config: { otel: false } }, (request, reply) => { return getMetrics(); }); ``` -------------------------------- ### Setting the Tracer Provider Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Demonstrates how to set the tracer provider for the Fastify OpenTelemetry instrumentation. ```javascript const instrumentation = new FastifyOtelInstrumentation(); // Set tracer provider before enabling instrumentation.setTracerProvider(provider); // Then enable instrumentation.enable(); ``` -------------------------------- ### Outbound HTTP Requests Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Example demonstrating how to instrument outbound HTTP requests using OpenTelemetry, including creating a span and injecting trace context into request headers. ```javascript const http = require('http'); app.post('/process', async (request, reply) => { const otel = request.opentelemetry(); // Create a span for the outbound request const externalSpan = otel.tracer.startSpan('external_api_call', { attributes: { 'http.method': 'POST', 'http.url': 'https://api.example.com/process' } }, otel.context); try { // Inject context into request headers const headers = {}; otel.inject(headers); const externalResponse = await fetch('https://api.example.com/process', { method: 'POST', headers: { 'Content-Type': 'application/json', ...headers // Include trace context }, body: JSON.stringify(request.body) }); const result = await externalResponse.json(); externalSpan.end(); return result; } catch (error) { externalSpan.recordException(error); externalSpan.end(); throw error; } }); ``` -------------------------------- ### Usage Example for context property Source: https://github.com/fastify/otel/blob/main/_autodocs/api-reference/request-context.md This example illustrates how to use the `context.with()` method to ensure that operations within a callback inherit the current request context, allowing for proper propagation of tracing information to child spans. ```javascript const { context } = require('@opentelemetry/api'); app.get('/', (request, reply) => { const otel = request.opentelemetry(); context.with(otel.context, () => { // Operations within this callback inherit the request context const tracer = otel.tracer; const childSpan = tracer.startSpan('child-operation'); // ... use childSpan childSpan.end(); }); }); ``` -------------------------------- ### Enriching Request Traces Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Demonstrates enriching request traces with deployment information, request details, and API version. ```javascript const instrumentation = new FastifyOtelInstrumentation({ requestHook: (span, request) => { // Add deployment info span.setAttribute('deployment.environment', process.env.NODE_ENV); span.setAttribute('deployment.version', process.env.APP_VERSION); span.setAttribute('deployment.region', process.env.AWS_REGION); // Add request details span.setAttribute('request.headers_count', Object.keys(request.headers).length); span.setAttribute('request.content_type', request.headers['content-type']); // Track API version const apiVersion = request.headers['api-version'] || 'v1'; span.setAttribute('api.version', apiVersion); } }); ``` -------------------------------- ### Usage Example for span property Source: https://github.com/fastify/otel/blob/main/_autodocs/api-reference/request-context.md This example shows how to set attributes and add events to the current request span, which is useful for tracking request-specific information. ```javascript app.get('/users/:id', (request, reply) => { const otel = request.opentelemetry(); if (otel.span) { otel.span.setAttribute('user.id', request.params.id); otel.span.setAttribute('request.source', request.headers['x-forwarded-for']); otel.span.addEvent('Querying database'); } // ... handler logic }); ``` -------------------------------- ### Usage Example for tracer property Source: https://github.com/fastify/otel/blob/main/_autodocs/api-reference/request-context.md This example demonstrates how to use the `tracer` object to create and manage child spans for specific operations within a request handler, such as database queries, ensuring detailed tracing of internal logic. ```javascript app.get('/items', async (request, reply) => { const otel = request.opentelemetry(); const tracer = otel.tracer; // Create a child span for database operation const dbSpan = tracer.startSpan('db.query', { attributes: { 'db.operation': 'select', 'db.table': 'items' } }, otel.context); try { const items = await db.query('SELECT * FROM items'); dbSpan.end(); return items; } catch (error) { dbSpan.recordException(error); dbSpan.end(); throw error; } }); ``` -------------------------------- ### Request Hook Example Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md Example of using a request hook to add custom attributes to spans, such as client IP, user ID, request ID, and environment. It also demonstrates renaming the span based on the route. ```javascript const instrumentation = new FastifyOtelInstrumentation({ requestHook: (span, request) => { // Add client IP span.setAttribute('http.client_ip', request.ip); // Add user ID from header const userId = request.headers['x-user-id']; if (userId) { span.setAttribute('user.id', userId); } // Add request ID for correlation const requestId = request.headers['x-request-id']; if (requestId) { span.setAttribute('request.id', requestId); } // Add environment span.setAttribute('environment', process.env.NODE_ENV); // Rename span based on route if (request.routeOptions?.url) { span.updateName(`${request.method} ${request.routeOptions.url}`); } } }); ``` -------------------------------- ### Lifecycle Hook Example Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md Example of using a lifecycle hook to add attributes related to Fastify's internal hooks, such as the hook name and handler name. It also shows custom span naming for handlers. ```javascript const instrumentation = new FastifyOtelInstrumentation({ lifecycleHook: (span, info) => { // Add hook name as attribute span.setAttribute('fastify.hook', info.hookName); // Add handler name if (info.handler) { span.setAttribute('handler.name', info.handler); } // Custom naming for handlers if (info.hookName === 'handler') { span.updateName(`handler:${info.handler || 'anonymous'}`); } // Track route context span.setAttribute('http.method', info.request.method); span.setAttribute('http.url', info.request.url); } }); ``` -------------------------------- ### Context Storage and Propagation Example Source: https://github.com/fastify/otel/blob/main/_autodocs/integration-architecture.md Demonstrates how the OpenTelemetry context is stored on the request object and used for subsequent operations. ```javascript // Store context on request object request[kRequestContext] = trace.setSpan(ctx, span) request[kRequestSpan] = span // Run subsequent code within this context context.with(request[kRequestContext], () => { hookDone() }) ``` -------------------------------- ### With Environment Variables Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md Configuration using environment variables. ```bash export OTEL_FASTIFY_IGNORE_PATHS="/health/*" export OTEL_SERVICE_NAME="my-service" ``` ```javascript const instrumentation = new FastifyOtelInstrumentation(); // Automatically uses env vars ``` -------------------------------- ### Distributed Tracing Example Source: https://github.com/fastify/otel/blob/main/_autodocs/api-reference/request-context.md Illustrates a workflow involving local processing and calling an external service with context propagation. ```javascript const http = require('http'); app.post('/process', async (request, reply) => { const otel = request.opentelemetry(); // Step 1: Process locally const localSpan = otel.tracer.startSpan('local_processing', {}, otel.context); await processLocally(request.body); localSpan.end(); // Step 2: Call external service with context propagation const headers = {}; otel.inject(headers); const externalResult = await callExternalService({ ...request.body, headers }); return externalResult; }); ``` -------------------------------- ### Context-Aware Async Operations Example Source: https://github.com/fastify/otel/blob/main/_autodocs/api-reference/request-context.md Shows how to maintain the request context across multiple asynchronous operations using `context.with`. ```javascript const { context } = require('@opentelemetry/api'); app.get('/batch-process', (request, reply) => { const otel = request.opentelemetry(); // Each async operation maintains the request context const promises = request.body.items.map((item) => { return context.with(otel.context, async () => { const span = otel.tracer.startSpan(`process_item.${item.id}`, {}, otel.context); try { const result = await processItem(item); span.end(); return result; } catch (error) { span.recordException(error); span.end(); throw error; } }); }); return Promise.all(promises); }); ``` -------------------------------- ### Batch Export (BatchSpanProcessor) Source: https://github.com/fastify/otel/blob/main/_autodocs/opentelemetry-integration.md Example of configuring periodic span export using BatchSpanProcessor. ```javascript // Batch and export periodically provider.addSpanProcessor( new BatchSpanProcessor(exporter, { maxQueueSize: 1024, maxExportBatchSize: 512, scheduledDelayMillis: 5000 // Export every 5s }) ); ``` -------------------------------- ### Minimal Configuration Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md Minimal configuration for FastifyOtelInstrumentation. ```javascript const FastifyOtelInstrumentation = require('@fastify/otel'); const instrumentation = new FastifyOtelInstrumentation(); // Uses defaults: everything enabled, no ignore paths ``` -------------------------------- ### Constructor Configuration Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md All configuration is passed to the FastifyOtelInstrumentation constructor. ```javascript const instrumentation = new FastifyOtelInstrumentation(config); ``` -------------------------------- ### init() method Source: https://github.com/fastify/otel/blob/main/_autodocs/api-reference/FastifyOtelInstrumentation.md Returns an empty array as this instrumentation uses Fastify's plugin system for integration instead of patching. ```javascript init(): InstrumentationNodeModuleDefinition[] ``` ```javascript Returns: `[]` (empty array) ``` -------------------------------- ### Adding User Context Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Shows how to use the requestHook to add user information, API key prefix, and client details to traces. ```javascript const instrumentation = new FastifyOtelInstrumentation({ requestHook: (span, request) => { // Extract user ID from header const userId = request.headers['x-user-id']; if (userId) { span.setAttribute('user.id', userId); } // Extract API key (masked) const apiKey = request.headers['authorization']; if (apiKey) { const masked = apiKey.substring(0, 10) + '***'; span.setAttribute('auth.key_prefix', masked); } // Add client information span.setAttribute('http.client_ip', request.ip); span.setAttribute('http.user_agent', request.headers['user-agent']); // Rename span for better readability if (request.routeOptions?.url) { span.updateName(`${request.method} ${request.routeOptions.url}`); } } }); ``` -------------------------------- ### With Ignore Paths (Glob) Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md Configuration with ignorePaths using a glob pattern. ```javascript const instrumentation = new FastifyOtelInstrumentation({ ignorePaths: '/health/*' }); // Ignores: // - /health/readiness // - /health/liveness // - Any route starting with /health/ ``` -------------------------------- ### With Ignore Paths (Function) Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md Configuration with ignorePaths using a function for complex logic. ```javascript const instrumentation = new FastifyOtelInstrumentation({ ignorePaths: (routeOpts) => { // Ignore health checks if (routeOpts.url.startsWith('/health')) return true; // Ignore metrics endpoints if (routeOpts.url === '/metrics') return true; // Ignore preflight requests if (routeOpts.method === 'OPTIONS') return true; return false; } }); ``` -------------------------------- ### FastifyOtelInstrumentationOptions lifecycleHook example Source: https://github.com/fastify/otel/blob/main/README.md Example of using the lifecycleHook to modify hook spans, such as renaming tRPC handler spans. ```javascript const otel = new FastifyOtelInstrumentation({ lifecycleHook: (span, info) => { if (info.hookName === 'handler' && info.request.headers['x-trpc-op'] != null) { span.updateName(`tRPC handler - ${info.request.headers['x-trpc-op']}`) } span.setAttribute('hook.handler.name', info.handler ?? 'anonymous') } }) ``` -------------------------------- ### Lifecycle Hook Example Source: https://github.com/fastify/otel/blob/main/_autodocs/types.md Example of using the lifecycleHook callback in FastifyOtelInstrumentationOpts to interact with spans and request information. ```typescript const opts: FastifyOtelInstrumentationOpts = { lifecycleHook: (span, info) => { console.log(`Hook: ${info.hookName}`); console.log(`Handler: ${info.handler}`); console.log(`Route: ${info.request.method} ${info.request.url}`); // Rename span based on hook type if (info.hookName === 'handler') { span.updateName(`handler: ${info.handler}`); } else if (info.hookName.includes('route')) { span.setAttribute('fastify.is_route_hook', true); } } }; ``` -------------------------------- ### Selective Exception Recording Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Example of selectively recording exceptions by disabling automatic recording and manually recording important exceptions. ```javascript // Don't record exceptions automatically const instrumentation = new FastifyOtelInstrumentation({ recordExceptions: false }); app.get('/operation', async (request, reply) => { const otel = request.opentelemetry(); try { const result = await someOperation(); return result; } catch (error) { // Manually record only important exceptions if (isImportantError(error)) { otel.span?.recordException(error); } throw error; } }); function isImportantError(error) { // Don't record 4xx errors as exceptions return !(error.statusCode >= 400 && error.statusCode < 500); } ``` -------------------------------- ### Custom Error Tracking Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md Example of implementing a custom error handler to track errors in spans, differentiating between client and server errors. ```javascript app.setErrorHandler((error, request, reply) => { const otel = request.opentelemetry(); // Add error details to span if (otel.span) { otel.span.setAttribute('error.type', error.constructor.name); otel.span.setAttribute('error.message', error.message); otel.span.setAttribute('error.code', error.code); // Don't record client errors as exceptions if (error.statusCode >= 500) { otel.span.recordException(error); } } reply.code(error.statusCode || 500).send({ error: error.message }); }); ``` -------------------------------- ### Using with OpenTelemetry Node SDK Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md Example of integrating Fastify OpenTelemetry Instrumentation with the OpenTelemetry Node SDK, including setting resource attributes and configuring trace exporters. ```javascript import { NodeSDK } from '@opentelemetry/sdk-node'; import FastifyOtelInstrumentation from '@fastify/otel'; const sdk = new NodeSDK({ resource: { attributes: { 'service.name': 'my-service', 'service.version': '1.0.0', }, }, traceExporter: new JaegerExporter({ endpoint: 'http://localhost:14268/api/traces', }), instrumentations: [ new FastifyOtelInstrumentation({ registerOnInitialization: true, // Auto-register on Fastify init ignorePaths: '/health/*', }), // ... other instrumentations ], }); sdk.start(); ``` -------------------------------- ### Validation Error Handling Source: https://github.com/fastify/otel/blob/main/_autodocs/usage-examples.md This example shows how to use Fastify's schema error handling to add attributes to spans when validation fails. ```javascript const { preValidationHook } = require('fastify-type-provider'); app.get('/search', { schema: { querystring: SearchSchema } }, (request, reply) => { const otel = request.opentelemetry(); if (otel.span) { otel.span.setAttribute('search.query', request.query.q); otel.span.setAttribute('search.limit', request.query.limit); } return search(request.query); }); app.setSchemaErrorHandler((error, request, reply) => { const otel = request.opentelemetry(); if (otel.span) { otel.span.setAttribute('validation.failed', true); otel.span.setAttribute('validation.errors', error.validation.length); } reply.code(400).send({ error: 'Validation failed', details: error.validation }); }); ``` -------------------------------- ### Registration using OpenTelemetry Node SDK Source: https://github.com/fastify/otel/blob/main/README.md Example of registering @fastify/otel using the OpenTelemetry Node SDK with the `registerOnInitialization` option. ```js // ... in your OTEL setup import { NodeSDK } from '@opentelemetry/sdk-node'; import FastifyOtelInstrumentation from "@fastify/otel"; const sdk = new NodeSDK({ resource: ..., traceExporter: ..., instrumentations: [ ...others, new FastifyOtelInstrumentation({ registerOnInitialization: true }) ], }); sdk.start(); ``` -------------------------------- ### Validation Rules for FastifyOtelInstrumentation Constructor Source: https://github.com/fastify/otel/blob/main/_autodocs/configuration.md Demonstrates valid and invalid configurations for the FastifyOtelInstrumentation constructor, showing expected TypeErrors for incorrect parameter types. ```javascript // Throws TypeError: recordExceptions must be a boolean new FastifyOtelInstrumentation({ recordExceptions: 'true' }); // Throws TypeError: ignorePaths must be a string or a function new FastifyOtelInstrumentation({ ignorePaths: 123 }); // Throws TypeError: ignorePaths must be a string or a function (empty string) new FastifyOtelInstrumentation({ ignorePaths: '' }); // Valid configurations new FastifyOtelInstrumentation({ recordExceptions: true }); new FastifyOtelInstrumentation({ ignorePaths: '/health/*' }); new FastifyOtelInstrumentation({ ignorePaths: (route) => false }); ``` -------------------------------- ### FastifyOtelRequestContext Usage Example Source: https://github.com/fastify/otel/blob/main/_autodocs/types.md Example demonstrating how to access and use the FastifyOtelRequestContext from a Fastify request, including type narrowing based on the 'enabled' property. ```typescript app.get('/', (request, reply) => { const otel: FastifyOtelRequestContext = request.opentelemetry(); if (otel.enabled) { // Type narrows to FastifyEnabledOtelRequestContext otel.span.setAttribute('key', 'value'); otel.context; // Context type } else { // Type narrows to FastifyDisabledOtelRequestContext otel.span; // null otel.context; // null } // Available in both branches const carrier = {}; otel.inject(carrier); const extracted = otel.extract(carrier); }); ``` -------------------------------- ### FastifyOtelInstrumentation Instance Methods Source: https://github.com/fastify/otel/blob/main/_autodocs/module-exports.md Details of instance methods available on the `FastifyOtelInstrumentation` class. ```javascript plugin() => FastifyPluginCallback enable() => void disable() => void init() => InstrumentationNodeModuleDefinition[] isEnabled() => boolean setTracerProvider(provider) => void ```