blob: c02aeefdde531768cc4b00f3ebca409299e3fed0 [file] [log] [blame]
Abhay Kumar40252eb2025-10-13 13:25:53 +00001// Copyright The OpenTelemetry Authors
2// SPDX-License-Identifier: Apache-2.0
3
4package resource // import "go.opentelemetry.io/otel/sdk/resource"
5
6import (
7 "context"
8 "errors"
9 "fmt"
10)
11
12// ErrPartialResource is returned by a detector when complete source
13// information for a Resource is unavailable or the source information
14// contains invalid values that are omitted from the returned Resource.
15var ErrPartialResource = errors.New("partial resource")
16
17// Detector detects OpenTelemetry resource information.
18type Detector interface {
19 // DO NOT CHANGE: any modification will not be backwards compatible and
20 // must never be done outside of a new major release.
21
22 // Detect returns an initialized Resource based on gathered information.
23 // If the source information to construct a Resource contains invalid
24 // values, a Resource is returned with the valid parts of the source
25 // information used for initialization along with an appropriately
26 // wrapped ErrPartialResource error.
27 Detect(ctx context.Context) (*Resource, error)
28 // DO NOT CHANGE: any modification will not be backwards compatible and
29 // must never be done outside of a new major release.
30}
31
32// Detect returns a new [Resource] merged from all the Resources each of the
33// detectors produces. Each of the detectors are called sequentially, in the
34// order they are passed, merging the produced resource into the previous.
35//
36// This may return a partial Resource along with an error containing
37// [ErrPartialResource] if that error is returned from a detector. It may also
38// return a merge-conflicting Resource along with an error containing
39// [ErrSchemaURLConflict] if merging Resources from different detectors results
40// in a schema URL conflict. It is up to the caller to determine if this
41// returned Resource should be used or not.
42//
43// If one of the detectors returns an error that is not [ErrPartialResource],
44// the resource produced by the detector will not be merged and the returned
45// error will wrap that detector's error.
46func Detect(ctx context.Context, detectors ...Detector) (*Resource, error) {
47 r := new(Resource)
48 return r, detect(ctx, r, detectors)
49}
50
51// detect runs all detectors using ctx and merges the result into res. This
52// assumes res is allocated and not nil, it will panic otherwise.
53//
54// If the detectors or merging resources produces any errors (i.e.
55// [ErrPartialResource] [ErrSchemaURLConflict]), a single error wrapping all of
56// these errors will be returned. Otherwise, nil is returned.
57func detect(ctx context.Context, res *Resource, detectors []Detector) error {
58 var (
59 r *Resource
60 err error
61 e error
62 )
63
64 for _, detector := range detectors {
65 if detector == nil {
66 continue
67 }
68 r, e = detector.Detect(ctx)
69 if e != nil {
70 err = errors.Join(err, e)
71 if !errors.Is(e, ErrPartialResource) {
72 continue
73 }
74 }
75 r, e = Merge(res, r)
76 if e != nil {
77 err = errors.Join(err, e)
78 }
79 *res = *r
80 }
81
82 if err != nil {
83 if errors.Is(err, ErrSchemaURLConflict) {
84 // If there has been a merge conflict, ensure the resource has no
85 // schema URL.
86 res.schemaURL = ""
87 }
88
89 err = fmt.Errorf("error detecting resource: %w", err)
90 }
91 return err
92}