observability

Request ID + structured logging (Express + pino)

Debugging distributed requests is miserable without a stable request id, so I generate it once at the edge, echo it back via x-request-id, and attach it to every log line with a child logger. I keep this intentionally boring because it delivers 80% of

OpenTelemetry tracing for Node HTTP

Once services talk to other services, logs alone don’t tell you where time goes. I like OpenTelemetry because it’s vendor-neutral: export to Honeycomb, Datadog, Tempo—whatever your team uses. I keep the initial setup minimal: instrument http, express,

Lograge-Style JSON Logging Without Extra Gems

Production debugging is about logs that are searchable. Emit JSON with consistent keys (requestid, memberid, duration). Even if you later add Lograge, this structure maps cleanly.

Web Vitals reporting to an API endpoint

Synthetic performance tests don’t always match what real users experience. Web Vitals reporting gives you field data (CLS, LCP, INP, etc.). I collect vitals on the client and POST them to a lightweight endpoint, then aggregate on the backend. Sampling

Prometheus metrics for request latency

During an incident, the first question is usually ‘is it getting worse?’, and log lines don’t answer that well. Prometheus-style metrics make it easy to track rates and percentiles over time. I instrument request duration as a histogram and label by m

HTTP Timeouts + Retries Wrapper (Faraday)

I wrapped external HTTP calls once I realized most “flaky APIs” were actually my fault: no timeouts, unclear retries, and logs that didn’t tell a story. In Client with timeouts, I centralize a Faraday connection with explicit open_timeout and timeout,

Instrument a Service with Notifications

I instrument services because I don’t want performance and reliability to be a guessing game. In Service instrumentation, I wrap the work in ActiveSupport::Notifications.instrument and emit a stable payload (things like IDs and counts, not giant blobs

CurrentAttributes for Request-Scoped Context

I use ActiveSupport::CurrentAttributes any time I need request-scoped context without turning my app into a tangle of thread-local globals. In Current, I define the attributes I care about (member, request_id, remote_ip) and I use the resets hook to c

Sentry initialization with release + environment

Noisy error reporting without context turns into a pile of untriaged alerts. I initialize Sentry early, set the release from the git SHA, and tag the environment so I can separate staging from production. I also set a sample rate and capture only what

API Error Handling with Problem Details (RFC7807-ish)

APIs are easier to operate when errors are structured and consistent. Wrap errors into a problem-details style response with a stable type and request_id so support can quickly trace issues.

Action Mailer Delivery Observability Hook

Email issues are painful in production. Subscribe to mailer notifications and log message IDs, recipients, and durations. This gives you a lightweight audit trail without adding a heavy dependency.

Turbo Drive lifecycle: attach global error handler

You’ll eventually hit non-200 responses or network flakiness. Hook Turbo events to log failures (and optionally show a toast). This is a pragmatic production addition that helps debugging without adding heavy tooling.