### Install and Configure @adonisjs/otel Source: https://context7.com/adonisjs/otel/llms.txt Use the AdonisJS CLI to automatically set up the provider, middleware, and configuration files. This command creates `config/otel.ts` and `otel.ts` initialization files and registers the necessary components. ```bash node ace configure @adonisjs/otel ``` -------------------------------- ### Initialize Auto-Instrumentation with init Source: https://context7.com/adonisjs/otel/llms.txt This initialization function must be called before your application starts to enable auto-instrumentation. Ensure `otel.ts` is imported first in your application's entry point (`bin/server.ts`). ```typescript // otel.ts (at project root) import { init } from '@adonisjs/otel/init' await init(import.meta.dirname) // bin/server.ts - MUST import otel.ts FIRST /** * OpenTelemetry initialization - MUST be the first import */ import '../otel.js' import { Ignitor } from '@adonisjs/core' // ... rest of server setup ``` -------------------------------- ### Define OpenTelemetry Configuration with defineConfig Source: https://context7.com/adonisjs/otel/llms.txt Configure OpenTelemetry settings using a type-safe helper for IDE autocompletion and validation. This example shows core settings, sampling ratio, debug mode, resource attributes, OTLP destinations, instrumentation options, and user context extraction. ```typescript // config/otel.ts import { defineConfig, destinations } from '@adonisjs/otel' import env from '#start/env' export default defineConfig({ // Core settings serviceName: env.get('APP_NAME'), serviceVersion: env.get('APP_VERSION'), environment: env.get('APP_ENV'), // Enable/disable (defaults to false in test environment) enabled: true, // Sampling ratio (0.0 to 1.0, default: 1.0 = 100%) samplingRatio: 0.1, // Sample 10% of traces // Debug mode - prints spans to console debug: env.get('NODE_ENV') === 'development', // Additional resource attributes resourceAttributes: { 'deployment.region': 'us-east-1', 'team.name': 'platform', }, // Configure OTLP destinations destinations: { primary: destinations.otlp({ endpoint: 'http://localhost:4318', signals: 'all', // 'all' | ['traces', 'metrics', 'logs'] headers: { 'Authorization': 'Bearer token' }, compression: 'gzip', }), secondary: destinations.otlp({ endpoint: 'https://tempo.example.com', signals: ['traces'], enabled: env.get('NODE_ENV') === 'production', }), }, // Instrumentation configuration instrumentations: { '@opentelemetry/instrumentation-http': { ignoredUrls: ['/custom-health', '/internal/*'], ignoreStaticFiles: true, ignoreOptionsRequests: true, }, '@opentelemetry/instrumentation-pino': { logHook: (span, record) => { record.custom_field = 'value' }, }, '@opentelemetry/instrumentation-pg': { enabled: false }, }, // User context extraction from auth userContext: { enabled: true, resolver: async (ctx) => ({ id: ctx.auth.user?.id, email: ctx.auth.user?.email, tenantId: ctx.auth.user?.tenantId, }), }, }) ``` -------------------------------- ### Re-export OpenTelemetry Classes Source: https://context7.com/adonisjs/otel/llms.txt Utilize convenience re-exports of common OpenTelemetry classes from `@adonisjs/otel` to simplify advanced configurations without needing to install multiple packages. This includes exporters, metric readers, and span processors. ```typescript import { OTLPTraceExporter, OTLPMetricExporter, PeriodicExportingMetricReader, ConsoleSpanExporter, SimpleSpanProcessor } from '@adonisjs/otel' // Use for advanced configurations import { defineConfig } from '@adonisjs/otel' export default defineConfig({ // Custom trace exporter traceExporter: new OTLPTraceExporter({ url: 'https://custom-collector.example.com/v1/traces', headers: { 'X-Custom': 'header' }, }), // Custom metric reader metricReaders: [ new PeriodicExportingMetricReader({ exporter: new OTLPMetricExporter({ url: 'https://custom-collector.example.com/v1/metrics', }), exportIntervalMillis: 30000, }), ], // Debug with console exporter spanProcessors: [ new SimpleSpanProcessor(new ConsoleSpanExporter()), ], }) ``` -------------------------------- ### Initialize and Manage OpenTelemetry with OtelManager Source: https://context7.com/adonisjs/otel/llms.txt The core SDK manager initializes and controls the OpenTelemetry Node SDK with AdonisJS-specific configuration. It allows access to service metadata, the underlying NodeSDK, and provides methods for checking enablement and graceful shutdown. ```typescript import { OtelManager } from '@adonisjs/otel' import config from '#config/otel' // Create and start the manager const manager = OtelManager.create(config) manager?.start() // Access service metadata console.log(manager?.serviceName) // 'my-app' console.log(manager?.serviceVersion) // '1.0.0' console.log(manager?.environment) // 'production' // Access underlying NodeSDK const sdk = manager?.sdk // Check if OTEL is enabled if (OtelManager.isEnabled(config)) { console.log('OpenTelemetry is active') } // Get singleton instance anywhere in your app const instance = OtelManager.getInstance() // Graceful shutdown (called automatically by OtelProvider) await manager?.shutdown() ``` -------------------------------- ### Configure Pino-pretty Preset for OTel Logging Source: https://context7.com/adonisjs/otel/llms.txt Customize the Pino-pretty logger preset to hide OpenTelemetry-specific fields in development logs. You can also specify fields to keep visible. ```typescript import { otelLoggingPreset } from '@adonisjs/otel/helpers' import { targets } from '@adonisjs/core/logger' //config/logger.ts export default { default: 'app', loggers: { app: { enabled: true, name: env.get('APP_NAME'), level: 'info', transport: { targets: targets() // Hide all OTEL fields (pid, hostname, trace_id, span_id, etc.) .pushIf(!app.inProduction, targets.pretty(otelLoggingPreset())) .toArray(), }, }, }, } // Keep some fields visible targets.pretty(otelLoggingPreset({ keep: ['trace_id', 'span_id'] })) // Hidden by default: pid, hostname, trace_id, span_id, // trace_flags, route, request_id, x-request-id ``` -------------------------------- ### Create Custom Spans with record Helper Source: https://context7.com/adonisjs/otel/llms.txt Use the `record` helper to create spans around synchronous or asynchronous code blocks. It automatically handles span lifecycle and error recording. You can also set attributes and add events during execution. ```typescript import { record } from '@adonisjs/otel/helpers' // Synchronous operation const result = record('database.query', () => { return db.query('SELECT * FROM users WHERE id = ?', [userId]) }) // Asynchronous operation const user = await record('user.fetch', async () => { return await userService.findById(id) }) // With span attributes const order = await record('order.process', async (span) => { span.setAttributes({ 'order.id': orderId, 'order.items_count': items.length, 'order.total': 99.99, }) const result = await processOrder(orderId) // Add events during execution span.addEvent('payment.authorized', { 'payment.method': 'card' }) return result }) // Nested spans (automatic parent-child relationship) await record('checkout.complete', async (parentSpan) => { await record('inventory.reserve', async () => { await inventoryService.reserve(items) }) await record('payment.charge', async () => { await paymentService.charge(total) }) await record('notification.send', async () => { await emailService.sendConfirmation(orderId) }) }) ``` -------------------------------- ### Configure Custom User Context Resolver Source: https://context7.com/adonisjs/otel/llms.txt Customize the user context extraction in your `config/otel.ts` file by providing a resolver function. This function can conditionally return user details or null to skip context for specific requests, enhancing trace data with application-specific user information. ```typescript // Custom user context resolver // config/otel.ts import { defineConfig } from '@adonisjs/otel' export default defineConfig({ userContext: { enabled: true, resolver: async (ctx) => { // Return null to skip user context for this request if (!ctx.auth.isAuthenticated) { return null } return { id: ctx.auth.user!.id, email: ctx.auth.user!.email, role: ctx.auth.user!.role, tenantId: ctx.auth.user!.tenantId, subscriptionPlan: ctx.auth.user!.plan, } }, }, // Disable user context extraction entirely // userContext: false, }) ``` -------------------------------- ### injectTraceContext and extractTraceContext Source: https://context7.com/adonisjs/otel/llms.txt Propagate trace context across service boundaries for distributed tracing continuity. ```APIDOC ## injectTraceContext and extractTraceContext ### Description Propagate trace context across service boundaries for distributed tracing continuity. ### Method Not applicable (helper functions) ### Endpoint Not applicable (helper functions) ### Parameters #### injectTraceContext - **headers** (object) - Required - An object to which trace context headers (e.g., `traceparent`, `tracestate`) will be added. #### extractTraceContext - **headers** (object) - Required - An object containing headers from which to extract trace context. ### Request Example (Injecting) ```json { "headers": { "Content-Type": "application/json" } } ``` ### Request Example (Extracting) ```json { "headers": { "traceparent": "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01", "tracestate": "rojo=00f067aa0ba902fc,congo=t61rcW0123456789" } } ``` ### Response - **injectTraceContext**: Modifies the provided headers object in place. - **extractTraceContext**: Returns an OpenTelemetry `Context` object representing the extracted trace information. ``` -------------------------------- ### setUser Source: https://context7.com/adonisjs/otel/llms.txt Set user context on the current span using OpenTelemetry semantic conventions for user attributes. ```APIDOC ## setUser ### Description Set user context on the current span using OpenTelemetry semantic conventions for user attributes. ### Method Not applicable (helper function) ### Endpoint Not applicable (helper function) ### Parameters #### Request Body - **id** (string | number) - Required - The user's unique identifier. - **email** (string) - Optional - The user's email address. - **role** (string) - Optional - The user's role. - **customAttributes** (object) - Optional - Additional attributes to be added to the user context, prefixed with `user.`. ### Request Example ```json { "id": "user-123", "email": "user@example.com", "role": "admin", "tenantId": "tenant-abc", "plan": "enterprise" } ``` ### Response This function does not return a value. It modifies the current span's context. ``` -------------------------------- ### Configure OTLP Destinations for Telemetry Source: https://context7.com/adonisjs/otel/llms.txt Define OTLP destinations for exporting telemetry data. Supports various configurations for endpoints, headers, signals, and compression. ```typescript import { defineConfig, destinations } from '@adonisjs/otel' export default defineConfig({ destinations: { // Basic OTLP destination (all signals) collector: destinations.otlp({ endpoint: 'http://localhost:4318', }), // Grafana Cloud LGTM stack grafana: destinations.otlp({ endpoint: 'https://otlp-gateway-prod-us-central-0.grafana.net/otlp', headers: { 'Authorization': `Basic ${Buffer.from(`${instanceId}:${apiKey}`).toString('base64')}`, }, signals: 'all', compression: 'gzip', }), // Traces only to Tempo tempo: destinations.otlp({ endpoint: 'https://tempo.example.com', signals: ['traces'], timeoutMillis: 5000, maxExportBatchSize: 512, scheduledDelayMillis: 1000, }), // Metrics only to Prometheus remote write prometheus: destinations.otlp({ endpoints: { metrics: 'https://prometheus.example.com/api/v1/otlp/v1/metrics', }, signals: ['metrics'], metricExportIntervalMillis: 60000, metricExportTimeoutMillis: 30000, }), // Logs to Loki loki: destinations.otlp({ endpoints: { logs: 'https://loki.example.com/otlp/v1/logs', }, signals: ['logs'], headers: { 'X-Scope-OrgID': 'tenant-1', }, }), // Conditional destination sentry: destinations.otlp({ endpoint: process.env.SENTRY_OTLP_ENDPOINT, signals: ['traces'], enabled: process.env.NODE_ENV === 'production', }), }, }) ``` -------------------------------- ### Configure HTTP Instrumentation Filtering Source: https://context7.com/adonisjs/otel/llms.txt Set up automatic filtering for HTTP requests to exclude health checks, static files, and custom patterns from OpenTelemetry tracing. You can also define custom ignore hooks. ```typescript import { defineConfig } from '@adonisjs/otel' export default defineConfig({ instrumentations: { '@opentelemetry/instrumentation-http': { // Add custom ignored URLs (merged with defaults) ignoredUrls: [ '/internal/*', // Prefix match '/custom-health', // Exact match '/api/v1/ping', ], // Don't merge with defaults, use only custom list mergeIgnoredUrls: false, // Ignore static files (default: true) // Ignores: .css, .js, .png, .jpg, .svg, .woff2, etc. ignoreStaticFiles: true, // Ignore OPTIONS requests (default: true) ignoreOptionsRequests: true, // Custom ignore hook for complex logic ignoreIncomingRequestHook: (request) => { // Ignore requests from monitoring systems if (request.headers?.['user-agent']?.includes('prometheus')) { return true } // Ignore internal service-to-service calls if (request.headers?.['x-internal-call'] === 'true') { return true } return false }, }, }, }) // Default ignored URLs: // /health, /healthz, /internal/healthz, /ready, /readiness, // /metrics, /internal/metrics, /favicon.ico, /robots.txt, // /sitemap.xml, /manifest.json, /site.webmanifest, // /browserconfig.xml, /ads.txt // Default ignored dev server patterns: // /@vite/, /@id/, /@fs/, /__vite, /@react-refresh ``` -------------------------------- ### Register OtelMiddleware in AdonisJS Source: https://context7.com/adonisjs/otel/llms.txt Register the OtelMiddleware globally in your AdonisJS application to automatically enrich spans with route patterns, user context, and response status. This middleware updates span names, sets HTTP attributes, extracts user information, and records response status codes. ```typescript // Automatically registered by configure command // Manual registration in start/kernel.ts: import router from '@adonisjs/core/services/router' router.use([ () => import('@adonisjs/otel/otel_middleware'), ]) // The middleware automatically: // 1. Updates span name to "GET /users/:id" format // 2. Sets http.route attribute to route pattern // 3. Sets adonis.route.name attribute // 4. Extracts user from ctx.auth.user (if available) // 5. Sets http.response.status_code on completion ``` -------------------------------- ### recordEvent Source: https://context7.com/adonisjs/otel/llms.txt Add timestamped events to the current span for discrete occurrences during execution. ```APIDOC ## recordEvent ### Description Add timestamped events to the current span for discrete occurrences during execution. ### Method Not applicable (helper function) ### Endpoint Not applicable (helper function) ### Parameters #### Path Parameters - **name** (string) - Required - The name of the event. #### Query Parameters - **attributes** (object) - Optional - Key-value pairs to add as attributes to the event. ### Request Example ```json { "name": "order.processed", "attributes": { "payment.success": true, "payment.transaction_id": "txn_xyz789" } } ``` ### Response This function does not return a value. It adds an event to the current span. ``` -------------------------------- ### Extract Trace Context with extractTraceContext Source: https://context7.com/adonisjs/otel/llms.txt Employ extractTraceContext to retrieve trace context information from incoming request headers, typically in queue workers or microservices. This allows the trace to be continued in the new service or process. ```typescript import { extractTraceContext, record } from '@adonisjs/otel/helpers' import { context } from '@opentelemetry/api' // Queue worker receiving trace context async function processJob(job: Job) { // Extract trace context from job headers const extractedContext = extractTraceContext(job.headers) // Continue the trace in the extracted context await context.with(extractedContext, async () => { await record('job.process', async () => { // This span is a child of the original trace await doWork(job.payload) }) }) } // Microservice receiving request with trace context export default class WebhookController { async handle({ request }: HttpContext) { const headers = request.headers() const parentContext = extractTraceContext(headers) return context.with(parentContext, async () => { return await record('webhook.process', async () => { // Continues the distributed trace return await processWebhook(request.body()) }) }) } } ``` -------------------------------- ### Record Events with recordEvent Source: https://context7.com/adonisjs/otel/llms.txt Utilize recordEvent to add timestamped events to the current span, marking discrete occurrences during execution. Events can include attributes for more detailed context. ```typescript import { recordEvent } from '@adonisjs/otel/helpers' async function processOrder(orderId: string) { // Simple event recordEvent('order.received') // Validate inventory const hasStock = await checkInventory(orderId) recordEvent('inventory.checked', { 'inventory.available': hasStock, 'inventory.warehouse': 'west-1', }) // Process payment const paymentResult = await chargePayment(orderId) recordEvent('payment.processed', { 'payment.success': paymentResult.success, 'payment.transaction_id': paymentResult.transactionId, 'payment.amount': paymentResult.amount, }) // Ship order await shipOrder(orderId) recordEvent('order.shipped', { 'shipping.carrier': 'fedex', 'shipping.tracking_number': 'FX123456', }) recordEvent('order.completed') } ``` -------------------------------- ### Access and Modify Current Span with Helpers Source: https://context7.com/adonisjs/otel/llms.txt Use `getCurrentSpan` to access the currently active span and `setAttributes` to modify its attributes or add new ones. These helpers are useful for adding context to spans from anywhere in your code, including controllers. ```typescript import { getCurrentSpan, setAttributes } from '@adonisjs/otel/helpers' function processPayment(orderId: string, amount: number) { // Get current span const span = getCurrentSpan() // Set attributes on current span span?.setAttributes({ 'payment.order_id': orderId, 'payment.amount': amount, 'payment.currency': 'USD', }) // Or use the convenience wrapper setAttributes({ 'payment.provider': 'stripe', 'payment.method': 'card', }) // Add event to span span?.addEvent('payment.initiated', { 'payment.gateway': 'stripe', }) return stripe.charge(amount) } // In a controller export default class PaymentsController { async charge({ request, response }: HttpContext) { setAttributes({ 'http.custom_header': request.header('X-Custom-Header'), 'business.client_id': request.input('client_id'), }) // Process payment... } } ``` -------------------------------- ### Propagate Trace Context with injectTraceContext Source: https://context7.com/adonisjs/otel/llms.txt Use injectTraceContext to embed the current trace context into outgoing request headers, ensuring distributed tracing continuity across service boundaries. This is essential for requests made to external services or when dispatching queue jobs. ```typescript import { injectTraceContext } from '@adonisjs/otel/helpers' // Outgoing HTTP request to another service async function callExternalService(data: any) { const headers: Record = { 'Content-Type': 'application/json', } // Inject current trace context into headers injectTraceContext(headers) // Adds: traceparent, tracestate headers const response = await fetch('https://api.example.com/process', { method: 'POST', headers, body: JSON.stringify(data), }) return response.json() } // Queue job dispatch with trace context async function dispatchJob(jobName: string, payload: any) { const headers: Record = {} injectTraceContext(headers) await queue.dispatch(jobName, payload, { headers // Pass trace context to worker }) } ``` -------------------------------- ### Set User Context with setUser Source: https://context7.com/adonisjs/otel/llms.txt Use setUser to add user-related attributes to the current span, following OpenTelemetry semantic conventions. Custom attributes are automatically prefixed with 'user.'. ```typescript import { setUser } from '@adonisjs/otel/helpers' // Basic usage with standard fields setUser({ id: auth.user.id, email: auth.user.email, role: auth.user.role, }) // Sets: user.id, user.email, user.roles // With custom attributes (auto-prefixed with "user.") setUser({ id: auth.user.id, email: auth.user.email, tenantId: auth.user.tenantId, // -> user.tenantId plan: 'enterprise', // -> user.plan accountAge: 365, // -> user.accountAge }) ``` ```typescript // In middleware or controller export default class AuthController { async login({ auth, response }: HttpContext) { await auth.attempt(email, password) setUser({ id: auth.user!.id, email: auth.user!.email, role: auth.user!.role, organizationId: auth.user!.organizationId, }) return response.ok({ message: 'Logged in' }) } } ``` -------------------------------- ### Use @spanAll Decorator for Class-wide Spans Source: https://context7.com/adonisjs/otel/llms.txt The `@spanAll` decorator wraps all methods of a class in spans without individual decoration. By default, span names follow the pattern 'ClassName.methodName'. Custom prefixes and attributes can be applied to all generated spans. ```typescript import { spanAll } from '@adonisjs/otel/decorators' // All methods get spans with pattern "ClassName.methodName" @spanAll() class OrderService { async create(data: OrderData) { // Span name: "OrderService.create" return await db.orders.create(data) } async findById(id: string) { // Span name: "OrderService.findById" return await db.orders.find(id) } async updateStatus(id: string, status: string) { // Span name: "OrderService.updateStatus" return await db.orders.update(id, { status }) } } // With custom prefix @spanAll({ prefix: 'order', attributes: { 'service.layer': 'domain' } }) class OrderService { async create(data: OrderData) { // Span name: "order.create" return await db.orders.create(data) } async process(id: string) { // Span name: "order.process" return await this.processInternal(id) } } ``` -------------------------------- ### Use @span Decorator for Method Spans Source: https://context7.com/adonisjs/otel/llms.txt The `@span` decorator automatically wraps method execution in a span. Configure span names and attributes directly in the decorator. Exceptions thrown within the method are automatically captured and recorded in the span. ```typescript import { span } from '@adonisjs/otel/decorators' class UserService { // Auto-generated span name: "UserService.findById" @span() async findById(id: string) { return await db.users.find(id) } // Custom span name and attributes @span({ name: 'user.create', attributes: { 'operation': 'create', 'entity': 'user', } }) async create(data: UserData) { return await db.users.create(data) } // Span automatically captures and records exceptions @span({ name: 'user.delete' }) async delete(id: string) { const user = await this.findById(id) if (!user) { throw new Error('User not found') // Exception recorded in span } await db.users.delete(id) } } // Usage const userService = new UserService() const user = await userService.findById('123') // Creates span "UserService.findById" ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.