import { dev } from "$app/environment"; import { configure, getConsoleSink, type LogRecord } from "@logtape/logtape"; import { requestContext } from "$lib/server/context"; interface RailwayLogEntry { timestamp: string; level: string; message: string; target: string; [key: string]: unknown; } function railwayFormatter(record: LogRecord): string { const ctx = requestContext.getStore(); const categoryTarget = record.category.join(":"); const entry: RailwayLogEntry = { timestamp: new Date().toISOString(), level: record.level.toLowerCase(), message: record.message.join(" "), target: categoryTarget ? `bun:${categoryTarget}` : "bun", ...(ctx?.requestId && { req_id: ctx.requestId }), }; if (record.properties && Object.keys(record.properties).length > 0) { Object.assign(entry, record.properties); } return JSON.stringify(entry) + "\n"; } export async function initLogger() { const useJsonLogs = process.env.LOG_JSON === "true" || process.env.LOG_JSON === "1"; const logLevel = (process.env.LOG_LEVEL?.toLowerCase() ?? (dev ? "debug" : "info")) as "debug" | "info" | "warning" | "error"; const jsonSink = (record: LogRecord) => { process.stdout.write(railwayFormatter(record)); }; const consoleSink = getConsoleSink(); try { await configure({ sinks: { json: useJsonLogs ? jsonSink : consoleSink, console: useJsonLogs ? jsonSink : consoleSink, }, filters: {}, loggers: [ { category: ["logtape", "meta"], lowestLevel: "warning", sinks: [useJsonLogs ? "json" : "console"], }, { category: [], lowestLevel: logLevel, sinks: [useJsonLogs ? "json" : "console"], }, ], }); } catch (error) { if ( error instanceof Error && error.message.includes("Already configured") ) { return; } throw error; } }