irr

package module
v0.0.0-...-774c295 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 8, 2025 License: MIT Imports: 10 Imported by: 31

README

🚀 IRR - The Most Advanced Error Handling Library for Go

Go Version Build Status codecov Go Report Card GoDoc

Transform your Go error handling from painful debugging nightmares into elegant, traceable, and actionable insights.

IRR revolutionizes error handling in Go by introducing handling-stack tracing - a game-changing approach that tracks not just where errors occur, but how they're handled throughout your application lifecycle.

🎯 Why IRR? The Problem with Traditional Go Error Handling

// Traditional Go error handling - Where did this actually fail? 🤔
func processUser(id string) error {
    user, err := getUserFromDB(id)
    if err != nil {
        return fmt.Errorf("failed to get user: %w", err)
    }
    
    if err := validateUser(user); err != nil {
        return fmt.Errorf("validation failed: %w", err) 
    }
    
    if err := sendEmail(user.Email); err != nil {
        return fmt.Errorf("email failed: %w", err)
    }
    
    return nil
}
// Result: "email failed: validation failed: failed to get user: connection timeout"
// 😰 Good luck debugging this in production!
// IRR approach - Crystal clear error handling 🎉
func processUser(id string) error {
    user, err := getUserFromDB(id)
    if err != nil {
        return irr.Track(err, "failed to get user for id=%s", id)
    }
    
    if err := validateUser(user); err != nil {
        return irr.Track(err, "user validation failed for user=%s", user.ID)
    }
    
    if err := sendEmail(user.Email); err != nil {
        return irr.Track(err, "email delivery failed to=%s", user.Email)
    }
    
    return nil
}
// Result with full stack trace, handling context, and debugging info! 🔥

⚡ Key Features That Make IRR Exceptional

🎯 Handling-Stack Tracing (Revolutionary!)

Unlike traditional call-stack tracing, IRR tracks the logical flow of error handling, giving you the complete picture of how errors propagate through your business logic.

🏢 Enterprise Error Code Management (IRC)

Structured error classification with systematic code ranges, automatic code propagation, and smart error-to-HTTP mapping for production-grade applications.

📊 Built-in Error Analytics

Real-time error metrics, code statistics, and performance monitoring out of the box.

🔄 Context-Aware Errors

Native Go context integration for request tracing, timeouts, and cancellation.

🏷️ Smart Error Categorization

Error codes, tags, and automatic classification for better error management.

🎛️ Result Type Support

Rust-inspired Result<T, E> pattern for functional error handling.

Zero-Allocation Fast Path

Optimized for performance with intelligent caching and memory pooling.

🚀 Quick Start

Installation
go get github.com/khicago/irr
Basic Usage - From Zero to Hero
1. 🆕 Creating Errors
package main

import (
    "fmt"
    "github.com/khicago/irr"
)

func main() {
    // Simple error
    err1 := irr.Error("user not found")
    
    // Error with formatting
    err2 := irr.Error("invalid user ID: %d", 12345)
    
    // Error with code (great for APIs!)
    err3 := irr.ErrorC(404, "user %s not found", "john_doe")
    
    fmt.Println(err1) // user not found
    fmt.Println(err2) // invalid user ID: 12345  
    fmt.Println(err3) // code(404), user john_doe not found
}
2. 🔗 Error Wrapping & Context
func getUserProfile(userID string) error {
    user, err := fetchUserFromDB(userID)
    if err != nil {
        // Wrap with context - shows the handling flow!
        return irr.Wrap(err, "failed to fetch user profile for ID=%s", userID)
    }
    
    profile, err := buildUserProfile(user)
    if err != nil {
        return irr.Wrap(err, "failed to build profile for user=%s", user.Username)
    }
    
    return nil
}

// Output example:
// failed to build profile for user=john_doe, failed to fetch user profile for ID=12345, connection timeout
3. 🔍 Stack Tracing for Debugging
func criticalOperation() error {
    // Trace creates error with stack information
    err := irr.Trace("database connection failed")
    
    // Track wraps existing error with stack trace
    if dbErr := connectToDatabase(); dbErr != nil {
        return irr.Track(dbErr, "critical operation failed in module=%s", "auth")
    }
    
    return nil
}

