1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-10-31 00:07:40 +02:00

Wrap errors returned from Detect and New in sdk/resource (#3844)

* Update Detect and New to wrap errors

* Add TestNewWrapedError

Test that New returns an error that can be unwrapped.

* Add changes to changelog

* Clarify and simplify errors
This commit is contained in:
Tyler Yahn
2023-03-08 15:15:27 -08:00
committed by GitHub
parent f993fac236
commit 1626ff746f
4 changed files with 70 additions and 22 deletions

View File

@@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Changed
- Avoid creating new objects on all calls to `WithDeferredSetup` and `SkipContextSetup` in OpenTracing bridge. (#3833)
- The `New` and `Detect` functions from `go.opentelemetry.io/otel/sdk/resource` return errors that wrap underlying errors instead of just containing the underlying error strings. (#3844)
### Removed

View File

@@ -18,6 +18,7 @@ import (
"context"
"errors"
"fmt"
"strings"
)
var (
@@ -45,28 +46,65 @@ type Detector interface {
// Detect calls all input detectors sequentially and merges each result with the previous one.
// It returns the merged error too.
func Detect(ctx context.Context, detectors ...Detector) (*Resource, error) {
var autoDetectedRes *Resource
var errInfo []string
r := new(Resource)
return r, detect(ctx, r, detectors)
}
// detect runs all detectors using ctx and merges the result into res. This
// assumes res is allocated and not nil, it will panic otherwise.
func detect(ctx context.Context, res *Resource, detectors []Detector) error {
var (
r *Resource
errs detectErrs
err error
)
for _, detector := range detectors {
if detector == nil {
continue
}
res, err := detector.Detect(ctx)
r, err = detector.Detect(ctx)
if err != nil {
errInfo = append(errInfo, err.Error())
errs = append(errs, err)
if !errors.Is(err, ErrPartialResource) {
continue
}
}
autoDetectedRes, err = Merge(autoDetectedRes, res)
r, err = Merge(res, r)
if err != nil {
errInfo = append(errInfo, err.Error())
errs = append(errs, err)
}
*res = *r
}
var aggregatedError error
if len(errInfo) > 0 {
aggregatedError = fmt.Errorf("detecting resources: %s", errInfo)
if len(errs) == 0 {
return nil
}
return autoDetectedRes, aggregatedError
return errs
}
type detectErrs []error
func (e detectErrs) Error() string {
errStr := make([]string, len(e))
for i, err := range e {
errStr[i] = fmt.Sprintf("* %s", err)
}
format := "%d errors occurred detecting resource:\n\t%s"
return fmt.Sprintf(format, len(e), strings.Join(errStr, "\n\t"))
}
func (e detectErrs) Unwrap() error {
switch len(e) {
case 0:
return nil
case 1:
return e[0]
}
return e[1:]
}
func (e detectErrs) Is(target error) bool {
return len(e) != 0 && errors.Is(e[0], target)
}

View File

@@ -17,7 +17,6 @@ package resource // import "go.opentelemetry.io/otel/sdk/resource"
import (
"context"
"errors"
"fmt"
"sync"
"go.opentelemetry.io/otel"
@@ -51,17 +50,8 @@ func New(ctx context.Context, opts ...Option) (*Resource, error) {
cfg = opt.apply(cfg)
}
resource, err := Detect(ctx, cfg.detectors...)
var err2 error
resource, err2 = Merge(resource, &Resource{schemaURL: cfg.schemaURL})
if err == nil {
err = err2
} else if err2 != nil {
err = fmt.Errorf("detecting resources: %s", []string{err.Error(), err2.Error()})
}
return resource, err
r := &Resource{schemaURL: cfg.schemaURL}
return r, detect(ctx, r, cfg.detectors)
}
// NewWithAttributes creates a resource from attrs and associates the resource with a

View File

@@ -452,6 +452,25 @@ func TestNew(t *testing.T) {
}
}
func TestNewWrapedError(t *testing.T) {
localErr := errors.New("local error")
_, err := resource.New(
context.Background(),
resource.WithDetectors(
resource.StringDetector("", "", func() (string, error) {
return "", localErr
}),
resource.StringDetector("", "", func() (string, error) {
return "", assert.AnError
}),
),
)
assert.ErrorIs(t, err, localErr)
assert.ErrorIs(t, err, assert.AnError)
assert.NotErrorIs(t, err, errors.New("false positive error"))
}
func TestWithOSType(t *testing.T) {
mockRuntimeProviders()
t.Cleanup(restoreAttributesProviders)