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
logger, _ := dd.New(dd.Config{
    Format: dd.FormatJSON,
    Targets: []dd.OutputTarget{
        dd.ConsoleOutput(),
        dd.FileOutput("logs/app.json"),
    },
})
dd.SetDefault(logger)

Fatal 级别日志会怎样?

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

配置

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

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

如何动态修改日志级别?

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 中执行并带超时保护,不阻塞日志写入。

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

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("未找到预期日志")
}

详见 测试辅助

下一步