Merge branch 'dev'

This commit is contained in:
chengqian committed 2026-08-14 15:36:32 +08:00
commit ebd2664d67
2 files changed
+35 -5

No files matched your search

+18 -5
View File
@@ -421,10 +421,21 @@ func buildUsageLogDO(record *common.UsageRecord) do.BilUsageLogs {
}
}
// maxAuditBodyLen 审计日志请求体/响应体/任务结果的字节截断上限(2 KiB)。
// maxAuditBodyLen 未配置独立审计库时,审计日志请求体/响应体/任务结果的字节截断上限(2 KiB)。
// 落库前由 truncateBody 统一截断;流式响应保留首部 + 末尾若干 SSE 消息。
// 配置了独立审计库(database.audit)时 auditBodyMaxLen 返回 0,不截断、按审计规则完整记录。
const maxAuditBodyLen = 2048
// auditBodyMaxLen 返回审计请求体/响应体/任务结果的落库截断上限。
// 配置了独立审计库时返回 0(truncateBody 视为不截断),此时有充足存储空间按审计规则完整记录;
// 未配置时返回 maxAuditBodyLen,防止与业务数据共用主库导致库膨胀。
func auditBodyMaxLen() int {
if lcommon.IsAuditDBConfigured() {
return 0
}
return maxAuditBodyLen
}
// RecordAudit 实现 DataProvider.RecordAudit
// 异步写入请求审计日志,同时按系统级别和租户级别分别处理请求/响应体
func (p *DataProviderImpl) RecordAudit(ctx context.Context, record *common.AuditRecord) {
@@ -453,8 +464,9 @@ func (p *DataProviderImpl) RecordAudit(ctx context.Context, record *common.Audit
// 按租户级别处理
tntReq, tntResp := lcommon.ApplyAuditLevel(tenantLevel, record.RequestBody, record.ResponseBody, record.IsStream, record.Path)
// 截断过长的内容
maxBodyLen := maxAuditBodyLen
// 截断过长的内容:配置了独立审计库时完整记录(auditBodyMaxLen=0 不截断),
// 否则截断到 2 KiB,防止与业务数据共用主库导致库膨胀。
maxBodyLen := auditBodyMaxLen()
sysReq, sysResp = truncateBody(sysReq, maxBodyLen), truncateBody(sysResp, maxBodyLen)
tntReq, tntResp = truncateBody(tntReq, maxBodyLen), truncateBody(tntResp, maxBodyLen)
@@ -556,7 +568,7 @@ func (p *DataProviderImpl) UpdateTaskAudit(ctx context.Context, record *common.A
} else if globalLevel == lcommon.AuditLevelMasked {
taskResult = lcommon.MaskSensitiveData(taskResult)
}
taskResult = truncateBody(taskResult, maxAuditBodyLen)
taskResult = truncateBody(taskResult, auditBodyMaxLen())
// 上游响应头仅在 full 级别记录
upstreamHeadersJSON := "null"
@@ -615,7 +627,8 @@ func (p *DataProviderImpl) UpdateTaskAudit(ctx context.Context, record *common.A
}
func truncateBody(s string, maxLen int) string {
if len(s) <= maxLen {
// maxLen <= 0 表示不截断(配置了独立审计库时完整记录)
if maxLen <= 0 || len(s) <= maxLen {
return s
}
// 流式响应:保留首部 + 最后 20 条消息,截断中间
+17
View File
@@ -84,6 +84,23 @@ func TestTruncateBody_LongNonStreamTruncated(t *testing.T) {
}
}
func TestTruncateBody_ZeroMaxLenDisablesTruncation(t *testing.T) {
// 配置了独立审计库时 auditBodyMaxLen 返回 0,truncateBody 应原样返回不截断。
s := strings.Repeat("x", 10000)
if got := truncateBody(s, 0); got != s {
t.Errorf("maxLen=0 should disable truncation and return input verbatim")
}
// 负数 maxLen 同样视为不截断(防御性)
if got := truncateBody(s, -1); got != s {
t.Errorf("negative maxLen should disable truncation and return input verbatim")
}
// 流式输入在 maxLen=0 时同样完整保留,不进入流式截断分支
stream := "data: first\ndata: second\ndata: [DONE]"
if got := truncateBody(stream, 0); got != stream {
t.Errorf("stream body with maxLen=0 should be returned verbatim")
}
}
func TestTruncateStreamBody_KeepsHeadAndTailDropsMiddle(t *testing.T) {
// 40 行短 SSE,每行 "data: Lxx"(9 字节)。尾部 20 行 = 199 字节。
// maxLen=250 留出 headBudget>0,结果形如 head + marker + tail。