AbsoluteJS

Logs

@absolutejs/logsv0.2.1betaObservability

Structured leveled logging with child loggers, pluggable sinks, secret redaction and OTel trace correlation for Bun services.

Structured logging for Bun services: leveled loggers with bound fields, child loggers and swappable sinks (console JSON, console pretty, in-memory, rotating file). It composes with the rest of the AbsoluteJS observability stack — pass a redact function from @absolutejs/secrets so secrets never reach disk, wire readActiveTraceId from @absolutejs/telemetry so every line carries the active OTel trace id, and read logger.metrics() for exposure via @absolutejs/metrics.

#Installation

BASH
bun add @absolutejs/logs

#Capabilities

Overview

Structured log primitive for the AbsoluteJS substrate. Levels, child loggers, sinks (console-JSON, console-pretty, memory, rotating file), optional secret redaction via @absolutejs/secrets, optional trace-id correlation via @absolutejs/telemetry.

Levels

trace → debug → info → warn → error → fatal. Filter at level; bump at runtime with log.setLevel('debug') (SIGUSR2-style incident triage).

Sinks

Sink — Purpose

consoleJsonSink() — One JSON line per event. stdout for < errorThreshold, stderr above.

consolePrettySink() — Human-readable lines for local dev.

Show 3 more

memorySink() — In-process FIFO buffer. .inspect() + .clear() for tests.

rotatingFileSink({ path, maxBytes, keep }) — Append-only file with size-based rotation.

Custom sinks just implement LogSink: { name?, write, flush?, close? }.

Composition

@absolutejs/secrets redaction. Pass redact: broker.redact and

every serialized event flows through the redactor before hitting a sink. Secrets never reach disk.

@absolutejs/telemetry trace correlation. Pass readTraceId:

Show 3 more

readActiveTraceId and every event carries the active OTel trace id. Failure (no provider wired) silently leaves traceId off — never breaks the log line.

@absolutejs/metrics exposure. logger.metrics() returns a

LoggerMetrics shape. A @absolutejs/metrics/logs collector subpath is planned for the next release.

Operator notes

Fire-and-forget writes. log.info(...) is synchronous and

returns immediately; sink writes run in the background. Use await log.flush() before shutdown.

Per-sink failures don't block others. One sink throwing

Show 3 more

bumps sinkErrors[name] and calls onError; the rest still receive the event. Same shape as @absolutejs/audit.

Closed loggers drop calls silently. Once await log.close()

has run, further log.info(...) calls are no-ops — no throw, no buffer.

Leveled logging

Six levels from trace to fatal, filtered at the logger and adjustable at runtime with setLevel for incident triage.

Child loggers

log.child({ requestId }) binds extra fields on top of the parent, giving per-request or per-job context without repeating it on every call.

Pluggable sinks

consoleJsonSink, consolePrettySink, memorySink and rotatingFileSink ship built in; custom sinks implement a small LogSink shape (name, write, flush, close).

Secret redaction

Pass redact from @absolutejs/secrets and every serialized event flows through the redactor before hitting any sink.

Trace correlation

Pass readTraceId from @absolutejs/telemetry and every event carries the active trace id; a missing provider silently leaves it off and never breaks the log line.

Fire-and-forget writes

Calls are synchronous and return immediately while sink writes run in the background; one sink throwing bumps sinkErrors without blocking the others, and flush() drains before shutdown.

Outcomes

What you can build

Overview

Structured log primitive for the AbsoluteJS substrate. Levels, child loggers, sinks (console-JSON, console-pretty, memory, rotating file), optional secret redaction via @absolutejs/secrets, optional trace-id correlation via @absolutejs/telemetry.

Levels

trace → debug → info → warn → error → fatal. Filter at level; bump at runtime with log.setLevel('debug') (SIGUSR2-style incident triage).

Sinks

Sink — Purpose

Hardening checklist

Production guidance

Make every external boundary explicitPin the deployed @absolutejs/logs version, replace example or memory-backed dependencies with durable implementations, bound external calls, protect credentials, and emit enough evidence to retry or recover safely.

Follow in order

Troubleshooting path

