When an Agentuity app already writes JSON process logs and your platform reads stdout, keep Pino as the process logger. Agentuity services can still run in the same server-only code.
npm install pinoCreate an App Logger
Keep the logger in a normal server module. The module can be imported by routes, workers, scripts, or server functions.
import pino from 'pino';
export const appLogger = pino({
level: process.env.LOG_LEVEL ?? 'info',
});Add Request and Domain Fields
Create child loggers at the boundary that knows the request ID, user ID, order ID, or tenant ID. Those fields stay on every log line emitted by that child.
import { appLogger } from './logger';
interface CheckoutInput {
readonly requestId: string;
readonly orderId: string;
readonly userId: string;
readonly totalCents: number;
}
export async function acceptCheckout(
input: CheckoutInput
): Promise<{ readonly accepted: boolean }> {
const checkoutLogger = appLogger.child({
requestId: input.requestId,
orderId: input.orderId,
userId: input.userId,
});
if (input.totalCents <= 0) {
checkoutLogger.warn({ totalCents: input.totalCents }, 'Checkout rejected');
return { accepted: false };
}
checkoutLogger.info({ totalCents: input.totalCents }, 'Checkout accepted');
return { accepted: true };
}This path does not require an Agentuity integration. Keep shipping stdout through the log drain, collector, or platform agent your app already uses.
Format Logs During Local Development
Keep prettifying out of app code. When you want readable local output, install pino-pretty as a dev tool and pipe the process output through its CLI:
npm install -D pino-pretty
bun run src/smoke-pino.ts | bunx pino-prettyUse the raw JSON output for log drains, collectors, and deployed runtimes unless your platform expects a different format.
Add Agentuity Beside It
When the same route also needs Agentuity, keep the service client in server-only code and keep Pino as the process logger. Use Key-Value Storage for exact-key state, Database for relational data, or AI Gateway for model routing.
Use @agentuity/telemetry instead when you want Agentuity's logger and telemetry export setup to own the log path.
Test the Function
This smoke test keeps the logger app-owned and checks the function result. The log line still writes to stdout.
import { test, expect } from 'bun:test';
import { acceptCheckout } from './checkout';
test('accepts positive checkout totals', async () => {
await expect(
acceptCheckout({
requestId: 'req_123',
orderId: 'ord_123',
userId: 'user_123',
totalCents: 4900,
})
).resolves.toEqual({ accepted: true });
});