Skip to content

错误处理

DD 定义了结构化的错误体系,便于精确识别和处理各类错误。

错误类型

LoggerError

结构化错误,包含错误码、消息、原因和上下文:

go
type LoggerError struct { ... }

// 创建(直接使用 LoggerError 结构体字段)
err := &dd.LoggerError{
    Code:    "CUSTOM_CODE",
    Message: "错误描述",
}

// 包装(使用 LoggerError 结构体字段)
err := &dd.LoggerError{
    Code:    "WRAP_CODE",
    Message: "包装描述",
    Cause:   originalErr,
}

方法:

方法说明
Error() string错误消息
Unwrap() error获取内部错误
Is(target error) bool错误比较
WithContext(key, value)添加上下文信息
WithField(key, value)添加字段信息
go
err := &dd.LoggerError{
    Code:    "DB_ERROR",
    Message: "查询失败",
    Cause:   dbErr,
}
err = err.WithContext("query", "SELECT * FROM users")
err = err.WithField("retry_count", 3)

WriterError

写入器错误,包含 Writer 索引和原始错误。

go
type WriterError struct {
    Index  int
    Writer io.Writer
    Err    error
}

MultiWriterError

多写入器聚合错误。

go
type MultiWriterError struct { ... }

方法:HasErrors()ErrorCount()FirstError()

错误处理模式

errors.Is 匹配

go
logger, err := dd.New(config)
if err != nil {
    if errors.Is(err, dd.ErrNilConfig) {
        // 处理配置为空
    }
    if errors.Is(err, dd.ErrInvalidLevel) {
        // 处理无效级别
    }
}

写入错误处理

go
logger.SetWriteErrorHandler(func(w io.Writer, err error) {
    // 自定义写入错误处理
    // 注意:此回调仅在 writer.Write() 失败时触发,传入的是 writer 自身错误;
    // dd.ErrWriterNotFound 由 RemoveWriter 直接返回给调用者,不会经此回调传递。
    if errors.Is(err, io.ErrShortWrite) {
        // 写入字节数不足
        return
    }
    // 记录错误指标
    metrics.WriteErrors.Inc()
})

运行时错误处理

go
// 添加 Writer
if err := logger.AddWriter(w); err != nil {
    if errors.Is(err, dd.ErrLoggerClosed) {
        // 日志记录器已关闭
        return
    }
    if errors.Is(err, dd.ErrNilWriter) {
        // Writer 为空
        return
    }
}

// 设置级别
if err := logger.SetLevel(dd.LevelDebug); err != nil {
    if errors.Is(err, dd.ErrInvalidLevel) {
        // 无效级别
    }
}

安全错误

go
fw, err := dd.NewFileWriter(userPath, dd.DefaultFileWriterConfig())
if err != nil {
    if errors.Is(err, dd.ErrPathTraversal) {
        // 路径遍历攻击
        log.Fatal("检测到路径遍历攻击")
    }
    if errors.Is(err, dd.ErrNullByte) {
        // Null 字节注入
        log.Fatal("检测到 null 字节注入")
    }
    if errors.Is(err, dd.ErrSymlinkNotAllowed) {
        // 符号链接不允许
    }
}

模式错误

go
filter, err := dd.NewCustomSensitiveDataFilter(pattern)
if err != nil {
    if errors.Is(err, dd.ErrReDoSPattern) {
        // ReDoS 风险模式
        log.Fatal("正则模式存在 ReDoS 风险")
    }
    if errors.Is(err, dd.ErrInvalidPattern) {
        // 无效正则
    }
    if errors.Is(err, dd.ErrPatternTooLong) {
        // 模式过长
    }
}

钩子错误

使用钩子时可通过钩子配置的 ErrorHandler 回调来捕获和处理钩子执行中的错误:

go
// 通过 HooksConfig 配置钩子错误处理
registry := dd.NewHooksFromConfig(dd.HooksConfig{
    ErrorHandler: func(event dd.HookEvent, hc *dd.HookContext, err error) {
        // 自定义钩子错误处理
        handleHookError(event.String(), err)
    },
})
logger, _ := dd.New(dd.Config{
    Hooks: registry,
})

全局日志记录器错误

go
// 初始化时检查
err := dd.InitDefault(cfg)
if err != nil {
    log.Fatal(err)
}

// 运行时检查
if err := dd.DefaultInitError(); err != nil {
    fmt.Println("全局日志记录器初始化有误:", err)
}

下一步