Skip to content

ElysiaJS Integration Server Bun

NPM Version

Source

An ElysiaJS plugin that provides request-scoped logging with automatic request/response logging and error handling. The auto-logging format follows pino-http conventions.

Installation

sh
npm i @loglayer/elysia loglayer @loglayer/transport-simple-pretty-terminal serialize-error
sh
pnpm add @loglayer/elysia loglayer @loglayer/transport-simple-pretty-terminal serialize-error
sh
yarn add @loglayer/elysia loglayer @loglayer/transport-simple-pretty-terminal serialize-error

We're using Simple Pretty Terminal here as an example to get nicely formatted logs. Any LogLayer-compatible transport can be used, including Pino, LogTape, Structured, Console, and others.

Basic Usage

typescript
import { Elysia } from "elysia";
import { LogLayer } from "loglayer";
import { serializeError } from "serialize-error";
import { getSimplePrettyTerminal, moonlight } from "@loglayer/transport-simple-pretty-terminal";
import { elysiaLogLayer } from "@loglayer/elysia";

const log = new LogLayer({
  errorSerializer: serializeError,
  transport: getSimplePrettyTerminal({
    runtime: "node",
    theme: moonlight,
  }),
});

const app = new Elysia()
  .use(elysiaLogLayer({ instance: log }))
  .get("/", ({ log }) => {
    log.info("Hello from route!");
    return "Hello World!";
  })
  .get("/api/users/:id", ({ log, params }) => {
    log.withMetadata({ userId: params.id }).info("Fetching user");
    return { id: params.id, name: "John" };
  })
  .listen(3000);

Each request automatically gets:

  • A child logger with a unique requestId in its context
  • Automatic request and response logging following pino-http conventions
  • Error logging via the onError hook

Configuration

OptionTypeDefaultDescription
instanceILogLayerrequiredThe LogLayer instance to use
requestIdboolean | (request: Request) => stringtrueControls request ID generation
autoLoggingboolean | ElysiaAutoLoggingConfigtrueControls automatic request/response logging
contextFn(ctx) => Record<string, any>-Extract additional context from requests

Auto-Logging Configuration

When autoLogging is an object:

OptionTypeDefaultDescription
logLevelstring"info"Default log level for request/response logs
ignoreArray<string | RegExp>[]Paths to exclude from auto-logging
requestboolean | ElysiaRequestLoggingConfigtrueControls request logging (fires when request is received)
responseboolean | ElysiaResponseLoggingConfigtrueControls response logging (fires after handler completes)

Both request and response accept an object with a logLevel property to override the default log level.

Request Log Output

When enabled (default), request logging produces:

  • Message: "incoming request"
  • Metadata: { req: { method, url, remoteAddress } }

Response Log Output

When enabled (default), response logging produces:

  • Message: "request completed"
  • Metadata: { req: { method, url, remoteAddress }, res: { statusCode }, responseTime }

The remoteAddress is resolved from x-forwarded-for or x-real-ip headers, or from Bun's server.requestIP() when available.

Example Log Output

With the default configuration using Pino as the transport, a GET /api/users request produces two log entries:

json
// incoming request
{
  "msg": "incoming request",
  "req": { "method": "GET", "url": "/api/users", "remoteAddress": "::1" },
  "requestId": "550e8400-e29b-41d4-a716-446655440000"
}

// request completed
{
  "msg": "request completed",
  "req": { "method": "GET", "url": "/api/users", "remoteAddress": "::1" },
  "res": { "statusCode": 200 },
  "responseTime": 12,
  "requestId": "550e8400-e29b-41d4-a716-446655440000"
}

Examples

Custom Log Levels

typescript
elysiaLogLayer({
  instance: log,
  autoLogging: {
    request: { logLevel: "debug" },
    response: { logLevel: "info" },
  },
})

Disable Request Logging (Response Only)

typescript
elysiaLogLayer({
  instance: log,
  autoLogging: {
    request: false,
  },
})

Custom Request ID

typescript
elysiaLogLayer({
  instance: log,
  requestId: (request) =>
    request.headers.get("x-request-id") ?? crypto.randomUUID(),
})

Disable Auto-Logging

typescript
elysiaLogLayer({
  instance: log,
  autoLogging: false,
})

Ignore Health Check Paths

typescript
elysiaLogLayer({
  instance: log,
  autoLogging: {
    ignore: ["/health", "/ready", /^\/internal\//],
  },
})

Additional Context from Request

typescript
elysiaLogLayer({
  instance: log,
  contextFn: ({ request }) => ({
    userAgent: request.headers.get("user-agent"),
    host: request.headers.get("host"),
  }),
})

Error Handling

Errors thrown in route handlers are automatically caught and logged:

typescript
const app = new Elysia()
  .use(elysiaLogLayer({ instance: log }))
  .get("/fail", () => {
    throw new Error("Something went wrong");
    // Automatically logged with the error object
  });

Using with Other Elysia Plugins

typescript
const app = new Elysia()
  .use(elysiaLogLayer({ instance: log }))
  .use(cors())
  .use(swagger())
  .get("/", ({ log }) => {
    log.info("Works with other plugins!");
    return "ok";
  });

Changelog

View the changelog here.