Skip to content

错误处理

Go Cursor SDK 提供了详细的错误类型和错误处理机制,帮助开发者快速定位和解决问题。

错误类型

常见错误

SDK 定义了以下常见错误类型:

go
var (
    ErrStorageNotFound   = errors.New("cursor storage not found")
    ErrDatabaseOpen      = errors.New("failed to open database")
    ErrDatabaseQuery     = errors.New("database query failed")
    ErrInvalidConfig     = errors.New("invalid configuration")
    ErrReaderNotFound    = errors.New("reader not found")
    ErrCacheMiss         = errors.New("cache miss")
    ErrExportFailed      = errors.New("export failed")
    ErrWatcherNotEnabled = errors.New("watcher not enabled")
)

基本错误处理

检查错误

go
client, err := cursor.NewCursorClient(config)
if err != nil {
    log.Fatal(err)
}
defer client.Close()

sessions, err := client.Sessions().ListSessions()
if err != nil {
    log.Printf("获取会话失败:%v\n", err)
    return
}

使用 errors.Is

go
sessions, err := client.Sessions().ListSessions()
if err != nil {
    if errors.Is(err, cursor.ErrDatabaseQuery) {
        log.Println("数据库查询失败")
    } else if errors.Is(err, cursor.ErrStorageNotFound) {
        log.Println("Cursor 存储路径未找到")
    } else {
        log.Printf("未知错误:%v\n", err)
    }
    return
}

使用 errors.As

go
var dbErr *cursor.DatabaseError
if errors.As(err, &dbErr) {
    log.Printf("数据库错误:%s (代码:%d)\n", dbErr.Message, dbErr.Code)
}

错误恢复

重试机制

go
func listSessionsWithRetry(client *cursor.CursorClient, maxRetries int) ([]cursor.Session, error) {
    var sessions []cursor.Session
    var err error
    
    for i := 0; i < maxRetries; i++ {
        sessions, err = client.Sessions().ListSessions()
        if err == nil {
            return sessions, nil
        }
        
        log.Printf("尝试 %d/%d 失败:%v\n", i+1, maxRetries, err)
        time.Sleep(time.Second * time.Duration(i+1))
    }
    
    return nil, fmt.Errorf("重试 %d 次后仍然失败:%w", maxRetries, err)
}

降级处理

go
func getSessionsWithFallback(client *cursor.CursorClient) []cursor.Session {
    // 尝试从缓存获取
    sessions, err := client.Sessions().ListSessions()
    if err == nil {
        return sessions
    }
    
    log.Printf("获取会话失败,使用空列表:%v\n", err)
    return []cursor.Session{}
}

错误日志

结构化日志

go
func processSession(client *cursor.CursorClient, sessionID string) error {
    session, err := client.Sessions().GetSessionByID(sessionID)
    if err != nil {
        log.Printf("错误:获取会话失败 | 会话ID=%s | 错误=%v\n", 
            sessionID, err)
        return err
    }
    
    // 处理会话...
    
    return nil
}

使用日志库

go
import "github.com/sirupsen/logrus"

func processData(client *cursor.CursorClient) error {
    sessions, err := client.Sessions().ListSessions()
    if err != nil {
        logrus.WithFields(logrus.Fields{
            "error": err,
            "func":  "processData",
        }).Error("获取会话失败")
        return err
    }
    
    logrus.WithFields(logrus.Fields{
        "count": len(sessions),
    }).Info("成功获取会话")
    
    return nil
}

错误传播

包装错误

go
func loadUserData(client *cursor.CursorClient) error {
    sessions, err := client.Sessions().ListSessions()
    if err != nil {
        return fmt.Errorf("加载用户数据失败:%w", err)
    }
    
    // 处理数据...
    
    return nil
}

自定义错误

go
type DataProcessError struct {
    Operation string
    Err       error
}

func (e *DataProcessError) Error() string {
    return fmt.Sprintf("数据处理错误 [%s]:%v", e.Operation, e.Err)
}

func (e *DataProcessError) Unwrap() error {
    return e.Err
}

func processData(client *cursor.CursorClient) error {
    sessions, err := client.Sessions().ListSessions()
    if err != nil {
        return &DataProcessError{
            Operation: "ListSessions",
            Err:       err,
        }
    }
    
    // 处理数据...
    
    return nil
}

错误监控

错误统计

go
type ErrorStats struct {
    mu     sync.Mutex
    errors map[string]int
}

func (s *ErrorStats) Record(err error) {
    s.mu.Lock()
    defer s.mu.Unlock()
    
    errType := fmt.Sprintf("%T", err)
    s.errors[errType]++
}

func (s *ErrorStats) Report() {
    s.mu.Lock()
    defer s.mu.Unlock()
    
    log.Println("错误统计:")
    for errType, count := range s.errors {
        log.Printf("  %s: %d\n", errType, count)
    }
}

错误告警

go
func processWithAlert(client *cursor.CursorClient) error {
    sessions, err := client.Sessions().ListSessions()
    if err != nil {
        // 发送告警
        sendAlert("获取会话失败", err)
        return err
    }
    
    return nil
}

func sendAlert(message string, err error) {
    // 发送到告警系统
    log.Printf("告警:%s | 错误:%v\n", message, err)
}

实际示例

完整的错误处理示例

go
package main

import (
    "errors"
    "fmt"
    "log"
    
    cursor "github.com/vibe-coding-labs/go-cursor-sdk"
)

func main() {
    if err := run(); err != nil {
        log.Fatal(err)
    }
}

func run() error {
    // 创建客户端
    client, err := cursor.NewCursorClient(nil)
    if err != nil {
        return handleClientError(err)
    }
    defer client.Close()
    
    // 获取会话
    sessions, err := getSessions(client)
    if err != nil {
        return fmt.Errorf("获取会话失败:%w", err)
    }
    
    // 处理会话
    if err := processSessions(sessions); err != nil {
        return fmt.Errorf("处理会话失败:%w", err)
    }
    
    return nil
}

func handleClientError(err error) error {
    switch {
    case errors.Is(err, cursor.ErrStorageNotFound):
        return fmt.Errorf("Cursor 未安装或存储路径未找到:%w", err)
    case errors.Is(err, cursor.ErrDatabaseOpen):
        return fmt.Errorf("无法打开数据库,请检查权限:%w", err)
    default:
        return fmt.Errorf("创建客户端失败:%w", err)
    }
}

func getSessions(client *cursor.CursorClient) ([]cursor.Session, error) {
    sessions, err := client.Sessions().ListSessions()
    if err != nil {
        if errors.Is(err, cursor.ErrDatabaseQuery) {
            // 尝试从缓存获取
            log.Println("数据库查询失败,尝试从缓存获取")
            return getSessionsFromCache(client)
        }
        return nil, err
    }
    return sessions, nil
}

func getSessionsFromCache(client *cursor.CursorClient) ([]cursor.Session, error) {
    // 实现缓存获取逻辑
    return nil, errors.New("缓存未实现")
}

func processSessions(sessions []cursor.Session) error {
    for _, session := range sessions {
        if err := processSession(session); err != nil {
            log.Printf("处理会话 %s 失败:%v\n", session.ID, err)
            continue // 继续处理其他会话
        }
    }
    return nil
}

func processSession(session cursor.Session) error {
    // 处理单个会话
    return nil
}

最佳实践

  1. 始终检查错误
  2. 使用 errors.Is 和 errors.As 判断错误类型
  3. 包装错误以提供上下文
  4. 记录详细的错误日志
  5. 实现重试和降级机制
  6. 监控和统计错误
  7. 为用户提供友好的错误信息

下一步

Released under the MIT License.