Skip to content

Console capture

Patch console.log / console.info / console.warn / console.error / console.debug and forward each call to AxonPush as an OpenTelemetry-shaped log event. Each captured call still passes through to the original console method, so your terminal output is unchanged.

Use this for AI agent projects where the agent (or its tools) emits free-form output via console.log instead of going through a structured logger.

[!TIP] Non-blocking by default (v0.0.2+)

Captured lines are pushed onto a bounded queue and drained by a background task. Call handle.flush(timeoutMs?) at known checkpoints to guarantee delivery, or use flushAfterInvocation. The SDK’s own internal logger (consola) writes directly to process.stdout.write and does NOT route through console.log, so there is no feedback-loop risk between this capture and the SDK’s diagnostics.

Terminal window
npm install @axonpush/sdk

No peer dependencies — this integration ships with the base package.

import { AxonPush } from "@axonpush/sdk";
import { setupConsoleCapture } from "@axonpush/sdk/integrations/console";
const client = new AxonPush({
apiKey: process.env.AXONPUSH_API_KEY!,
tenantId: process.env.AXONPUSH_TENANT_ID!,
});
const handle = setupConsoleCapture({
client,
channelId: 1,
agentId: "my-agent",
serviceName: "my-agent",
});
console.log("agent starting up");
console.log("step 1: loaded tools = ['web_search', 'calculator']");
console.error("retrying after 429");

Each call is written to the original console AND shipped to AxonPush.

By default, captured logs are tagged as agent.log events (for AI agent projects). Pass source: "app" to tag them as app.log instead:

setupConsoleCapture({ client, channelId: 1, source: "app" });
handle.unpatch(); // restore the original console.* methods
await handle.flush(1000); // drain any pending publishes
await handle.close(); // stop the background worker

Always unpatch() in a finally: block (or before process.exit()) so that test teardown and subprocess spawning don’t inherit the patch. The module-level beforeExit / SIGTERM / SIGINT hook closes the publisher at normal process exit — you don’t need to call .close() explicitly in long-running servers.

OptionTypeDefaultDescription
clientAxonPushrequiredThe pre-built SDK client.
channelIdnumberrequiredTarget channel for captured log events.
source"agent" | "app""agent"Event type tag — agent.log or app.log.
agentIdstringOptional agent correlation ID.
serviceNamestringOTel service.name resource attribute.
maxBodyLengthnumber4000Maximum characters per captured body.
mode"background" | "sync""background"Publishing mode.
queueSizenumber1000Max records buffered before drop.
FieldValue
identifier"console"
eventTypeagent.log (default) or app.log if source: "app"
payload.bodyThe formatted argument list
payload.severityNumber / payload.severityTextMapped from the console method: debug→DEBUG, log/info→INFO, warn→WARN, error→ERROR
payload.attributeslog.iostream (stdout / stderr), log.source (console)