Skip to content
/ ewrap Public
generated from hyp3rd/go-base-app-skel

A sophisticated, configurable error wrapper for Go applications that provides: Stack trace capture Error wrapping with context, Metadata attachment, Logger integration, Compatibility with Go 1.13+ error chains, Rich error information for debugging, Thread-safe operations.

License

Notifications You must be signed in to change notification settings

hyp3rd/ewrap

Repository files navigation

ewrap

Go Docs Go Report Card Go Reference License: MIT GitHub Sponsors

A sophisticated, configurable error wrapper for Go applications that provides comprehensive error handling capabilities with a focus on performance and flexibility.

Core Features

  • Stack Traces: Automatically captures and filters stack traces for meaningful error debugging
  • Error Wrapping: Maintains error chains while preserving context through the entire chain
  • Metadata Attachment: Attach and manage arbitrary key-value pairs to errors
  • Logging Integration: Flexible logger interface supporting major logging frameworks (logrus, zap, zerolog)
  • Error Categorization: Built-in error types and severity levels for better error handling
  • Circuit Breaker Pattern: Protect your systems from cascading failures
  • Efficient Error Grouping: Pool-based error group management for high-performance scenarios
  • Context Preservation: Rich error context including request IDs, user information, and operation details
  • Thread-Safe Operations: Safe for concurrent use in all operations
  • Format Options: JSON and YAML output support with customizable formatting
  • Go 1.13+ Compatible: Full support for errors.Is, errors.As, and error chains

Installation

go get github.com/hyp3rd/ewrap

Documentation

ewrap has plenty of features with an exhaustive documentation, browse it here.

Usage Examples

Basic Error Handling

Create and wrap errors with context:

// Create a new error
err := ewrap.New("database connection failed")

// Wrap an existing error with context
if err != nil {
    return ewrap.Wrap(err, "failed to process request")
}

Advanced Error Context

Add rich context and metadata to errors:

err := ewrap.New("operation failed",
    ewrap.WithContext(ctx, ewrap.ErrorTypeDatabase, ewrap.SeverityCritical),
    ewrap.WithLogger(logger)).
    WithMetadata("query", "SELECT * FROM users").
    WithMetadata("retry_count", 3)

// Log the error with all context
err.Log()

Error Groups with Pooling

Use error groups efficiently in high-throughput scenarios:

// Create an error group pool with initial capacity
pool := ewrap.NewErrorGroupPool(4)

// Get an error group from the pool
eg := pool.Get()
defer eg.Release()  // Return to pool when done

// Add errors as needed
eg.Add(err1)
eg.Add(err2)

if eg.HasErrors() {
    return eg.Error()
}

Circuit Breaker Pattern

Protect your system from cascading failures:

// Create a circuit breaker for database operations
cb := ewrap.NewCircuitBreaker("database", 3, time.Minute)

if cb.CanExecute() {
    if err := performDatabaseOperation(); err != nil {
        cb.RecordFailure()
        return ewrap.Wrap(err, "database operation failed",
            ewrap.WithContext(ctx, ewrap.ErrorTypeDatabase, ewrap.SeverityCritical))
    }
    cb.RecordSuccess()
}

Complete Example

Here's a comprehensive example combining multiple features:

func processOrder(ctx context.Context, orderID string) error {
    // Get an error group from the pool
    pool := ewrap.NewErrorGroupPool(4)
    eg := pool.Get()
    defer eg.Release()

    // Create a circuit breaker for database operations
    cb := ewrap.NewCircuitBreaker("database", 3, time.Minute)

    // Validate order
    if err := validateOrderID(orderID); err != nil {
        eg.Add(ewrap.Wrap(err, "invalid order ID",
            ewrap.WithContext(ctx, ewrap.ErrorTypeValidation, ewrap.SeverityError)))
    }

    if !eg.HasErrors() && cb.CanExecute() {
        if err := saveToDatabase(orderID); err != nil {
            cb.RecordFailure()
            return ewrap.Wrap(err, "database operation failed",
                ewrap.WithContext(ctx, ewrap.ErrorTypeDatabase, ewrap.SeverityCritical))
        }
        cb.RecordSuccess()
    }

    return eg.Error()
}

Error Types and Severity

The package provides pre-defined error types and severity levels:

