New Upstream Release - golang-github-getlantern-errors
Ready changes
Summary
Merged new upstream version: 1.0.3 (was: 1.0.1).
Diff
diff --git a/LICENSE b/LICENSE
index 416dd69..2d1cb59 100644
--- a/LICENSE
+++ b/LICENSE
@@ -187,7 +187,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright 2018 Brave New Software Project, Inc.
+ Copyright 2021 Brave New Software Project, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/debian/changelog b/debian/changelog
index 19d6924..101c0cf 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+golang-github-getlantern-errors (1.0.3-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+ * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk> Wed, 07 Jun 2023 21:37:40 -0000
+
golang-github-getlantern-errors (0.0~git20190325.abdb3e3-2) unstable; urgency=medium
* Add missing (build-)dep on getlantern-hex (Closes: #927250)
diff --git a/errors.go b/errors.go
index 8b2b84f..8ff64d6 100644
--- a/errors.go
+++ b/errors.go
@@ -8,8 +8,8 @@ Package errors defines error types used across Lantern project.
or
- n, err := Foo()
- return n, errors.Wrap(err)
+ n, err := Foo()
+ return n, errors.Wrap(err)
New() method will create a new error with err as its cause. Wrap will wrap err,
returning nil if err is nil. If err is an error from Go's standard library,
@@ -18,15 +18,15 @@ return value of err.Error().
One can record the operation on which the error occurred using Op():
- return n, errors.New("Unable to do Foo: %v", err).Op("FooDooer")
+ return n, errors.New("Unable to do Foo: %v", err).Op("FooDooer")
One can also record additional data:
- return n, errors.
- New("Unable to do Foo: %v", err).
- Op("FooDooer").
- With("mydata", "myvalue").
- With("moredata", 5)
+ return n, errors.
+ New("Unable to do Foo: %v", err).
+ Op("FooDooer").
+ With("mydata", "myvalue").
+ With("moredata", 5)
When used with github.com/getlantern/ops, Error captures its current context
and propagates that data for use in calling layers.
@@ -81,7 +81,6 @@ import (
"unicode"
"github.com/getlantern/context"
- "github.com/getlantern/hidden"
"github.com/getlantern/ops"
"github.com/go-stack/stack"
)
@@ -123,13 +122,9 @@ type Error interface {
RootCause() error
}
-type structured struct {
- id uint64
- hiddenID string
+type baseError struct {
data context.Map
context context.Map
- wrapped error
- cause Error
callStack stack.CallStack
}
@@ -142,16 +137,22 @@ func New(desc string, args ...interface{}) Error {
// NewOffset is like New but offsets the stack by the given offset. This is
// useful for utilities like golog that may create errors on behalf of others.
func NewOffset(offset int, desc string, args ...interface{}) Error {
- var cause error
+ e := buildError(desc, fmt.Sprintf(desc, args...))
+ e.attachStack(2 + offset)
for _, arg := range args {
- err, isError := arg.(error)
+ wrapped, isError := arg.(error)
if isError {
- cause = err
- break
+ op, _, _, extraData := parseError(wrapped)
+ if op != "" {
+ e.Op(op)
+ }
+ for k, v := range extraData {
+ e.data[k] = v
+ }
+ we := &wrappingError{e, wrapped}
+ return we
}
}
- e := buildError(desc, fmt.Sprintf(desc, args...), nil, Wrap(cause))
- e.attachStack(2 + offset)
return e
}
@@ -160,33 +161,57 @@ func NewOffset(offset int, desc string, args ...interface{}) Error {
// errors.Wrap(s.l.Close()) regardless there's an error or not. If the error is
// already wrapped, it is returned as is.
func Wrap(err error) Error {
- return wrapSkipFrames(err, 1)
+ if err == nil {
+ return nil
+ }
+ if e, ok := err.(Error); ok {
+ return e
+ }
+
+ op, goType, desc, extraData := parseError(err)
+ if desc == "" {
+ desc = err.Error()
+ }
+ e := buildError(desc, desc)
+ e.attachStack(2)
+ if op != "" {
+ e.Op(op)
+ }
+ e.data["error_type"] = goType
+ for k, v := range extraData {
+ e.data[k] = v
+ }
+
+ // Make sure we maintain existing wrapping.
+ if uw, ok := err.(unwrapper); ok {
+ return &wrappingError{e, uw.Unwrap()}
+ }
+
+ return e
}
// Fill implements the method from the context.Contextual interface.
-func (e *structured) Fill(m context.Map) {
- if e != nil {
- if e.cause != nil {
- // Include data from cause, which supercedes context
- e.cause.Fill(m)
- }
- // Include the context, which supercedes the cause
- for key, value := range e.context {
- m[key] = value
- }
- // Now include the error's data, which supercedes everything
- for key, value := range e.data {
- m[key] = value
- }
+func (e *baseError) Fill(m context.Map) {
+ if e == nil {
+ return
+ }
+
+ // Include the context, which supercedes the cause
+ for key, value := range e.context {
+ m[key] = value
+ }
+ // Now include the error's data, which supercedes everything
+ for key, value := range e.data {
+ m[key] = value
}
}
-func (e *structured) Op(op string) Error {
+func (e *baseError) Op(op string) Error {
e.data["error_op"] = op
return e
}
-func (e *structured) With(key string, value interface{}) Error {
+func (e *baseError) With(key string, value interface{}) Error {
parts := strings.FieldsFunc(key, func(c rune) bool {
return !unicode.IsLetter(c) && !unicode.IsNumber(c)
})
@@ -204,140 +229,164 @@ func (e *structured) With(key string, value interface{}) Error {
return e
}
-func (e *structured) RootCause() error {
- if e.cause == nil {
- if e.wrapped != nil {
- return e.wrapped
- }
- return e
- }
- return e.cause.RootCause()
+func (e *baseError) RootCause() error {
+ return e
}
-func (e *structured) ErrorClean() string {
+func (e *baseError) ErrorClean() string {
return e.data["error"].(string)
}
// Error satisfies the error interface
-func (e *structured) Error() string {
- return e.data["error_text"].(string) + e.hiddenID
+func (e *baseError) Error() string {
+ return e.data["error_text"].(string)
+}
+
+func (e *baseError) MultiLinePrinter() func(*bytes.Buffer) bool {
+ return e.topLevelPrinter()
}
-func (e *structured) MultiLinePrinter() func(buf *bytes.Buffer) bool {
- first := true
- indent := false
- err := e
+func (e *baseError) topLevelPrinter() func(*bytes.Buffer) bool {
+ printingStack := false
stackPosition := 0
- switchedCause := false
return func(buf *bytes.Buffer) bool {
- if indent {
- buf.WriteString(" ")
- }
- if first {
+ if !printingStack {
buf.WriteString(e.Error())
- first = false
- indent = true
- return true
- }
- if switchedCause {
- fmt.Fprintf(buf, "Caused by: %v", err)
- if err.callStack != nil && len(err.callStack) > 0 {
- switchedCause = false
- indent = true
- return true
- }
- if err.cause == nil {
- return false
- }
- err = err.cause.(*structured)
- return true
- }
- if stackPosition < len(err.callStack) {
- buf.WriteString("at ")
- call := err.callStack[stackPosition]
- fmt.Fprintf(buf, "%+n (%s:%d)", call, call, call)
- stackPosition++
- }
- if stackPosition >= len(err.callStack) {
- switch cause := err.cause.(type) {
- case *structured:
- err = cause
- indent = false
- stackPosition = 0
- switchedCause = true
- default:
- return false
- }
+ printingStack = true
+ return len(e.callStack) > 0
}
- return err != nil
+ call := e.callStack[stackPosition]
+ fmt.Fprintf(buf, " at %+n (%s:%d)", call, call, call)
+ stackPosition++
+ return stackPosition < len(e.callStack)
}
}
-func wrapSkipFrames(err error, skip int) Error {
- if err == nil {
- return nil
- }
-
- // Look for *structureds
- if e, ok := err.(*structured); ok {
- return e
- }
-
- var cause Error
- // Look for hidden *structureds
- hiddenIDs, err2 := hidden.Extract(err.Error())
- if err2 == nil && len(hiddenIDs) > 0 {
- // Take the first hidden ID as our cause
- cause = get(hiddenIDs[0])
- }
-
- // Create a new *structured
- return buildError("", "", err, cause)
-}
-
-func (e *structured) attachStack(skip int) {
+func (e *baseError) attachStack(skip int) {
call := stack.Caller(skip)
e.callStack = stack.Trace().TrimBelow(call)
e.data["error_location"] = fmt.Sprintf("%+n (%s:%d)", call, call, call)
}
-func buildError(desc string, fullText string, wrapped error, cause Error) *structured {
- e := &structured{
+func buildError(desc string, fullText string) *baseError {
+ e := &baseError{
data: make(context.Map),
// We capture the current context to allow it to propagate to higher layers.
context: ops.AsMap(nil, false),
- wrapped: wrapped,
- cause: cause,
}
- e.save()
- errorType := "errors.Error"
- if wrapped != nil {
- op, goType, wrappedDesc, extra := parseError(wrapped)
- if desc == "" {
- desc = wrappedDesc
+ e.data["error"] = desc
+ if fullText != "" {
+ e.data["error_text"] = fullText
+ } else {
+ e.data["error_text"] = desc
+ }
+ e.data["error_type"] = "errors.Error"
+
+ return e
+}
+
+type topLevelPrinter interface {
+ // Returns a printer which prints only the top-level error and any associated stack trace. The
+ // output of this printer will be a prefix of the output from MultiLinePrinter().
+ topLevelPrinter() func(*bytes.Buffer) bool
+}
+
+type unwrapper interface {
+ Unwrap() error
+}
+
+type wrappingError struct {
+ *baseError
+ wrapped error
+}
+
+// Implements error unwrapping as described in the standard library's errors package:
+// https://golang.org/pkg/errors/#pkg-overview
+func (e *wrappingError) Unwrap() error {
+ return e.wrapped
+}
+
+func (e *wrappingError) Fill(m context.Map) {
+ type filler interface{ Fill(context.Map) }
+
+ applyToChain(e.wrapped, func(err error) {
+ if f, ok := err.(filler); ok {
+ f.Fill(m)
}
- e.Op(op)
- errorType = goType
- if extra != nil {
- for key, value := range extra {
- e.data[key] = value
- }
+ })
+ e.baseError.Fill(m)
+}
+
+func (e *wrappingError) RootCause() error {
+ return unwrapToRoot(e)
+}
+
+func (e *wrappingError) MultiLinePrinter() func(*bytes.Buffer) bool {
+ var (
+ currentPrinter = e.baseError.topLevelPrinter()
+ nextErr = e.wrapped
+ prefix = ""
+ )
+ return func(buf *bytes.Buffer) bool {
+ fmt.Fprint(buf, prefix)
+ if currentPrinter(buf) {
+ prefix = ""
+ return true
+ }
+ if nextErr == nil {
+ return false
+ }
+ currentPrinter = getTopLevelPrinter(nextErr)
+ prefix = "Caused by: "
+ if uw, ok := nextErr.(unwrapper); ok {
+ nextErr = uw.Unwrap()
+ } else {
+ nextErr = nil
}
+ return true
}
+}
- cleanedDesc := hidden.Clean(desc)
- e.data["error"] = cleanedDesc
- if fullText != "" {
- e.data["error_text"] = hidden.Clean(fullText)
- } else {
- e.data["error_text"] = cleanedDesc
+// We have to implement these two methods or the fluid syntax will result in the embedded *baseError
+// being returned, not the *wrappingError.
+
+func (e *wrappingError) Op(op string) Error {
+ e.baseError = e.baseError.Op(op).(*baseError)
+ return e
+}
+
+func (e *wrappingError) With(key string, value interface{}) Error {
+ e.baseError = e.baseError.With(key, value).(*baseError)
+ return e
+}
+
+func getTopLevelPrinter(err error) func(*bytes.Buffer) bool {
+ if tlp, ok := err.(topLevelPrinter); ok {
+ return tlp.topLevelPrinter()
+ }
+ return func(buf *bytes.Buffer) bool {
+ fmt.Fprint(buf, err)
+ return false
}
- e.data["error_type"] = errorType
+}
+func unwrapToRoot(e error) error {
+ if uw, ok := e.(unwrapper); ok {
+ return unwrapToRoot(uw.Unwrap())
+ }
return e
}
+// Applies f to the chain of errors unwrapped from err. The function is applied to the root cause
+// first and err last.
+func applyToChain(err error, f func(error)) {
+ if uw, ok := err.(unwrapper); ok {
+ applyToChain(uw.Unwrap(), f)
+ }
+ f(err)
+}
+
func parseError(err error) (op string, goType string, desc string, extra map[string]string) {
extra = make(map[string]string)
diff --git a/errors_test.go b/errors_test.go
index 7c4887a..d0f78d5 100644
--- a/errors_test.go
+++ b/errors_test.go
@@ -2,63 +2,33 @@ package errors
import (
"bytes"
+ "errors"
"fmt"
+ "io"
+ "net"
"regexp"
"testing"
"github.com/getlantern/context"
- "github.com/getlantern/hidden"
- "github.com/getlantern/ops"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
var (
- replaceNumbers = regexp.MustCompile("[0-9]+")
+ replaceNumbers = regexp.MustCompile(`[0-9]+`)
+ replaceArch = regexp.MustCompile(`asm_[a-z0-9]+\.s`)
)
-func TestFull(t *testing.T) {
- var firstErr Error
-
- // Iterate past the size of the hidden buffer
- for i := 0; i < len(hiddenErrors)*2; i++ {
- op := ops.Begin("op1").Set("ca", 100).Set("cd", 100)
- e := New("Hello %v", "There").Op("My Op").With("DaTa_1", 1)
- op.End()
- if firstErr == nil {
- firstErr = e
- }
- assert.Equal(t, "Hello There", e.Error()[:11])
- op = ops.Begin("op2").Set("ca", 200).Set("cb", 200).Set("cc", 200)
- e3 := Wrap(fmt.Errorf("I'm wrapping your text: %v", e)).Op("outer op").With("dATA+1", i).With("cb", 300)
- op.End()
- assert.Equal(t, e, e3.(*structured).cause, "Wrapping a regular error should have extracted the contained *Error")
- m := make(context.Map)
- e3.Fill(m)
- assert.Equal(t, i, m["data_1"], "Error's data should dominate all")
- assert.Equal(t, 200, m["ca"], "Error's context should dominate cause")
- assert.Equal(t, 300, m["cb"], "Error's data should dominate its context")
- assert.Equal(t, 200, m["cc"], "Error's context should come through")
- assert.Equal(t, 100, m["cd"], "Cause's context should come through")
- assert.Equal(t, "My Op", e.(*structured).data["error_op"], "Op should be available from cause")
-
- for _, call := range e3.(*structured).callStack {
- t.Logf("at %v", call)
- }
- }
-
- e3 := Wrap(fmt.Errorf("I'm wrapping your text: %v", firstErr)).With("a", 2)
- assert.Nil(t, e3.(*structured).cause, "Wrapping an *Error that's no longer buffered should have yielded no cause")
-}
-
func TestNewWithCause(t *testing.T) {
cause := buildCause()
outer := New("Hello %v", cause)
- assert.Equal(t, "Hello World", hidden.Clean(outer.Error()))
- assert.Equal(t, "Hello %v", outer.(*structured).ErrorClean())
+ assert.Equal(t, "Hello World", outer.Error())
+ assert.Equal(t, "Hello %v", outer.ErrorClean())
+ require.IsType(t, (*wrappingError)(nil), outer, "Including an error arg should have resulted in a *wrappingError")
assert.Equal(t,
"github.com/getlantern/errors.TestNewWithCause (errors_test.go:999)",
- replaceNumbers.ReplaceAllString(outer.(*structured).data["error_location"].(string), "999"))
- assert.Equal(t, cause, outer.(*structured).cause)
+ replaceNumbers.ReplaceAllString(outer.(*wrappingError).data["error_location"].(string), "999"))
+ assert.Equal(t, cause, outer.(*wrappingError).wrapped)
// Make sure that stacktrace prints out okay
buf := &bytes.Buffer{}
@@ -73,12 +43,12 @@ func TestNewWithCause(t *testing.T) {
expected := `Hello World
at github.com/getlantern/errors.TestNewWithCause (errors_test.go:999)
at testing.tRunner (testing.go:999)
- at runtime.goexit (asm_amd999.s:999)
+ at runtime.goexit (asm_arch.s:999)
Caused by: World
at github.com/getlantern/errors.buildCause (errors_test.go:999)
at github.com/getlantern/errors.TestNewWithCause (errors_test.go:999)
at testing.tRunner (testing.go:999)
- at runtime.goexit (asm_amd999.s:999)
+ at runtime.goexit (asm_arch.s:999)
Caused by: orld
Caused by: ld
at github.com/getlantern/errors.buildSubSubCause (errors_test.go:999)
@@ -86,11 +56,16 @@ Caused by: ld
at github.com/getlantern/errors.buildCause (errors_test.go:999)
at github.com/getlantern/errors.TestNewWithCause (errors_test.go:999)
at testing.tRunner (testing.go:999)
- at runtime.goexit (asm_amd999.s:999)
+ at runtime.goexit (asm_arch.s:999)
Caused by: d
`
- assert.Equal(t, expected, replaceNumbers.ReplaceAllString(hidden.Clean(buf.String()), "999"))
+ assert.Equal(t,
+ expected,
+ replaceArch.ReplaceAllString(
+ replaceNumbers.ReplaceAllString(buf.String(), "999"),
+ "asm_arch.s",
+ ))
assert.Equal(t, buildSubSubSubCause(), outer.RootCause())
}
@@ -99,7 +74,7 @@ func buildCause() Error {
}
func buildSubCause() error {
- return fmt.Errorf("or%v", buildSubSubCause())
+ return fmt.Errorf("or%w", buildSubSubCause())
}
func buildSubSubCause() error {
@@ -118,25 +93,50 @@ func doWrapNil() error {
return Wrap(nil)
}
-func TestHiddenWithCause(t *testing.T) {
- e1 := fmt.Errorf("I failed %v", "dude")
- e2 := New("I wrap: %v", e1)
- e3 := fmt.Errorf("Hiding %v", e2)
- // clear hidden buffer
- hiddenErrors = make([]*structured, 100)
- e4 := Wrap(e3)
- e5 := New("I'm really outer: %v", e4)
+func TestFill(t *testing.T) {
+ e := New("something happened").(*baseError)
+ e2 := New("uh oh: %v", e).(*wrappingError)
+ e3 := fmt.Errorf("hmm: %w", e2)
+ e4 := New("umm: %v", e3).(*wrappingError)
+
+ e4.data["name"] = "e4"
+ e2.data["name"] = "e2"
+ e.data["name"] = "e"
+ e2.data["k"] = "v2"
+ e.data["k"] = "v"
+ e.data["a"] = "b"
+
+ m := context.Map{}
+ e4.Fill(m)
+ require.Equal(t, "e4", m["name"])
+ require.Equal(t, "v2", m["k"])
+ require.Equal(t, "b", m["a"])
+}
- buf := &bytes.Buffer{}
- print := e5.MultiLinePrinter()
- for {
- more := print(buf)
- buf.WriteByte('\n')
- if !more {
- break
- }
- }
- fmt.Println(buf.String())
- // We're not asserting the output because we're just making sure that printing
- // doesn't panic. If we get to this point without panicking, we're happy.
+// Ensures that this package implements error unwrapping as described in:
+// https://golang.org/pkg/errors/#pkg-overview
+func TestUnwrapping(t *testing.T) {
+ sampleUnwrapper := fmt.Errorf("%w", fmt.Errorf("something happened"))
+
+ errNoCause := New("something happened")
+ _, ok := errNoCause.(unwrapper)
+ assert.False(t, ok, "error with no cause should not implement Unwrap method")
+ wrappedNoCause := Wrap(errNoCause)
+ _, ok = wrappedNoCause.(unwrapper)
+ assert.False(t, ok, "wrapped error with no cause should not implement Unwrap method")
+
+ errFromEOF := New("something happened: %v", io.EOF)
+ assert.Implements(t, &sampleUnwrapper, errFromEOF)
+ assert.True(t, errors.Is(errFromEOF, io.EOF))
+ wrappedFromEOF := Wrap(errFromEOF)
+ assert.Implements(t, &sampleUnwrapper, wrappedFromEOF)
+ assert.True(t, errors.Is(wrappedFromEOF, io.EOF))
+
+ addrErrHolder := new(net.AddrError)
+ errFromAddrErr := New("something happend: %v", new(net.AddrError))
+ assert.Implements(t, &sampleUnwrapper, errFromAddrErr)
+ assert.True(t, errors.As(errFromAddrErr, &addrErrHolder))
+ wrappedFromAddrErr := Wrap(errFromAddrErr)
+ assert.Implements(t, &sampleUnwrapper, wrappedFromAddrErr)
+ assert.True(t, errors.As(wrappedFromAddrErr, &addrErrHolder))
}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..f2580a5
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,12 @@
+module github.com/getlantern/errors
+
+go 1.0
+
+require (
+ github.com/getlantern/context v0.0.0-20220418194847-3d5e7a086201
+ github.com/getlantern/ops v0.0.0-20220713155959-1315d978fff7
+ github.com/go-stack/stack v1.8.1
+ github.com/stretchr/testify v1.8.0
+)
+
+require go.opentelemetry.io/otel v1.9.0 // indirect
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..74f9ddb
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,32 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/getlantern/context v0.0.0-20220418194847-3d5e7a086201 h1:oEZYEpZo28Wdx+5FZo4aU7JFXu0WG/4wJWese5reQSA=
+github.com/getlantern/context v0.0.0-20220418194847-3d5e7a086201/go.mod h1:Y9WZUHEb+mpra02CbQ/QczLUe6f0Dezxaw5DCJlJQGo=
+github.com/getlantern/ops v0.0.0-20220713155959-1315d978fff7 h1:Od0xvR4iK3gZwhkIbxnHw4Teusv+n5G/F9dW7x+C2f0=
+github.com/getlantern/ops v0.0.0-20220713155959-1315d978fff7/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
+github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
+github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
+github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
+github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+go.opentelemetry.io/otel v1.9.0 h1:8WZNQFIB2a71LnANS9JeyidJKKGOOremcUtb/OtHISw=
+go.opentelemetry.io/otel v1.9.0/go.mod h1:np4EoPGzoPs3O67xUVNoPPcmSvsfOxNlNA4F4AC+0Eo=
+go.opentelemetry.io/otel/trace v1.9.0 h1:oZaCNJUjWcg60VXWee8lJKlqhPbXAPB51URuR47pQYc=
+go.opentelemetry.io/otel/trace v1.9.0/go.mod h1:2737Q0MuG8q1uILYm2YYVkAyLtOofiTNGg6VODnOiPo=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/hide.go b/hide.go
deleted file mode 100644
index f10d863..0000000
--- a/hide.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package errors
-
-import (
- "encoding/binary"
- "sync"
-
- "github.com/getlantern/hidden"
-)
-
-var (
- hiddenErrors = make([]*structured, 100)
- nextID = uint64(0)
- hiddenMutex sync.RWMutex
-)
-
-// This trick saves the error to a ring buffer and embeds a non-printing
-// hiddenID in the error's description, so that if the errors is later wrapped
-// by a standard error using something like
-// fmt.Errorf("An error occurred: %v", thisError), we can subsequently extract
-// the error simply using the hiddenID in the string.
-func (e *structured) save() {
- hiddenMutex.Lock()
- b := make([]byte, 8)
- binary.BigEndian.PutUint64(b, nextID)
- e.id = nextID
- e.hiddenID = hidden.ToString(b)
- hiddenErrors[idxForID(nextID)] = e
- nextID++
- hiddenMutex.Unlock()
-}
-
-func get(hiddenID []byte) Error {
- if len(hiddenID) != 8 {
- return nil
- }
- id := binary.BigEndian.Uint64(hiddenID)
- hiddenMutex.RLock()
- err := hiddenErrors[idxForID(id)]
- hiddenMutex.RUnlock()
- if err != nil && err.id == id {
- // Found it!
- return err
- }
- // buffer has rolled over
- return nil
-}
-
-func idxForID(id uint64) int {
- return int(id % uint64(len(hiddenErrors)))
-}