goerrors

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: May 19, 2019 License: GPL-3.0 Imports: 7 Imported by: 1

README

GoErrors - Easy error informations and stack traces for Go with rich informations and a Try/Catch/Finally mechanism.

Report Build Status Coverage Status GoDoc GitHub license Release Dependency status

It's a package that's allow you to make Go errors more comprehensive, more featured and easier to use. This project is the realisation of the idea introduced by the GIST try-catch-finally.go.

Features

  • Verbose with stack trace
  • Ready for Try/Catch/Finally paradigm
  • Extensible with your own error
  • Error hierarchy
  • Entirely customizable

Installation

go get github.com/corebreaker/goerrors

How is it work ?

A normal error is just an interface. But here we added an extended interface IError which can transport other infomations. Therefore to add informations, the standard error (error interface) is «decorated» with informations and so we obtain a new error value. These informations are:

  • stack trace informations (files + lines)
  • additionnal customized string
  • optionnal error code

When the Error method is called, all these informations will be formated in a string.

This type of error gives you rich informations on an error without using panic function (even if with a panic, you could show your additionnal infomations).

How to use it ?

Decorate error to add a stack trace
// for example, let's open a file
func OpenMyFile() (*os.File, error) {
    file, err := os.Open("MyFile.txt")
    if err != nil {
        // Here, we decorate the error
        return nil, goerrors.DecorateError(err)
    }

    return file, nil
}

Then, we can panic this decorated error or simply print it, like this:

func main() {
    // First we must enable the debug mode to activate the stacktrace
    goerrors.SetDebug(true)

    // Use a function that use the `goerrors` package
    file, err := OpenMyFile()

    // Check the error
    if err != nil {
        // Show the error
        fmt.Println(err)

        // Terminate
        return
    }

    // …
}

You will see some thing like this:

github.com/corebreaker/goerrors.tStandardError: open MyFile.txt: no such file or directory
    github.com/corebreaker/goerrors.(*GoError).Init (/home/frederic/go/src/github.com/corebreaker/goerrors/errors.go:219)
    github.com/corebreaker/goerrors.DecorateError (/home/frederic/go/src/github.com/corebreaker/goerrors/standard.go:51)
    main.OpenMyFile (/home/frederic/.local/share/data/liteide/liteide/goplay.go:13)
    main.main (/home/frederic/.local/share/data/liteide/liteide/goplay.go:24)
------------------------------------------------------------------------------
A Try/Catch/Finally mechanism

Plus, this library uses the panic() function, the recover() function and the defer instruction, as a Throw and a Try/Catch/Finally mechanisms and can be used like this:

goerrors.Try(func(err goerrors.IError) error {
    // Try block
}, func(err goerrors.IError) error {
    // Catch block
}, func(err goerrors.IError) error {
    // Finally block
})

The error passed in Try block is the error which called the Try method:

theError := goerrors.MakeError("the error in `Try` block")
theError.Try(func(err goerrors.IError) error {
	// Here err === theError
	
	return nil
})

In the case in using the Try function in the GoError package, the error passed as argument is an error created by the call the Try function. Then, that error can be customized with the GoError API.

An example with a throw, called "raise" here

Actually, returning an error in the Try block is a Throw, and a Go panic call is too like a throw but there is a panic-like function for keeping Try/Catch formalism, the Raise function, used like that:

goerrors.Try(func(err goerrors.IError) error {
	if aCondition {
        // `Raise` call
        goerrors.Raise("an error")
    }
    
    // Do something
    
    return nil
}, func(err goerrors.IError) error {
    // Catch block
}, func(err goerrors.IError) error {
    // Finally block
})

At last, all errors generated by GoError have a Raise method. So, you can throw an error like that:

goerrors.Try(func(err goerrors.IError) error {
    if aCondition {
        // `Raise` method call
        goerrors.MakeError("an error").Raise()
    }
    
    // Do something
    
    return nil
}, func(err goerrors.IError) error {
    // Catch block
}, func(err goerrors.IError) error {
    // Finally block
})

A simple example

package main

import (
    "fmt"
    gerr "github.com/corebreaker/goerrors"
)

// A function which return checked quotient
func my_func(i, j int) (int, error) {
    if j == 0 {
        return 0, gerr.MakeError("Division by zero")
    }

    return i / j, nil
}

// Main function
func main() {
    // Activate stack trace
    gerr.SetDebug(true)

    i, j := 1, 0

    // Call checked function
    q, err := my_func(i, j)
    if err != nil {
        fmt.Println(err)

        return
    }

    // Here, in this example, this code won't never be executed
    fmt.Print(i, "/", j, "=", q)
}

This will show:

