autotel-cloudflare
Version:
The #1 OpenTelemetry package for Cloudflare Workers - complete bindings coverage, native CF OTel integration, advanced sampling
106 lines (96 loc) • 3.48 kB
text/typescript
/**
* Queue producer binding instrumentation
*/
import {
trace,
SpanKind,
SpanStatusCode,
} from '@opentelemetry/api';
import type { WorkerTracer } from 'autotel-edge';
import { wrap, setAttr } from './common';
/**
* Instrument Queue producer binding
*/
export function instrumentQueueProducer<T extends Queue>(queue: T, queueName?: string): T {
const name = queueName || 'queue';
const handler: ProxyHandler<T> = {
get(target, prop) {
const value = Reflect.get(target, prop);
if (prop === 'send' && typeof value === 'function') {
return new Proxy(value, {
apply: (fnTarget, _thisArg, args) => {
const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
return tracer.startActiveSpan(
`Queue ${name}: send`,
{
kind: SpanKind.PRODUCER,
attributes: {
'messaging.system': 'cloudflare-queues',
'messaging.operation.type': 'publish',
'messaging.operation': 'send',
'messaging.destination.name': name,
},
},
async (span) => {
try {
const result = await Reflect.apply(fnTarget, target, args);
setAttr(span, 'messaging.message.id', (result as any)?.messageId);
span.setStatus({ code: SpanStatusCode.OK });
return result;
} catch (error) {
span.recordException(error as Error);
span.setStatus({
code: SpanStatusCode.ERROR,
message: error instanceof Error ? error.message : String(error),
});
throw error;
} finally {
span.end();
}
},
);
},
});
}
if (prop === 'sendBatch' && typeof value === 'function') {
return new Proxy(value, {
apply: (fnTarget, _thisArg, args) => {
const [messages] = args as [{ body: unknown }[]];
const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
return tracer.startActiveSpan(
`Queue ${name}: sendBatch`,
{
kind: SpanKind.PRODUCER,
attributes: {
'messaging.system': 'cloudflare-queues',
'messaging.operation.type': 'publish',
'messaging.operation': 'sendBatch',
'messaging.destination.name': name,
'messaging.batch.message_count': Array.isArray(messages) ? messages.length : 0,
},
},
async (span) => {
try {
const result = await Reflect.apply(fnTarget, target, args);
span.setStatus({ code: SpanStatusCode.OK });
return result;
} catch (error) {
span.recordException(error as Error);
span.setStatus({
code: SpanStatusCode.ERROR,
message: error instanceof Error ? error.message : String(error),
});
throw error;
} finally {
span.end();
}
},
);
},
});
}
return value;
},
};
return wrap(queue, handler);
}