getsentry / getsentry/sentry-javascript

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

Cerrado
#24,443 2 comentarios 0 reacciones 0 asignados Ver en GitHub
Cloudflare Workers
Lenguaje dominante
TypeScript
Estrellas
8.7k
Forks
1.8k
Merge medio
1 d 17 h
PR fusionados (30 d)
523

Descripción

### 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.

Guía de contribución

Abrir la guía de contribución

Línea de trabajo

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.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
typescript
Área
observability
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Activo
Claridad
Bastante claro
Aptitud para principiantes
63/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.