Skip to content

feat(api): semantic traces for HTTP and DB calls via internal tracing wrapper #390

Description

@masch

Description

Add full semantic traces for HTTP calls and database operations in apps/api.

We do not want to depend on Cloudflare's tracing API directly across the codebase. This issue includes building a thin internal tracing wrapper that encapsulates cloudflare:workers tracing behind our own interface. The Cloudflare implementation is the default; a no-op implementation is used in tests.

This builds on the observability work in #387 (logs) and requires observability.traces.enabled = true for custom spans to be recorded.

Goals

  • Full visibility into HTTP + DB paths in the Workers dashboard waterfall
  • Decouple business code from Cloudflare's tracing API (swappable provider)
  • Consistent span naming and attributes across the codebase
  • Testable: spans can be mocked/asserted in unit tests
  • No sensitive data is ever recorded (see Security section)

Security — no sensitive data in logs or traces

Request/response data in this API includes auth tokens, session cookies, device identifiers, payment data, and signed audio URLs. Logs and traces are persisted on Cloudflare (Workers Logs: 7-day retention) — treat anything written to a span attribute or log as potentially stored. Rules:

  • Headers: never record full header sets. Only whitelisted safe headers (e.g. content-type, user-agent). NEVER: authorization, cookie, set-cookie, x-api-key, MercadoPago signature headers.
  • Bodies: never record full request/response bodies. Only explicit, selected fields; redact PII (emails, names, device ids) and payment data.
  • URLs: record the path only, never the query string (may contain tokens/codes).
  • Attribute naming guard: names matching token|secret|key|password|cookie|authorization|signature are never recorded.
  • Env secrets (DB connection strings, signing keys) never appear in attributes.
  • The existing middleware/logger.ts and lib/http-client.ts currently log full headers + bodies — span attributes added there must follow this policy. Sanitizing the existing logger is a separate follow-up.

Tasks

  • Create internal tracing wrapper (src/lib/tracing.ts): own Span / Tracer interface, Cloudflare implementation over cloudflare:workers (enterSpan, startActiveSpan, setAttribute), and a no-op implementation for tests
  • Enforce the sensitive-data policy in the wrapper: no full headers/bodies, path-only URLs, redacted fields only (see Security section)
  • Enable [observability.traces] (with head_sampling_rate) in wrangler.toml and wrangler.staging.toml
  • Wrap DB operations in src/db/index.ts with semantic spans (db:operation, attributes: table, op) — Neon is HTTP-based, so platform instrumentation alone shows generic fetch spans
  • Wrap outgoing HTTP calls in src/lib/http-client.ts (http:request, attributes: method, path, status — no headers, no query string, no bodies)
  • Wrap MercadoPago operations in src/payments/mercadopago.ts (mp:operation, attribute: payment id — no card/PII data)
  • Update/extend unit tests to assert span creation (mock tracer)
  • Add tests asserting recorded span attributes/logs never contain sensitive data (headers, query strings, bodies, secrets)
  • Verify spans appear in the Workers dashboard with the full request waterfall (deploy staging first)

Refactor note

Acceptable to refactor db/index.ts, http-client.ts, and mercadopago.ts as needed to thread the tracer through. Keep the wrapper as the ONLY module that imports cloudflare:workers tracing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions