axonpush
TypeScript SDKIntegrations

Console capture

Mirror console.log, info, warn, error, and debug calls to axonpush without changing what your terminal prints.

setupConsoleCapture patches console.log, console.info, console.warn, console.error, and console.debug, and forwards each call to axonpush as an OpenTelemetry-shaped log event. The original method still runs first, so your terminal output is unchanged.

Use it for agent projects where the agent or its tools emit free-form output through console.log instead of a structured logger. No peer dependencies, this one ships with the base package.

Install

npm install @axonpush/sdk

Patch the console

import { AxonPush } from "@axonpush/sdk";
import { setupConsoleCapture } from "@axonpush/sdk/integrations/console";

const client = new AxonPush();
const handle = setupConsoleCapture({
  client,
  channelId: process.env.AXONPUSH_CHANNEL_ID!,
  agentId: "research-agent",
  serviceName: "research-agent",
});

console.log("agent starting up");
console.error("retrying after 429");

Each call is written to the real console and published.

agent.log or app.log

Captured lines are tagged agent.log by default, which is what you want for agent projects. Pass source: "app" for a backend service and they become app.log instead:

setupConsoleCapture({ client, channelId, source: "app" });

Non-blocking by default

Captured lines are pushed onto a bounded in-memory queue and drained by a background loop, so console.log stays fast. Records live in memory until drained, set mode: "bullmq" if losing them on a crash is unacceptable.

Options

OptionTypeDefaultDescription
clientAxonPushrequiredThe SDK client to publish through.
channelIdstringrequiredChannel UUID for captured events.
source"agent" | "app""agent"Chooses agent.log or app.log.
serviceNamestringOTel service.name on the payload’s resource.
maxBodyLengthnumber4000Characters kept per captured body.
agentIdstringAgent correlation id.
traceIdstringnew traceSeed an existing trace.
mode"background" | "sync" | "bullmq""background"Publishing strategy.
queueSizenumber1000Records buffered before overflow.
overflowPolicy"drop-oldest" | "drop-newest" | "block""drop-oldest"What a full queue does.
shutdownTimeoutMsnumber2000Drain budget on close().
concurrencynumber1Parallel in-flight publishes.
bullmqOptionsBullMQPublisherOptionsRequired when mode: "bullmq".

Unpatching

handle.unpatch();          // restore the original console methods
await handle.flush(1000);  // drain pending publishes
await handle.close();      // restore, then stop the background loop

Always unpatch in tests and before forking

A patched console is process-global. Restore it in a finally block so test teardown and spawned subprocesses do not inherit it.

The patch also restores itself on exit, beforeExit, and uncaughtException, so a crashing process still prints its stack through the real console. The uncaught-exception handler re-throws on the next tick, which keeps Node’s default behaviour, stack printed, exit code 1, intact. Long-running servers do not need to call close(): the module-level beforeExit / SIGTERM / SIGINT hooks close every live publisher.

Body formatting

A single string argument is used as-is. A single non-string is JSON-stringified with two-space indentation. Multiple arguments are stringified individually and joined with spaces. Whatever comes out is cut at maxBodyLength with a …[truncated] marker, then run through the client’s redactor.

Event shape

FieldValue
identifier"console"
eventTypeagent.log, or app.log when source: "app"
payload.timeUnixNanocapture time in nanoseconds
payload.severityNumber / severityTextdebug → DEBUG (5), log/info → INFO (9), warn → WARN (13), error → ERROR (17)
payload.bodythe formatted argument list
payload.attributeslog.iostream (stderr for warn and error, else stdout), log.source: "console"
payload.resourceservice.name, when configured
metadata.framework"console-capture"

Re-entrancy

The SDK’s own diagnostics go through consola, and records emitted while the publisher is mid-publish are skipped, so a warning raised during a failed publish cannot re-enter the capture and loop.