Skip to content

Commit

Permalink
Exposed ErrorDetail for manipulation and added some important functio…
Browse files Browse the repository at this point in the history
…ns, such as PrintStackTrace() and PrintCause(), and some getters to obtain data from the structure, in addition we have a new formatting when printing the error, with full visibility of the error with debugStack.
  • Loading branch information
Gabriel Cataldo committed Jan 26, 2024
1 parent 7403a39 commit 4442317
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 58 deletions.
22 changes: 16 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Go Errors Detail
<!--suppress ALL -->
<img align="right" src="gopher-debug.png" alt="">

[![Project status](https://img.shields.io/badge/version-v1.0.9-vividgreen.svg)](https://github.com/GabrielHCataldo/go-errors/releases/tag/v1.0.9)
[![Project status](https://img.shields.io/badge/version-v1.1.0-vividgreen.svg)](https://github.com/GabrielHCataldo/go-errors/releases/tag/v1.1.0)
[![Go Report Card](https://goreportcard.com/badge/github.com/GabrielHCataldo/go-errors)](https://goreportcard.com/report/github.com/GabrielHCataldo/go-errors)
[![Coverage Status](https://coveralls.io/repos/GabrielHCataldo/go-errors/badge.svg?branch=main&service=github)](https://coveralls.io/github/GabrielHCataldo/go-errors?branch=main)
[![Open Source Helpers](https://www.codetriage.com/gabrielhcataldo/go-errors/badges/users.svg)](https://www.codetriage.com/gabrielhcataldo/go-errors)
Expand All @@ -16,8 +16,8 @@ Go Errors Detail

[//]: # ([![TODOs]&#40;https://badgen.net/https/api.tickgit.com/badgen/github.com/GabrielHCataldo/go-errors/errors&#41;]&#40;https://www.tickgit.com/browse?repo=github.com/GabrielHCataldo/go-errors&#41;)

The go-errors project came to make the return of errors, very common in Golang, clearer, thus facilitating the
debugging of your applications.
The go-errors project came to clarify the return of errors, which are very common in Golang, thus facilitating the
debugging your projects.

Installation
------------
Expand All @@ -35,7 +35,7 @@ import "github.com/GabrielHCataldo/go-errors/errors"
Usability and documentation
------------
**IMPORTANT**: Always check the documentation in the structures and functions fields.
For more details on the examples, visit [All examples link](https://github/GabrielHCataldo/go-errors/blob/main/_example/main)
For more details on the examples, visit [All examples link](https://github/GabrielHCataldo/go-errors/blob/main/_example/main).

### Simple example

Expand All @@ -49,7 +49,12 @@ import (

func main() {
err := simple()
logger.Error("simple err:", err)
logger.Info("simple err msg:", errors.Details(err).GetMessage())
logger.Info("simple err file:", errors.Details(err).GetFile())
logger.Info("simple err line:", errors.Details(err).GetLine())
logger.Info("simple err func:", errors.Details(err).GetFuncName())
errors.Details(err).PrintCause()
errors.Details(err).PrintStackTrace()
}

func simple() error {
Expand All @@ -59,7 +64,12 @@ func simple() error {

Output:

[ERROR 2024/01/24 05:05:25] main.go:10: simple err: [_example/main.go:14] simple: error by message with any value 2 true
[INFO 2024/01/26 10:16:38] _example/main.go:12: simple err msg: error by message with any value 2 true
[INFO 2024/01/26 10:16:38] _example/main.go:13: simple err file: _example/main.go
[INFO 2024/01/26 10:16:38] _example/main.go:14: simple err line: 25
[INFO 2024/01/26 10:16:38] _example/main.go:15: simple err func: simple
[ERROR 2024/01/26 10:16:38] _example/main.go:16: (_example/main.go:25) simple: error by message with any value 2 true
[ERROR 2024/01/26 10:16:38] _example/main.go:17: goroutine 1 [running]:

How to contribute
------
Expand Down
41 changes: 32 additions & 9 deletions _example/main.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,53 @@
package main

import (
errors2 "errors"
"github.com/GabrielHCataldo/go-errors/errors"
"github.com/GabrielHCataldo/go-helper/helper"
"github.com/GabrielHCataldo/go-logger/logger"
)

func main() {
err := simple()
logger.Error("simple err:", err)
all()
logger.Info("simple err msg:", errors.Details(err).GetMessage())
logger.Info("simple err file:", errors.Details(err).GetFile())
logger.Info("simple err line:", errors.Details(err).GetLine())
logger.Info("simple err func:", errors.Details(err).GetFuncName())
errors.Details(err).PrintCause()
errors.Details(err).PrintStackTrace()
is()
nilErr()
details(err)
}

func simple() error {
return errors.New("error by message with any value", 2, true)
}

func all() {
func details(err error) {
errDetail := errors.Details(err)
logger.Info("message:", errDetail.GetMessage())
logger.Info("file:", errDetail.GetFile())
logger.Info("line:", errDetail.GetLine())
logger.Info("funcName:", errDetail.GetFuncName())
logger.Info("debugStack:", errDetail.GetDebugStack())
logger.Info("cause:", errDetail.GetCause())
errDetail.PrintStackTrace()
errDetail.PrintCause()
}

func nilErr() {
err := errors.NewSkipCaller(2, nil)
logger.Error("nilErr err:", err == nil, helper.IsNil(err))
}

func is() {
err2 := errors2.New("test")
err := errors.New("error by message with any value", 2)
logger.Error(err)
err = errors.NewSkipCaller(1, "error by message with any value", 2)
logger.Error(err)
err = errors.New("test")
target := errors.New("test")
logger.Info("errors is:", errors.Is(err, target))
logger.Info("errors2 is:", errors.Is(err2, target))
logger.Info("errors is not:", errors.IsNot(err, target))
logger.Info("is error detail?", errors.IsErrorDetail(err))
file, line, funcName, message := errors.GetErrorDetails(err)
logger.Info("error details:", file, line, funcName, message)
logger.Info("is error detail?", errors.IsErrorDetail(err2))
}
66 changes: 45 additions & 21 deletions errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"runtime/debug"
)

const regexErrorDetail = `\[(.+?):(\d+)] (.+?): (.+)`
const regexErrorDetail = `CAUSE: \(([^:]+):(\d+)\) (.+): (.+) STACK:\s*(.+)`

type ErrorDetail struct {
file string
Expand All @@ -21,7 +21,7 @@ type ErrorDetail struct {

// New error with space separated message values, if the message parameter is empty we return a
// nil value, otherwise returns normal value
func New(message ...any) *ErrorDetail {
func New(message ...any) error {
msg := printMessage(message...)
if helper.IsEmpty(msg) {
return nil
Expand All @@ -39,7 +39,7 @@ func New(message ...any) *ErrorDetail {

// NewSkipCaller error with message values separate per space and skipCaller, if the message parameter is empty we return a
// nil value, otherwise returns normal value
func NewSkipCaller(skipCaller int, message ...any) *ErrorDetail {
func NewSkipCaller(skipCaller int, message ...any) error {
msg := printMessage(message...)
if helper.IsEmpty(msg) {
return nil
Expand All @@ -58,12 +58,12 @@ func NewSkipCaller(skipCaller int, message ...any) *ErrorDetail {
// Is validate equal errors
func Is(err, target error) bool {
if IsErrorDetail(err) {
_, _, _, message := GetErrorDetails(err)
err = errors.New(message)
errDetails := Details(err)
err = errors.New(errDetails.GetMessage())
}
if IsErrorDetail(target) {
_, _, _, message := GetErrorDetails(target)
target = errors.New(message)
errDetails := Details(target)
target = errors.New(errDetails.GetMessage())
}
return helper.IsNotNil(err) && helper.Equals(err, target)
}
Expand All @@ -75,12 +75,22 @@ func IsNot(err, target error) bool {

// Error print the error as a string, genetic implementation of error in go
func (e *ErrorDetail) Error() string {
return fmt.Sprint("[", e.file, ":", e.line, "]", " ", e.funcName, ": ", e.message)
return fmt.Sprint("CAUSE: ", e.GetCause(), " STACK: \n", e.debugStack)
}

// PrintStack print red message with detail error and debug stack
func (e *ErrorDetail) PrintStack() {
logger.ErrorSkipCaller(2, "Error:", e.Error(), "Stack:", e.debugStack)
// PrintStackTrace print red message with detail error and debug stack
func (e *ErrorDetail) PrintStackTrace() {
logger.ErrorSkipCaller(2, e.debugStack)
}

// PrintCause print red message with cause error
func (e *ErrorDetail) PrintCause() {
logger.ErrorSkipCaller(2, e.GetCause())
}

// GetCause returns formatted error cause
func (e *ErrorDetail) GetCause() string {
return fmt.Sprint("(", e.file, ":", e.line, ")", " ", e.funcName, ": ", e.message)
}

// GetMessage returns the value of the error message field
Expand Down Expand Up @@ -108,30 +118,44 @@ func (e *ErrorDetail) GetDebugStack() string {
return e.debugStack
}

// IsErrorDetail check if the error is an ErrorDetail containing the pattern with file name, line, function name
// and message
// IsErrorDetail check if the error is an ErrorDetail containing the pattern with file name, line, function name,
// message and debugStack
func IsErrorDetail(err error) bool {
regex := regexp.MustCompile(regexErrorDetail)
return helper.IsNotNil(err) && regex.MatchString(err.Error())
}

// GetErrorDetails we obtain the values of an error detail separately, if the parameter is nil we return all empty
// values, and if the passed error parameter is not in the desired pattern, we return only the filled message and the
// rest empty.
func GetErrorDetails(err error) (file, line, funcName, message string) {
// Details we obtain the values of an error passed in the parameter, and transform them into an ErrorDetail object, if
// the passed parameter is null, the return will also be null and if it is not in the desired errorDetail pattern, we
// return a new ErrDetail with the message being the err passed in the parameter.
func Details(err error) *ErrorDetail {
if helper.IsNil(err) {
return
return nil
}
message = err.Error()
var file string
var line string
var funcName string
var message string
var debugStack string
regex := regexp.MustCompile(regexErrorDetail)
matches := regex.FindStringSubmatch(message)
matches := regex.FindStringSubmatch(err.Error())
if helper.IsNotEmpty(matches) {
file = matches[1]
line = matches[2]
funcName = matches[3]
message = matches[4]
debugStack = matches[5]
} else {
file, line, funcName = helper.GetCallerInfo(2)
debugStack = string(debug.Stack())
}
return &ErrorDetail{
file: file,
line: line,
funcName: funcName,
message: message,
debugStack: debugStack,
}
return
}

func printMessage(v ...any) string {
Expand Down
41 changes: 19 additions & 22 deletions errors/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ func TestNew(t *testing.T) {
}

func TestNewSkipCaller(t *testing.T) {
logger.Info("err:", NewSkipCaller(1, "test error detail"))
logger.Info("err:", NewSkipCaller(1, ""))
err := NewSkipCaller(1, "test error detail")
logger.Info("err:", err)
err = NewSkipCaller(1, nil)
logger.Info("err:", err)
}

func TestIs(t *testing.T) {
Expand Down Expand Up @@ -44,51 +46,46 @@ func TestError(t *testing.T) {

func TestErrorPrintStack(t *testing.T) {
err := New("test error detail")
err.PrintStack()
Details(err).PrintStackTrace()
}

func TestErrorPrintCause(t *testing.T) {
err := New("test error detail")
Details(err).PrintCause()
}

func TestErrorGetMessage(t *testing.T) {
err := New("test error detail")
err.GetMessage()
logger.Info("err message:", err.GetMessage())
logger.Info("err message:", Details(err).GetMessage())
}

func TestErrorGetFile(t *testing.T) {
err := New("test error detail")
err.GetMessage()
logger.Info("err message:", err.GetFile())
logger.Info("err file:", Details(err).GetFile())
}

func TestErrorGetLine(t *testing.T) {
err := New("test error detail")
err.GetMessage()
logger.Info("err message:", err.GetLine())
logger.Info("err line:", Details(err).GetLine())
}

func TestErrorGetFuncName(t *testing.T) {
err := New("test error detail")
err.GetMessage()
logger.Info("err message:", err.GetFuncName())
logger.Info("err message:", Details(err).GetFuncName())
}

func TestErrorGetDebugStack(t *testing.T) {
err := New("test error detail")
err.GetMessage()
logger.Info("err message:", err.GetDebugStack())
logger.Info("err message:", Details(err).GetDebugStack())
}

func TestIsErrorDetail(t *testing.T) {
err := New("test error detail")
logger.Info("err:", IsErrorDetail(err))
}

func TestGetErrorDetails(t *testing.T) {
err := New("test error detail").Error()
file, line, funcName, message := GetErrorDetails(errors.New(err))
logger.Info("details:", file, line, funcName, message)
v := "test"
file, line, funcName, message = GetErrorDetails(errors.New(v))
logger.Info("details:", file, line, funcName, message)
file, line, funcName, message = GetErrorDetails(nil)
logger.Info("details:", file, line, funcName, message)
func TestDetails(t *testing.T) {
logger.Info("err details:", Details(nil))
logger.Info("err details:", Details(errors.New("test")))
logger.Info("err details:", Details(New("test")))
}

0 comments on commit 4442317

Please sign in to comment.