errorx

package module
v1.6.0 Latest Latest
Warning

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

Go to latest
Published: Mar 21, 2024 License: MIT Imports: 17 Imported by: 65

README

errorx

Godoc Build Status Gitter

a very convenient error handler.

Table of Contents generated with DocToc

1. What is different from the officials

  • Supporting generate error stacktrace, locating more efficiently than runtime stacktrace.
  • Supporting report error to HTTP URL.
  • Supporting generate json-marshalled error detail for outer pipeline.
  • Supporting differrent mode uses different error handlers.

2. Start

go get github.com/fwhezfwhez/errorx

3. Module

3.1 Error stacktrace
package main

import (
	"fmt"
	"github.com/fwhezfwhez/errorx"
)

func main() {
	e := fmt.Errorf("nil return")
	fmt.Println(errorx.Wrap(e).Error())
}

Output

2019-08-30 17:51:42 | G:/go_workspace/GOPATH/src/test_X/tmp/main.go: 10 | nil return
3.2 Service error

In most cases, client requires server to provide specific errmsg and errcode. Service error is exact what you expects.

func Control(c *gin.Context) {
	e := Service()

	if se, ok := errorx.IsServiceErr(e, balanceLackErr); ok {
		c.JSON(200, gin.H{
			"errcode": se.Errcode,
			"errmsg": se.Errmsg,
		})
		return
	}
	if e != nil {
		fmt.Println(Wrap(e).Error())
        c.JSON(200, gin.H{
            "errmsg": "unexpected error",
            "errcode": -1,
            "debug_message": errorx.Wrap(e).Error()
        })
		return
	}
	c.JSON(200, gin.H{"errcode":0})
}


func ManyService() error {
	if e:= ServiceToCash();e!=nil {
		return errorx.Wrap(e)
	}
	return nil
}
func ServiceToCash() error {
	if e:=UtilToCash();e!=nil {
		return errorx.Wrap(e)
	}
	return nil
}

var balanceLackErr = NewServiceError("balance not enough", 10001)

func UtilToCash() error {
	return balanceLackErr
}

HTTP Response:

{"errcode": 10001, "errmsg":"balance not enough"}
3.3 Error Report

Using defaultHandler print in console

error will be log as json on console.

package main

import (
	"github.com/fwhezfwhez/errorx"
	"fmt"
)

var rp *errorx.Reporter

func init() {
	rp = errorx.NewReporter("dev")
	rp.AddModeHandler("dev", rp.DefaultHandler)
}
func main() {
	e := fmt.Errorf("nil return")
	if e != nil {
		rp.SaveError(errorx.Wrap(e), map[string]interface{}{
			"username": "errorx",
			"age":      1,
		})
		return
	}
}

output:

{
    "context": {
      "api": "/xxx/yyy/"
    },
    "error_uuid": "11d35e60-5abc-462d-9df1-bb5b01d79807",
    "message": "2019-08-31 08:58:29 | G:/go_workspace/GOPATH/src/errorX/error-report.go: 123 | err 'nil return' \n goroutine 51 [running]:\nruntime/debug.Stack(0xc0002022e0, 0xb3604d, 0xa)\n\tE:/go1.12/src/runtime/debug/stack.go:24 +0xa4\nerrorX.Reporter.SaveError(0xc0001fc1e0, 0xb30f5d, 0x3, 0xc0001fc180, 0x0, 0x0, 0x0, 0xc0001fc1b0, 0x0, 0x0, ...)\n\tG:/go_workspace/GOPATH/src/errorX/error-report.go:123 +0x30b\ncreated by errorX.TestReporter\n\tG:/go_workspace/GOPATH/src/errorX/error-report_test.go:45 +0x702\n\n2019-08-31 08:58:29 | G:/go_workspace/GOPATH/src/errorX/error-report.go: 144 | err 'nil return' \n goroutine 51 [running]:\nruntime/debug.Stack(0xc0002022e0, 0xb3604d, 0xa)\n\tE:/go1.12/src/runtime/debug/stack.go:24 +0xa4\nerrorX.Reporter.SaveError(0xc0001fc1e0, 0xb30f5d, 0x3, 0xc0001fc180, 0x0, 0x0, 0x0, 0xc0001fc1b0, 0x0, 0x0, ...)\n\tG:/go_workspace/GOPATH/src/errorX/error-report.go:123 +0x30b\ncreated by errorX.TestReporter\n\tG:/go_workspace/GOPATH/src/errorX/error-report_test.go:45 +0x702\n\n2019-08-31 08:58:29 | G:/go_workspace/GOPATH/src/errorX/error-report.go: 49 | err 'nil return' \n goroutine 51 [running]:\nruntime/debug.Stack(0xc0002022e0, 0xb3604d, 0xa)\n\tE:/go1.12/src/runtime/debug/stack.go:24 +0xa4\nerrorX.Reporter.SaveError(0xc0001fc1e0, 0xb30f5d, 0x3, 0xc0001fc180, 0x0, 0x0, 0x0, 0xc0001fc1b0, 0x0, 0x0, ...)\n\tG:/go_workspace/GOPATH/src/errorX/error-report.go:123 +0x30b\ncreated by errorX.TestReporter\n\tG:/go_workspace/GOPATH/src/errorX/error-report_test.go:45 +0x702\n\n"
}

