richerror

package module
v0.6.7 Latest Latest
Warning

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

Go to latest
Published: Apr 14, 2022 License: MIT Imports: 15 Imported by: 0

README

Rich Error

Rich Error is an error library that:

  • allows nested errors
  • makes it easy to store extra information along errors
  • provides an easy to use API
  • follows go1.13 errors conventions

Installation

As we're publishing this module in our private repo, you'll need to do following steps before running go get:

  1. Add repo address to GOPRIVATE env, to prevent go from using the proxy server:

    go env -w GOPRIVATE=github.com/vortahq/rich-error
    

    This is a shortcut for GONOPROXY and GONOSUMDB.

  2. Add your Gitlab credentials to allow git to access to your gitlab account using http API

    After creating a new Personal Access Token with write_repository permission from "Profile" -> "Access Tokens", create a ~/.netrc file with the following content

    machine gitlab.com
    login oauth2
    password <your access token>
    
    

    ~/.netrc is the file that curl uses for authentication purposes. As git uses curl internally this will allow git to access to your repository by git-over-http

Public API

For more information about public API checkout contract.go

Usage

Using rich error is easy, you can create a new RichError using richerror.New("error message"). It automatically adds runtime information to your error (like line number, file name, etc.). If you wish to add extra information to your error you can use following methods. You can chain them together and except NilIfNoError their ordering is not important.

WithFields & WithField

These methods add a metadata (or a number of metadata) to your error. You can access them using RichError.Metadata() method. These metadata are a good place to store information like request ID, user ID, etc. and allow you to debug errors more efficiently.

WithKind & WithLevel

These methods allow you to assign a kind and level to your errors. Kind and Level are predefined enums and you have to choose from provided options. This allows you to hint to caller functions that the error is recoverable or not, or what kind of issue caused the error.

WithOperation

Operation is a hint that you can store in error to make debugging and grouping of errors easier.

WithType

WithType lets you assign a type to your error. The type stores information that you're going to show to the user. Because each service has it's own error types, You have to define your type struct yourself, it just have to implements Type interface. You'll probably end up with something like:

type MyErrorType string

func (t *MyErrorType) string {
    return string(t)
}

const (
    ErrX = MyErrorType("x")
)
WithError

WithError allows you to wrap another error inside your error. It follows go 1.13 conventions and supports Unwrap, Is, and As methods.

WithError tries to fill type, level, type, operation, etc. if they haven't been filled explicitly.

NilIfNoError

NilIfNoError returns nil if the underling error is not present. It helps you avoid if err != nil check as much as possible.

JsonMode

JsonMode is a flag controlling the format of generated output, the default format is string. You can change the output format by setting the JsonMode to true.

Helpers

This package provides a set of helper function and structs to help users to utilize the full power of the RichError. Currently, there are following constructs:

  • gRPC interception which uses RichError's Kind to determine gRPC's status code.
  • Logger which tries to log RichErrors in the most complete way (based on the logger given to it).
  • Sentry which reports errors to sentry using sentry-go and uses RichErrors metadata to enrich the reported errors.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetEchoLoggerMiddleware

func GetEchoLoggerMiddleware(logger ErrorLogger) echo.MiddlewareFunc

func New

func New(message string) *richError

New creates a new richError

Types

type BasicLogger

type BasicLogger interface {
	Debug(...interface{})
	Info(...interface{})
	Warn(...interface{})
	Error(...interface{})
	Panic(...interface{})
	Fatal(...interface{})
}

type ChainLogger

type ChainLogger struct {
	Loggers []ErrorLogger
}

ChainLogger is an ErrorLogger that upon being called will call a set of loggers one after the other

func (ChainLogger) Log

func (c ChainLogger) Log(err error)

func (ChainLogger) LogInfo

func (c ChainLogger) LogInfo(msg string)

func (ChainLogger) LogInfoWithMetadata

func (c ChainLogger) LogInfoWithMetadata(msg string, metadata ...interface{})

type CodeInfo deprecated

type CodeInfo RuntimeInfo

Deprecated: CodeInfo has been renamed to RuntimeInfo and will be removed in V2

type ContextLogger

type ContextLogger interface {
	Debugw(string, ...interface{})
	Infow(string, ...interface{})
	Warnw(string, ...interface{})
	Errorw(string, ...interface{})
	Panicw(string, ...interface{})
	Fatalw(string, ...interface{})
}

type ErrorLogger

type ErrorLogger interface {
	Log(error)
	LogInfo(string)
	LogInfoWithMetadata(string, ...interface{})
}

func ChainLoggers

func ChainLoggers(loggers ...ErrorLogger) ErrorLogger

type FormattedLogger

type FormattedLogger interface {
	Debugf(string, ...interface{})
	Infof(string, ...interface{})
	Warnf(string, ...interface{})
	Errorf(string, ...interface{})
	Panicf(string, ...interface{})
	Fatalf(string, ...interface{})
}

type GRPCInterceptors

type GRPCInterceptors struct {
	Logger ErrorLogger
}

GRPCInterceptors is a helper that provides unary and stream grpc interceptors that will catch and log errors of your grpc server. If your grpc services return RichError it will set the grpc status code based on their Kind. Keep in mind that these interceptors will not log errors regarding the reflection API.

func (GRPCInterceptors) StreamInterceptor

