Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | /** * OpenTelemetry Tracing Utilities * * This file exports helper functions for working with traces in the application. * The OpenTelemetry SDK is initialized via instrumentation.js (loaded with --require). * * IMPORTANT: @opentelemetry/api is imported lazily (inside functions) to avoid * pulling it into the Next.js vendor chunk graph at module scope, which causes * "Cannot find module './vendor-chunks/@opentelemetry+api@..." errors in dev. * * Usage: * import { getCurrentTraceId, recordError } from '@/lib/tracing' * * // In error handlers: * const traceId = getCurrentTraceId() * return NextResponse.json({ error: 'Something failed', traceId }, { status: 500 }) */ type OtelApi = typeof import('@opentelemetry/api') function getOtel(): OtelApi { // eslint-disable-next-line @typescript-eslint/no-require-imports return require('@opentelemetry/api') } /** * Get the current trace ID (useful for error responses) */ export function getCurrentTraceId(): string | null { const { trace } = getOtel() const span = trace.getActiveSpan() if (!span) return null return span.spanContext().traceId } /** * Get the current span context for logging */ export function getTraceContext(): { traceId: string; spanId: string } | null { const { trace } = getOtel() const span = trace.getActiveSpan() if (!span) return null const ctx = span.spanContext() return { traceId: ctx.traceId, spanId: ctx.spanId, } } /** * Add an error to the current span */ export function recordError(error: Error, attributes?: Record<string, string>): void { const { trace, SpanStatusCode } = getOtel() const span = trace.getActiveSpan() if (!span) return span.recordException(error) span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }) if (attributes) { span.setAttributes(attributes) } } /** * Create a custom span for tracing a specific operation */ export function withSpan<T>(name: string, fn: () => T, attributes?: Record<string, string>): T { const { trace, SpanStatusCode } = getOtel() const tracer = trace.getTracer('abaci-app') return tracer.startActiveSpan(name, (span) => { try { if (attributes) { span.setAttributes(attributes) } const result = fn() span.end() return result } catch (error) { if (error instanceof Error) { span.recordException(error) span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }) } span.end() throw error } }) } /** * Create a custom span for tracing an async operation */ export async function withSpanAsync<T>( name: string, fn: () => Promise<T>, attributes?: Record<string, string> ): Promise<T> { const { trace, SpanStatusCode } = getOtel() const tracer = trace.getTracer('abaci-app') return tracer.startActiveSpan(name, async (span) => { try { if (attributes) { span.setAttributes(attributes) } const result = await fn() span.end() return result } catch (error) { if (error instanceof Error) { span.recordException(error) span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }) } span.end() throw error } }) } |