diff --git a/.changeset/hot-dodos-burn.md b/.changeset/hot-dodos-burn.md new file mode 100644 index 0000000..ac93226 --- /dev/null +++ b/.changeset/hot-dodos-burn.md @@ -0,0 +1,5 @@ +--- +"@microlabs/otel-cf-workers": patch +--- + +Add version metadata to attributes if found diff --git a/src/instrumentation/env.ts b/src/instrumentation/env.ts index ce8424c..a939981 100644 --- a/src/instrumentation/env.ts +++ b/src/instrumentation/env.ts @@ -27,6 +27,10 @@ const isServiceBinding = (item?: unknown): item is Fetcher => { return !!binding.connect || !!binding.fetch || binding.queue || binding.scheduled } +export const isVersionMetadata = (item?: unknown): item is WorkerVersionMetadata => { + return !!(item as WorkerVersionMetadata).id && !!(item as WorkerVersionMetadata).tag +} + const isAnalyticsEngineDataset = (item?: unknown): item is AnalyticsEngineDataset => { return !!(item as AnalyticsEngineDataset)?.writeDataPoint } @@ -49,6 +53,9 @@ const instrumentEnv = (env: Record): Record => return instrumentDOBinding(item, String(prop)) } else if (isServiceBinding(item)) { return instrumentServiceBinding(item, String(prop)) + } else if (isVersionMetadata(item)) { + // we do not need to log accesses to the metadata + return item } else if (isAnalyticsEngineDataset(item)) { return instrumentAnalyticsEngineDataset(item, String(prop)) } else { diff --git a/src/instrumentation/fetch.ts b/src/instrumentation/fetch.ts index 8f3df4b..3f0f268 100644 --- a/src/instrumentation/fetch.ts +++ b/src/instrumentation/fetch.ts @@ -15,6 +15,7 @@ import { instrumentEnv } from './env.js' import { exportSpans, proxyExecutionContext } from './common.js' import { ResolvedTraceConfig } from '../types.js' import { ReadableSpan } from '@opentelemetry/sdk-trace-base' +import { versionAttributes } from './version.js' export type IncludeTraceContextFn = (request: Request) => boolean export interface FetcherConfig { @@ -140,6 +141,7 @@ export function executeFetchHandler(fetchFn: FetchHandler, [request, env, ctx]: cold_start = false Object.assign(attributes, gatherRequestAttributes(request)) Object.assign(attributes, gatherIncomingCfAttributes(request)) + Object.assign(attributes, versionAttributes(env)) const options: SpanOptions = { attributes, kind: SpanKind.SERVER, diff --git a/src/instrumentation/queue.ts b/src/instrumentation/queue.ts index 50ebfb4..40d1f10 100644 --- a/src/instrumentation/queue.ts +++ b/src/instrumentation/queue.ts @@ -4,6 +4,7 @@ import { Initialiser, setConfig } from '../config.js' import { exportSpans, proxyExecutionContext } from './common.js' import { instrumentEnv } from './env.js' import { unwrap, wrap } from '../wrap.js' +import { versionAttributes } from './version.js' type QueueHandler = ExportedHandlerQueueHandler export type QueueHandlerArgs = Parameters @@ -141,6 +142,7 @@ export function executeQueueHandler(queueFn: QueueHandler, [batch, env, ctx]: Qu }, kind: SpanKind.CONSUMER, } + Object.assign(options.attributes!, versionAttributes(env)) const promise = tracer.startActiveSpan(`queueHandler:${batch.queue}`, options, async (span) => { const traceId = span.spanContext().traceId api_context.active().setValue(traceIdSymbol, traceId) diff --git a/src/instrumentation/scheduled.ts b/src/instrumentation/scheduled.ts index cffa519..64e53fa 100644 --- a/src/instrumentation/scheduled.ts +++ b/src/instrumentation/scheduled.ts @@ -4,6 +4,7 @@ import { Initialiser, setConfig } from '../config.js' import { exportSpans, proxyExecutionContext } from './common.js' import { instrumentEnv } from './env.js' import { wrap } from '../wrap.js' +import { versionAttributes } from './version.js' type ScheduledHandler = ExportedHandlerScheduledHandler export type ScheduledHandlerArgs = Parameters @@ -23,6 +24,7 @@ export function executeScheduledHandler( [SemanticAttributes.FAAS_TIME]: new Date(controller.scheduledTime).toISOString(), } cold_start = false + Object.assign(attributes, versionAttributes(env)) const options: SpanOptions = { attributes, kind: SpanKind.SERVER, diff --git a/src/instrumentation/version.ts b/src/instrumentation/version.ts new file mode 100644 index 0000000..6b66049 --- /dev/null +++ b/src/instrumentation/version.ts @@ -0,0 +1,19 @@ +import { isVersionMetadata } from './env.js' + +export function versionAttributes(env: unknown): Record { + const attributes = {} as Record + + if (typeof env === 'object' && env !== null) { + for (const [binding, data] of Object.entries(env)) { + if (isVersionMetadata(data)) { + attributes['cf.script_version.binding'] = binding + attributes['cf.script_version.id'] = data.id + attributes['cf.script_version.tag'] = data.tag + // Version metadata bindings are identical, so we can stop after the first one found + break + } + } + } + + return attributes +}