Skip to content

字段验证

📖 使用教程 · 完整 API 签名见 结构化字段 - Field 构造器

DD 的字段验证子系统在日志写入前对结构化字段的键名进行命名约定校验和安全防护。它能防止字段键不一致导致的日志解析困难,并拦截通过字段键注入的恶意内容。

验证模式

模式常量行为
关闭(默认)FieldValidationNone不校验,所有键均接受
警告FieldValidationWarn不合规范的键输出 stderr 警告,日志仍写入
严格FieldValidationStrict不合规范的键输出 stderr 错误,日志仍写入

日志方法不返回错误

由于日志方法(InfoWith 等)不返回 error,验证失败只能通过 stderr 输出提示。严格模式不会阻止日志写入,但会在 stderr 明确报错。

命名约定

约定常量示例
任意(默认)NamingConventionAny不校验命名风格
snake_caseNamingConventionSnakeCaseuser_idcreated_at
camelCaseNamingConventionCamelCaseuserIdcreatedAt
PascalCaseNamingConventionPascalCaseUserIdCreatedAt
kebab-caseNamingConventionKebabCaseuser-idcreated-at

快速启用

方案一:预设配置

go
package main

import (
    "log"

    "github.com/cybergodev/dd"
)

func main() {
    cfg := dd.DefaultConfig()
    cfg.FieldValidation = dd.StrictSnakeCaseConfig()
    // 等价于:
    // &dd.FieldValidationConfig{
    //     Mode:                     dd.FieldValidationStrict,
    //     Convention:               dd.NamingConventionSnakeCase,
    //     AllowCommonAbbreviations: true,
    //     EnableSecurityValidation: true,
    // }

    logger, err := dd.New(cfg)
    if err != nil {
        log.Fatal(err)
    }
    defer logger.Close()

    logger.InfoWith("用户操作",
        dd.String("user_id", "123"),    // ✅ 符合 snake_case
        dd.String("userName", "alice"), // ⚠️ 不符合,stderr 输出错误
    )
}

方案二:自定义配置

go
cfg := dd.DefaultConfig()
cfg.FieldValidation = &dd.FieldValidationConfig{
    Mode:                     dd.FieldValidationWarn,
    Convention:               dd.NamingConventionCamelCase,
    AllowCommonAbbreviations: true,
    EnableSecurityValidation: true,
}

方案三:运行时动态切换

go
// 启用严格 snake_case
logger.SetFieldValidation(dd.StrictSnakeCaseConfig())

// 关闭验证
logger.SetFieldValidation(nil)

// 查询当前配置
fv := logger.GetFieldValidation()

常见缩写豁免

启用 AllowCommonAbbreviations: true(预设默认开启)后,以下缩写即使不完全匹配命名约定也予以放行:

缩写说明
idurluriip基础标识
httphttpsapi协议与接口
jsonxmlhtmlsql数据格式
tcpudpssltls网络协议
jwtoauth认证
*_id*_url*_api 等后缀以缩写结尾的组合(如 user_id

安全验证

EnableSecurityValidation: true(预设默认开启)在命名约定之前执行以下安全检查:

检查项拦截内容说明
Log4Shell 检测${jndi:ldap://...}防止 JNDI 注入攻击通过日志键传播
同形异义字符Cyrillic а 替代 Latin a防止视觉欺骗攻击
过长 UTF-8 编码非最短形式编码防止绕过安全过滤

零值陷阱

直接使用 &dd.FieldValidationConfig{Mode: dd.FieldValidationStrict} 而不设置 EnableSecurityValidation 时,安全验证为 false(零值),会静默跳过安全检查。始终使用 DefaultFieldValidationConfig() 或预设函数(StrictSnakeCaseConfig() 等),它们将此字段设为 true

多约定混合项目

如果项目同时有 Go 后端(snake_case)和 JavaScript 前端(camelCase)日志,可以分 Logger 使用不同约定:

go
// 后端 Logger:snake_case
backendCfg := dd.DefaultConfig()
backendCfg.FieldValidation = dd.StrictSnakeCaseConfig()
backendLogger, _ := dd.New(backendCfg)

// 前端日志聚合 Logger:camelCase
frontendCfg := dd.DefaultConfig()
frontendCfg.FieldValidation = dd.StrictCamelCaseConfig()
frontendLogger, _ := dd.New(frontendCfg)

验证规则细节

每种命名约定的具体校验规则:

约定规则
snake_case小写字母 + 数字 + 下划线;不以 _ 开头/结尾;无连续 __
camelCase字母 + 数字;首字符为小写字母
PascalCase字母 + 数字;首字符为大写字母
kebab-case小写字母 + 数字 + 连字符;不以 - 开头/结尾;无连续 --

下一步