一、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`并可关联上下游。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部