// Print with stack trace
err := criticalOperation()
if err != nil {
    fmt.Println(err.ToString(true, "\n"))
    // Output:
    // critical operation failed in module=auth main.criticalOperation@/app/main.go:25
    // database connection failed main.connectToDatabase@/app/db.go:15
}
4. 🏷️ Error Categorization & Metrics
func handleAPIRequest() error {
    err := irr.ErrorC(400, "invalid request format")
    err.SetTag("module", "api")
    err.SetTag("severity", "high")
    err.SetTag("user_id", "12345")
    
    return err
}

// Get comprehensive error statistics
stats := irr.GetMetrics()
fmt.Printf("Total errors: %d\n", stats.ErrorCreated)
fmt.Printf("Errors with code 400: %d\n", stats.CodeStats[400])
4.5. 🎯 Enterprise Error Code Management with IRC

The irc package provides enterprise-grade error code management with structured error classification:

import "github.com/khicago/irr/irc"

// 🏢 Define your error code taxonomy
const (
    // System errors (1000-1999)
    ErrSystemDatabase    irc.Code = 1001
    ErrSystemNetwork     irc.Code = 1002
    ErrSystemTimeout     irc.Code = 1003
    ErrSystemMemory      irc.Code = 1004
    
    // Business errors (2000-2999)
    ErrBusinessValidation irc.Code = 2001
    ErrBusinessAuth       irc.Code = 2002
    ErrBusinessPermission irc.Code = 2003
    ErrBusinessQuota      irc.Code = 2004
    
    // API errors (3000-3999)
    ErrAPIBadRequest     irc.Code = 3001
    ErrAPINotFound       irc.Code = 3002
    ErrAPIRateLimit      irc.Code = 3003
    ErrAPIDeprecated     irc.Code = 3004
)

// 🎯 Create structured errors with automatic code assignment
func validateUser(user *User) error {
    if user.Email == "" {
        return ErrBusinessValidation.Error("email is required")
    }
    
    if !isValidEmail(user.Email) {
        return ErrBusinessValidation.Trace("invalid email format: %s", user.Email)
    }
    
    return nil
}

// 🔄 Handle database operations with system error codes
func getUserFromDB(id string) (*User, error) {
    user, err := db.Query("SELECT * FROM users WHERE id = ?", id)
    if err != nil {
        if isTimeoutError(err) {
            return nil, ErrSystemTimeout.Track(err, "database query timeout for user=%s", id)
        }
        return nil, ErrSystemDatabase.Track(err, "failed to query user=%s", id)
    }
    
    if user == nil {
        return nil, ErrAPINotFound.Error("user not found: id=%s", id)
    }
    
    return user, nil
}

// 🎛️ Smart error code extraction and handling
func handleError(err error) (httpCode int, response map[string]interface{}) {
    // Extract the closest error code from the error chain
    successCode := irc.Code(0)
    unknownCode := irc.Code(9999)
    
    code, message := irc.DumpToCodeNError(successCode, unknownCode, err, "operation failed")
    
    switch {
    case code >= 1000 && code < 2000: // System errors
        return 500, map[string]interface{}{
            "error": "internal_server_error",
            "code":  code,
            "message": message,
        }
    case code >= 2000 && code < 3000: // Business errors  
        return 422, map[string]interface{}{
            "error": "business_logic_error",
            "code":  code,
            "message": message,
        }
    case code >= 3000 && code < 4000: // API errors
        return int(code - 2600), map[string]interface{}{ // 3001 -> 401, 3002 -> 402, etc.
            "error": "api_error", 
            "code":  code,
            "message": message,
        }
    default:
        return 500, map[string]interface{}{
            "error": "unknown_error",
            "code":  code,
            "message": message,
        }
    }
}

🏗️ Error Code Architecture Best Practices:

💡 Want to dive deeper? Check out our comprehensive IRC Enterprise Error Handling Guide for production-ready patterns, monitoring strategies, and real-world examples.

  1. 📊 Systematic Code Ranges

    • 1000-1999: Infrastructure/System errors (DB, network, memory)
    • 2000-2999: Business logic errors (validation, authorization)
    • 3000-3999: API/Interface errors (bad request, not found)
    • 4000-4999: Integration errors (external services)
    • 5000-5999: Security errors (authentication, encryption)
  2. 🎯 Consistent Error Creation

    // ✅ Good: Use code constants
    return ErrBusinessValidation.Error("invalid input: %s", input)
    
    // ❌ Bad: Magic numbers
    return irr.ErrorC(2001, "invalid input: %s", input)
    
  3. 🔄 Error Code Propagation

    // Automatically preserves the original error code
    if err := validateUser(user); err != nil {
        return ErrSystemDatabase.Track(err, "user validation failed in signup flow")
    }
    
  4. 📈 Monitoring & Alerting

    // Different alert levels based on error code ranges
    metrics := irr.GetMetrics()
    for code, count := range metrics.CodeStats {
        switch {
        case code >= 1000 && code < 2000:
            alerting.Critical("System error spike", code, count)
        case code >= 2000 && code < 3000:
            alerting.Warning("Business error increase", code, count)
        }
    }
    
