Skip to content

常见问题 ​

基础使用 ​

全局日志记录器和自定义日志记录器有什么区别? ​

全局日志记录器通过 dd.Info() 等包级函数直接使用,适合简单场景。自定义日志记录器通过 dd.New() 创建,支持独立配置和生命周期管理。

go
// 全局日志记录器
dd.Info("全局日志")

// 自定义日志记录器
logger, _ := dd.New(dd.JSONConfig())
logger.Info("独立日志")

如何在程序启动时初始化全局日志记录器? ​

go
func init() {
    err := dd.InitDefault(dd.JSONConfig())
    if err != nil {
        log.Fatal(err)
    }
}

或通过 SetDefault:

go
cfg := dd.DefaultConfig()
cfg.Format = dd.FormatJSON
cfg.Targets = []dd.OutputTarget{
    dd.ConsoleOutput(),
    dd.FileOutput("logs/app.json"),
}
logger, _ := dd.New(cfg)
dd.SetDefault(logger)

Fatal 级别日志会怎样? ​

Fatal / Fatalf / FatalWith 在输出日志后调用 os.Exit(1)(defer 语句不会执行;内部会先尝试 Close() 刷新挂起日志,最多等待 5 秒)。可通过 FatalHandler 自定义退出行为;如需资源清理,请改用 ErrorWith + 显式 Shutdown(ctx)。

配置 ​

如何同时输出到控制台和文件? ​

go
cfg := dd.DefaultConfig()
cfg.Targets = []dd.OutputTarget{
    dd.ConsoleOutput(),
    dd.FileOutput("logs/app.log"),
}
logger, _ := dd.New(cfg)

// 或 JSON 格式
cfg = dd.DefaultConfig()
cfg.Format = dd.FormatJSON
cfg.Targets = []dd.OutputTarget{
    dd.ConsoleOutput(),
    dd.FileOutput("logs/app.json"),
}
logger, _ = dd.New(cfg)

如何动态修改日志级别? ​

go
_ = logger.SetLevel(dd.LevelDebug)  // 运行时修改(返回 error)
_ = dd.SetLevel(dd.LevelDebug)      // 修改全局日志记录器级别

如何配置文件轮换策略? ​

通过 FileWriter 配置:

go
fw, _ := dd.NewFileWriter("logs/app.log",
    dd.DefaultFileWriterConfig(),  // 100MB, 30 天,10 个备份
)

性能 ​

日志会影响程序性能吗? ​

DD 在设计上追求高性能:

  • 热路径低分配优化
  • 原子级别检查,无锁
  • 大输入(≥10KB)的敏感数据过滤在独立 goroutine 中执行并带超时保护;小输入同步处理
  • 可选缓冲写入减少 I/O

高吞吐场景如何优化? ​

  1. 使用 BufferedWriter 减少 I/O
  2. 先检查级别再构造字段
  3. 考虑启用日志采样
  4. 避免在高频路径使用 Any 字段

详见 性能优化。

安全 ​

敏感数据过滤是如何工作的? ​

SensitiveDataFilter 使用正则模式匹配,在日志写入前自动替换匹配的敏感值为 [REDACTED]。小输入同步处理;大输入的正则扫描在独立 goroutine 中执行,但调用方会阻塞等待结果(等待时长随输入大小扩展:32KB 以内固定 50ms,超过后每 32KB 增加 200ms;超时返回 [REDACTED])。

如何自定义敏感数据模式? ​

go
filter, _ := dd.NewCustomSensitiveDataFilter(
    `(?i)my_secret_field\s*[:=]\s*\S+`,
)

如何确保日志不被篡改? ​

使用 IntegritySigner 对日志进行 HMAC 签名:

go
cfg, _ := dd.DefaultIntegrityConfigSafe()
signer, _ := dd.NewIntegritySigner(cfg)
sig := signer.Sign(logMessage)
// 验证:signer.Verify(signedEntry)

错误处理 ​

为什么 AddWriter 返回错误? ​

可能的原因:

  • ErrNilWriter -- 传入了 nil Writer
  • ErrLoggerClosed -- 日志记录器已关闭
  • ErrMaxWritersExceeded -- Writer 数量超限

如何处理写入失败? ​

go
logger.SetWriteErrorHandler(func(w io.Writer, err error) {
    // 自定义处理
    metrics.WriteErrors.Inc()
})

测试 ​

如何在测试中捕获日志? ​

使用 LoggerRecorder:

go
rec := dd.NewLoggerRecorder()
logger, _ := rec.NewLogger()

logger.Info("test")

if !rec.ContainsMessage("test") {
    t.Error("未找到预期日志")
}

详见 测试辅助。

下一步 ​