StandardError: Division by zero
    main.my_func (/projects/go/prototype/main.go:11)
    main.main (/projects/go/prototype/main.go:23)
------------------------------------------------------------------------------

Another example with existing error

package main

import (
    "fmt"
    "os"
    gerr "github.com/corebreaker/goerrors"
)

// A function which open a file
func openFile(name string) (*os.File, error) {
    f, err := os.Open(name)

    // Decorate the opening error
    if err != nil {
        return nil, gerr.DecorateError(err)
    }

    return f, nil
}

// A function which read one byte in the opened file
func readFile(f *os.File) (byte, error) {
    var b [1]byte

    n, err := f.Read(b[:])

    // Decorate the read error
    if err != nil {
        return 0, gerr.DecorateError(err)
    }

    // Return custom error
    if n == 0 {
        return 0, gerr.MakeError("No data to read")
    }

    return b[0], nil
}

// Main function
func main() {
    // Activate stack trace
    gerr.SetDebug(true)

    // Call the checked open function
    f, err := openFile("a_file.txt")
    if err != nil {
        fmt.Println(err)

        return
    }

    // Here, in this example, this code won't never be executed if the file can't be opened
    defer f.Close()

    _, err = readFile(f)
}

This will show:

StandardError: open a_file.txt: no such file or directory
    main.open_file (/projects/go/src/github.com/corebreaker/goerrors.go:15)
    main.main (/projects/go/src/github.com/corebreaker/goerrors.go:46)
------------------------------------------------------------------------------
A Try/Catch example with error inheritance
package main

import (
    "fmt"
    gerr "github.com/corebreaker/goerrors"
)

type ErrorBase struct{ gerr.GoError }

type ErrorA struct{ ErrorBase }
type ErrorB struct{ ErrorBase }

type ChildError struct{ ErrorA }

func newErrorBase() gerr.IError {
    err := &ErrorBase{}

    return err.Init(err, "message from Error base", nil, nil, 0)
}

func newErrorB() gerr.IError {
    err := &ErrorB{}

    return err.Init(err, "message from Error B", nil, nil, 0)
}

func newChildError() gerr.IError {
    err := &ChildError{}

    return err.Init(err, "message from Child Error", nil, nil, 0)
}

// A function which raise and try to catch the error which is not in the same hierarchy
func myFunc() () {
    _ = newErrorB().Try(func(err gerr.IError) error {
        newChildError().Raise()

        return nil
    }, func(err gerr.IError) error {
        // This catch block will not called because ErrorB is not in the same error hierarchy of ChildError
        return nil
    }, nil)
}

// Main function
func main() {
    _ = newErrorBase().Try(func(err gerr.IError) error {
        myFunc()

        return nil
    }, func(err gerr.IError) error {
        fmt.Println("Catched error:", err)

        return nil
    }, nil)
}

This will show:

Catched error: main.ChildError: message from Child Error

Documentation

Overview

Package goerrors - Easy error informations and stack traces for Go with rich informations and a Try/Catch/Finally mechanism.

Example
// A function which open a file
openFile := func(name string) (*os.File, error) {
	f, err := os.Open(name)

	// Decorate the opening error
	if err != nil {
		return nil, DecorateError(err)
	}

	return f, nil
}

// A function which read one byte in the opened file
readFile := func(f *os.File) (byte, error) {
	var b [1]byte

	n, err := f.Read(b[:])

	// Decorate the read error
	if err != nil {
		return 0, DecorateError(err)
	}

	// Return custom error
	if n == 0 {
		return 0, MakeError("No data to read")
	}

	return b[0], nil
}

// Deactivate stack trace
// (cause stacktrace produced for testing package is specific to go installation and may change with Go version)
SetDebug(false)

// Make an unfindable filename
const name = ".a_file_5123351069599224559.txt"

// Call the checked open function
f, err := openFile(name)
if err != nil {
	fmt.Println(err)

	return
}

// Here, in this example, this code won't never be executed if the file can't be opened
defer f.Close()

_, err = readFile(f)
if err != nil {
	fmt.Println(err)

	return
}
Output:

StandardError: open .a_file_5123351069599224559.txt: no such file or directory

Index

Examples

Constants

View Source
const STACKTRACE_MAXLEN = 65536

STACKTRACE_MAXLEN this version of stack trace asks to have a limit which arbitrary set.

Variables

This section is empty.

Functions

func Catch

func Catch(err *error, catch, finally ErrorHandler)

Catch is the global function to catch an error

func CheckedMain

func CheckedMain(handler MainHandler)

CheckedMain should be called in the main function body. It assumes the uncatched error to see errors with stacktraces.

func DiscardPanic

func DiscardPanic()

DiscardPanic discard a panic.

