@kleb/logging (0.4.0)

Published 2026-07-07 09:04:36 +02:00 by kleb

Installation

@kleb:registry=
npm install @kleb/logging@0.4.0
"@kleb/logging": "0.4.0"

About this package

@kleb/logging

Structured logging for TypeScript projects.

Install from the private Forgejo npm registry after configuring auth for https://git.kleb.sh/api/packages/kleb/npm/:

bun add @kleb/logging
import { createLogger } from "@kleb/logging";

const logger = createLogger();
logger.info("app.started", { port: 3000 });

Use the config integration when @kleb/config is installed and logging should be driven by app configuration:

import { kConfig } from "@kleb/config/server";
import { createLoggerFromConfig, loggingConfig } from "@kleb/logging/config";

const appConfig = kConfig("server.json").section("logging", loggingConfig());
const loaded = appConfig.load({ logger });
const logger = createLoggerFromConfig(loaded.value.logging);

Use the server entrypoint for rotating file logs:

import { createLogger } from "@kleb/logging";
import { createRotatingFileSink } from "@kleb/logging/server";

const logger = createLogger({
  sinks: [
    createRotatingFileSink({
      directory: "logs",
      archiveDirectory: "archive",
      formats: ["json", "text"],
      rotation: { every: "day", atHour: 0 },
      maxArchived: 31,
    }),
  ],
});

Archives are written below the active log directory by default:

logs/
  current.log
  current.json.log
  error.log
  errors.json.log
  archive/
    text/
    json/

Use a custom archive folder when active logs and archived logs should be separated:

createRotatingFileSink({
  directory: "logs/active",
  archiveDirectory: "../archive",
  formats: ["json", "text"],
  rotation: { every: "hour" },
});

For short-lived validation or interval-based rotation, use rotation.every.milliseconds:

createRotatingFileSink({
  directory: "logs",
  formats: ["json", "text"],
  rotation: { every: { milliseconds: 60_000 } },
});

Log entries are queued in memory and written to disk by a background drain loop; they are only durable once an awaited flush()/shutdown() resolves. There is no fsync, so entries can still be lost on an unclean process termination (crash, power loss) between a resolved write() call and the next successful drain.

Disable automatic rotation while keeping manual rotation available:

const sink = createRotatingFileSink({
  directory: "logs",
  rotation: false,
});

await sink.rotate();

Use the context entrypoint to attach request-scoped fields across async calls:

import { createLogger } from "@kleb/logging";
import { logContextProvider, withLogContext } from "@kleb/logging/context";

const logger = createLogger({
  contextProvider: logContextProvider,
});

await withLogContext({ requestId: "req-123", userId: "user-1" }, async () => {
  await doWork();
  logger.info("work.completed");
});

Fields passed directly to a log call override active context fields:

logger.info("work.completed", { requestId: "req-explicit" });

Redaction is explicit:

const logger = createLogger({
  redaction: {
    keys: ["authorization", /password/i],
    patterns: [/token-[a-z0-9]+/gi],
  },
});

HTTP helpers require already-safe route patterns:

logger.info(
  "http.request.completed",
  createHttpLogFields({
    requestId: "req-123",
    method: "GET",
    routePattern: "/api/users/:id",
    status: 200,
    durationMs: 12.5,
  }),
);

Dependencies

Peer dependencies

ID Version
@kleb/config ^0.5.0
Details
npm
2026-07-07 09:04:36 +02:00
15
UNLICENSED
14 KiB
Assets (1)
Versions (7) View all
0.6.0 2026-07-20
0.5.0 2026-07-14
0.4.0 2026-07-07
0.3.1 2026-07-04
0.3.0 2026-07-03