Observability middleware in Bun.js: logs, request id, tracing, and latency budgets
A practical deep dive into observability middleware in Bun.js: request id, structured logs, traceparent, OpenTelemetry, latency budgets, timing headers, error correlation, redaction, sampling, and bad logging practices.

Bun.js Middleware Production Guide 2026
A series about production middleware in Bun.js: overview, security, performance, observability, rate limiting, body parsing, WebSocket/SSE, and request pipeline testing.
All articles in this guide
01
Bun.js middleware in 2026: overview, best practices, and anti-patterns
The base mental model for middleware in native Bun, Hono, and Elysia, with examples, optimization, and a roadmap for the next deep dive articles.
02
Auth middleware in Bun.js: JWT, sessions, API keys, and multi-tenant context
How to build auth middleware in Bun correctly: check order, cache, token rotation, tenant context, 401/403 errors, and testing.
03
Rate limiting in Bun.js: in-memory, Redis, sliding window, and edge cases
A detailed breakdown of rate limiting for Bun APIs: algorithms, Redis, distributed limits, abuse protection, and graceful degradation.
04
Observability middleware in Bun.js: logs, request id, tracing, and latency budgets
How to add request id, structured logs, timing headers, an OpenTelemetry-like flow, and avoid turning logging into a bottleneck.
05
Body parsing and validation in Bun.js: JSON, uploads, streams, and payload limits
How to safely read request bodies in Bun, where to place limits, and how not to break streams, uploads, idempotency, and schema validation.
Logs without request id, traces without a sampling policy, errors without tenant/user context, metrics without route groups, and debug bodies in production are not observability. They are noise that sometimes helps by accident.
Observability middleware should answer practical questions: which request, which route, which tenant, which user/API key, how long auth, rate limit, handler, database, and downstream took, which error class appeared, and where to find it in logs.
In Bun, this is better designed as a thin request-scoped layer, not as random console.log calls inside handlers.
This is the fourth chapter in the Bun middleware series. After auth and rate limiting, production behavior needs to become visible, not just “fast locally”.
console.log(req), body logs, different request ids in different layers, tracing without context propagation.Observability should not be reduced to “we added a logger”. Logs, metrics, and traces have different roles, and middleware should collect the minimal context needed for all three.
| Signal | What it answers | What to write | Risk |
|---|---|---|---|
| Logs | What happened to a specific request or error | requestId, traceId, route, status, duration, error class, tenant/user ids | Noise, PII, secrets, body dumps, expensive serialization |
| Metrics | What is happening in the system in aggregate | latency percentiles, error rate, request count, limiter decisions | Too much cardinality from userId/path params |
| Traces | Where the request spent time in a distributed flow | spans, parent/child relationship, downstream calls, timings | No value without propagation and a sampling policy |
Logs, metrics, and traces do not duplicate one another. They provide different viewing angles on the same request flow.
Section observability-model screenshotSummary
For Bun middleware, the best baseline is request id in logs, latency in metrics, and trace context in downstream calls.
A request id should be created at the entry point or accepted from a trusted edge/proxy. Then it should flow through logs, response headers, error reports, and downstream calls. If different middleware layers generate different ids, correlation is lost.
A minimal native Bun pattern:
type Context = { requestId: string; startedAt: number };
type Handler = (req: Request, ctx: Context) => Promise<Response> | Response;
type Middleware = (next: Handler) => Handler;
const withRequestId: Middleware = (next) => async (req, ctx) => {
const incoming = req.headers.get("x-request-id");
const requestId = incoming && incoming.length <= 128 ? incoming : crypto.randomUUID();
const res = await next(req, { ...ctx, requestId });
res.headers.set("x-request-id", requestId);
return res;
};
Bun.serve({
fetch: withRequestId(async (_req, ctx) => {
return Response.json({ ok: true, requestId: ctx.requestId });
}),
});In production, define the trust boundary clearly. If x-request-id comes from a public client, validate or replace it. If it comes from your gateway, you can accept it as the upstream correlation id.
Request id should be one identifier for the whole request flow: response, logs, errors, and downstream calls should reference the same id.
Section request-id screenshotPractical rule
Generate request id once at the edge or at the Bun API entry point, then only pass it forward.
Structured logging means a log entry is a JSON-like event with fields you can filter: requestId, traceId, route, method, status, durationMs, tenantId, subjectId, errorClass. A string like user failed does not scale when an incident has 200 thousand events.
Pino is popular in the Node ecosystem specifically as a fast JSON logger and includes a redaction mechanism for hiding sensitive fields. Even if you do not use Pino directly in Bun, the principles are the same: structured fields, low overhead, redaction, sampling, and no secrets in the payload. [4]
A typical Bun API log entry shape:
logger.info({
event: "request.completed",
requestId: ctx.requestId,
traceId: ctx.traceId,
method: req.method,
route: ctx.routePattern,
status,
durationMs,
tenantId: ctx.auth?.tenantId,
subjectId: ctx.auth?.subjectId,
});What not to log
Do not log Authorization headers, cookies, refresh tokens, full API keys, raw request bodies, passwords, payment data, or large payloads without an explicit security review.
W3C Trace Context standardizes the traceparent and tracestate headers so different systems can pass trace identity between services. OpenTelemetry uses context propagation so spans become part of one distributed trace. [2][3]
In a Bun API, this means: if a request arrives with traceparent, you should either accept it from a trusted upstream or create a new trace. If your handler calls another service, queue, worker, or AI gateway, trace context should continue downstream.
Do not confuse request id with trace id. Request id is useful for support/debugging a single response. Trace id is needed for the distributed path. They can be different, but both should appear together in logs.
Trace context matters when a request passes through multiple services. Without propagation, a trace falls apart into unrelated fragments.
Section trace-context screenshotSummary
Request id helps find one request. Trace context shows the full path of a request through the system.
If you only see total duration, you know the API is slow, but you do not know why. Observability middleware should split a request into important stages.
How much credential verification costs
JWT verification, session lookup, API key lookup, tenant resolution, and permissions cache should each have their own timing. Otherwise, auth silently becomes the bottleneck.
How much limiter storage costs
Redis latency or local limiter overhead should be visible. If the limiter adds 15ms to every request, that is already a product decision.
How long business logic takes
Handler timing should be separated from middleware timing so you do not optimize the wrong layer.
How much time goes to DB, APIs, queues
DB and external services should have separate spans or timing events. Otherwise, a slow query looks like a slow Bun server.
Summary
Latency without breakdown turns into guesses. Breakdown without budget turns into endless noise.
In a high-traffic Bun API, full logging for every request may cost more than the handler itself. Sampling should be part of the design, not an emergency switch.
Good: full logs for errors and slow requests
Errors, 5xx, 429 spikes, auth failures, and slow requests should be logged in more detail, but still without secrets.
Careful: debug logs for all traffic
In production, this creates a storage bill, latency, noise, and security exposure. Debug sampling should be narrow and temporary.
Good: route-aware sampling
Critical flows, checkout, login, exports, and webhooks can have a different sampling policy than cheap public GET routes.
Careful: sampling without incident override
During an incident, the team should have a controlled way to temporarily increase detail for a route, tenant, or request class.
Observability can easily become the problem: slow logs, secret leaks, noise, and trace data that no one can connect.
console.log(req) or logging the raw request object.
Logging Authorization, cookies, refresh tokens, full API keys, or request body.
Generating a new request id in every middleware.
Trace id exists, but it is not written to logs.
Downstream calls do not receive trace context.
Metrics have high cardinality from raw URLs with ids or userId labels.
Error logs do not include route, status, requestId, or error class.
Debug logging is globally enabled in production.
Observability middleware runs after the handler and does not see early rejects.
No sampling policy and no storage budget.
Review rule
Observability should answer incident questions faster than it creates new performance and security risks.
Use this checklist before launching a Bun API in staging or production, especially if the API has auth, rate limiting, and downstream calls.
One request id for the whole flow
Accepted from a trusted upstream or generated at entry, added to the response and all logs.
Trace context propagates
traceparent and tracestate are accepted/created according to policy and passed into downstream calls.
Structured logs have a stable schema
event, requestId, traceId, route, method, status, durationMs, tenant/subject ids, error class.
Secrets are redacted
Authorization, cookies, API keys, tokens, passwords, PII, and raw body do not enter logs.
Latency breakdown exists
Auth, rate limit, handler, DB/downstream have separate timings or spans.
Sampling policy is defined
Errors and slow requests are logged in more detail; high-volume success logs use sampling or aggregation.
Route labels are normalized
Metrics use route patterns, for example /users/:id, not raw /users/123.
Incident override is controlled
There is a temporary way to increase detail for a route/tenant/request class without global debug chaos.
A Bun API can respond quickly, but without observability the team still loses time during incidents. Request id, structured logs, trace context, and latency breakdown make it possible to quickly understand what happened, where it happened, and who was affected.
The main trade-off: observability must not become a new bottleneck or a new data leak channel. That means middleware should be thin, redaction should be the default, sampling should be intentional, and timings should measure the layers that can actually hurt.
In production, the useful log is not the one that contains everything. It is the one that contains the right minimum and consistently connects to request, trace, route, tenant, and error.
Not for production. `console.log` can help locally, but a production API needs structured logs with requestId, route, status, duration, error class, and redaction. Otherwise, logs are hard to search, aggregate, and store safely.
No. Request id is usually used for support/debug correlation of a single HTTP request. Trace id shows the distributed path across multiple services. It is best to have both in logs.
Authorization headers, cookies, refresh tokens, full API keys, passwords, PII, payment data, and raw request body without explicit security review. Redaction should be the default.
Not always from day one. For a small API, request id, structured logs, and latency breakdown may be enough. Once downstream services, queues, or distributed flows appear, trace context and OpenTelemetry become much more useful.
Keep middleware thin, do not serialize large objects, do not log bodies, use sampling for high-volume success traffic, measure logger overhead, and write route labels without high-cardinality values.
At the very beginning, so it can see early rejects from auth/rate limit/body validation. But redaction and context enrichment must be careful not to read bodies or secrets unnecessarily.
These sources confirm trace context standards, the OpenTelemetry propagation approach, the Bun server model, and structured logging/redaction practices.
PAS7 Studio can help design observability middleware for Bun, Hono, or Elysia: request id, structured logs, trace context, latency budgets, redaction, sampling, and dashboards for production APIs.
This is especially useful for SaaS, internal platforms, integration APIs, and high-traffic products where incidents need to be explained quickly, not by reading thousands of random log lines.
Observability middleware in Bun.js: logs, request id, tracing, and latency budgets
Related Articles
AI Assistant Development Cost in 2026: RAG Chatbots, CRM Integrations, Guardrails, and Support
A practical buyer guide to AI assistant development cost in 2026: prototypes, RAG chatbots, knowledge-base assistants, CRM and website integrations, guardrails, evaluations, monitoring, and support.
AI for landing page development: where it speeds up launches and where it hurts conversion
A practical research piece on using AI for landing page development: v0, Webflow AI, Builder.io, Framer-like builders, UX generation, copy, SEO, personalization, A/B testing, template risk, accessibility, security and technical debt.
AI SEO / GEO in 2026: Your Next Customers Aren’t Humans — They’re Agents
Search is shifting from clicks to answers. Bots and AI agents crawl, cite, recommend, and increasingly buy. Learn what AI SEO / GEO means, why classic SEO is no longer enough, and how PAS7 Studio helps brands win visibility in the agentic web.
The most powerful Apple chip yet? M5 Pro and M5 Max are breaking records
A data-backed March 2026 analysis of Apple M5 Pro and M5 Max. We break down why these chips can credibly be called Apple's most powerful pro laptop silicon, how they compare with M4 Pro, M4 Max, M1 Pro, M1 Max, and how they stack up against Intel and AMD laptop rivals.
Professional development for your business
We create modern web solutions and bots for businesses. Learn how we can help you achieve your goals.