getsentry / getsentry/sentry-javascript

@sentry/cloudflare: Durable Object RPC methods drop metrics, logs and errors unless the caller propagates a trace

Fermée
#24,443 2 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
Cloudflare Workers
Langage dominant
TypeScript
Étoiles
8.7k
Forks
1.8k
Merge moyen
1 j 17 h
PR mergées (30 j)
523

Description

### Environment
- `@sentry/cloudflare`: 10.74.0 (same logic on `develop` / `11.0.0-beta.2`)
- DO wrapped with `instrumentDurableObjectWithSentry`, `enableRpcTracePropagation: true` (the only
supported way to instrument RPC methods in v11, now that `instrumentPrototypeMethods` is removed)

### Description
`createRpcPrototypeWrapper` only calls `wrapMethodWithSentry` when the last argument carries
`__sentry_rpc_meta__`. Otherwise the original method runs with no client bound. Then:

- `Sentry.metrics.count/gauge/distribution` return early (no client);
- `Sentry.captureException` and `Sentry.logger.*` are dropped;
- no `rpc` span is recorded, and a thrown error is not captured.

Callers send the metadata only if they are Sentry-instrumented, have an active trace, **and** got the stub
through `get`/`getByName` on the instrumented env (see #24442). Common cases that lose everything:

- calls from uninstrumented workers or mixed deployments;
- calls from code running outside the request's async context;
- any call through `jurisdiction()`.

`WorkerEntrypoint` already covers this case: `instrumentWorkerEntrypoint` uses a capture-only wrapper
when the metadata is missing. Durable Objects have no equivalent. `fetch`, `alarm` and `webSocket*` are
always wrapped, so only RPC is affected. That makes the gap easy to miss: our production data had
14 days of DO `alarm` spans and zero DO `rpc` spans.

### Reproduction
```ts
class MyDO extends DurableObject {
async ping() {
Sentry.metrics.count('my_do.ping', 1);
throw new Error('boom');
}
}
export const MyDOInstrumented = Sentry.instrumentDurableObjectWithSentry(
env => ({ dsn: env.SENTRY_DSN, tracesSampleRate: 1, enableRpcTracePropagation: true }),
MyDO,
);
// From a plain (uninstrumented) worker:
await env.MY_DO.get(env.MY_DO.idFromName('x')).ping();
```
Neither the metric nor the error reaches Sentry.

### Expected
External RPC calls without metadata still run inside a client and isolation scope with flush, as
`WorkerEntrypoint` does. Internal `this.method()` calls stay unwrapped.

### Proposed fix
A PR with this change will follow.

Guide de contribution

Ouvrir le guide de contribution

Piste de recherche

Start at createRpcPrototypeWrapper and compare its metadata-missing path with instrumentWorkerEntrypoint's capture-only wrapper and wrapMethodWithSentry. Reproduce an external RPC call from the plain worker in the issue, then verify that calls without metadata run with a client and isolation scope, flush metrics and errors, and leave internal this.method() calls unwrapped.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
typescript
Domaine
observability
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
Active
Clarté
Plutôt claire
Accessibilité débutants
63/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.