Using url report

error will POST into specific url.

server

package main

import (
	"fmt"
	"github.com/fwhezfwhez/errorx"
	"github.com/gin-gonic/gin"
	"io/ioutil"
)

func main() {

	r := gin.Default()

	r.POST("/", func(c *gin.Context) {
		buf, e := ioutil.ReadAll(c.Request.Body)
		if e != nil {
			fmt.Println(errorx.Wrap(e).Error())
			return
		}
		fmt.Println("Recv:", string(buf))
	})
	r.Run(":9191")
}

package main

import (
	"github.com/fwhezfwhez/errorx"
	"fmt"
)

var rp *errorx.Reporter

func init() {
	rp = errorx.NewReporter("pro")
	rp.AddURL("pro", "http://localhost:9191")
	rp.AddURL("dev", "http://localhost:9192")
	rp.AddModeHandler("pro", rp.ReportURLHandler)
	rp.AddModeHandler("dev", rp.Mode("dev").DefaultHandler)
}
func main() {
	e := fmt.Errorf("nil return")
	if e != nil {
	    // rp's mode is pro, it will send error to localhost:9191
		_ = rp.SaveError(errorx.Wrap(e), map[string]interface{}{
			"username": "errorx",
			"age":      1,
		})
		// clone a rp and reset its mode to dev, it will print error in console by DefaultHandler
        _ = rp.Mode("dev").SaveError(errorx.Wrap(e), map[string]interface{}{
            "username": "errorx",
            "age":      1,
        })
		return
	}
}

Output in server panel:

Recv:
{
    "context": {
      "api": "/xxx/yyy/"
    },
    "error_uuid": "11d35e60-5abc-462d-9df1-bb5b01d79807",
    "message": "2019-08-31 08:58:29 | G:/go_workspace/GOPATH/src/errorX/error-report.go: 123 | err 'nil return' \n goroutine 51 [running]:\nruntime/debug.Stack(0xc0002022e0, 0xb3604d, 0xa)\n\tE:/go1.12/src/runtime/debug/stack.go:24 +0xa4\nerrorX.Reporter.SaveError(0xc0001fc1e0, 0xb30f5d, 0x3, 0xc0001fc180, 0x0, 0x0, 0x0, 0xc0001fc1b0, 0x0, 0x0, ...)\n\tG:/go_workspace/GOPATH/src/errorX/error-report.go:123 +0x30b\ncreated by errorX.TestReporter\n\tG:/go_workspace/GOPATH/src/errorX/error-report_test.go:45 +0x702\n\n2019-08-31 08:58:29 | G:/go_workspace/GOPATH/src/errorX/error-report.go: 144 | err 'nil return' \n goroutine 51 [running]:\nruntime/debug.Stack(0xc0002022e0, 0xb3604d, 0xa)\n\tE:/go1.12/src/runtime/debug/stack.go:24 +0xa4\nerrorX.Reporter.SaveError(0xc0001fc1e0, 0xb30f5d, 0x3, 0xc0001fc180, 0x0, 0x0, 0x0, 0xc0001fc1b0, 0x0, 0x0, ...)\n\tG:/go_workspace/GOPATH/src/errorX/error-report.go:123 +0x30b\ncreated by errorX.TestReporter\n\tG:/go_workspace/GOPATH/src/errorX/error-report_test.go:45 +0x702\n\n2019-08-31 08:58:29 | G:/go_workspace/GOPATH/src/errorX/error-report.go: 49 | err 'nil return' \n goroutine 51 [running]:\nruntime/debug.Stack(0xc0002022e0, 0xb3604d, 0xa)\n\tE:/go1.12/src/runtime/debug/stack.go:24 +0xa4\nerrorX.Reporter.SaveError(0xc0001fc1e0, 0xb30f5d, 0x3, 0xc0001fc180, 0x0, 0x0, 0x0, 0xc0001fc1b0, 0x0, 0x0, ...)\n\tG:/go_workspace/GOPATH/src/errorX/error-report.go:123 +0x30b\ncreated by errorX.TestReporter\n\tG:/go_workspace/GOPATH/src/errorX/error-report_test.go:45 +0x702\n\n"
}
3.4 JSON