1
Levels
trace → debug → info → warn → error → fatal. Filter at level; bump at runtime with log.setLevel('debug') (SIGUSR2-style incident triage).

#Quick start

Partial snippet

Working example for Quick start.

TS
import { createLogger, consoleJsonSink, rotatingFileSink } from '@absolutejs/logs';
import { readActiveTraceId } from '@absolutejs/telemetry';

const log = createLogger({
  level: 'info',
  fields: { service: 'api', region: 'us-east-2' },
  sinks: [
    consoleJsonSink(),
    rotatingFileSink({ path: '/var/log/api/app.log', maxBytes: 10_000_000, keep: 5 }),
  ],
  redact: (text) => broker.redact(text),     // @absolutejs/secrets
  readTraceId: readActiveTraceId,            // @absolutejs/telemetry
});

log.info('User signed in', { userId: 'u_42', tenant: 'acme' });
// → {"at":1700000000000,"level":"info","message":"User signed in","tenant":"acme","traceId":"abc123","fields":{"service":"api","region":"us-east-2","userId":"u_42"}}

const requestLog = log.child({ requestId: req.id });
requestLog.warn('rate limit exceeded', { remaining: 0 });
// Same as parent, plus requestId in fields.

#Metrics

Partial snippet

Working example for Metrics.

TS
logger.metrics();
// {
//   logged: { trace: 0, debug: 0, info: 100, warn: 5, error: 2, fatal: 0 },
//   writes: 214,          // 107 events × 2 sinks
//   writeErrors: 0,
//   sinkErrors: {}
// }

#Quick Start

Partial snippet

Create a logger with JSON and rotating-file sinks, optional redaction and trace correlation, then derive a per-request child.

TS
import {
	consoleJsonSink,
	createLogger,
	rotatingFileSink
} from '@absolutejs/logs';
import { readActiveTraceId } from '@absolutejs/telemetry';

const log = createLogger({
	fields: { region: 'us-east-2', service: 'api' },
	level: 'info',
	readTraceId: readActiveTraceId, // @absolutejs/telemetry
	redact: (text) => broker.redact(text), // @absolutejs/secrets
	sinks: [
		consoleJsonSink(),
		rotatingFileSink({
			keep: 5,
			maxBytes: 10_000_000,
			path: '/var/log/api/app.log'
		})
	]
});

log.info('User signed in', { tenant: 'acme', userId: 'u_42' });

const requestLog = log.child({ requestId: req.id });
requestLog.warn('rate limit exceeded', { remaining: 0 });

#Metrics and Shutdown

Partial snippet

Inspect the LoggerMetrics snapshot and flush sinks cleanly on shutdown.

TS
logger.metrics();
// {
//   logged: { trace: 0, debug: 0, info: 100, warn: 5, error: 2, fatal: 0 },
//   writes: 214,          // 107 events × 2 sinks
//   writeErrors: 0,
//   sinkErrors: {}
// }

// Drain buffered sink writes before shutdown:
await logger.flush();
await logger.close();
Metrics surface
logger.metrics() returns per-level counts, write totals, and per-sink error counts. Expose that shape as Prometheus metrics with the shipped @absolutejs/metrics/logs collector.
Beta
Pre-1.0: the LogSink contract and metrics shape may change between minor versions. Once close() has run, further log calls are silent no-ops.

#API reference

Search the declarations exported by the current package type files. Expand a symbol to inspect its source-backed signature.

17 symbols
LOG_LEVELSvaluePermalink

@absolutejs/logs — structured log primitive for the AbsoluteJS substrate. Closes the second part of G9 (observability triad). The runtime's onLog callback emits per-tenant stdout/stderr lines; this package gives applications a structured way to emit those lines. Composes with the rest of the substrate: - @absolutejs/secrets — pass redact: broker.redact and every serialized event flows through the redactor before hitting a sink. Secrets in logs never reach disk. - @absolutejs/telemetry — pass rea

TS
const LOG_LEVELS: readonly ["trace", "debug", "info", "warn", "error", "fatal"];
Exported from @absolutejs/logs

Current package surface

What ships today

@absolutejs/logsv0.2.1 · betaObservabilitynpmSource
3entry points18symbols

Import surface · click to copy