rotisserie / eris Goto Github PK
View Code? Open in Web Editor NEWError handling library with readable stack traces and flexible formatting support π
Home Page: https://pkg.go.dev/github.com/rotisserie/eris
License: MIT License
Error handling library with readable stack traces and flexible formatting support π
Home Page: https://pkg.go.dev/github.com/rotisserie/eris
License: MIT License
When eris.Wrap is used on an external error to add a stacktrace, only its error message is preserved. The external error might already contain context information which is lost.
Possible solution:
Add a field of type error to eris.rootError and return its value on Unwrap
Alternative:
Expose funcs for creating a stacktrace to add an eris.Stack to the external error type (only applicable for owned types)
Describe the bug
To Reproduce
Expected behavior
Screenshots
Additional context
Describe the bug
while using Wrap or Wrapf, wrapPCs stack array must be checked before getting values from it. it is not always populated, for instance, if you are in a go routine, then you have no stack trace there. I put a code snippet for that.
To Reproduce
Steps to reproduce the behavior:
package main
import (
"fmt"
"time"
"github.com/rotisserie/eris"
)
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
go func() {
err := dummyStack()
fmt.Println(eris.Wrap(err, "my wrap func").Error())
}()
time.Sleep(1 * time.Second)
}
func dummyStack() error {
return eris.New("my little tiny error")
}
Expected behavior
stack operation needs to be enhanced. So, when you call Wrap in the go routine or main go routine, there is no stack to use in wrap.
code steps are:
https://github.com/rotisserie/eris/blob/master/eris.go#L69
https://github.com/rotisserie/eris/blob/master/stack.go#L90
and boom
Screenshots
panic: runtime error: index out of range [0] with length 0
goroutine 18 [running]:
github.com/rotisserie/eris.(*stack).insertPC(0xc000102000, 0xc000100200, 0x0, 0x40)
/go/pkg/mod/github.com/rotisserie/[email protected]/stack.go:90 +0x303
github.com/rotisserie/eris.wrap(0x10f3420, 0xc000106030, 0xc000108020, 0xc, 0xc, 0xc000106030)
/go/pkg/mod/github.com/rotisserie/[email protected]/eris.go:69 +0x351
github.com/rotisserie/eris.Wrap(0x10f3420, 0xc000106030, 0x10d5d1d, 0xc, 0x0, 0x0)
/go/pkg/mod/github.com/rotisserie/[email protected]/eris.go:38 +0xa3
main.main.func2()
/go/cmd/playground.go:19 +0x67
created by main.main
/go/cmd/playground.go:17 +0x57
exit status 2
Desktop (please complete the following information):
Additional context
before inserting stack, it might be good to check have a stack first, but i don't know how will change stack formating
// insertPC inserts a wrap error program counter (pc) into the correct place of the root error stack trace.
func (s *stack) insertPC(wrapPCs stack) {
if len(wrapPCs) == 1 {
// append the pc to the end if there's only one
*s = append(*s, wrapPCs[0])
return
}
for at, f := range *s {
////===>> we don't know we have a stack at wrapPC ???
if f == wrapPCs[0] {
// break if the stack already contains the pc
break
} else if f == wrapPCs[1] {
// insert the first pc into the stack if the second pc is found
*s = insert(*s, wrapPCs[0], at)
break
}
}
}
The current trace order is root first and the wrapped calls last, it will be nice to have a way to invert this order
This is related to disabling stack trace at the error type level as opposed to formatting.
In the doc comment you have the example code
if eris.Is(err, NotFound) || eris.Cause(err) == NotFound
I think the second half is redundant. The only way Is
returns false is if it reaches the end of the chain, which means that the last error in the chain would already have been compared to NotFound
.
Describe the bug
The go.mod file contains the path "github.com/morningvera/eris" instead of "github.com/rotisserie/eris".
To Reproduce
go get github.com/rotisserie/eris
Expected behavior
The module is installed.
Is your feature request related to a problem? Please describe.
Currently, file, line, and method names are inconvenient to access UnpackedError object. It will be useful to have getters for some of these.
Describe the solution you'd like
API can be
Is your feature request related to a problem? Please describe.
I would like to call eris.Wrap inside a utility Logging function but have it attribute the stack to where my function is called vs where .Wrap is called. (e.g. a typical skip level arg)
Describe the solution you'd like
I would prefer to call eris.Wrap inside mypackage.LogError instead of passing it in. But have eris skip a stack level and report one level above instead of inside my utility function.
So imagine I have mypackage.LogError(eris.Wrap(err, "blah"));
But instead I want to hide the eris.Wrap call inside mypackage.LogError(err, "blah") so that I don't have to litter my code with eris.Wrap everywhere.
I want to tell eris.Wrap to skip the immediate stack frame and record the one above as the frame.
Describe alternatives you've considered
Putting mypackage.LogError(eris.Wrap()) all over my code.
Additional context
Add any other context or screenshots about the feature request here.
Add support for passing encoding errors over the wire for GRPC/HTTP call and an ability to decode the same error received.
Sorry, I am afraid that I'm not sure when I should use eris.New() or eris.NewGlobal(). What is difference between eris.New() and eris.NewGlobal()? Would you mind providing us more details, please? Thank you
For completion, we should offer an As
method like the one in Go 1.13 errors (https://golang.org/pkg/errors/#As). We should try to make this more reliable than Go's version by preventing panics: "As will panic if target is not a non-nil pointer to either a type that implements error, or to any interface type." Seems like we could just return false in these cases instead.
Describe the bug
To Reproduce
Expected behavior
Screenshots
Additional context
This could be really useful debugging aspect if developers want to focus on some keywords in error trace
Is your feature request related to a problem? Please describe.
I'm using a message queue that utilizes gob/encoding for encoding arbitrary data into messages. I have messages that need to persist errors between various points of interaction. I would like a simple way of including errors in this, while maintaining all the stack traces and various benefits eris provides.
Describe the solution you'd like
Provide a companion API to eris.ToJSON and eris.ToString (or at least just JSON). Ideally, these functions would take the output of eris.ToJSON and when passed into the new eris.FromJSON, we get back an error (that implements the interface) and has all the relevant stack/external info from wrapping errors.
Alternatively, you could add a companion method to eris.Unpack called eris.Pack that would take an UnpackedError and return a regular error, again keeping all the information.
Describe alternatives you've considered
Manually JSON encoding/decoding, however after crossing this boundary, no code can access the eris functions like eris.Cause, which are very useful for unwrapping.
Thanks for considering.
I came across some issues that suggested CallersFrames is preferred over how we're currently getting stack traces. This may not apply to us but we should make sure of it. For reference:
Have an is() method for Unwrap to check for opaqueness
Ways to error match
When logging to Sentry, error chain trace is missing. Text representation of wrapped errors is there, but no File:Location
trace.
Using provided example:
go run examples/sentry/example.go -dsn=<Valid Sentry DSN>
Results in Sentry FULL mode:
EXCEPTION(most recent call first)
*eris.rootError
test
*eris.wrapError
wrap 1: test
*eris.wrapError
wrap 2: wrap 1: test
*eris.wrapError
wrap 3: wrap 2: wrap 1: test
example.go in main at line 54
})
if initErr != nil {
log.Fatalf("failed to initialize Sentry: %v", initErr)
}
sentry.CaptureException(err)
sentry.Flush(time.Second * 5)
}
Results in Sentry RAW mode:
EXCEPTION(most recent call first)
*eris.wrapError: wrap 3: wrap 2: wrap 1: test
File "example.go", line 54, in main
sentry.CaptureException(err)
Is your feature request related to a problem? Please describe.
Currently, it is not possible to show/hide a certain part of the error frame. For ex., only show the method name or line number instead of a complete frame.
Describe the solution you'd like
One solution could be to provide some utility methods for the format object, like format.Show(file, method, line)
and users can pass format.Show(true, true, false).
Describe alternatives you've considered
Another solution could be to have an object like options
and users could pass options.line = false
or something like that.
Should it work if any part of the target error chain matches the error? Or should we require it to include all layers of the target chain?
Basically which of these example targets should return true for an error a: b: c
?
a: b
, a: c
, b: a
, b: d
, d: a: b: c
, a: b: c: d
, b: c
Is your feature request related to a problem? Please describe.
When getting errors from other libraries that use github.com/pkg/errors
or forks of it, I noticed that the error is just flattened by calling error.Error()
and then returning a rootError
.
This is fine for custom errors, but pkg/errors
is very widespread and integration with it would make the created errors more complete.
Describe the solution you'd like
It would be nice if eris
tries to unpack the error instead of just turning it into string, by recursively calling Unpack
. As pkg/errors
is very popular, checking for the old func Cause() error
in addition to func Unpack() error
would be great.
Not just errors from pkg/errors
but any error in general that implements Unpack
makes sense to unpack in my opinion.
Not sure how to unmangle the stack trace though.
Describe alternatives you've considered
Additional context
Is your feature request related to a problem? Please describe.
A potential user requested support for uploading stacks to Sentry (https://github.com/getsentry/sentry).
Describe the solution you'd like
If possible, it would be nice to come up with a general solution that works for more than one error monitoring library.
Do we always want to return all three pieces (name, file, line number)? Or do we want to let users decide what to print? This could include an option to shorten file paths (to just the file name?).
This could also include an option for printing logical stack traces instead of full stack traces (see https://middlemost.com/failure-is-your-domain/).
Is your feature request related to a problem? Please describe.
When I'm wrapping an error, I often have some interesting data that I'd like to include in the wrapping that can be programmatically accessed later. For example: I have an error produced in the process of doing some I/O, and I want to return an error that both wraps that error and also includes some information about the larger operation I was trying to perform, so that the caller can either respond in some way it deems appropriate, or log some structured data that can be easily retrieved later, or so on. I want stack traces to continue to be generated as if I were just wrapping with a string.
Describe the solution you'd like
I'm thinking of adding a Wraps
(s for structured) that takes an error
. The provided error will be used by the wrapError
to:
Error()
output.Is()
, As()
(if I return eris.Wraps(err, &MyError{...})
, then that returned error should yield true for `eris.As(err, &MyError{}). similarly).Unwrap()
will remain unchanged so that traversing the causal chain remains functional.
Describe alternatives you've considered
**Additional context
None, I think. I started prototyping this out but am as yet unsure if my current approach will prove satisfactory, but I thought to leave a note here early to gather any feedback.
Is your feature request related to a problem? Please describe.
eris.ToJSON
& eris.ToString
doesn't capture wrapped error stacks after joining multiple errors with standard errors.Join
. Even though the data is there.
func main() {
errOne := eris.New("error one")
errTwo := eris.New("error two")
errThree := eris.Wrap(errors.Join(errTwo, errOne), "error three")
fmt.Println(eris.ToString(errThree, true))
}
// Outputs:
// error three
// main.main:/tmp/sandbox2016565250/prog.go:14
// error two
// error one
This is because the eris.Unpack
expects the the error to always be a linear chain of eris errors ending with one external error. The un-wrap loop breaks upon finding the first "external error". In the above case being described, the Error chain would be something like this: *eris.rootError
-> `*errors.joinError{errs: []error{*eris.rootError, *eris.rootError}}.
Describe the solution you'd like
Update the eris.Unpack
to expect multiple external errors in the chain of eris errors.
something like this:
// UnpackV2 returns a human-readable UnpackedError type for a given error.
func UnpackV2(err error) UnpackedErrorV2 {
var upErr UnpackedErrorV2
for err != nil {
switch err := err.(type) {
case *rootError:
upErr.ErrChain = append(upErr.ErrChain, ErrRoot{
Msg: err.msg,
Stack: err.stack.get(),
})
case *wrapError:
// prepend links in stack trace order
upErr.ErrChain = append(upErr.ErrChain, ErrLink{
Msg: err.msg,
Frame: err.frame.get(),
})
default:
upErr.ErrChain = append(upErr.ErrChain, ErrExternal(err))
}
err = Unwrap(err)
}
return upErr
}
type UnpackedErrorV2 struct {
ErrChain []interface{
errType() string
formatJSON() map[string]interface{}
formatStr() string
}
}
Describe alternatives you've considered
I've considered following feature request, although the blast radius seems too big in that so I was trying to imagine a smaller and backward-compatible way of doing this.
Additional context
When using a custom error and then wrapping that error with eris.Wrap it's not possible to use errors.As to identify if error is made of target, even if Unwrap is implemented.
package main
import (
"errors"
"fmt"
"github.com/rotisserie/eris"
)
type AnError struct {
Msg string
Err error
}
func (ae AnError) Error() string {
return ae.Msg
}
func (ae AnError) Unwrap() error {
return ae.Err
}
func main() {
aerror := AnError{Msg: "invalid", Err: eris.New("eris test error")}
berr := eris.Wrap(aerror, "the error")
switch {
case errors.As(berr, &AnError{}):
fmt.Println("anerror")
}
}
I expected this code should print "anerror", if I instead wrap the error with fmt.Errorf and %w, it works as expected.
Describe the bug
eris.ToString
panics. Latest master.
BTW, eris.ToString
isn't available in latest released version of library, that's why I've switched to master.
To Reproduce
func main() {
err := eris.New("oops")
err = eris.Wrap(err, "oops 2")
fmt.Println(eris.ToString(err, true))
}
Expected behavior
Stacktrace.
Actual behavior
$ go run main.go
panic: runtime error: index out of range [1] with length 1
goroutine 1 [running]:
github.com/rotisserie/eris.(*Stack).insertFrame(0xc00007ec28, 0xc0000a40f0, 0x1, 0x1)
/Users/dobegor/go/pkg/mod/github.com/rotisserie/[email protected]/stack.go:25 +0x805
github.com/rotisserie/eris.(*UnpackedError).unpackWrapErr(0xc00007ec18, 0xc0000a40c0)
/Users/dobegor/go/pkg/mod/github.com/rotisserie/[email protected]/format.go:234 +0x2b4
github.com/rotisserie/eris.Unpack(0x111e300, 0xc0000a40c0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/dobegor/go/pkg/mod/github.com/rotisserie/[email protected]/format.go:51 +0x168
github.com/rotisserie/eris.ToCustomString(0x111e300, 0xc0000a40c0, 0x1, 0x10ff8b7, 0x1, 0x10ff8b8, 0x1, 0x10ff8ab, 0x1, 0x10ff8b7, ...)
/Users/dobegor/go/pkg/mod/github.com/rotisserie/[email protected]/format.go:73 +0x50
github.com/rotisserie/eris.ToString(0x111e300, 0xc0000a40c0, 0x10ffd01, 0x6, 0x111e300)
/Users/dobegor/go/pkg/mod/github.com/rotisserie/[email protected]/format.go:113 +0x1b3
main.main()
/Users/dobegor/coding/email/main.go:163 +0xbe
exit status 2
Describe the bug
Because error wrapping just wraps a ptr to the global val, we can see errors in the stack traces if multiple errors are wrapped before printing or logging. Basically every time the global is wrapped, it ends up resetting the stack for every error that wrapped it before.
To Reproduce
Observe that the root stack trace for err1 is incorrect in this case. It will be the same as err2 (apart from the inserted wrap frame).
err1 := eris.Wrap(ErrBadRequest, "test 1")
err2 := eris.Wrap(ErrBadRequest, "test 2")
fmt.Printf("%+v\n", err1)
fmt.Printf("%+v\n", err2)
Expected behavior
Wrapping global vals should produce consistent stack traces for all errors. We probably need to deep copy the global so that wrapping it produces an error that can't be interfered with.
Error levels like Info, Debug, Warn, Panic can be a really useful debugging feature.
according to the document of Wrap(),
// Wrap adds additional context to all error types while maintaining the type of the original error.
//
// This method behaves differently for each error type. For root errors, the stack trace is reset to the current
// callers which ensures traces are correct when using global/sentinel error values. Wrapped error types are simply
// wrapped with the new context. For external types (i.e. something other than root or wrap errors), this method
// attempts to unwrap them while building a new error chain. If an external type does not implement the unwrap
// interface, it flattens the error and creates a new root error from it before wrapping with the additional
// context.
it says for external types, it attempts to unwrap the (the unwrap interface), but I didn't find the Unwrap() is called
btw, what is the best practice to wrap an external error, say
type MyError struct {
Code int // error code
}
Is your feature request related to a problem? Please describe.
75(3)5Describe the solution you'd like))((
((((@))))Describe alternatives you've considered
Additional context
#- _7_ππππππlook)blook)
Is your feature request related to a problem? Please describe.
Since the UnWrappedError object stores the complete trace information, it will be cool to have some filtering operations on error traces. This can be a really useful debugging tool
Describe the solution you'd like
Multiple ways to do it. We can allow string matching filters or lambda functions.
Additional context
Exploring some potential use cases might help coming up with a better API
It probably makes sense to separate the jobs in our current workflows so that we don't have to duplicate them for PRs and merges to main. Example: we could have a lint.yml
that defines the lint workflow for both push
and pull_request
. For the test workflow, we need to figure out how to handle slight differences between the two (e.g., the push
case uploads the test coverage results to CodeCov).
Is your feature request related to a problem? Please describe.
Implement new API to have only one error package to manage all common errors related cases/problems.
With this change, I don't have to import other errors packages and eris would become the ultimate solution for almost
all error handling cases.
Describe the solution you'd like
Add/Import more functions and functionalities to this pkg. I've prepared a go docs:
// Wraps adds additional context to all error types while maintaining the type of the original error.
//
// This is a convenience method for wrapping errors with stack trace and is otherwise the same as Wrap(err, "").
func Wraps(err error) error
// Append is a helper function that will append more errors onto an Error in order to create a larger multi-error.
func Append(err error, errs ...error) error
// WrappedErrors returns the list of errors that this Error is wrapping.
func WrappedErrors(err error) []error
// Group is a collection of goroutines that returns errors that need to be coalesced.
type Group struct {
// if true group will continue execution until the last goroutine is finished.
// It will return multierror in case of more than one error, which can be
// turn into the slice with WrappedErrors.
ContinueOnError bool
}
// WithContext returns a new Group and an associated Context derived from ctx.
func WithContext(ctx context.Context) (*Group, context.Context)
// Go calls the given function in a new goroutine. It can work in two modes
//
// 1. The first call to return a non-nil error cancels the group
//
// 2. If the function returns an error it is added to the
// group multierror which is returned by Wait.
//
// You can control this behavour by setting ContinueOnError in Group.
func (g *Group) Go(f func() error)
// Wait blocks until all function calls from the Go method have returned, then returns either
// the first non-nill error (if any) or multierror. This depends on ContinueOnError setting.
func (g *Group) Wait() error
Describe alternatives you've considered
Still using other packages like github.com/hashicorp/go-multierror
or golang.org/x/sync/errgroup
Additional context
I know maybe this Issue should be split into smaller ones but I thought it would be easier to gather all this into one Issue.
One real example that shows how multerror
and Wraps
can be used.
// This is a version with comments. Below you can find two versions to compare readability.
func (p *Postgres) ExecuteInTx(ctx context.Context, fn func(tx *Tx) error) error {
tx, err := p.BeginTx(ctx)
if err != nil {
// just save a stacktrace without any message
// it would be nice to have a function like pkgerros WithStack()
// maybe with shorter name (eris.Stack() or eris.Wraps()),
// to tell that I want to capture only a stack without any message.
// right now I use Wrap for this.
return eris.Wrap(err, "")
}
if err := fn(tx); err != nil {
if rerr := tx.Rollback(ctx); rerr != nil {
// "github.com/hashicorp/go-multierror"
// It would be great to have api to combine
// multiple errors into one. Ofc I can use
// eris.Wrap here but it seems a bit overkill
// to have two calls in stacktrace when in fact
// I just need two error messages combined into one.
// This can be used also in many other places
err = multierror.Append(err, rerr)
}
return eris.Wrap(err, "") // eris.Wraps()
}
return eris.Wrap(tx.Commit(ctx), "") // eris.Wraps())
}
// This is version with external package and Wrap
func (p *Postgres) ExecuteInTx(ctx context.Context, fn func(tx *Tx) error) error {
tx, err := p.BeginTx(ctx)
if err != nil {
return eris.Wrap(err, "")
}
if err := fn(tx); err != nil {
if rerr := tx.Rollback(ctx); rerr != nil {
err = multierror.Append(err, rerr)
}
return eris.Wrap(err, "")
}
return eris.Wrap(tx.Commit(ctx), "")
}
// This is version with eris only.
func (p *Postgres) ExecuteInTx(ctx context.Context, fn func(tx *Tx) error) error {
tx, err := p.BeginTx(ctx)
if err != nil {
return eris.Wraps(err)
}
if err := fn(tx); err != nil {
if rerr := tx.Rollback(ctx); rerr != nil {
err = eris.Append(err, rerr)
}
return eris.Wraps(err)
}
return eris.Wraps(tx.Commit(ctx))
}
Sometimes errors can have multiple types which makes the root cause slightly ambiguous. The Is() method doesn't really solve this because it'll return true for any error type that appears in the chain. Would be nice to have a method that returns the cause of the error. Is it just the first error in the chain?
This is separate from adding examples in the docs. We should maintain some examples in error_test.go.
Occasionally, it could be a good idea to create a new error with a type and some debug info (e.g. eris.New(type string, info string)
, eris.New("error not found", "sql no rows")
). This will make comparing errors to error not found
easy while also letting users add debug context to new errors (which could be shown or not based on a format option). This could also make it easier to send debug info to logs while hiding debug info from clients.
Even though the Wrap/f methods are preferred, we should also allow users to do something like this: Errorf("some context: %w", err)
Describe the bug
eris.As
does not work as intended when wrapping with eris.Wrap()
To Reproduce
Run this program:
package main
import (
"errors"
"fmt"
"github.com/rotisserie/eris"
)
type X struct {
}
func (X) Error() string {
return "X"
}
func main() {
original := X{}
wrap1std := fmt.Errorf("wrap1: %w", original)
wrap2std := fmt.Errorf("wrap2: %w", wrap1std)
wrap1eris := eris.Wrap(original, "wrap1")
wrap2eris := eris.Wrap(wrap1eris, "wrap2")
var x X
fmt.Println(errors.As(wrap2std, &x))
fmt.Println(errors.As(wrap2eris, &x))
fmt.Println(eris.As(wrap2std, &x))
fmt.Println(eris.As(wrap2eris, &x))
}
Expected behavior
The program should output true
4 times. Instead it outputs:
true
true
true
false
Go: 1.16.5
Eris: github.com/rotisserie/[email protected]
Describe the bug
All tests are failing, if using gollvm .
To Reproduce
Steps to reproduce the behavior:
$sudo cp -R * /usr/
$go version
$ go test ./...
--- FAIL: TestGlobalStack (0.00s)
stack_test.go:165: eris_test.TestLocalStack: expected number of root error frames { 5 } got { 1 }
--- FAIL: TestGoRoutines (0.25s)
stack_test.go:151: eris_test.TestLocalStack: expected wrap func name { eris_test.TestGoRoutines.func1 } got { eris_test.TestGoRoutines..func1 }
FAIL
FAIL github.com/rotisserie/eris 0.732s
FAIL
Expected behavior
Probably I expected that (at least some) tests would succeed.
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
Additional context
I was able to run your benchmarks:
$ make bench
Running benchmark tests
goos: linux
goarch: amd64
pkg: github.com/rotisserie/eris/benchmark
BenchmarkWrap/std_errors_1_layers-2 1383235 826 ns/op 88 B/op 4 allocs/op
BenchmarkWrap/pkg_errors_1_layers-2 41601 26564 ns/op 3760 B/op 11 allocs/op
BenchmarkWrap/eris_1_layers-2 26457 43931 ns/op 7960 B/op 25 allocs/op
BenchmarkWrap/std_errors_10_layers-2 155646 7690 ns/op 1056 B/op 31 allocs/op
BenchmarkWrap/pkg_errors_10_layers-2 8312 151270 ns/op 20897 B/op 74 allocs/op
BenchmarkWrap/eris_10_layers-2 4574 240630 ns/op 41155 B/op 88 allocs/op
BenchmarkWrap/std_errors_100_layers-2 7444 134451 ns/op 52054 B/op 301 allocs/op
BenchmarkWrap/pkg_errors_100_layers-2 888 1366197 ns/op 192272 B/op 704 allocs/op
BenchmarkWrap/eris_100_layers-2 433 2489635 ns/op 373100 B/op 718 allocs/op
BenchmarkWrap/std_errors_1000_layers-2 213 5172471 ns/op 5263831 B/op 3002 allocs/op
BenchmarkWrap/pkg_errors_1000_layers-2 94 14191480 ns/op 1906061 B/op 7005 allocs/op
BenchmarkWrap/eris_1000_layers-2 21 52687659 ns/op 3692592 B/op 7020 allocs/op
BenchmarkFormat/std_errors_1_layers-2 3405969 364 ns/op 32 B/op 1 allocs/op
BenchmarkFormat/pkg_errors_1_layers-2 1527482 770 ns/op 96 B/op 3 allocs/op
BenchmarkFormat/eris_1_layers-2 159298 7606 ns/op 920 B/op 23 allocs/op
BenchmarkFormat/std_errors_10_layers-2 2634273 438 ns/op 96 B/op 1 allocs/op
BenchmarkFormat/pkg_errors_10_layers-2 299623 4335 ns/op 1056 B/op 21 allocs/op
BenchmarkFormat/eris_10_layers-2 35584 28518 ns/op 6336 B/op 95 allocs/op
BenchmarkFormat/std_errors_100_layers-2 778509 1550 ns/op 1024 B/op 1 allocs/op
BenchmarkFormat/pkg_errors_100_layers-2 14496 79682 ns/op 52259 B/op 201 allocs/op
BenchmarkFormat/eris_100_layers-2 1969 650065 ns/op 371932 B/op 815 allocs/op
BenchmarkFormat/std_errors_1000_layers-2 116500 10131 ns/op 10240 B/op 1 allocs/op
BenchmarkFormat/pkg_errors_1000_layers-2 183 6927381 ns/op 5265777 B/op 2003 allocs/op
BenchmarkFormat/eris_1000_layers-2 20 50511730 ns/op 35846958 B/op 8018 allocs/op
BenchmarkStack/pkg_errors_1_layers-2 33230 34056 ns/op 2256 B/op 49 allocs/op
BenchmarkStack/eris_1_layers-2 56469 20795 ns/op 4760 B/op 67 allocs/op
BenchmarkStack/pkg_errors_10_layers-2 5378 207628 ns/op 12223 B/op 265 allocs/op
BenchmarkStack/eris_10_layers-2 19087 62277 ns/op 18516 B/op 202 allocs/op
BenchmarkStack/pkg_errors_100_layers-2 256 4283942 ns/op 122995 B/op 2425 allocs/op
BenchmarkStack/eris_100_layers-2 978 1490096 ns/op 855978 B/op 1553 allocs/op
BenchmarkStack/pkg_errors_1000_layers-2 2 936693294 ns/op 577890956 B/op 28246 allocs/op
BenchmarkStack/eris_1000_layers-2 14 97293242 ns/op 79552572 B/op 15096 allocs/op
BenchmarkJSON/eris_1_layers-2 15138 73616 ns/op 6885 B/op 111 allocs/op
BenchmarkJSON/eris_10_layers-2 4846 215716 ns/op 26201 B/op 403 allocs/op
BenchmarkJSON/eris_100_layers-2 523 2267172 ns/op 507676 B/op 3289 allocs/op
BenchmarkJSON/eris_1000_layers-2 18 94480986 ns/op 34654235 B/op 32142 allocs/op
PASS
ok github.com/rotisserie/eris/benchmark 65.102s
CC @thanm @cherrymui for any gollvm related issues
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.