export interface JsonLogEntry { timestamp: string; level: "info" | "warn" | "error"; service: string; message: string; sessionId?: string; runId?: string; taskId?: string; eventType?: string; details?: unknown; } const REDACT_KEYS = new Set(["apiKey", "authorization", "Authorization", "openai_api_key", "OPENAI_API_KEY"]); function redactObject(value: unknown): unknown { if (Array.isArray(value)) { return value.map(redactObject); } if (value !== null && typeof value === "object") { const source = value as Record; const out: Record = {}; for (const [key, field] of Object.entries(source)) { if (REDACT_KEYS.has(key)) { out[key] = "***REDACTED***"; } else { out[key] = redactObject(field); } } return out; } return value; } export function logJson(entry: JsonLogEntry): void { if (process.env.NODE_ENV === "test" && process.env.FEATURE_JSON_STDOUT_LOGS_IN_TESTS !== "1") { return; } const safe = { ...entry, details: redactObject(entry.details) }; // Structured JSON logs for diagnostics/trace aggregation. try { process.stdout.write(JSON.stringify(safe) + "\n"); } catch (error) { const code = (error as { code?: unknown } | null)?.code; if (code === "ENOSPC" || code === "EPIPE") { return; } throw error; } }