Skip to content

feat(cloudflare): Instrument async KV API#19404

Merged
JPeer264 merged 1 commit intodevelopfrom
jp/instrument-storage
Feb 20, 2026
Merged

feat(cloudflare): Instrument async KV API#19404
JPeer264 merged 1 commit intodevelopfrom
jp/instrument-storage

Conversation

@JPeer264
Copy link
Member

closes #19384
closes JS-1744

With that we start to instrument DO objects starting with the Async KV API.

Cloudflare is instrumenting these with underlines between: durable_object_storage_get, without any more information to it.

In the future to make them a little more useful we could store the keys as span attributes on it with db.cloudflare.durable_object.storage.key or db.cloudflare.durable_object.storage.keys. First we have to add them to our semantic conventions though

@JPeer264 JPeer264 self-assigned this Feb 19, 2026
@linear
Copy link

linear bot commented Feb 19, 2026

@github-actions
Copy link
Contributor

github-actions bot commented Feb 19, 2026

Codecov Results 📊


Generated by Codecov Action

@github-actions
Copy link
Contributor

github-actions bot commented Feb 19, 2026

size-limit report 📦

⚠️ Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

Path Size % Change Change
@sentry/browser 25.61 kB - -
@sentry/browser - with treeshaking flags 24.12 kB - -
@sentry/browser (incl. Tracing) 42.42 kB - -
@sentry/browser (incl. Tracing, Profiling) 47.08 kB - -
@sentry/browser (incl. Tracing, Replay) 81.24 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 70.86 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 85.93 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 98.09 kB - -
@sentry/browser (incl. Feedback) 42.33 kB - -
@sentry/browser (incl. sendFeedback) 30.28 kB - -
@sentry/browser (incl. FeedbackAsync) 35.28 kB - -
@sentry/browser (incl. Metrics) 26.78 kB - -
@sentry/browser (incl. Logs) 26.92 kB - -
@sentry/browser (incl. Metrics & Logs) 27.6 kB - -
@sentry/react 27.37 kB - -
@sentry/react (incl. Tracing) 44.76 kB - -
@sentry/vue 30.06 kB - -
@sentry/vue (incl. Tracing) 44.26 kB - -
@sentry/svelte 25.64 kB - -
CDN Bundle 28.16 kB - -
CDN Bundle (incl. Tracing) 43.25 kB - -
CDN Bundle (incl. Logs, Metrics) 29 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 44.09 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 68.08 kB - -
CDN Bundle (incl. Tracing, Replay) 80.12 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 80.99 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 85.56 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 86.46 kB - -
CDN Bundle - uncompressed 82.33 kB - -
CDN Bundle (incl. Tracing) - uncompressed 128.05 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 85.17 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 130.88 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 208.83 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 244.93 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 247.75 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 257.73 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 260.54 kB - -
@sentry/nextjs (client) 47.17 kB - -
@sentry/sveltekit (client) 42.88 kB - -
@sentry/node-core 52.16 kB +0.02% +7 B 🔺
@sentry/node 166.53 kB +0.01% +7 B 🔺
@sentry/node - without tracing 93.95 kB +0.02% +11 B 🔺
@sentry/aws-serverless 109.45 kB +0.01% +6 B 🔺

View base workflow run

@JPeer264 JPeer264 force-pushed the jp/instrument-storage branch from 04b7bbb to 0eb536e Compare February 19, 2026 10:50
@JPeer264 JPeer264 marked this pull request as ready for review February 19, 2026 11:24
const currentClient = scope.getClient();
if (!currentClient) {
const client = init({ ...wrapperOptions.options, ctx: context });
const client = init({ ...wrapperOptions.options, ctx: context as unknown as ExecutionContext | undefined });
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The flush lock mechanism is ineffective for Durable Objects because it relies on waitUntil, which is a no-op in that context, potentially causing premature flushes.
Severity: MEDIUM

Suggested Fix

Detect if the context is a DurableObjectState and either use a different mechanism to await async operations (like blockConcurrencyWhile) or rely solely on the client's internal span tracking for flushing within Durable Objects. The current ineffective implementation should be corrected or documented as a known limitation.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: packages/cloudflare/src/wrapMethodWithSentry.ts#L73

Potential issue: The `makeFlushLock` mechanism is initialized with a context that, in
the case of a Cloudflare Durable Object, has a `waitUntil` method that is a no-op. The
lock relies on `waitUntil` to track the completion of asynchronous tasks. Since
`DurableObjectState.waitUntil` has no effect on the request lifetime, the flush lock
will not correctly wait for all async work to finish. This can lead to the `flush()`
operation resolving prematurely, potentially causing loss of telemetry data if the
Durable Object's process terminates before the SDK has finished sending all events.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Member

@andreiborza andreiborza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM, just one idea around caching.

Comment on lines +31 to +47
return function (this: unknown, ...args: unknown[]) {
return startSpan(
{
// Use underscore naming to match Cloudflare's native instrumentation (e.g., "durable_object_storage_get")
name: `durable_object_storage_${methodName}`,
op: 'db',
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.cloudflare.durable_object',
'db.system.name': 'cloudflare.durable_object.storage',
'db.operation.name': methodName,
},
},
() => {
return (original as (...args: unknown[]) => unknown).apply(target, args);
},
);
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about caching this function and retrieving from cache? The underlying storage functions should never really change, and I think especially in a KV-storage we should consider perf implications.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a task for this: #19451
I want to go deeper a little before making this decision

@JPeer264 JPeer264 merged commit 91d7244 into develop Feb 20, 2026
55 checks passed
@JPeer264 JPeer264 deleted the jp/instrument-storage branch February 20, 2026 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cloudflare Instrument Async KV Api

2 participants

Comments