This is an helper function that should be called with a defer instruction to blocks a panic and permits to
continuing the excution instead of exiting the program.

func GetDebug

func GetDebug() bool

GetDebug returns the Debug boolean flag which indicates that the stack trace will be provided in errors

func GetSource

func GetSource(err error) error

GetSource gets the error source from an error, or returns nil if the error passed in argument is not an IError

func Raise

func Raise(message string, args ...interface{})

Raise is the global function to raise an anonymous error

func RaiseError

func RaiseError(err error)

RaiseError is the global function to raise the error passed in argument

func RaiseWithInfos

func RaiseWithInfos(errorCode int64, data interface{}, message string, args ...interface{})

RaiseWithInfos is like Raise with error code and custom data

func SetDebug

func SetDebug(debug bool)

SetDebug modifies the Debug boolean flag for enable or disable the stack trace in errors. If the `debug` parameter is true, so the stack trace will be provided in errors.

func Try

func Try(try, catch, finally ErrorHandler) (err error)

Try is the global function to call a try block

Types

type ErrorHandler

type ErrorHandler func(err IError) error

ErrorHandler Handler for executing Try, Catch, or Finally block

func SetUncatchedErrorHandler

func SetUncatchedErrorHandler(handler ErrorHandler) ErrorHandler

SetUncatchedErrorHandler defines the handler called when an error is not catched.

But the handled is called only if the CheckedMain function is called (indeed, the handler is called by CheckedMain).

type GoError

type GoError struct {
	// contains filtered or unexported fields
}

GoError Basic error structure

func (*GoError) Catch

func (goErr *GoError) Catch(err *error, catch, finally ErrorHandler)

Catch catchs error (used as a defered call)

func (*GoError) Error

func (goErr *GoError) Error() string

Standard method of `error` interface

func (*GoError) GetData

func (goErr *GoError) GetData() interface{}

GetData gets custon data

func (*GoError) GetMessage

func (goErr *GoError) GetMessage() string

GetMessage gets error message

func (*GoError) GetName

func (goErr *GoError) GetName() string

GetName gets error name

func (*GoError) GetSource

func (goErr *GoError) GetSource() error

GetSource gets cause error (parent error)

func (*GoError) Init

func (goErr *GoError) Init(value interface{}, message string, data interface{}, source error, pruneLevels uint) IError

Init for initializing customized error

func (*GoError) IsParentOf

func (goErr *GoError) IsParentOf(err error) bool

IsParentOf tests if this error is one of parents of error `err` passed in parameter

func (*GoError) Raise

func (goErr *GoError) Raise()

Raise for raising error (obviously)

func (*GoError) Try

func (goErr *GoError) Try(try, catch, finally ErrorHandler) (err error)

Try completes try/catch/finally block

type IError

type IError interface {
	// This is an error
	error

	// Get error name
	GetName() string

	// Get original error
	GetSource() error

	// Get error message
	GetMessage() string

	// Get custon data
	GetData() interface{}

	// Complete try/catch/finally block
	Try(try, catch, finally ErrorHandler) error

	// Catch error (used as a defered call)
	Catch(err *error, catch, finally ErrorHandler)

	// Raise error
	Raise()

	// Test if this error is one of parents of error `err` passed in parameter
	IsParentOf(err error) bool
	// contains filtered or unexported methods
}

IError Interface for extended Go errors

type IStandardError

type IStandardError interface {
	// Base interface
	IError

	// Add more informations on that error
	AddInfo(info string, args ...interface{}) IStandardError

	// Get error code
	GetCode() int64
}

IStandardError Interface for a standard error which decorate another basic go error (`error` go interface) with an error code, message and other additionnal informations

func AddInfo

func AddInfo(err error, info string, args ...interface{}) IStandardError

AddInfo is the global function to add information in an error whatever. This function just call the "AddInfo" method of an standard error.

func DecorateError

func DecorateError(err error) IStandardError

DecorateError «decorates» the error passed as "err" parameter. The error returned will be an standard error with additionnal informations and stack trace.

func DecorateErrorWithDatas

func DecorateErrorWithDatas(err error, code int64, data interface{}, msg string, args ...interface{}) IStandardError

DecorateErrorWithDatas is like `DecorateError` with error code and custom data

func MakeError

func MakeError(message string, args ...interface{}) IStandardError

MakeError makes an standard error from a message passed as "message" parameter

func MakeErrorWithDatas

func MakeErrorWithDatas(code int64, data interface{}, message string, args ...interface{}) IStandardError

MakeErrorWithDatas is like `MakeError` with error code and custom data

type MainHandler

type MainHandler func() error

MainHandler is the handler for main function used with the CheckedMain function

Jump to

Keyboard shortcuts

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