Better Stack Hono logging

Log every request your Hono app handles, plus anything else you want to log, with a few lines of middleware.

1. Install

Install the Better Stack logging library for the runtime your Hono app runs on:

Cloudflare Workers Node.js
npm install @logtail/edge
npm install @logtail/node

2. Set up

In your src/index.ts, create the Better Stack client and add a middleware that logs each request once its response is ready:

Cloudflare Workers Node.js
import { Hono } from "hono";
import { Logtail } from "@logtail/edge";

const app = new Hono();
const logtail = new Logtail("$SOURCE_TOKEN", {
  endpoint: "https://$INGESTING_HOST",
});

app.use(async (c, next) => {
  const startedAt = Date.now();
  await next();

  const { status } = c.res;
  const level = status >= 500 ? "error" : status >= 400 ? "warn" : "info";

  // The execution context ensure log delivery after the response is sent
  logtail.withExecutionContext(c.executionCtx)
    .log(`${c.req.method} ${c.req.path} ${status}`, level, {
      method: c.req.method,
      path: c.req.path,
      route: c.req.routePath,
      status,
      duration_ms: Date.now() - startedAt,
      error: c.error,
    });
});

app.get("/", (c) => c.text("Hello Hono!"));

export default app;
import { Hono } from "hono";
import { serve } from "@hono/node-server";
import { Logtail } from "@logtail/node";

const app = new Hono();
const logtail = new Logtail("$SOURCE_TOKEN", {
  endpoint: "https://$INGESTING_HOST",
});

app.use(async (c, next) => {
  const startedAt = Date.now();
  await next();

  const { status } = c.res;
  const level = status >= 500 ? "error" : status >= 400 ? "warn" : "info";

  logtail.log(`${c.req.method} ${c.req.path} ${status}`, level, {
    method: c.req.method,
    path: c.req.path,
    route: c.req.routePath,
    status,
    duration_ms: Date.now() - startedAt,
    error: c.error,
  });
});

app.get("/", (c) => c.text("Hello Hono!"));

serve(app);


Other edge runtimes without an execution context, such as Deno Deploy, use logtail.log(...) directly like the Node.js version.

3. Start logging

All HTTP requests handled by Hono will be logged and sent to Better Stack.

Log anything else with debug(), info(), warn(), and error():

Cloudflare Workers Node.js
app.get("/orders/:id", (c) => {
  logtail.withExecutionContext(c.executionCtx)
    .info("Order viewed", { order_id: c.req.param("id") });

  return c.json({ id: c.req.param("id") });
});
app.get("/orders/:id", (c) => {
  logtail.info("Order viewed", { order_id: c.req.param("id") });

  return c.json({ id: c.req.param("id") });
});

On Node.js, logs are sent in batches. Ensure all logs are flushed to Better Stack before the process exits:

Send logs to Better Stack
await logtail.flush();

You should see your logs in Better Stack β†’ Live tail.

Hono 4 or higher is required

The middleware uses c.req.routePath and c.error, available since Hono v4.

Need help?

Please let us know at hello@betterstack.com.
We're happy to help! πŸ™

Additional information

How the middleware works

The middleware runs after await next(), when Hono has finished the response, and logs each request once with these fields:

  • method and path: the request as it came in, without the query string.
  • route: the matched route pattern such as /users/:id, handy for grouping requests in dashboards.
  • status and duration_ms: the response status and how long the request took.

Successful requests

Requests that end with a 2xx or 3xx status code are logged to Better Stack with Info log level.

4xx status codes

Requests with 4xx status codes, including 404 for unknown routes, are considered warnings. They are logged with Warn log level.

5xx status codes

Requests with 5xx status codes are considered errors. They are logged with Error log level.

Uncaught errors

When a handler throws, Hono's error handler turns the error into the response (500 by default, or the status of an HTTPException) before the middleware logs the request. The exception is available as c.error and is sent under the error field together with its message and stack trace.

Customizing the log

The middleware is part of your app, so extend it as you need:

  • Add fields from the request, for example user_agent: c.req.header("user-agent") or query: c.req.query().
  • Skip noisy routes by returning early after await next(), for example if (c.req.path === "/health") return;.
  • Change the message to whatever reads best in Live tail.

Additional logging

Everything from the Logtail JavaScript client applies, and the Cloudflare Workers logging page covers the execution context in more depth.