JSON and JSONIndent will generate a json buf from error and context.

package main

import (
	"github.com/fwhezfwhez/errorx"
	"fmt"
)

func main() {
	eUuid, buf, e := errorx.JSON(errorx.NewFromString("nil return"), map[string]interface{}{
		"api": "/xx/xxx/xx",
	})
	fmt.Println(eUuid)
	fmt.Println(string(buf))
	fmt.Println(e)
}

Output:

befe4742-6905-4817-96aa-19fdb63bd83f
{"context":{"api":"/xx/xxx/xx"},"error_uuid":"befe4742-6905-4817-96aa-19fdb63bd83f","message":"2019-08-31 09:18:41 | G:/go_workspace/GOPATH/src/errorX/error-report_test.go: 56 | nil return\n2019-08-31 09:18:41 | G:/go_workspace/GOPATH/src/errorX/error-report.go: 171 | nil return\n"}

Documentation

Index

Constants

View Source
const (
	LcauseBy = 1 << iota
	LdateTime
	Llongfile
)
View Source
const Size = 16

Size of a UUID in bytes.

Variables

View Source
var DefaultHandler = func(e error, context map[string]interface{}) {
	var tmp = make(map[string]interface{}, 0)
	tmp["error_uuid"] = context["error_uuid"]
	delete(context, "error_uuid")
	tmp["message"] = Wrap(e).Error()
	tmp["context"] = context

	var buf = []byte("")
	var er error
	buf, er = json.MarshalIndent(tmp, "  ", "  ")
	if er != nil {
		buf = []byte(Wrap(er).Error())
	}
	fmt.Println(string(buf))
}

It will fmt error log into console.

Functions

func GenerateKeyword

func GenerateKeyword(e error) string

generate key word to an error type

func GetStack added in v1.0.5

func GetStack(e error) []string

func GroupErrors

func GroupErrors(es ...error) error

group series of error to a single error

func IsError

func IsError(src error, dest error) (string, bool)

func JSON

func JSON(e error, context map[string]interface{}) (string, []byte, error)

func JSONIndent

func JSONIndent(e error, context map[string]interface{}, prefix, indent string) (string, []byte, error)

func New

func New(e error) error

New a error

func NewFromStackTrace

func NewFromStackTrace(stackTrace []string, msg string) error

new an error with existed stacktrace and generate the new error with new msg

func NewFromString

func NewFromString(msg string) error

new an error from string

func NewFromStringWithAttach deprecated

func NewFromStringWithAttach(msg string, attach interface{}) error

Deprecated: using NewFromStringf

func NewFromStringWithAttachf deprecated

func NewFromStringWithAttachf(format string, msg string, attach interface{}) error

Deprecated: using NewFromStringf

func NewFromStringWithDepth

func NewFromStringWithDepth(msg string, depth int) error

func NewFromStringWithHeader

func NewFromStringWithHeader(msg string, header map[string]interface{}) error

new an error from string with header

func NewFromStringWithHeaderf

func NewFromStringWithHeaderf(format string, msg string, header map[string]interface{}) error

new a error from a well format string with header

func NewFromStringWithParam

func NewFromStringWithParam(msg string, params ...interface{}) error

func NewFromStringf

func NewFromStringf(format string, args ...interface{}) error

new a error from a well format string

func NewWithAttach

func NewWithAttach(e error, msg interface{}) error

func NewWithHeader

func NewWithHeader(e error, header map[string]interface{}) error

New an error with header info

func NewWithParam deprecated

func NewWithParam(e error, params ...interface{}) error

Deprecated: using WrapContext

func PrintStackFormat

func PrintStackFormat(flag int, file string, line int, cause string) string

func ReGen

func ReGen(old error, new error) error

Decrecated

func Split

func Split(s string, sub string) []string

Split better strings.Split,对 a,,,,,,,b,,c 以","进行切割成[a,b,c]

func Split2

func Split2(s string, sub string, tmp *string, rs *[]string)

Split2 附属于Split,可独立使用

func ToString

func ToString(arg interface{}) string

func Wrap

func Wrap(e error) error

wrap an official error to Error type function do the same as New() New() or Wrap() depends on its semantics. mixing them is also correct.

func WrapContext

func WrapContext(e error, ctx map[string]interface{}) error

Types

type Error

