# Better Stack Hono logging

Log every request your [Hono](https://hono.dev/ ";_blank") 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:

[code-tabs]
```bash
[label Cloudflare Workers]
npm install @logtail/edge
```
```bash
[label Node.js]
npm install @logtail/node
```
[/code-tabs]

### 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:

[code-tabs]
```ts
[label Cloudflare Workers]
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;
```
```ts
[label Node.js]
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);
```
[/code-tabs]

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()`:

[code-tabs]
```ts
[label Cloudflare Workers]
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") });
});
```
```ts
[label Node.js]
app.get("/orders/:id", (c) => {
  logtail.info("Order viewed", { order_id: c.req.param("id") });

  return c.json({ id: c.req.param("id") });
});
```
[/code-tabs]

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

```ts
[label Send logs to Better Stack]
await logtail.flush();
```

You should see your logs in [Better Stack → Live tail](https://telemetry.betterstack.com/team/0/tail ";_blank").

[warning]
#### Hono 4 or higher is required
The middleware uses `c.req.routePath` and `c.error`, available since Hono v4.
[/warning]

## 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](https://github.com/logtail/logtail-js/tree/master/packages/types#loglevel).

#### 4xx status codes

Requests with `4xx` status codes, including `404` for unknown routes, are considered warnings. They are logged with [Warn log level](https://github.com/logtail/logtail-js/tree/master/packages/types#loglevel).

#### 5xx status codes

Requests with `5xx` status codes are considered errors. They are logged with [Error log level](https://github.com/logtail/logtail-js/tree/master/packages/types#loglevel).

#### 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](https://betterstack.com/docs/logs/javascript/logging/) applies, and the [Cloudflare Workers logging](https://betterstack.com/docs/logs/cloudflare-worker/) page covers the execution context in more depth.