5. 🔄 Context Integration - Request Tracing & Timeout Handling

Context integration allows you to attach Go's context.Context to errors, enabling powerful features like:

  • Request tracing across microservices
  • Automatic timeout detection in error messages
  • Cancellation-aware error handling
  • Request metadata propagation (user ID, trace ID, etc.)
import (
    "context"
    "time"
)

// 🎯 Request tracing example
func handleUserRequest(ctx context.Context, userID string) error {
    // Context carries request metadata (trace ID, user info, etc.)
    user, err := fetchUserFromDB(ctx, userID)
    if err != nil {
        // Error automatically includes context info like timeouts
        return irr.TrackWithContext(ctx, err, "failed to fetch user=%s", userID)
    }
    
    // Process with timeout awareness
    processCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()
    
    if err := processUserData(processCtx, user); err != nil {
        // Error will show if it was due to timeout/cancellation
        return irr.TrackWithContext(processCtx, err, "user processing failed")
    }
    
    return nil
}

// 🚨 Timeout detection in action
func simulateTimeout() {
    ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
    defer cancel()
    
    time.Sleep(200 * time.Millisecond) // Simulate slow operation
    
    err := irr.ErrorWithContext(ctx, "operation completed")
    fmt.Println(err.ToString(false, ", "))
    // Output: operation completed [ctx-err:context deadline exceeded]
    //         ↑ Automatically detects timeout!
}

// 🏷️ Request metadata propagation
func authenticatedRequest(ctx context.Context) error {
    userID := ctx.Value("user_id").(string)
    traceID := ctx.Value("trace_id").(string)
    
    err := irr.ErrorWithContext(ctx, "authentication failed")
    err = err.WithValue("user_id", userID)
    err = err.WithValue("trace_id", traceID)
    
    // Error now carries all request context for debugging
    return err
}

Why Context Integration Matters:

  • 🔍 Distributed Tracing: Track errors across multiple services
  • ⏱️ Timeout Debugging: Instantly see if errors were caused by timeouts
  • 🎯 Request Correlation: Link errors to specific user requests
  • 🚫 Cancellation Handling: Detect when operations were cancelled
6. 🦀 Result Type (Rust-inspired)
import "github.com/khicago/irr/result"

func safeDivision(a, b int) result.Result[int] {
    if b == 0 {
        return result.Err[int](irr.Error("division by zero"))
    }
    return result.OK(a / b)
}

func main() {
    res := safeDivision(10, 2)
    if res.IsOK() {
        fmt.Printf("Result: %d\n", res.Unwrap()) // Result: 5
    }
    
    res2 := safeDivision(10, 0)
    if res2.IsErr() {
        fmt.Printf("Error: %v\n", res2.UnwrapErr()) // Error: division by zero
    }
}

🏗️ Advanced Usage Patterns

🔄 Error Chain Traversal
func analyzeErrorChain(err error) {
    if irrErr, ok := err.(irr.IRR); ok {
        // Traverse to the source error
        sourceErr := irrErr.Source()
        rootErr := irrErr.Root()
        
        // Custom traversal with callback
        irrErr.TraverseToSource(func(e error, isSource bool) error {
            fmt.Printf("Level: %v, IsSource: %t\n", e, isSource)
            return nil // continue traversal
        })
    }
}
📊 Production Monitoring
// Custom error logger for production monitoring
type ProductionLogger struct{}

func (p *ProductionLogger) Error(args ...interface{}) {
    // Send to your monitoring system (e.g., Sentry, DataDog)
    log.Error(args...)
}

func handleProductionError(err error) {
    if irrErr, ok := err.(irr.IRR); ok {
        // Log with full context and metrics
        irrErr.LogError(&ProductionLogger{})
        
        // Extract metrics for monitoring
        metrics := irr.GetMetrics()
        sendToMonitoring(metrics)
    }
}
🎯 Error Recovery & Retry Logic
func retryWithIRR(operation func() error, maxRetries int) error {
    for attempt := 1; attempt <= maxRetries; attempt++ {
        err := operation()
        if err == nil {
            return nil
        }
        
        // Wrap with retry context
        wrappedErr := irr.Wrap(err, "attempt %d/%d failed", attempt, maxRetries)
        
        if attempt == maxRetries {
            return irr.Track(wrappedErr, "all retry attempts exhausted")
        }
        
        // Log intermediate failures
        wrappedErr.LogWarn(&logger)
        time.Sleep(time.Duration(attempt) * time.Second)
    }
    return nil
}

