2026-02-27 14:09:33 -05:00

69 lines
1.8 KiB
TypeScript

import { toErrorCode } from "@/server/lib/errors";
type LogContext = Record<string, unknown>;
const SENSITIVE_KEY_PATTERN = /token|secret|password|key|email|authorization/i;
function sanitizeValue(key: string, value: unknown): unknown {
if (SENSITIVE_KEY_PATTERN.test(key)) return "[REDACTED]";
if (typeof value === "string") {
return value.length > 300 ? `${value.slice(0, 300)}...` : value;
}
if (Array.isArray(value)) {
return value.slice(0, 10).map((item) => sanitizeValue(key, item));
}
if (value && typeof value === "object") {
const output: Record<string, unknown> = {};
for (const [k, v] of Object.entries(value)) {
output[k] = sanitizeValue(k, v);
}
return output;
}
return value;
}
function sanitizeContext(context: LogContext): LogContext {
const safe: LogContext = {};
for (const [key, value] of Object.entries(context)) {
safe[key] = sanitizeValue(key, value);
}
return safe;
}
export function logServerError(
operation: string,
error: unknown,
context: LogContext = {},
): void {
const code = toErrorCode(error);
const safeErrorMessage =
error instanceof Error
? sanitizeValue("message", error.message)
: "unknown";
const safeStack =
error instanceof Error && typeof error.stack === "string"
? sanitizeValue("stack", error.stack)
: undefined;
const safeCause =
error instanceof Error && "cause" in error
? sanitizeValue("cause", (error as { cause?: unknown }).cause)
: undefined;
console.error(
JSON.stringify({
level: "error",
operation,
code,
errorName: error instanceof Error ? error.name : "UnknownError",
message: safeErrorMessage,
stack: safeStack,
cause: safeCause,
context: sanitizeContext(context),
}),
);
}