For Agentuity apps, keep your framework's normal stdout path or structured logger for process logs. Keep Pino, LogTape, a platform log drain, or a vendor agent when your app already standardizes on it. Use @agentuity/telemetry when server code needs Agentuity's logger and telemetry export setup. Hono apps can use @agentuity/hono when route handlers need the same logger from c.var.logger.
Bring Your Own Pino Logger
Keep this path when the app already owns process logs and your platform or log drain reads stdout. This is app-owned logging; Agentuity does not need a Pino integration for these lines to keep working.
npm install pinoimport pino from 'pino';
const appLogger = pino({
level: process.env.LOG_LEVEL ?? 'info',
});
const checkoutLogger = appLogger.child({
requestId: 'req_123',
orderId: 'ord_123',
});
checkoutLogger.info({ totalCents: 4900 }, 'Checkout accepted');Child loggers keep request and order fields on every line in that scope. See Structured Logging with Pino for a complete server-function example that keeps Pino app-owned.
Bring Your Own LogTape Logger
Keep this path when the app already uses LogTape categories, structured message placeholders, or a LogTape OpenTelemetry sink. Agentuity does not need a LogTape integration for those logs to keep flowing through your process logger or collector.
npm install @logtape/logtape @logtape/otelSee Using LogTape with an OpenTelemetry Sink for a complete startup and server-function example.
Use Agentuity Telemetry Logger
Use the Agentuity logger when you want child loggers and the same telemetry configuration as your traces:
npm install @agentuity/telemetryimport { logger } from '@agentuity/telemetry';
interface CheckoutInput {
readonly orderId: string;
readonly userId: string;
readonly totalCents: number;
}
export async function recordCheckout(
input: CheckoutInput
): Promise<{ readonly accepted: boolean }> {
const checkoutLogger = logger.child({
orderId: input.orderId,
userId: input.userId,
});
checkoutLogger.info('Checkout started');
if (input.totalCents <= 0) {
checkoutLogger.warn('Checkout rejected');
return { accepted: false };
}
checkoutLogger.child({ totalCents: input.totalCents }).info('Checkout accepted');
return { accepted: true };
}logger.child(fields) attaches fields as log attributes. Additional arguments passed to info(), warn(), or error() are formatted into the log message body. When Agentuity telemetry env is present, these logs export through the same telemetry pipeline as traces.
These paths compose: keep the app logger for process logs, then add OpenTelemetry spans where timing and cross-service context matter.
Configure at Startup
The named exports initialize telemetry from Agentuity environment variables on first use. Call register() once at app startup when you want explicit service metadata, a different log level, or predictable initialization before other modules log.
import { register } from '@agentuity/telemetry';
const telemetry = register({
name: 'checkout-api',
version: '1.4.0',
environment: process.env.NODE_ENV ?? 'development',
logLevel: 'info',
});
telemetry.logger.info('Telemetry initialized');The telemetry package supports trace, debug, info, warn, and error as minimum levels. If you do not pass logLevel, the package default is warn.
Log Levels
| Method | Use For |
|---|---|
trace() | noisy diagnostics you only enable briefly |
debug() | local request context and intermediate values |
info() | normal milestones, state changes, and accepted work |
warn() | recoverable problems or missing optional configuration |
error() | failed operations that need investigation |
fatal() | unrecoverable errors that exit the process |
fatal() logs through the error path and exits the process. Use it sparingly in server apps, because it terminates the current process.
Child Loggers
Create child loggers when every line in a small scope needs the same IDs or category fields.
import { logger } from '@agentuity/telemetry';
const requestLogger = logger.child({
requestId: 'req_123',
component: 'billing',
});
requestLogger.info('Invoice requested');
requestLogger.child({ durationMs: 42, rows: 8 }).debug('Invoice rows loaded');Nested children inherit parent fields and add their own fields.
Hono Routes
@agentuity/hono initializes telemetry once and exposes the logger on c.var.logger.
npm install @agentuity/hono honoimport { Hono } from 'hono';
import { agentuity } from '@agentuity/hono';
import type { Logger } from '@agentuity/hono';
interface Env {
readonly Variables: {
readonly logger: Logger;
};
}
function readEventType(value: unknown): string | undefined {
if (typeof value !== 'object' || value === null || !('type' in value)) {
return undefined;
}
const { type } = value;
return typeof type === 'string' && type.trim() ? type.trim() : undefined;
}
const app = new Hono<Env>();
app.use('*', agentuity({ telemetry: { logLevel: 'info' } }));
app.post('/webhooks/payments', async (c) => {
const body: unknown = await c.req.json();
const eventType = readEventType(body);
const routeLogger = c.var.logger.child({
provider: 'stripe',
eventType: eventType ?? 'unknown',
});
routeLogger.info('Webhook received');
if (!eventType) {
routeLogger.warn('Webhook missing event type');
return c.json({ error: 'type is required' }, 400);
}
routeLogger.info('Webhook accepted');
return c.json({ received: true });
});
export default app;View Logs
During local development, agentuity dev runs your framework's own dev script with injected service environment values, so stdout and console output appear in the terminal. In deployed apps, inspect logs by session or deployment.
agentuity dev
agentuity cloud session list
agentuity cloud session logs sess_abc123xyz
agentuity cloud deployment logs deploy_abc123xyz --limit=50Best Practices
- Use stdout, console JSON, or your existing logger when that is already your app standard.
- Use
loggerorc.var.loggerwhen you want Agentuity telemetry configuration and child logger fields. - Add IDs, counts, and durations through child logger fields.
- Keep log messages short. Put queryable context in attributes.
- Use
infofor accepted work,warnfor recoverable problems, anderrorfor failed operations. - Avoid logging secrets, tokens, raw emails, or full request bodies.
Next Steps
- Tracing: add OpenTelemetry spans around slow or multi-step work
- Sessions & Debugging: find the session that contains a log line
- Using LogTape with an OpenTelemetry Sink: keep LogTape logging app-owned