karma

package module
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Dec 7, 2023 License: MIT Imports: 8 Imported by: 138

README

Contexts

karma has contexts support, which allows to add arbitrary key-value fields to the error to ease debug.

Simplest usage is to add key-values for existing error:

func bar(arg string) error {
    return fmt.Errorf("arg is invalid: %s", arg)
}

func foo(arg string) error {
    err := bar(arg)
    if err != nil {
        return karma.Describe("method", "bar").Reason(err)
    }
}

fmt.Println(foo("hello"))

// Output:
//
// arg is invalid: hello
// └─ method: bar

Comparison

Feature karma errors emperror
Nested Errors
Key-Value Context ~
Descriptive Pretty Print
Embedded Stack Trace
JSON Friendly
Multi-error Support ~
Fluid Interface

License

This project is licensed under the terms of the MIT license.

Documentation

Overview

Package karma provides a simple way to return and display hierarchical messages or errors.

Transforms:

can't pull remote 'origin': can't run git fetch 'origin' 'refs/tokens/*:refs/tokens/*': exit status 128

Into:

can't pull remote 'origin'
└─ can't run git fetch 'origin' 'refs/tokens/*:refs/tokens/*'
   └─ exit status 128

Index

Examples

Constants

View Source
const (
	// BranchDelimiterASCII represents a simple ASCII delimiter for hierarchy
	// branches.
	//
	// Use: karma.BranchDelimiter = karma.BranchDelimiterASCII
	BranchDelimiterASCII = `\_ `

	// BranchDelimiterBox represents UTF8 delimiter for hierarchy branches.
	//
	// Use: karma.BranchDelimiter = karma.BranchDelimiterBox
	BranchDelimiterBox = `└─ `

	// BranchChainerASCII represents a simple ASCII chainer for hierarchy
	// branches.
	//
	// Use: karma.BranchChainer = karma.BranchChainerASCII
	BranchChainerASCII = `| `

	// BranchChainerBox represents UTF8 chainer for hierarchy branches.
	//
	// Use: karma.BranchChainer = karma.BranchChainerBox
	BranchChainerBox = `│ `

	// BranchSplitterASCII represents a simple ASCII splitter for hierarchy
	// branches.
	//
	// Use: karma.BranchSplitter = karma.BranchSplitterASCII
	BranchSplitterASCII = `+ `

	// BranchSplitterBox represents UTF8 splitter for hierarchy branches.
	//
	// Use: karma.BranchSplitter = karma.BranchSplitterBox
	BranchSplitterBox = `├─ `
)

Variables

View Source
var (
	// BranchDelimiter set delimiter each nested message text will be started
	// from.
	BranchDelimiter = BranchDelimiterBox

	// BranchChainer set chainer each nested message tree text will be started
	// from.
	BranchChainer = BranchChainerBox

	// BranchSplitter set splitter each nested messages splitted by.
	BranchSplitter = BranchSplitterBox

	// BranchIndent set number of spaces each nested message will be indented by.
	BranchIndent = 3
)
View Source
var ContextValueFormatter = func(value interface{}) string {
	if value, ok := value.(string); ok {
		if value == "" {
			return "<empty>"
		}
	}

	switch value := value.(type) {
	case string:
		return value
	case fmt.Stringer:
		return fmt.Sprint(value)
	case bool:
		return strconv.FormatBool(value)
	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
		return fmt.Sprint(value)
	case float32, float64:
		return fmt.Sprint(value)
	default:
		result, err := json.MarshalIndent(value, "", "  ")
		if err != nil {
			return fmt.Sprintf("unable to marshal value: %s", err)
		}

		return string(result)
	}
}

ContextValueFormatter returns string representation of context value when Format() is called on Karma struct.

Functions

func Contains

func Contains(chain Reason, branch Reason) bool

Contains returns true when branch is found in reasons of given chain. Or chain has the same value as branch error. Useful when you work with result of multi-level error and just wanted to check that error contains os.ErrNoExist.

func Find

func Find(err Reason, typed interface{}) bool

Find typed object in given chain of reasons, returns true if reason with the same type found, if typed object is addressable, value will be stored in it.

func Flatten

func Flatten(err error) error
Example
package main

import (
	"fmt"
	"io"

	"github.com/reconquest/karma-go"
)

func foo(a int) error {
	return karma.Format(io.EOF, "eof or something")
}

func bar(quz int) error {
	wox := quz * 2

	err := foo(wox)
	if err != nil {
		return karma.
			Describe("wox", wox).
			Format(err, "foo")
	}

	return nil
}

func twix() error {
	err := bar(42)
	if err != nil {
		return karma.Describe("barval", 42).Format(err, "bar")
	}

	return nil
}

func run() error {
	err := twix()
	if err != nil {
		return karma.Format(err, "twix")
	}

	return nil
}

func main() {
	{
		err := io.EOF
		fmt.Println("regular:")
		fmt.Println(err)
		fmt.Println("flatten:")
		fmt.Println(karma.Flatten(err))
	}

	{
		err := run()
		fmt.Println("regular (hierarchical):")
		fmt.Println(err)
		fmt.Println("flatten:")
		fmt.Println(karma.Flatten(err))
	}

}
Output:


regular:
EOF
flatten:
EOF
regular (hierarchical):
twix
└─ bar
   ├─ foo
   │  ├─ eof or something
   │  │  └─ EOF
   │  │
   │  └─ wox: 84
   │
   └─ barval: 42
flatten:
twix: bar: foo: eof or something: EOF | barval=42 wox=84

Types

type Context

type Context struct {
	KeyValue
	Next *Context
}

Context is a element of key-value linked list of message contexts.

func Describe

func Describe(key string, value interface{}) *Context

Describe creates new context list, which can be used to produce context-rich hierarchical message.

func DescribeDeep

func DescribeDeep(prefixKey string, obj interface{}) *Context

func (*Context) Describe

func (context *Context) Describe(
	key string,
	value interface{},
) *Context

Context adds new key-value context pair to current context list and return new context list.

func (*Context) Format

func (context *Context) Format(
	reason Reason,
	message string,
	args ...interface{},
) Karma

Format produces context-rich hierarchical message, which will include all previously declared context key-value pairs.

func (*Context) GetKeyValuePairs

func (context *Context) GetKeyValuePairs() []interface{}

GetKeyValuePairs returns slice of key-value context pairs, which will be always even, each even index is key and each odd index is value.

func (*Context) GetKeyValues

func (context *Context) GetKeyValues() []KeyValue

GetKeyValues returns context as slice of key-values.

func (*Context) MarshalJSON

func (context *Context) MarshalJSON() ([]byte, error)

func (*Context) Reason

func (context *Context) Reason(reason Reason) Karma

Reason adds current context to the specified message. If message is not hierarchical, it will be converted to such.

func (*Context) UnmarshalJSON

func (context *Context) UnmarshalJSON(data []byte) error

func (*Context) Walk

func (context *Context) Walk(callback func(string, interface{}))

Walk iterates over all key-value context pairs and calls specified callback for each.

type Hierarchical

type Hierarchical interface {
	// String returns hierarchical string representation.
	String() string

	// GetReasons returns slice of nested reasons.
	GetReasons() []Reason

	// GetMessage returns top-level message.
	GetMessage() string
}

Hierarchical represents interface, which methods will be used instead of calling String() and Karma() methods.

type Karma

type Karma struct {
	// Reason of message, which can be Karma as well.
	Reason Reason

	// Message is formatted message, which will be returned when String()
	// will be invoked.
	Message string

	// Context is a key-pair linked list, which represents runtime context
	// of the situtation.
	Context *Context
}

Karma represents hierarchy message, linked with nested message.

func Collect added in v1.3.0

func Collect(parent Reason, err ...error) Karma

Collect function collects multiple errors into a hierarchical one. It uses karma.Push to add all errors as children for the parent error.

Example
err1 := errors.New("error 1")
err2 := errors.New("error 2")
err3 := errors.New("error 3")

collected := Collect("parent error", err1, err2, err3)

fmt.Println(collected)
Output:

parent error
├─ error 1
├─ error 2
└─ error 3

func Format

func Format(
	reason Reason,
	message string,
	args ...interface{},
) Karma

Format creates new hierarchical message.

With reason == nil call will be equal to `fmt.Errorf()`.

func Push

func Push(reason Reason, reasons ...Reason) Karma

Push creates new hierarchy message with multiple branches separated by separator, delimited by delimiter and prolongated by prolongator.

func (Karma) Descend

func (karma Karma) Descend(callback func(Reason))

Descend calls specified callback for every nested hierarchical message.

func (Karma) Error

func (karma Karma) Error() string

Error implements error interface, Karma can be returned as error.

func (Karma) GetContext

func (karma Karma) GetContext() *Context

GetContext returns context

func (Karma) GetMessage

func (karma Karma) GetMessage() string

GetMessage returns message message

func (Karma) GetReasons

func (karma Karma) GetReasons() []Reason

GetReasons returns nested messages, embedded into message.

func (Karma) MarshalJSON

func (karma Karma) MarshalJSON() ([]byte, error)

func (Karma) String

func (karma Karma) String() string

Karma returns hierarchical string representation. If no nested message was specified, then only current message will be returned.

func (*Karma) UnmarshalJSON

func (karma *Karma) UnmarshalJSON(data []byte) error

func (Karma) Unwrap added in v1.4.0

func (karma Karma) Unwrap() error

type KeyValue

type KeyValue struct {
	Key   string      `json:"key"`
	Value interface{} `json:"value"`
}

type Reason

type Reason interface{}

Reason is either `error` or string.

func GetReasons

func GetReasons(err error) []Reason

GetReasons returns nested messages

Jump to

Keyboard shortcuts

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