Files
mp-pilates/packages/server/src/common/utils/request-log.ts
2026-04-07 16:47:56 +08:00

61 lines
1.6 KiB
TypeScript

import type { Request } from 'express'
/** Fields stripped from logged request bodies to avoid leaking secrets. */
const SENSITIVE_FIELDS: ReadonlySet<string> = new Set([
'password',
'token',
'secret',
'code',
'sessionKey',
'encryptedData',
'iv',
])
const BODY_METHODS: ReadonlySet<string> = new Set(['POST', 'PUT', 'PATCH'])
/** Max characters of JSON-serialised body/query included in a log line. */
const MAX_LOG_PAYLOAD = 2048
function truncate(value: string): string {
return value.length > MAX_LOG_PAYLOAD
? `${value.slice(0, MAX_LOG_PAYLOAD)}…(truncated)`
: value
}
export function sanitizeBody(
body: Record<string, unknown> | undefined,
): Record<string, unknown> | undefined {
if (!body || typeof body !== 'object') return undefined
const keys = Object.keys(body)
if (keys.length === 0) return undefined
const result: Record<string, unknown> = {}
for (const key of keys) {
result[key] = SENSITIVE_FIELDS.has(key) ? '***' : body[key]
}
return result
}
/**
* Build a human-readable suffix for a log line:
* ` | query={…} body={…}`
* Returns an empty string when there is nothing to append.
*/
export function formatRequestExtras(request: Request): string {
const parts: string[] = []
const query = request.query
if (query && Object.keys(query).length > 0) {
parts.push(`query=${truncate(JSON.stringify(query))}`)
}
if (BODY_METHODS.has(request.method)) {
const sanitized = sanitizeBody(request.body as Record<string, unknown>)
if (sanitized) {
parts.push(`body=${truncate(JSON.stringify(sanitized))}`)
}
}
return parts.length > 0 ? ` | ${parts.join(' ')}` : ''
}