📈 Performance Benchmarks

IRR is designed for production workloads with minimal overhead:

BenchmarkError-8           2000000    750 ns/op    112 B/op    2 allocs/op
BenchmarkWrap-8            1500000    950 ns/op    144 B/op    3 allocs/op  
BenchmarkTrace-8           1000000   1200 ns/op    256 B/op    4 allocs/op
BenchmarkTrack-8            800000   1450 ns/op    288 B/op    5 allocs/op

// Comparison with standard library:
BenchmarkStdError-8        3000000    420 ns/op     64 B/op    1 allocs/op
BenchmarkStdWrap-8         2000000    680 ns/op     96 B/op    2 allocs/op

Key Performance Features:

  • 🚀 Memory pooling for trace objects
  • ⚡ Lazy string building with caching
  • 🎯 Zero-allocation fast paths for simple cases
  • 📊 Efficient atomic operations for metrics

🆚 Comparison with Other Libraries

Feature IRR pkg/errors std errors go-errors
Stack Traces ✅ Handling-stack ✅ Call-stack ✅ Call-stack
Error Wrapping ✅ Advanced ✅ Basic ✅ Basic ✅ Basic
Context Support ✅ Native
Enterprise Error Codes ✅ IRC Package
Error Metrics ✅ Built-in
Result Type ✅ Yes
Error Codes ✅ Yes
Performance ✅ Optimized ⚠️ Moderate ✅ Fast ⚠️ Moderate

🎨 Real-World Examples

🌐 Web API Error Handling
func handleUserRegistration(w http.ResponseWriter, r *http.Request) {
    user, err := parseUserFromRequest(r)
    if err != nil {
        apiErr := irr.ErrorC(400, "invalid user data: %v", err)
        apiErr.SetTag("endpoint", "user_registration")
        apiErr.SetTag("ip", r.RemoteAddr)
        
        http.Error(w, apiErr.Error(), 400)
        return
    }
    
    if err := saveUser(user); err != nil {
        serverErr := irr.TrackWithContext(r.Context(), err, "failed to save user=%s", user.Email)
        serverErr.LogError(&logger)
        
        http.Error(w, "internal server error", 500)
        return
    }
    
    w.WriteHeader(201)
}
🔄 Database Operation Patterns
func getUserOrders(ctx context.Context, userID string) ([]Order, error) {
    return result.AndThen(
        getUserFromDB(ctx, userID),
        func(user User) result.Result[[]Order] {
            return getOrdersForUser(ctx, user.ID)
        },
    ).Match(
        func(orders []Order) ([]Order, error) {
            return orders, nil
        },
        func(err error) ([]Order, error) {
            return nil, irr.TrackWithContext(ctx, err, "failed to get orders for user=%s", userID)
        },
    )
}
🔧 Microservice Integration
func callExternalService(ctx context.Context, endpoint string, data interface{}) error {
    resp, err := httpClient.Post(endpoint, data)
    if err != nil {
        return irr.TrackWithContext(ctx, err, "external service call failed to=%s", endpoint)
    }
    defer resp.Body.Close()
    
    if resp.StatusCode >= 400 {
        body, _ := io.ReadAll(resp.Body)
        serviceErr := irr.ErrorC(int64(resp.StatusCode), "service error: %s", string(body))
        serviceErr.SetTag("service", endpoint)
        serviceErr.SetTag("status_code", strconv.Itoa(resp.StatusCode))
        
        return irr.TrackWithContext(ctx, serviceErr, "external service returned error")
    }
    
    return nil
}

🛠️ Best Practices

✅ Do's
  1. Use Track for stack traces in critical paths

    if err := criticalOperation(); err != nil {
        return irr.Track(err, "critical operation failed in service=%s", serviceName)
    }
    
  2. Add context with error codes for APIs

    return irr.ErrorC(404, "user not found: id=%s", userID)
    
  3. Leverage tags for structured logging

    err.SetTag("module", "auth")
    err.SetTag("operation", "login")
    err.SetTag("user_id", userID)
    
  4. Use Result types for functional programming

    return result.OK(value).Map(transformFunction)
    
