When an Agentuity app already uses LogTape categories and structured log records, keep LogTape as the process logger. Agentuity services and telemetry can still sit beside it in server-only app code.
npm install @logtape/logtape @logtape/otelConfigure Sinks at Startup
Configure LogTape once before route modules or workers start logging. Keep the OpenTelemetry sink behind an explicit option so local tests can run with console output only.
import {
configure,
dispose,
getConsoleSink,
getLogger,
type Sink,
} from '@logtape/logtape';
import { getOpenTelemetrySink } from '@logtape/otel';
const supportLogger = getLogger(['support']);
export async function configureSupportLogging(options: {
readonly useOtel: boolean;
}): Promise<void> {
const sinks: Record<string, Sink> = {
console: getConsoleSink(),
};
const loggerSinks = ['console'];
if (options.useOtel) {
sinks.otel = getOpenTelemetrySink();
loggerSinks.push('otel');
}
await configure({
reset: true,
sinks,
loggers: [
{
category: ['support'],
lowestLevel: 'info',
sinks: loggerSinks,
},
{
category: ['logtape', 'meta'],
lowestLevel: 'warning',
sinks: ['console'],
},
],
});
}
export function logSupportAnswer(input: {
readonly question: string;
readonly sourceCount: number;
readonly escalated: boolean;
}): void {
supportLogger.info('Support answer {questionLength} completed', {
questionLength: input.question.length,
sourceCount: input.sourceCount,
escalated: input.escalated,
});
}
export async function disposeSupportLogging(): Promise<void> {
await dispose();
}Point the Sink at a Collector
The LogTape OpenTelemetry sink reads standard OTLP log exporter environment variables. Use the log-specific variables when your collector has separate endpoints.
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://127.0.0.1:4318/v1/logs
OTEL_EXPORTER_OTLP_LOGS_PROTOCOL=http/jsonFor vendor collectors, add the headers that collector requires:
OTEL_EXPORTER_OTLP_LOGS_HEADERS='Authorization=Bearer ...'Use It from App Code
Keep the logger call close to the app boundary that knows IDs, counts, and outcome fields.
import { logSupportAnswer } from './logging';
interface SupportAnswer {
readonly answer: string;
readonly sources: readonly string[];
readonly escalated: boolean;
}
export function recordSupportAnswer(
question: string,
output: SupportAnswer
): SupportAnswer {
logSupportAnswer({
question,
sourceCount: output.sources.length,
escalated: output.escalated,
});
return output;
}LogTape message placeholders become structured fields on the record. Keep secrets, raw prompts, tokens, and full request bodies out of the properties object.
Keep Agentuity Beside It
This path does not require an Agentuity logging integration. Keep LogTape for process logs, then add Tracing or Sessions & Debugging when you need Agentuity timelines, deployment logs, or spans from Agentuity telemetry.
Use @agentuity/telemetry instead when you want Agentuity's logger and telemetry export setup to own the log path.
Next Steps
- Logging: choose between app-owned logs and Agentuity telemetry logs
- Tracing: add spans around slow or multi-step work
- OpenTelemetry route spans: send spans through the collector your app already uses