type Error struct {

	// basic
	E           error
	StackTraces []string // Deprecated,保留了字段防止外部应用直接使用引起无法编译问题

	// do not use context, it's tracking bug on development
	Context map[string]interface{}
	Header  map[string][]string

	// upper
	ReGenerated bool
	Errors      []error
	Flag        int
	Keyword     string
	// contains filtered or unexported fields
}

an Error instance wraps an official error and storage its stackTrace. When tries to wrap the origin error to another, logic does like:

if er := f(); er!=nil{
    log.Println(er.Error())
	return errors.New("inner service error")
}

'ReGenerated' should be set true and different errors should be saved in 'Errors',and the 'stackTrace' should include all stackTraces above.But in this case,'Error.E' only point to the origin one It's ok to storage both official error and 'Error'

func Empty

func Empty() Error

func MustWrap

func MustWrap(e error) Error

return an Error regardless of e's type

func (Error) BasicError

func (e Error) BasicError() string

func (Error) Error

func (e Error) Error() string

func (Error) GenerateKeyword

func (e Error) GenerateKeyword() string

generate an error key word. key word is used to help save errors in database It's suggested to set unique(date, keyword), when error with same keyword in a day,database only saves field 'times' rather than another error record

func (Error) GetHeader

func (e Error) GetHeader(key string) string

GetHeader is safe wheter header is nil

func (Error) PrintStackTrace

func (e Error) PrintStackTrace() string

print error stack trace e.Flag only controls 'Error' type or official error which has been wrapped to 'Error'. e.Flag only controls stack trace inner an Error type ,rather than some stack trace which has been init by api NewFromStackTrace([]string,string)

func (*Error) SetHeader

func (e *Error) SetHeader(key string, value string)

set header for an error obj SetHeader is safe whether e.Header is nil or not

func (Error) Stack added in v1.0.5

func (e Error) Stack() []string

func (Error) StackTrace

func (e Error) StackTrace() string

return its stacktrace

func (Error) StackTraceValue

func (e Error) StackTraceValue() string

func (Error) String

func (e Error) String() string

type Generator

type Generator interface {
	NewV4() (UUID, error)
}

Generator provides interface for generating UUIDs.

type Reporter

type Reporter struct {
	Url map[string]string

	HandleMode map[string]func(e error, context map[string]interface{})
	// contains filtered or unexported fields
}

func NewReporter

func NewReporter(mode string) *Reporter

func (*Reporter) AddModeHandler

func (r *Reporter) AddModeHandler(mode string, f func(e error, context map[string]interface{})) *Reporter

func (*Reporter) AddURL

func (r *Reporter) AddURL(mode string, url string) *Reporter

func (Reporter) DefaultHandler

func (r Reporter) DefaultHandler(e error, context map[string]interface{})

func (Reporter) JSON

func (r Reporter) JSON(e error, context map[string]interface{}) (string, []byte, error)

rp.Mode unrelated returns errorUUID, json-buf, error

func (Reporter) JSONIndent

func (r Reporter) JSONIndent(e error, context map[string]interface{}, prefix, indent string) (string, []byte, error)

func (*Reporter) Mode

func (r *Reporter) Mode(mode string) *Reporter

Mode will clone a copy of reporter to avoid different goroutine using a unsafe clone

func (Reporter) ReportURLHandler

func (r Reporter) ReportURLHandler(e error, context map[string]interface{})

rp.Mode related, should call like rp.Mode("dev").ReportURLHandler It will post error with context to an url storaged in reporter.Url

func (Reporter) SaveError

func (r Reporter) SaveError(e error, context map[string]interface{}) string

rp.Mode related, should call as r.Mode("dev").SaveError()

func (*Reporter) SetContextName

func (r *Reporter) SetContextName(name string)

func (*Reporter) SetMode

func (r *Reporter) SetMode(mode string)

type ServiceError

type ServiceError struct {
	Errcode int
	Errmsg  string
}

func IsServiceErr

func IsServiceErr(src error, dest ...error) (ServiceError, bool)

IsServiceErr is used to handle service error.

Case below will be regarded as service error and return se,true

func NewServiceError

func NewServiceError(errmsg string, errcode int) ServiceError

func (ServiceError) Equal

func (se ServiceError) Equal(dest ServiceError) bool

func (ServiceError) Error

func (se ServiceError) Error() string

type UUID

type UUID [Size]byte

UUID representation compliant with specification described in RFC 4122.

func NewV4

func NewV4() (UUID, error)

func (*UUID) SetVariant

func (u *UUID) SetVariant(v byte)

SetVariant sets variant bits.

func (*UUID) SetVersion

func (u *UUID) SetVersion(v byte)

func (UUID) String

func (u UUID) String() string

Returns canonical string representation of UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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