Files
OCS_service/server/utils/logging.ts
T
2026-05-22 15:02:31 +08:00

81 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// server/utils/logging.ts - 安全日志工具,避免输出密钥、cookie 和完整敏感内容
import { randomUUID } from "node:crypto";
import type { H3Event } from "h3";
/**
* 常见敏感片段匹配
*
* 这里不是完整 DLP,只处理最容易误打出来的 key、Bearer token 和 token=xxx
* 真实请求体、响应体本来就不应该进入日志
*/
const SENSITIVE_VALUE_RE =
/(sk-[A-Za-z0-9_-]+|Bearer\s+[A-Za-z0-9._-]+|token[=:]\s*[^,\s}]+)/giu;
/** 对错误摘要做最小脱敏和截断,避免日志过长或泄露密钥 */
const sanitizeLogText = (value: string) => {
return value.replace(SENSITIVE_VALUE_RE, "[redacted]").slice(0, 500);
};
/**
* 将 unknown 异常变成安全可打印对象
*
* API 对前端统一返回“服务器内部错误”,日志里只保留类型和脱敏摘要,
* 既能排查方向,又不把上游响应体或 key 打出去
*/
export const toSafeLogError = (error: unknown) => {
if (error instanceof Error) {
return {
name: error.name,
message: sanitizeLogText(error.message)
};
}
return {
name: "UnknownError",
message: sanitizeLogText(String(error))
};
};
/**
* 创建带 requestId 的 API 日志器
*
* 每个 handler 只需要记录“阶段”和少量结构化字段;这里统一补 method、path、
* 耗时等上下文,方便后续按一次请求串起来查
*/
export const createApiLogger = (event: H3Event, scope: string) => {
const requestId =
event.node.req.headers["x-request-id"]?.toString() || randomUUID();
const startedAt = Date.now();
/** 内部统一出口,避免不同 level 打出的字段不一致 */
const write = (
level: "info" | "warn" | "error",
stage: string,
extra: Record<string, unknown> = {}
) => {
const payload = {
requestId,
scope,
stage,
method: event.node.req.method,
path: event.path,
elapsedMs: Date.now() - startedAt,
...extra
};
console[level](`[${scope}] ${stage}`, JSON.stringify(payload));
};
/** 返回轻量 APIhandler 不直接接触 console,便于以后替换日志实现 */
return {
requestId,
info: (stage: string, extra?: Record<string, unknown>) =>
write("info", stage, extra),
warn: (stage: string, extra?: Record<string, unknown>) =>
write("warn", stage, extra),
error: (stage: string, extra?: Record<string, unknown>) =>
write("error", stage, extra)
};
};