一、Trace-ID注入与传播type Req = { headers: Record<string, string | undefined> }
type Res = { setHeader: (k: string, v: string) => void }
function randId(): string { return Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2) }
function attachTrace(req: Req, res: Res): string {
const id = req.headers['x-trace-id'] || randId()
res.setHeader('X-Trace-Id', id)
return id
}
二、采样与速率限制class RateGate {
windowMs: number
max: number
hits = new Map<string, number[]>()
constructor(windowMs: number, max: number) { this.windowMs = windowMs; this.max = max }
allow(key: string): boolean {
const now = Date.now()
const arr = (this.hits.get(key) || []).filter(t => now - t < this.windowMs)
if (arr.length >= this.max) return false
arr.push(now); this.hits.set(key, arr); return true
}
}
function sample(p: number): boolean { return Math.random() < p }
三、脱敏与Schematype LogItem = { traceId: string; level: 'info' | 'warn' | 'error'; route: string; method: string; status?: number; userId?: string; payload?: Record<string, any>; timestamp: string }
function redactPII(obj: Record<string, any>): Record<string, any> {
const out: Record<string, any> = {}
for (const [k, v] of Object.entries(obj)) {
const key = k.toLowerCase()
if (key.includes('password') || key.includes('secret') || key.includes('token')) out[k] = '***'
else if (key.includes('email')) out[k] = String(v).replace(/^[^@]+/, '***')
else out[k] = v
}
return out
}
四、日志输出与审计function nowIso(): string { return new Date().toISOString() }
function makeLog(traceId: string, route: string, method: string, level: 'info' | 'warn' | 'error', payload?: Record<string, any>, status?: number, userId?: string): LogItem {
const p = payload ? redactPII(payload) : undefined
return { traceId, level, route, method, status, userId, payload: p, timestamp: nowIso() }
}
function serializeLog(item: LogItem): string { return JSON.stringify(item) }
五、整合中间件type Ctx = { req: Req; res: Res; route: string; method: string; userId?: string }
function loggingMiddleware(ctx: Ctx, gate: RateGate, p: number, emit: (line: string) => void) {
const traceId = attachTrace(ctx.req, ctx.res)
const ok = gate.allow(traceId)
if (!ok) return
if (sample(p)) emit(serializeLog(makeLog(traceId, ctx.route, ctx.method, 'info', undefined, undefined, ctx.userId)))
}
六、验收清单`X-Trace-Id`注入与传播一致;采样概率与速率限制生效。PII字段脱敏覆盖密码/Secret/Token与邮箱前缀;日志Schema统一且JSON输出。审计记录包含`traceId/route/method/status/userId/timestamp`并可关联上下游。

发表评论 取消回复