WIP! A BB-style forum, on the ATmosphere!
We're still working... we'll be back soon when we have something to show off!
node
typescript
hono
htmx
atproto
1import type { MiddlewareHandler } from "hono";
2import { createMiddleware } from "hono/factory";
3import type { Logger } from "./types.js";
4
5/**
6 * Hono middleware that logs structured HTTP request/response data.
7 *
8 * Replaces Hono's built-in `logger()` middleware with OpenTelemetry-backed
9 * structured logging. Each request gets a child logger with request context
10 * that is available to downstream handlers via `c.get("logger")`.
11 *
12 * Log output:
13 * - Incoming request: method, path (at debug level)
14 * - Completed response: method, path, status, duration_ms
15 * (info for 2xx, warn for 4xx, error for 5xx — including errors handled by onError)
16 *
17 * @example
18 * ```ts
19 * import { createLogger } from "@atbb/logger";
20 * import { requestLogger } from "@atbb/logger/middleware";
21 *
22 * const logger = createLogger({ service: "atbb-appview" });
23 * app.use("*", requestLogger(logger));
24 *
25 * // In route handlers:
26 * app.get("/api/forum", (c) => {
27 * const log = c.get("logger");
28 * log.info("Fetching forum metadata");
29 * // ...
30 * });
31 * ```
32 */
33export function requestLogger(logger: Logger): MiddlewareHandler {
34 return createMiddleware(async (c, next) => {
35 const start = performance.now();
36 const method = c.req.method;
37 const path = c.req.path;
38
39 // Create a child logger scoped to this request
40 const reqLogger = logger.child({
41 method,
42 path,
43 });
44
45 // Make the logger available to downstream handlers
46 c.set("logger", reqLogger);
47
48 reqLogger.debug("Request received");
49
50 await next();
51
52 const duration = Math.round(performance.now() - start);
53 const status = c.res.status;
54 const level = status >= 500 ? "error" : status >= 400 ? "warn" : "info";
55
56 reqLogger[level]("Request completed", {
57 status,
58 duration_ms: duration,
59 });
60 });
61}