refactor(logging): 二次审计修复 oracle 漏掉的可观测性缺口与占位符冗余
二次深度审计发现:
1. shutdown.ts SIGINT/SIGTERM 路径完全沉默——生产环境 k8s pod 终止时
操作者在日志里看不到任何痕迹。补 getLogger(['shutdown']) 三条日志:
- "Draining for shutdown" {signal, graceMs} (优雅关停起点)
- "Forcing exit on repeated signal" {signal} (二次信号强制退出)
- "DB pool closed, exiting" (干净退出确认)
2. interceptors.ts 与 shutdown.ts 的 {error}/{signal} 占位符在 JSON 模式
下导致 message 字段重复 inspect 转义 properties 里的同一份内容
(Error/对象会被 JSON.stringify 内联进 message,引号被反斜杠转义)。
规则收敛:占位符仅用于"想要内联渲染"的基本类型(id、count、duration),
对象/Error 直接放 properties,message 保持人类可读短句。
3. AGENTS.md Logging 段更新示例与规则,反映实际最佳实践。
端到端验证(compose + Postgres 18-alpine):
- /api/rpc/todo/list 成功 → logger=db level=INFO 输出 SQL ✓
- /api/rpc/todo/create 校验失败 → logger=api level=ERROR
message="Unhandled error in ORPC handler" 干净,properties.error
完整保留 code/status/message/data 字段 ✓
- SIGTERM → 三条 shutdown logger 事件按预期输出 ✓
- typecheck / test 3/3 / build / compile 117M 全绿 ✓
This commit is contained in:
@@ -5,7 +5,7 @@ import { getLogger } from '@/server/logger'
|
||||
const logger = getLogger(['api'])
|
||||
|
||||
export const logError = (error: unknown) => {
|
||||
logger.error('Unhandled error in ORPC handler: {error}', { error })
|
||||
logger.error('Unhandled error in ORPC handler', { error })
|
||||
}
|
||||
|
||||
export const handleValidationError = (error: unknown) => {
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
import { db } from '@/server/db'
|
||||
import { getLogger } from '@/server/logger'
|
||||
|
||||
export default () => {
|
||||
if (import.meta.dev) return
|
||||
|
||||
const logger = getLogger(['shutdown'])
|
||||
let exiting = false
|
||||
|
||||
const shutdown = () => {
|
||||
const shutdown = (signal: NodeJS.Signals) => {
|
||||
if (exiting) {
|
||||
logger.warn('Forcing exit on repeated signal', { signal })
|
||||
process.exit(0)
|
||||
}
|
||||
exiting = true
|
||||
logger.info('Draining for shutdown', { signal, graceMs: 500 })
|
||||
|
||||
setTimeout(() => {
|
||||
db.$client.end().finally(() => process.exit(0))
|
||||
db.$client.end().finally(() => {
|
||||
logger.info('DB pool closed, exiting')
|
||||
process.exit(0)
|
||||
})
|
||||
}, 500)
|
||||
}
|
||||
|
||||
process.on('SIGINT', shutdown)
|
||||
process.on('SIGTERM', shutdown)
|
||||
process.on('SIGINT', () => shutdown('SIGINT'))
|
||||
process.on('SIGTERM', () => shutdown('SIGTERM'))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user