❌ Don'ts
  1. Don't overuse stack traces - Use Wrap for simple cases
  2. Don't ignore error metrics - Monitor them in production
  3. Don't mix error handling paradigms - Choose one approach per module

🤝 Contributing

We welcome contributions! Here's how to get started:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/awesome-feature
  3. Run tests: go test -v ./...
  4. Run benchmarks: go test -bench=. -benchmem
  5. Submit a pull request
Development Setup
git clone https://github.com/khicago/irr.git
cd irr
go mod tidy
go test -v ./...

📚 Documentation

🌟 Star History

Star History Chart

📝 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • Inspired by Rust's error handling patterns
  • Built for the Go community's need for better error tracing
  • Special thanks to all contributors and early adopters

Made with ❤️ for the Go community

⭐ Star us on GitHub | 🐛 Report Issues | 💬 Join Discussions

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrUntypedExecutionFailure = errors.New("!!!panic")

Functions

func CatchFailure

func CatchFailure(set func(err error))

CatchFailure is used to catch and handle panics within a function, preventing them from causing the program to crash while unifying the encapsulation of non-error information. It is declared at the beginning of a function with the defer keyword, ensuring that any panic during function execution can be caught. This function takes a callback function as a parameter, which is called when a panic occurs to handle the recovered error.

Usage example:

// A sample function that may cause panic

func riskyOperation() (err error) {
    // Defer calling CatchFailure at the start of riskyOperation
    // to ensure any subsequent panics can be caught and handled
    defer irr.CatchFailure(func(e error) {
        // Convert the recovered panic into a regular error so the function can return it
        // err can be set as a side effect, or the caught e can be handled directly (e.g., logging)
        // If the panic parameter is nil, e will be nil
        // If the panic is triggered with an error, the corresponding err will be passed directly
        // If the panic is another value, ErrUntypedExecutionFailure will be passed in, with the panic value attached to the error message
        err = e
    })

    // Trigger an out-of-bounds error that will cause a panic
    _ = make([]int, 0)[1]
    // Due to the panic above, the following code will not execute
    fmt.Println("This line of code will not be executed.")

    // If there is no panic, the function will return a nil error
    return nil
}

// Calling riskyOperation elsewhere, handling errors returned by it

func main() {
    if err := riskyOperation(); err != nil {
        fmt.Printf("Caught error: %v\n", err)
    } else {
        fmt.Println("Operation successful, no errors occurred")
    }
}

Note: CatchFailure should only be used to deal with panics caused by unforeseen situations, while regular error handling should be done using the error.

func ExtractContext

func ExtractContext(err error) context.Context

ExtractContext 从错误中提取上下文

func IsContextError

func IsContextError(err error) bool

IsContextError 检查是否为上下文相关错误

func LogStats

func LogStats(logger ErrorStatsLogger)

LogStats 记录错误统计信息到日志

func ResetMetrics

func ResetMetrics()

ResetMetrics 重置统计信息

Types

type BasicIrr

type BasicIrr struct {
	Code int64 `json:"code"`

	Msg   string     `json:"msg"`
	Trace *traceInfo `json:"trace"`
	// contains filtered or unexported fields
}

func (*BasicIrr) ClosestCode

func (ir *BasicIrr) ClosestCode() int64

ClosestCode 返回最近的有效错误码 Deprecated: 使用 NearestCode() 获得更清晰的语义

func (*BasicIrr) CurrentCode

func (ir *BasicIrr) CurrentCode() int64

CurrentCode 返回当前错误对象的错误码(可能为0)

func (*BasicIrr) Error

func (ir *BasicIrr) Error() string

Error the implementation of error

func (*BasicIrr) GetCode

func (ir *BasicIrr) GetCode() int64

GetCode 返回最近的有效错误码 Deprecated: 使用 NearestCode() 获得更清晰的语义

func (*BasicIrr) GetCodeStr

func (ir *BasicIrr) GetCodeStr() string

GetCodeStr Determines how the code is written to the message, so that this method can input an empty string to avoid outputting the code in the message

func (*BasicIrr) GetTag

func (ir *BasicIrr) GetTag(key string) (val []string)

GetTag the implementation of ITagger

func (*BasicIrr) GetTraceInfo

func (ir *BasicIrr) GetTraceInfo() *traceInfo

func (*BasicIrr) HasAnyCode

func (ir *BasicIrr) HasAnyCode() bool

HasAnyCode 检查错误链中是否有任何错误码