func (h GRPCInterceptors) StreamInterceptor() grpc.StreamServerInterceptor

StreamInterceptor returns a gRPC stream interceptor that intercepts every gRPC request and in case of error prints (or logs) error and sets the grpc status code according to the error Kind. It also recovers panics.

func (GRPCInterceptors) UnaryInterceptor

func (h GRPCInterceptors) UnaryInterceptor() grpc.UnaryServerInterceptor

UnaryInterceptor returns a gRPC unary interceptor that intercepts every gRPC request and in case of error prints (or logs) error and sets the grpc status code according to the error Kind. It also recovers panics.

type GoLogger

type GoLogger interface {
	Printf(format string, v ...interface{})
	Println(v ...interface{})
	Fatalf(format string, v ...interface{})
}

type Kind

type Kind kind

Kind hints about underlying cause of error

const (
	UnknownKind      Kind = iota
	Canceled              // grpc: CANCELLED 			- http 500 Internal Server Error
	Unknown               // grpc: UNKNOWN 				- http 500 Internal Server Error
	InvalidArgument       // grpc: INVALID_ARGUMENT 	- http 400 Bad Request
	Timeout               // grpc: DEADLINE_EXCEEDED 	- http 500 Internal Server Error
	NotFound              // grpc: NOT_FOUND 			- http 404 Not Found
	AlreadyExists         // grpc: ALREADY_EXISTS		- http 409 Conflict
	PermissionDenied      // grpc: PERMISSION_DENIED 	- http 403 Forbidden
	TooManyRequests       // grpc: RESOURCE_EXHAUSTED 	- http 429 Too Many Requests
	Unimplemented         // grpc: UNIMPLEMENTED		- http 501 Not Implemented
	Internal              // grpc: INTERNAL 			- http 500 Internal Server Error
	Unavailable           // grpc: UNAVAILABLE 			- http 503 Service Unavailable
	Unauthenticated       // grpc: UNAUTHENTICATED 		- http 401 Unauthorized

	Unauthorized = Unauthenticated
	Invalid      = InvalidArgument
	Unexpected   = Unknown
)

func (Kind) GRPCStatusCode

func (k Kind) GRPCStatusCode() codes.Code

func (Kind) HttpStatusCode

func (k Kind) HttpStatusCode() int

func (Kind) MarshalJSON

func (k Kind) MarshalJSON() ([]byte, error)

func (Kind) String

func (k Kind) String() string

type Level

type Level level

Level identifies severity of the error

const (
	UnknownLevel Level = iota
	Fatal
	Error
	Warning
	Info
)

func (Level) MarshalJSON

func (l Level) MarshalJSON() ([]byte, error)

func (Level) SentryLevel

func (l Level) SentryLevel() sentry.Level

func (Level) String

func (l Level) String() string

type Logger

type Logger struct {
	GoLogger        GoLogger
	BasicLogger     BasicLogger
	FormattedLogger FormattedLogger
	ContextLogger   ContextLogger
}

Logger is a struct that provides an ErrorLogger. The resulting ErrorLogger will log RichErrors given to it as descriptive as it can (based on the loggers abilities). Keep in mind that it's the module users' responsibility to give the struct their desired loggers. It will try to use ContextLogger which logs the error along with all of its Metadata. If not exists it will try FormattedLogger, BasicLogger, and GoLogger in that order. Finally, if no logger has been defined it will use fmt.Println to log the error.

func (Logger) Log

func (l Logger) Log(err error)

func (Logger) LogInfo

func (l Logger) LogInfo(msg string)

func (Logger) LogInfoWithMetadata

func (l Logger) LogInfoWithMetadata(msg string, metadata ...interface{})

type Metadata

type Metadata map[string]interface{}

Metadata stores metadata of error

type Operation

type Operation string

Operation can be used to group or organize error

type RichError

type RichError interface {
	String() string
	Error() string
	Unwrap() error
	Is(target error) bool
	As(target interface{}) bool

	Metadata() Metadata
	RuntimeInfo() []RuntimeInfo

	Operation() Operation
	Level() Level
	Type() Type
	Kind() Kind

	// Deprecated: CodeInfo has been renamed to RuntimeInfo and will be removed in V2
	CodeInfo() CodeInfo
}

RichError is a richer type of error that holds runtime information with itself

type RuntimeInfo

type RuntimeInfo struct {
	LineNumber   int    `json:"line_number,omitempty"`
	FileName     string `json:"file_name,omitempty"`
	FunctionName string `json:"function_name,omitempty"`
}

RuntimeInfo stores runtime information about the code

func (*RuntimeInfo) String

func (s *RuntimeInfo) String() string

type SentryLogger

type SentryLogger struct {
	Environment string
	ServerName  string
}

SentryLogger is a ErrorLogger that logs to sentry. The returned ErrorLogger will report details of your errors (if they're RichError) to the sentry using `sentry-go` module.

func (SentryLogger) Log

func (s SentryLogger) Log(err error)

func (SentryLogger) LogInfo

func (s SentryLogger) LogInfo(string)

func (SentryLogger) LogInfoWithMetadata

func (s SentryLogger) LogInfoWithMetadata(string, ...interface{})

type StringType

type StringType string

func (StringType) String

func (et StringType) String() string

type Type

type Type interface {
	String() string
}

Type stores information that we want to show to user

Jump to

Keyboard shortcuts

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