// Error Types
ErrorTypeValidation    // Input validation failures
ErrorTypeNotFound      // Resource not found
ErrorTypePermission    // Authorization/authentication failures
ErrorTypeDatabase      // Database operation failures
ErrorTypeNetwork       // Network-related failures
ErrorTypeConfiguration // Configuration issues
ErrorTypeInternal      // Internal system errors
ErrorTypeExternal      // External service errors

// Severity Levels
SeverityInfo      // Informational messages
SeverityWarning   // Warning conditions
SeverityError     // Error conditions
SeverityCritical  // Critical failures

Logging Integration

Implement the Logger interface to integrate with your logging system:

type Logger interface {
    Error(msg string, keysAndValues ...interface{})
    Debug(msg string, keysAndValues ...interface{})
    Info(msg string, keysAndValues ...interface{})
}

Built-in adapters are provided for popular logging frameworks:

// Zap logger
zapLogger, _ := zap.NewProduction()
err := ewrap.New("error occurred",
    ewrap.WithLogger(adapters.NewZapAdapter(zapLogger)))

// Logrus logger
logrusLogger := logrus.New()
err := ewrap.New("error occurred",
    ewrap.WithLogger(adapters.NewLogrusAdapter(logrusLogger)))

// Zerolog logger
zerologLogger := zerolog.New(os.Stdout)
err := ewrap.New("error occurred",
    ewrap.WithLogger(adapters.NewZerologAdapter(zerologLogger)))

Error Formatting

Convert errors to structured formats:

// Convert to JSON
jsonStr, _ := err.ToJSON(
    ewrap.WithTimestampFormat(time.RFC3339),
    ewrap.WithStackTrace(true))

// Convert to YAML
yamlStr, _ := err.ToYAML(
    ewrap.WithStackTrace(true))

Performance Considerations

The package is designed with performance in mind:

  • Error groups use sync.Pool for efficient memory usage
  • Minimal allocations in hot paths
  • Thread-safe operations with low contention
  • Pre-allocated buffers for string operations
  • Efficient stack trace capture and filtering

Development Setup

  1. Clone this repository:

    git clone https://github.com/hyp3rd/ewrap.git
  2. Install VS Code Extensions Recommended (optional):

    {
      "recommendations": [
        "github.vscode-github-actions",
        "golang.go",
        "ms-vscode.makefile-tools",
        "esbenp.prettier-vscode",
        "pbkit.vscode-pbkit",
        "trunk.io",
        "streetsidesoftware.code-spell-checker",
        "ms-azuretools.vscode-docker",
        "eamodio.gitlens"
      ]
    }
    1. Install Golang.

    2. Install GitVersion.

    3. Install Make, follow the procedure for your OS.

    4. Set up the toolchain:

      make prepare-toolchain
    5. Initialize pre-commit (strongly recommended to create a virtual env, using for instance PyEnv) and its hooks:

       pip install pre-commit
       pre-commit install
       pre-commit install-hooks

Project Structure

├── internal/ # Private code
│   └── logger/ # Application specific code
├── pkg/ # Public libraries)
├── scripts/ # Scripts for development
├── test/ # Additional test files
└── docs/ # Documentation

Best Practices

  • Follow the Go Code Review Comments
  • Run golangci-lint before committing code
  • Ensure the pre-commit hooks pass
  • Write tests for new functionality
  • Keep packages small and focused
  • Use meaningful package names
  • Document exported functions and types

Available Make Commands

  • make test: Run tests.
  • make benchmark: Run benchmark tests.
  • make update-deps: Update all dependencies in the project.
  • make prepare-toolchain: Install all tools required to build the project.
  • make lint: Run the staticcheck and golangci-lint static analysis tools on all packages in the project.
  • make run: Build and run the application in Docker.

License

MIT License

Contributing

  1. Fork the repository
  2. Create your feature branch
  3. Commit your changes
  4. Push to the branch
  5. Create a Pull Request

Refer to CONTRIBUTING for more information.

Author

I'm a surfer, and a software architect with 15 years of experience designing highly available distributed production systems and developing cloud-native apps in public and private clouds. Feel free to connect with me on LinkedIn.

LinkedIn

About

A sophisticated, configurable error wrapper for Go applications that provides: Stack trace capture Error wrapping with context, Metadata attachment, Logger integration, Compatibility with Go 1.13+ error chains, Rich error information for debugging, Thread-safe operations.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published