func (*BasicIrr) HasCurrentCode

func (ir *BasicIrr) HasCurrentCode() bool

HasCurrentCode 检查当前错误对象是否显式设置了错误码

func (*BasicIrr) LogError

func (ir *BasicIrr) LogError(logger IErrorLogger) IRR

LogError the implementation of ILogCaller

func (*BasicIrr) LogFatal

func (ir *BasicIrr) LogFatal(logger IFatalLogger) IRR

LogFatal the implementation of ILogCaller

func (*BasicIrr) LogWarn

func (ir *BasicIrr) LogWarn(logger IWarnLogger) IRR

LogWarn the implementation of ILogCaller

func (*BasicIrr) NearestCode

func (ir *BasicIrr) NearestCode() int64

NearestCode 返回错误链中最近的有效错误码(非零) 这是推荐使用的方法,符合用户直觉

func (*BasicIrr) Root

func (ir *BasicIrr) Root() error

Root the implementation of ITraverseError

func (*BasicIrr) RootCode

func (ir *BasicIrr) RootCode() int64

RootCode 返回错误链根部的错误码

func (*BasicIrr) SetCode

func (ir *BasicIrr) SetCode(val int64) IRR

SetCode the implementation of SetCode method

func (*BasicIrr) SetTag

func (ir *BasicIrr) SetTag(key, val string)

SetTag the implementation of ITagger

func (*BasicIrr) Source

func (ir *BasicIrr) Source() (err error)

Source the implementation of ITraverseIrr

func (*BasicIrr) ToString

func (ir *BasicIrr) ToString(printTrace bool, split string) string

ToString consecutive equal codes will be printed only once during the traceback process

func (*BasicIrr) TraverseCode

func (ir *BasicIrr) TraverseCode(fn func(err error, code int64) error) (err error)

TraverseCode the implementation of ITraverseCoder[int64]

func (*BasicIrr) TraverseToRoot

func (ir *BasicIrr) TraverseToRoot(fn func(err error) error) (err error)

TraverseToRoot the implementation of ITraverseError

func (*BasicIrr) TraverseToSource

func (ir *BasicIrr) TraverseToSource(fn func(err error, isSource bool) error) (err error)

TraverseToSource the implementation of ITraverseIrr

func (*BasicIrr) Unwrap

func (ir *BasicIrr) Unwrap() error

Unwrap the implementation of IUnwrap

type ContextualError

type ContextualError interface {
	IRR
	Context() context.Context
	WithContext(ctx context.Context) ContextualError
	WithDeadline(deadline time.Time) ContextualError
	WithTimeout(timeout time.Duration) ContextualError
	WithValue(key, val interface{}) ContextualError
}

ContextualError 带上下文的错误接口

func ErrorWithContext

func ErrorWithContext(ctx context.Context, formatOrMsg string, args ...any) ContextualError

ErrorWithContext 创建带上下文的错误

func TraceWithContext

func TraceWithContext(ctx context.Context, formatOrMsg string, args ...any) ContextualError

TraceWithContext 创建带堆栈跟踪和上下文的错误

func TrackWithContext

func TrackWithContext(ctx context.Context, innerErr error, formatOrMsg string, args ...any) ContextualError

TrackWithContext 包装错误并添加堆栈跟踪和上下文

func WrapWithContext

func WrapWithContext(ctx context.Context, innerErr error, formatOrMsg string, args ...any) ContextualError

WrapWithContext 包装错误并添加上下文

type ContextualIrr

type ContextualIrr struct {
	*BasicIrr
	// contains filtered or unexported fields
}

ContextualIrr 实现了带上下文的错误

func (*ContextualIrr) Context

func (ce *ContextualIrr) Context() context.Context

Context 返回关联的上下文

func (*ContextualIrr) ToString

func (ce *ContextualIrr) ToString(printTrace bool, split string) string

ToString 重写以包含上下文信息

func (*ContextualIrr) WithContext

func (ce *ContextualIrr) WithContext(ctx context.Context) ContextualError

WithContext 使用新的上下文创建副本

func (*ContextualIrr) WithDeadline

func (ce *ContextualIrr) WithDeadline(deadline time.Time) ContextualError

WithDeadline 设置截止时间

func (*ContextualIrr) WithTimeout

func (ce *ContextualIrr) WithTimeout(timeout time.Duration) ContextualError

WithTimeout 设置超时时间

func (*ContextualIrr) WithValue

func (ce *ContextualIrr) WithValue(key, val interface{}) ContextualError

