Skip to content

核心概念

理解 DD 的核心概念是高效使用本库的基础。本章介绍 Logger 体系、字段系统、处理管道和接口层次。

Logger 体系

DD 的日志记录围绕三个核心类型展开:

text
Logger(日志记录器)

  ├── 直接使用 → logger.Info("message")

  └── WithFields() → LoggerEntry(带预设字段的 Entry)

                        └── entry.Info("message")  // 自动携带预设字段

Logger

Logger 是核心日志记录器,由 dd.New() 创建:

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

logger.Info("服务启动")
logger.InfoWith("请求处理",
    dd.String("method", "GET"),
    dd.Int("status", 200),
)

每个 Logger 拥有独立的配置、输出目标、安全过滤器和生命周期,可在不同模块间安全共享。

LoggerEntry

LoggerEntry 通过 WithFields() 创建,是不可变的预设字段容器:

go
// 创建带预设字段的 Entry
requestLog := logger.WithFields(
    dd.String("service", "user-api"),
    dd.String("version", "2.1.0"),
)

// 每次调用自动携带预设字段
requestLog.Info("服务启动")
// 输出:... 服务启动 service=user-api version=2.1.0

requestLog.InfoWith("用户登录",
    dd.String("user", "alice"),
)
// 输出:... 用户登录 service=user-api version=2.1.0 user=alice

不可变设计

每次调用 WithFields() 都会创建新的 LoggerEntry,原有 Entry 不受影响。这意味着你可以在不同 goroutine 中安全地复用同一个 Entry。

全局日志记录器

DD 提供全局日志记录器,适合简单场景或快速原型:

go
// 直接使用包级函数(通过全局 Logger)
dd.Info("全局日志")

// 等价于
dd.Default().Info("全局日志")

字段系统

Field 类型

Field 是结构化日志的基本单元,由键值对构成:

go
// 字段构造器覆盖所有常用类型
dd.String("method", "GET")           // 字符串
dd.Int("status", 200)                // 整数
dd.Float64("latency", 0.123)         // 浮点数
dd.Bool("success", true)             // 布尔
dd.Duration("elapsed", 150*time.Millisecond) // 时间段
dd.Time("timestamp", time.Now())     // 时间戳
dd.Err(err)                          // 错误(key 固定为 "error")
dd.ErrWithKey("db_error", err)       // 错误(自定义 key)
dd.Any("data", payload)              // 任意类型

字段链式传递

字段可以在 Logger、Entry 之间层层传递:

go
// 第一层:服务级字段
serviceLog := logger.WithFields(
    dd.String("service", "api-gateway"),
)

// 第二层:请求级字段(追加到服务级)
requestLog := serviceLog.WithFields(
    dd.String("request_id", "req-001"),
    dd.String("path", "/api/users"),
)

// 第三层:实际日志(再追加字段)
requestLog.InfoWith("处理完成",
    dd.Int("status", 200),
    dd.Duration("elapsed", 50*time.Millisecond),
)
// 输出包含:service=api-gateway request_id=req-001 path=/api/users status=200 elapsed=50ms

日志处理管道

每条日志经过以下处理流程:

text
用户调用 logger.InfoWith("msg", fields...)


  ① 级别检查 ─── 级别未启用 → 直接返回(零开销)


  ② 安全过滤 ─── 消息和字段中的敏感数据 → [REDACTED]


  ③ 上下文提取 ── 调用已注册的提取器附加静态/全局字段(用 context.Background() 调用,无法读取请求作用域的 TraceID)


  ④ BeforeLog 钩子


  ⑤ 格式化 ──── 文本格式 或 JSON 格式


  ⑥ 安全大小限制 ─── 超过 Security.MaxMessageSize 则截断(0 表示不限制)


  ⑦ 写入 ────── 输出到一个或多个 Writer


  ⑧ AfterLog 钩子


  ⑨ Fatal 处理 ── 仅 LevelFatal:先异步 Close Logger(最长等待 5s,触发 OnClose 钩子并 flush writer),再调用 os.Exit(1) 或自定义 FatalHandler

性能设计

级别检查(步骤 ①)使用原子操作,无需加锁,几乎零开销。安全过滤(步骤 ②)带超时保护,防止长时间阻塞主流程(大输入通过 goroutine + 超时保证最坏约 50ms 内返回)。Fatal 处理(步骤 ⑨)会异步触发 Logger 的 Close(含 flush 与 OnClose 钩子),最长等待 5s;用户 main 中的 defer 仍不执行,但 Logger 自身的 Close 会被调用。

接口层次

DD 定义了四个接口,支持精确的依赖注入:

text
CoreLogger                    ← 基础日志:Debug/Info/Warn/Error/Fatal + WithFields

    ├── LevelLogger           ← 级别管理:GetLevel/SetLevel/IsLevelEnabled(嵌入 CoreLogger)

    └── ConfigurableLogger    ← 配置管理:Writer/安全/上下文/钩子(嵌入 CoreLogger)

LogProvider                   ← 完整功能:独立扁平接口,包含所有方法
go
// 只需基础日志?注入 CoreLogger
type Service struct {
    log dd.CoreLogger
}

// 需要动态调整级别?注入 LevelLogger
type Handler struct {
    log dd.LevelLogger
}

最佳实践

在构造函数中接受最小必需的接口,而不是具体类型。这使代码更易测试、更灵活。

线程安全模型

DD 的核心设计原则:多 goroutine 安全使用,无需额外同步

组件安全机制
Logger所有方法可安全并发调用
LoggerEntry不可变,创建后只读
ConfigClone() 方法用于安全复制
Writers原子指针,无锁读取
SensitiveDataFilter读写分离,独立 goroutine
HookRegistryRWMutex 保护注册与读取(Logger 通过 atomic.Value 持有其指针)
go
// 安全:多个 goroutine 共享同一个 Logger
var logger *dd.Logger  // 初始化一次

func handleRequest(w http.ResponseWriter, r *http.Request) {
    // 安全:并发调用
    logger.InfoWith("请求到达",
        dd.String("path", r.URL.Path),
        dd.String("method", r.Method),
    )
}

输出目标体系

DD 支持三种输出目标,可任意组合:

go
logger, err := dd.New(dd.Config{
    Targets: []dd.OutputTarget{
        dd.ConsoleOutput(),                    // 控制台
        dd.FileOutput("logs/app.log"),         // 文件(自动轮换)
        dd.CustomOutput(customWriter),         // 自定义 io.Writer
    },
})
if err != nil {
    log.Fatal(err)
}
defer logger.Close()

内置 Writer 组件:

组件用途
FileWriter文件写入 + 大小/时间轮换 + 压缩
BufferedWriter缓冲写入,减少 I/O 次数
MultiWriter多目标分发,写入到多个 Writer

下一步