an atproto based link aggregator
1/**
2 * Shared OpenTelemetry tracing utilities
3 *
4 * This module provides helpers for manual span creation and
5 * initializing tracing for standalone processes (like the ingester).
6 */
7
8import { trace, context, SpanStatusCode, type Span } from '@opentelemetry/api';
9
10/** Get a tracer for creating spans */
11export function getTracer(name: string = 'papili') {
12 return trace.getTracer(name);
13}
14
15/** Get the current active span */
16export function getCurrentSpan(): Span | undefined {
17 return trace.getSpan(context.active());
18}
19
20/**
21 * Execute a function within a new span
22 */
23export async function withSpan<T>(
24 name: string,
25 fn: (span: Span) => Promise<T>,
26 attributes?: Record<string, string | number | boolean>
27): Promise<T> {
28 const tracer = getTracer();
29 return tracer.startActiveSpan(name, async (span) => {
30 if (attributes) {
31 span.setAttributes(attributes);
32 }
33 try {
34 const result = await fn(span);
35 span.setStatus({ code: SpanStatusCode.OK });
36 return result;
37 } catch (error) {
38 span.setStatus({
39 code: SpanStatusCode.ERROR,
40 message: error instanceof Error ? error.message : 'Unknown error'
41 });
42 span.recordException(error instanceof Error ? error : new Error(String(error)));
43 throw error;
44 } finally {
45 span.end();
46 }
47 });
48}
49
50/**
51 * Execute a sync function within a new span
52 */
53export function withSpanSync<T>(
54 name: string,
55 fn: (span: Span) => T,
56 attributes?: Record<string, string | number | boolean>
57): T {
58 const tracer = getTracer();
59 const span = tracer.startSpan(name);
60 if (attributes) {
61 span.setAttributes(attributes);
62 }
63 try {
64 const result = fn(span);
65 span.setStatus({ code: SpanStatusCode.OK });
66 return result;
67 } catch (error) {
68 span.setStatus({
69 code: SpanStatusCode.ERROR,
70 message: error instanceof Error ? error.message : 'Unknown error'
71 });
72 span.recordException(error instanceof Error ? error : new Error(String(error)));
73 throw error;
74 } finally {
75 span.end();
76 }
77}