WithValue 添加键值对

type ErrorMetrics

type ErrorMetrics struct {
	// 错误创建统计
	ErrorCreated   int64 `json:"error_created"`
	ErrorWithCode  int64 `json:"error_with_code"`
	ErrorWithTrace int64 `json:"error_with_trace"`
	ErrorWrapped   int64 `json:"error_wrapped"`

	// 错误遍历统计
	TraverseOps int64 `json:"traverse_ops"`

	// 时间统计
	LastErrorTime time.Time `json:"last_error_time"`

	// 错误码统计
	CodeStats map[int64]int64 `json:"code_stats"`
	// contains filtered or unexported fields
}

ErrorMetrics 错误统计信息

func GetMetrics

func GetMetrics() *ErrorMetrics

GetMetrics 获取全局错误统计信息

type ErrorStatsLogger

type ErrorStatsLogger interface {
	LogErrorStats(metrics *ErrorMetrics)
}

ErrorStatsLogger 错误统计日志接口

type ICodeGetter

type ICodeGetter[TCode any] interface {
	GetCode() (val TCode)
	GetCodeStr() string
}

type ICodeManager

type ICodeManager[TCode any] interface {
	// 错误码获取
	NearestCode() TCode // 最近的有效错误码
	CurrentCode() TCode // 当前对象的错误码
	RootCode() TCode    // 根错误的错误码

	// 错误码状态检查
	HasCurrentCode() bool // 当前对象是否设置了错误码
	HasAnyCode() bool     // 错误链中是否有任何错误码

	// 向后兼容(标记为废弃)
	GetCode() TCode     // @deprecated: 使用 NearestCode()
	ClosestCode() TCode // @deprecated: 使用 NearestCode()
}

新的清晰错误码API接口

type ICoder

type ICoder[TCode any] interface {
	ICodeGetter[TCode]
	SetCode(val TCode) IRR
}

type IErrorLogger

type IErrorLogger interface{ Error(args ...any) }

type IFatalLogger

type IFatalLogger interface{ Fatal(args ...any) }

type ILogCaller

type ILogCaller interface {
	LogWarn(logger IWarnLogger) IRR
	LogError(logger IErrorLogger) IRR
	LogFatal(logger IFatalLogger) IRR
}

type IRR

type IRR interface {
	ITraverseIrr

	error
	ITraverseError
	IUnwrap

	ICodeManager[int64]    // 使用新的清晰错误码API
	SetCode(val int64) IRR // 保留SetCode方法
	GetCodeStr() string    // 保留GetCodeStr方法

	ITraverseCoder[int64]

	ITagger
	ILogCaller

	ToString(printTrace bool, split string) string
	GetTraceInfo() *traceInfo
}

func Error

func Error(formatOrMsg string, args ...any) IRR

Error creates a new IRR error object with a formatted message. formatOrMsg is a string that accepts printf style format specifiers. args are variadic parameters that represent the arguments for the formatting string.

Example
package main

import (
	"fmt"

	"github.com/khicago/irr"
)

func main() {
	err := irr.Error("this is a new error")
	errWithParam := irr.Error("this is a new error with integer %d", 1)

	fmt.Println(err)
	fmt.Println(errWithParam)
}
Output:

this is a new error
this is a new error with integer 1

func ErrorC

func ErrorC[T int64](code T, formatOrMsg string, args ...any) IRR

ErrorC creates a new IRR error object with an error code and a formatted message. code is an int64 type error code used to identify and classify errors. formatOrMsg is a string that accepts printf style format specifiers to generate the error message. args are variadic parameters that represent the arguments for the formatting string. It returns an IRR error object set with the specific error code.

Usage example:

// Define a sample error code const ErrCodeInvalidInput int64 = 1001

// ValidateInput checks the input string and returns an error if it is empty

func ValidateInput(input string) error {
    if input == "" {
        // Create an error object with a specific error code and formatted message using ErrorC
        return irr.ErrorC(ErrCodeInvalidInput, "validation failed: %s", "input cannot be empty")
    }
    // Other input validation logic...
    return nil
}

Note: ErrorC is typically used when you wish to categorize errors or define specific status codes for easier error handling and response later on.

func Trace

func Trace(formatOrMsg string, args ...any) IRR

Trace creates an error object with stack trace and a formatted message. formatOrMsg is a string that accepts printf style format specifiers. args are variadic parameters that represent the arguments for the formatting string. It defaults to skipping one call frame, usually the place where Trace is called.

Example
package main

import (
	"fmt"

	"github.com/khicago/irr"
)

func main() {
	err := irr.Trace("this is a new error")
	errWithParam := irr.Trace("this is a new error with integer %d", 1)

	fmt.Println(err.ToString(true, ""))
	fmt.Println(errWithParam.ToString(true, ""))

	wrappedErr := irr.Track(err, "some wrap information")
	wrappedErrWithParam := irr.Track(err, "some wrap information with integer %d", 1)

	fmt.Println(wrappedErr.ToString(true, " && "))
	fmt.Println(wrappedErrWithParam.ToString(true, "\n"))
}

func TraceSkip

func TraceSkip(skip int, formatOrMsg string, args ...any) IRR

TraceSkip creates an error object with stack trace and formatted message, skipping a certain number of stack frames. skip indicates the number of call frames to skip in the stack trace. formatOrMsg is a string that accepts printf style format specifiers. args are variadic parameters that represent the arguments for the formatting string.

func Track

func Track(innerErr error, formatOrMsg string, args ...any) IRR

Track creates an error object with a stack trace and wraps an inner error. innerErr is the error being wrapped. formatOrMsg is a string that accepts printf style format specifiers. args are variadic parameters that represent the arguments for the formatting string. It defaults to skipping one call frame, starting the trace where Track is called.

func TrackSkip

func TrackSkip(skip int, innerErr error, formatOrMsg string, args ...any) IRR

TrackSkip creates an error object with a stack trace and wraps an inner error, skipping a specified number of stack frames. skip indicates the number of call frames to skip in the stack trace. innerErr is the error being wrapped. formatOrMsg is a string that accepts printf style format specifiers. args are variadic parameters that represent the arguments for the formatting string.

func Wrap

func Wrap(innerErr error, formatOrMsg string, args ...any) IRR

Wrap wraps an existing error object with a given message and an inner error. innerErr is the error being wrapped. formatOrMsg is a string that accepts printf style format specifiers. args are variadic parameters that represent the arguments for the formatting string.

Example
package main

import (
	"fmt"

	"github.com/khicago/irr"
)

func main() {
	err := fmt.Errorf("default err message")
	wrappedErr := irr.Wrap(err, "some wrap information")
	wrappedErrWithParam := irr.Wrap(err, "some wrap information with integer %d", 1)

	fmt.Println(wrappedErr)
	fmt.Println(wrappedErrWithParam)
}
Output:

some wrap information, default err message
some wrap information with integer 1, default err message
Example (CustomPrint)
package main

import (
	"fmt"

	"github.com/khicago/irr"
)

func main() {
	err := fmt.Errorf("default err message")
	wrappedErr := irr.Wrap(err, "some wrap information")
	wrappedErrWithParam := irr.Wrap(err, "some wrap information with integer %d", 1)

	fmt.Println(wrappedErr.ToString(false, " ==> "))
	fmt.Println(wrappedErrWithParam.ToString(false, " ==> "))
}
Output:

some wrap information ==> default err message
some wrap information with integer 1 ==> default err message

type ITagger

type ITagger interface {
	SetTag(key, value string)
	GetTag(key string) (values []string)
}

type ITraverseCoder

type ITraverseCoder[TCode any] interface {
	ClosestCode() TCode
	TraverseCode(fn func(err error, code TCode) error) (err error)
	ICodeGetter[TCode]
}

type ITraverseError

type ITraverseError interface {
	Root() error
	TraverseToRoot(fn func(err error) error) (err error)
}

type ITraverseIrr

type ITraverseIrr interface {
	Source() error
	TraverseToSource(fn func(err error, isSource bool) error) (err error)
}

type IUnwrap

type IUnwrap interface {
	Unwrap() error
}

type IWarnLogger

type IWarnLogger interface{ Warn(args ...any) }

type Spawner

type Spawner interface {
	Error(formatOrMsg string, args ...interface{}) IRR
	Wrap(innerErr error, formatOrMsg string, args ...interface{}) IRR
	TraceSkip(skip int, formatOrMsg string, args ...interface{}) IRR
	Trace(formatOrMsg string, args ...interface{}) IRR
	TrackSkip(skip int, innerErr error, formatOrMsg string, args ...interface{}) IRR
	Track(innerErr error, formatOrMsg string, args ...interface{}) IRR
}

Directories

Path Synopsis
Package irc provides a customized error code system extending the IRR library.
Package irc provides a customized error code system extending the IRR library.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL