This commit is contained in:
3
vendor/go.opentelemetry.io/otel/sdk/resource/README.md
generated
vendored
Normal file
3
vendor/go.opentelemetry.io/otel/sdk/resource/README.md
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# SDK Resource
|
||||
|
||||
[](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/resource)
|
118
vendor/go.opentelemetry.io/otel/sdk/resource/auto.go
generated
vendored
Normal file
118
vendor/go.opentelemetry.io/otel/sdk/resource/auto.go
generated
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrPartialResource is returned by a detector when complete source
|
||||
// information for a Resource is unavailable or the source information
|
||||
// contains invalid values that are omitted from the returned Resource.
|
||||
var ErrPartialResource = errors.New("partial resource")
|
||||
|
||||
// Detector detects OpenTelemetry resource information.
|
||||
type Detector interface {
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
|
||||
// Detect returns an initialized Resource based on gathered information.
|
||||
// If the source information to construct a Resource contains invalid
|
||||
// values, a Resource is returned with the valid parts of the source
|
||||
// information used for initialization along with an appropriately
|
||||
// wrapped ErrPartialResource error.
|
||||
Detect(ctx context.Context) (*Resource, error)
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
}
|
||||
|
||||
// Detect returns a new [Resource] merged from all the Resources each of the
|
||||
// detectors produces. Each of the detectors are called sequentially, in the
|
||||
// order they are passed, merging the produced resource into the previous.
|
||||
//
|
||||
// This may return a partial Resource along with an error containing
|
||||
// [ErrPartialResource] if that error is returned from a detector. It may also
|
||||
// return a merge-conflicting Resource along with an error containing
|
||||
// [ErrSchemaURLConflict] if merging Resources from different detectors results
|
||||
// in a schema URL conflict. It is up to the caller to determine if this
|
||||
// returned Resource should be used or not.
|
||||
//
|
||||
// If one of the detectors returns an error that is not [ErrPartialResource],
|
||||
// the resource produced by the detector will not be merged and the returned
|
||||
// error will wrap that detector's error.
|
||||
func Detect(ctx context.Context, detectors ...Detector) (*Resource, error) {
|
||||
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.
|
||||
//
|
||||
// If the detectors or merging resources produces any errors (i.e.
|
||||
// [ErrPartialResource] [ErrSchemaURLConflict]), a single error wrapping all of
|
||||
// these errors will be returned. Otherwise, nil is returned.
|
||||
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
|
||||
}
|
||||
r, err = detector.Detect(ctx)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
if !errors.Is(err, ErrPartialResource) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
r, err = Merge(res, r)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
*res = *r
|
||||
}
|
||||
|
||||
if len(errs) == 0 {
|
||||
return nil
|
||||
}
|
||||
if errors.Is(errs, ErrSchemaURLConflict) {
|
||||
// If there has been a merge conflict, ensure the resource has no
|
||||
// schema URL.
|
||||
res.schemaURL = ""
|
||||
}
|
||||
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)
|
||||
}
|
118
vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go
generated
vendored
Normal file
118
vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go
generated
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/sdk"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||
)
|
||||
|
||||
type (
|
||||
// telemetrySDK is a Detector that provides information about
|
||||
// the OpenTelemetry SDK used. This Detector is included as a
|
||||
// builtin. If these resource attributes are not wanted, use
|
||||
// the WithTelemetrySDK(nil) or WithoutBuiltin() options to
|
||||
// explicitly disable them.
|
||||
telemetrySDK struct{}
|
||||
|
||||
// host is a Detector that provides information about the host
|
||||
// being run on. This Detector is included as a builtin. If
|
||||
// these resource attributes are not wanted, use the
|
||||
// WithHost(nil) or WithoutBuiltin() options to explicitly
|
||||
// disable them.
|
||||
host struct{}
|
||||
|
||||
stringDetector struct {
|
||||
schemaURL string
|
||||
K attribute.Key
|
||||
F func() (string, error)
|
||||
}
|
||||
|
||||
defaultServiceNameDetector struct{}
|
||||
|
||||
defaultServiceInstanceIDDetector struct{}
|
||||
)
|
||||
|
||||
var (
|
||||
_ Detector = telemetrySDK{}
|
||||
_ Detector = host{}
|
||||
_ Detector = stringDetector{}
|
||||
_ Detector = defaultServiceNameDetector{}
|
||||
_ Detector = defaultServiceInstanceIDDetector{}
|
||||
)
|
||||
|
||||
// Detect returns a *Resource that describes the OpenTelemetry SDK used.
|
||||
func (telemetrySDK) Detect(context.Context) (*Resource, error) {
|
||||
return NewWithAttributes(
|
||||
semconv.SchemaURL,
|
||||
semconv.TelemetrySDKName("opentelemetry"),
|
||||
semconv.TelemetrySDKLanguageGo,
|
||||
semconv.TelemetrySDKVersion(sdk.Version()),
|
||||
), nil
|
||||
}
|
||||
|
||||
// Detect returns a *Resource that describes the host being run on.
|
||||
func (host) Detect(ctx context.Context) (*Resource, error) {
|
||||
return StringDetector(semconv.SchemaURL, semconv.HostNameKey, os.Hostname).Detect(ctx)
|
||||
}
|
||||
|
||||
// StringDetector returns a Detector that will produce a *Resource
|
||||
// containing the string as a value corresponding to k. The resulting Resource
|
||||
// will have the specified schemaURL.
|
||||
func StringDetector(schemaURL string, k attribute.Key, f func() (string, error)) Detector {
|
||||
return stringDetector{schemaURL: schemaURL, K: k, F: f}
|
||||
}
|
||||
|
||||
// Detect returns a *Resource that describes the string as a value
|
||||
// corresponding to attribute.Key as well as the specific schemaURL.
|
||||
func (sd stringDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
value, err := sd.F()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", string(sd.K), err)
|
||||
}
|
||||
a := sd.K.String(value)
|
||||
if !a.Valid() {
|
||||
return nil, fmt.Errorf("invalid attribute: %q -> %q", a.Key, a.Value.Emit())
|
||||
}
|
||||
return NewWithAttributes(sd.schemaURL, sd.K.String(value)), nil
|
||||
}
|
||||
|
||||
// Detect implements Detector.
|
||||
func (defaultServiceNameDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
return StringDetector(
|
||||
semconv.SchemaURL,
|
||||
semconv.ServiceNameKey,
|
||||
func() (string, error) {
|
||||
executable, err := os.Executable()
|
||||
if err != nil {
|
||||
return "unknown_service:go", nil
|
||||
}
|
||||
return "unknown_service:" + filepath.Base(executable), nil
|
||||
},
|
||||
).Detect(ctx)
|
||||
}
|
||||
|
||||
// Detect implements Detector.
|
||||
func (defaultServiceInstanceIDDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
return StringDetector(
|
||||
semconv.SchemaURL,
|
||||
semconv.ServiceInstanceIDKey,
|
||||
func() (string, error) {
|
||||
version4Uuid, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return version4Uuid.String(), nil
|
||||
},
|
||||
).Detect(ctx)
|
||||
}
|
195
vendor/go.opentelemetry.io/otel/sdk/resource/config.go
generated
vendored
Normal file
195
vendor/go.opentelemetry.io/otel/sdk/resource/config.go
generated
vendored
Normal file
@ -0,0 +1,195 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
)
|
||||
|
||||
// config contains configuration for Resource creation.
|
||||
type config struct {
|
||||
// detectors that will be evaluated.
|
||||
detectors []Detector
|
||||
// SchemaURL to associate with the Resource.
|
||||
schemaURL string
|
||||
}
|
||||
|
||||
// Option is the interface that applies a configuration option.
|
||||
type Option interface {
|
||||
// apply sets the Option value of a config.
|
||||
apply(config) config
|
||||
}
|
||||
|
||||
// WithAttributes adds attributes to the configured Resource.
|
||||
func WithAttributes(attributes ...attribute.KeyValue) Option {
|
||||
return WithDetectors(detectAttributes{attributes})
|
||||
}
|
||||
|
||||
type detectAttributes struct {
|
||||
attributes []attribute.KeyValue
|
||||
}
|
||||
|
||||
func (d detectAttributes) Detect(context.Context) (*Resource, error) {
|
||||
return NewSchemaless(d.attributes...), nil
|
||||
}
|
||||
|
||||
// WithDetectors adds detectors to be evaluated for the configured resource.
|
||||
func WithDetectors(detectors ...Detector) Option {
|
||||
return detectorsOption{detectors: detectors}
|
||||
}
|
||||
|
||||
type detectorsOption struct {
|
||||
detectors []Detector
|
||||
}
|
||||
|
||||
func (o detectorsOption) apply(cfg config) config {
|
||||
cfg.detectors = append(cfg.detectors, o.detectors...)
|
||||
return cfg
|
||||
}
|
||||
|
||||
// WithFromEnv adds attributes from environment variables to the configured resource.
|
||||
func WithFromEnv() Option {
|
||||
return WithDetectors(fromEnv{})
|
||||
}
|
||||
|
||||
// WithHost adds attributes from the host to the configured resource.
|
||||
func WithHost() Option {
|
||||
return WithDetectors(host{})
|
||||
}
|
||||
|
||||
// WithHostID adds host ID information to the configured resource.
|
||||
func WithHostID() Option {
|
||||
return WithDetectors(hostIDDetector{})
|
||||
}
|
||||
|
||||
// WithTelemetrySDK adds TelemetrySDK version info to the configured resource.
|
||||
func WithTelemetrySDK() Option {
|
||||
return WithDetectors(telemetrySDK{})
|
||||
}
|
||||
|
||||
// WithSchemaURL sets the schema URL for the configured resource.
|
||||
func WithSchemaURL(schemaURL string) Option {
|
||||
return schemaURLOption(schemaURL)
|
||||
}
|
||||
|
||||
type schemaURLOption string
|
||||
|
||||
func (o schemaURLOption) apply(cfg config) config {
|
||||
cfg.schemaURL = string(o)
|
||||
return cfg
|
||||
}
|
||||
|
||||
// WithOS adds all the OS attributes to the configured Resource.
|
||||
// See individual WithOS* functions to configure specific attributes.
|
||||
func WithOS() Option {
|
||||
return WithDetectors(
|
||||
osTypeDetector{},
|
||||
osDescriptionDetector{},
|
||||
)
|
||||
}
|
||||
|
||||
// WithOSType adds an attribute with the operating system type to the configured Resource.
|
||||
func WithOSType() Option {
|
||||
return WithDetectors(osTypeDetector{})
|
||||
}
|
||||
|
||||
// WithOSDescription adds an attribute with the operating system description to the
|
||||
// configured Resource. The formatted string is equivalent to the output of the
|
||||
// `uname -snrvm` command.
|
||||
func WithOSDescription() Option {
|
||||
return WithDetectors(osDescriptionDetector{})
|
||||
}
|
||||
|
||||
// WithProcess adds all the Process attributes to the configured Resource.
|
||||
//
|
||||
// Warning! This option will include process command line arguments. If these
|
||||
// contain sensitive information it will be included in the exported resource.
|
||||
//
|
||||
// This option is equivalent to calling WithProcessPID,
|
||||
// WithProcessExecutableName, WithProcessExecutablePath,
|
||||
// WithProcessCommandArgs, WithProcessOwner, WithProcessRuntimeName,
|
||||
// WithProcessRuntimeVersion, and WithProcessRuntimeDescription. See each
|
||||
// option function for information about what resource attributes each
|
||||
// includes.
|
||||
func WithProcess() Option {
|
||||
return WithDetectors(
|
||||
processPIDDetector{},
|
||||
processExecutableNameDetector{},
|
||||
processExecutablePathDetector{},
|
||||
processCommandArgsDetector{},
|
||||
processOwnerDetector{},
|
||||
processRuntimeNameDetector{},
|
||||
processRuntimeVersionDetector{},
|
||||
processRuntimeDescriptionDetector{},
|
||||
)
|
||||
}
|
||||
|
||||
// WithProcessPID adds an attribute with the process identifier (PID) to the
|
||||
// configured Resource.
|
||||
func WithProcessPID() Option {
|
||||
return WithDetectors(processPIDDetector{})
|
||||
}
|
||||
|
||||
// WithProcessExecutableName adds an attribute with the name of the process
|
||||
// executable to the configured Resource.
|
||||
func WithProcessExecutableName() Option {
|
||||
return WithDetectors(processExecutableNameDetector{})
|
||||
}
|
||||
|
||||
// WithProcessExecutablePath adds an attribute with the full path to the process
|
||||
// executable to the configured Resource.
|
||||
func WithProcessExecutablePath() Option {
|
||||
return WithDetectors(processExecutablePathDetector{})
|
||||
}
|
||||
|
||||
// WithProcessCommandArgs adds an attribute with all the command arguments (including
|
||||
// the command/executable itself) as received by the process to the configured
|
||||
// Resource.
|
||||
//
|
||||
// Warning! This option will include process command line arguments. If these
|
||||
// contain sensitive information it will be included in the exported resource.
|
||||
func WithProcessCommandArgs() Option {
|
||||
return WithDetectors(processCommandArgsDetector{})
|
||||
}
|
||||
|
||||
// WithProcessOwner adds an attribute with the username of the user that owns the process
|
||||
// to the configured Resource.
|
||||
func WithProcessOwner() Option {
|
||||
return WithDetectors(processOwnerDetector{})
|
||||
}
|
||||
|
||||
// WithProcessRuntimeName adds an attribute with the name of the runtime of this
|
||||
// process to the configured Resource.
|
||||
func WithProcessRuntimeName() Option {
|
||||
return WithDetectors(processRuntimeNameDetector{})
|
||||
}
|
||||
|
||||
// WithProcessRuntimeVersion adds an attribute with the version of the runtime of
|
||||
// this process to the configured Resource.
|
||||
func WithProcessRuntimeVersion() Option {
|
||||
return WithDetectors(processRuntimeVersionDetector{})
|
||||
}
|
||||
|
||||
// WithProcessRuntimeDescription adds an attribute with an additional description
|
||||
// about the runtime of the process to the configured Resource.
|
||||
func WithProcessRuntimeDescription() Option {
|
||||
return WithDetectors(processRuntimeDescriptionDetector{})
|
||||
}
|
||||
|
||||
// WithContainer adds all the Container attributes to the configured Resource.
|
||||
// See individual WithContainer* functions to configure specific attributes.
|
||||
func WithContainer() Option {
|
||||
return WithDetectors(
|
||||
cgroupContainerIDDetector{},
|
||||
)
|
||||
}
|
||||
|
||||
// WithContainerID adds an attribute with the id of the container to the configured Resource.
|
||||
// Note: WithContainerID will not extract the correct container ID in an ECS environment.
|
||||
// Please use the ECS resource detector instead (https://pkg.go.dev/go.opentelemetry.io/contrib/detectors/aws/ecs).
|
||||
func WithContainerID() Option {
|
||||
return WithDetectors(cgroupContainerIDDetector{})
|
||||
}
|
89
vendor/go.opentelemetry.io/otel/sdk/resource/container.go
generated
vendored
Normal file
89
vendor/go.opentelemetry.io/otel/sdk/resource/container.go
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||
)
|
||||
|
||||
type containerIDProvider func() (string, error)
|
||||
|
||||
var (
|
||||
containerID containerIDProvider = getContainerIDFromCGroup
|
||||
cgroupContainerIDRe = regexp.MustCompile(`^.*/(?:.*[-:])?([0-9a-f]+)(?:\.|\s*$)`)
|
||||
)
|
||||
|
||||
type cgroupContainerIDDetector struct{}
|
||||
|
||||
const cgroupPath = "/proc/self/cgroup"
|
||||
|
||||
// Detect returns a *Resource that describes the id of the container.
|
||||
// If no container id found, an empty resource will be returned.
|
||||
func (cgroupContainerIDDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
containerID, err := containerID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if containerID == "" {
|
||||
return Empty(), nil
|
||||
}
|
||||
return NewWithAttributes(semconv.SchemaURL, semconv.ContainerID(containerID)), nil
|
||||
}
|
||||
|
||||
var (
|
||||
defaultOSStat = os.Stat
|
||||
osStat = defaultOSStat
|
||||
|
||||
defaultOSOpen = func(name string) (io.ReadCloser, error) {
|
||||
return os.Open(name)
|
||||
}
|
||||
osOpen = defaultOSOpen
|
||||
)
|
||||
|
||||
// getContainerIDFromCGroup returns the id of the container from the cgroup file.
|
||||
// If no container id found, an empty string will be returned.
|
||||
func getContainerIDFromCGroup() (string, error) {
|
||||
if _, err := osStat(cgroupPath); errors.Is(err, os.ErrNotExist) {
|
||||
// File does not exist, skip
|
||||
return "", nil
|
||||
}
|
||||
|
||||
file, err := osOpen(cgroupPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
return getContainerIDFromReader(file), nil
|
||||
}
|
||||
|
||||
// getContainerIDFromReader returns the id of the container from reader.
|
||||
func getContainerIDFromReader(reader io.Reader) string {
|
||||
scanner := bufio.NewScanner(reader)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
if id := getContainerIDFromLine(line); id != "" {
|
||||
return id
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// getContainerIDFromLine returns the id of the container from one string line.
|
||||
func getContainerIDFromLine(line string) string {
|
||||
matches := cgroupContainerIDRe.FindStringSubmatch(line)
|
||||
if len(matches) <= 1 {
|
||||
return ""
|
||||
}
|
||||
return matches[1]
|
||||
}
|
20
vendor/go.opentelemetry.io/otel/sdk/resource/doc.go
generated
vendored
Normal file
20
vendor/go.opentelemetry.io/otel/sdk/resource/doc.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package resource provides detecting and representing resources.
|
||||
//
|
||||
// The fundamental struct is a Resource which holds identifying information
|
||||
// about the entities for which telemetry is exported.
|
||||
//
|
||||
// To automatically construct Resources from an environment a Detector
|
||||
// interface is defined. Implementations of this interface can be passed to
|
||||
// the Detect function to generate a Resource from the merged information.
|
||||
//
|
||||
// To load a user defined Resource from the environment variable
|
||||
// OTEL_RESOURCE_ATTRIBUTES the FromEnv Detector can be used. It will interpret
|
||||
// the value as a list of comma delimited key/value pairs
|
||||
// (e.g. `<key1>=<value1>,<key2>=<value2>,...`).
|
||||
//
|
||||
// While this package provides a stable API,
|
||||
// the attributes added by resource detectors may change.
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
95
vendor/go.opentelemetry.io/otel/sdk/resource/env.go
generated
vendored
Normal file
95
vendor/go.opentelemetry.io/otel/sdk/resource/env.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||
)
|
||||
|
||||
const (
|
||||
// resourceAttrKey is the environment variable name OpenTelemetry Resource information will be read from.
|
||||
resourceAttrKey = "OTEL_RESOURCE_ATTRIBUTES" //nolint:gosec // False positive G101: Potential hardcoded credentials
|
||||
|
||||
// svcNameKey is the environment variable name that Service Name information will be read from.
|
||||
svcNameKey = "OTEL_SERVICE_NAME"
|
||||
)
|
||||
|
||||
// errMissingValue is returned when a resource value is missing.
|
||||
var errMissingValue = fmt.Errorf("%w: missing value", ErrPartialResource)
|
||||
|
||||
// fromEnv is a Detector that implements the Detector and collects
|
||||
// resources from environment. This Detector is included as a
|
||||
// builtin.
|
||||
type fromEnv struct{}
|
||||
|
||||
// compile time assertion that FromEnv implements Detector interface.
|
||||
var _ Detector = fromEnv{}
|
||||
|
||||
// Detect collects resources from environment.
|
||||
func (fromEnv) Detect(context.Context) (*Resource, error) {
|
||||
attrs := strings.TrimSpace(os.Getenv(resourceAttrKey))
|
||||
svcName := strings.TrimSpace(os.Getenv(svcNameKey))
|
||||
|
||||
if attrs == "" && svcName == "" {
|
||||
return Empty(), nil
|
||||
}
|
||||
|
||||
var res *Resource
|
||||
|
||||
if svcName != "" {
|
||||
res = NewSchemaless(semconv.ServiceName(svcName))
|
||||
}
|
||||
|
||||
r2, err := constructOTResources(attrs)
|
||||
|
||||
// Ensure that the resource with the service name from OTEL_SERVICE_NAME
|
||||
// takes precedence, if it was defined.
|
||||
res, err2 := Merge(r2, res)
|
||||
|
||||
if err == nil {
|
||||
err = err2
|
||||
} else if err2 != nil {
|
||||
err = fmt.Errorf("detecting resources: %s", []string{err.Error(), err2.Error()})
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func constructOTResources(s string) (*Resource, error) {
|
||||
if s == "" {
|
||||
return Empty(), nil
|
||||
}
|
||||
pairs := strings.Split(s, ",")
|
||||
var attrs []attribute.KeyValue
|
||||
var invalid []string
|
||||
for _, p := range pairs {
|
||||
k, v, found := strings.Cut(p, "=")
|
||||
if !found {
|
||||
invalid = append(invalid, p)
|
||||
continue
|
||||
}
|
||||
key := strings.TrimSpace(k)
|
||||
val, err := url.PathUnescape(strings.TrimSpace(v))
|
||||
if err != nil {
|
||||
// Retain original value if decoding fails, otherwise it will be
|
||||
// an empty string.
|
||||
val = v
|
||||
otel.Handle(err)
|
||||
}
|
||||
attrs = append(attrs, attribute.String(key, val))
|
||||
}
|
||||
var err error
|
||||
if len(invalid) > 0 {
|
||||
err = fmt.Errorf("%w: %v", errMissingValue, invalid)
|
||||
}
|
||||
return NewSchemaless(attrs...), err
|
||||
}
|
109
vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go
generated
vendored
Normal file
109
vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||
)
|
||||
|
||||
type hostIDProvider func() (string, error)
|
||||
|
||||
var defaultHostIDProvider hostIDProvider = platformHostIDReader.read
|
||||
|
||||
var hostID = defaultHostIDProvider
|
||||
|
||||
type hostIDReader interface {
|
||||
read() (string, error)
|
||||
}
|
||||
|
||||
type fileReader func(string) (string, error)
|
||||
|
||||
type commandExecutor func(string, ...string) (string, error)
|
||||
|
||||
// hostIDReaderBSD implements hostIDReader.
|
||||
type hostIDReaderBSD struct {
|
||||
execCommand commandExecutor
|
||||
readFile fileReader
|
||||
}
|
||||
|
||||
// read attempts to read the machine-id from /etc/hostid. If not found it will
|
||||
// execute `kenv -q smbios.system.uuid`. If neither location yields an id an
|
||||
// error will be returned.
|
||||
func (r *hostIDReaderBSD) read() (string, error) {
|
||||
if result, err := r.readFile("/etc/hostid"); err == nil {
|
||||
return strings.TrimSpace(result), nil
|
||||
}
|
||||
|
||||
if result, err := r.execCommand("kenv", "-q", "smbios.system.uuid"); err == nil {
|
||||
return strings.TrimSpace(result), nil
|
||||
}
|
||||
|
||||
return "", errors.New("host id not found in: /etc/hostid or kenv")
|
||||
}
|
||||
|
||||
// hostIDReaderDarwin implements hostIDReader.
|
||||
type hostIDReaderDarwin struct {
|
||||
execCommand commandExecutor
|
||||
}
|
||||
|
||||
// read executes `ioreg -rd1 -c "IOPlatformExpertDevice"` and parses host id
|
||||
// from the IOPlatformUUID line. If the command fails or the uuid cannot be
|
||||
// parsed an error will be returned.
|
||||
func (r *hostIDReaderDarwin) read() (string, error) {
|
||||
result, err := r.execCommand("ioreg", "-rd1", "-c", "IOPlatformExpertDevice")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
lines := strings.Split(result, "\n")
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "IOPlatformUUID") {
|
||||
parts := strings.Split(line, " = ")
|
||||
if len(parts) == 2 {
|
||||
return strings.Trim(parts[1], "\""), nil
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("could not parse IOPlatformUUID")
|
||||
}
|
||||
|
||||
type hostIDReaderLinux struct {
|
||||
readFile fileReader
|
||||
}
|
||||
|
||||
// read attempts to read the machine-id from /etc/machine-id followed by
|
||||
// /var/lib/dbus/machine-id. If neither location yields an ID an error will
|
||||
// be returned.
|
||||
func (r *hostIDReaderLinux) read() (string, error) {
|
||||
if result, err := r.readFile("/etc/machine-id"); err == nil {
|
||||
return strings.TrimSpace(result), nil
|
||||
}
|
||||
|
||||
if result, err := r.readFile("/var/lib/dbus/machine-id"); err == nil {
|
||||
return strings.TrimSpace(result), nil
|
||||
}
|
||||
|
||||
return "", errors.New("host id not found in: /etc/machine-id or /var/lib/dbus/machine-id")
|
||||
}
|
||||
|
||||
type hostIDDetector struct{}
|
||||
|
||||
// Detect returns a *Resource containing the platform specific host id.
|
||||
func (hostIDDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
hostID, err := hostID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewWithAttributes(
|
||||
semconv.SchemaURL,
|
||||
semconv.HostID(hostID),
|
||||
), nil
|
||||
}
|
12
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_bsd.go
generated
vendored
Normal file
12
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_bsd.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build dragonfly || freebsd || netbsd || openbsd || solaris
|
||||
// +build dragonfly freebsd netbsd openbsd solaris
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
var platformHostIDReader hostIDReader = &hostIDReaderBSD{
|
||||
execCommand: execCommand,
|
||||
readFile: readFile,
|
||||
}
|
8
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_darwin.go
generated
vendored
Normal file
8
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_darwin.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
var platformHostIDReader hostIDReader = &hostIDReaderDarwin{
|
||||
execCommand: execCommand,
|
||||
}
|
18
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_exec.go
generated
vendored
Normal file
18
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_exec.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build darwin || dragonfly || freebsd || netbsd || openbsd || solaris
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import "os/exec"
|
||||
|
||||
func execCommand(name string, arg ...string) (string, error) {
|
||||
cmd := exec.Command(name, arg...)
|
||||
b, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(b), nil
|
||||
}
|
11
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_linux.go
generated
vendored
Normal file
11
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_linux.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
var platformHostIDReader hostIDReader = &hostIDReaderLinux{
|
||||
readFile: readFile,
|
||||
}
|
17
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_readfile.go
generated
vendored
Normal file
17
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_readfile.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build linux || dragonfly || freebsd || netbsd || openbsd || solaris
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import "os"
|
||||
|
||||
func readFile(filename string) (string, error) {
|
||||
b, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(b), nil
|
||||
}
|
19
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_unsupported.go
generated
vendored
Normal file
19
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_unsupported.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows
|
||||
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
// hostIDReaderUnsupported is a placeholder implementation for operating systems
|
||||
// for which this project currently doesn't support host.id
|
||||
// attribute detection. See build tags declaration early on this file
|
||||
// for a list of unsupported OSes.
|
||||
type hostIDReaderUnsupported struct{}
|
||||
|
||||
func (*hostIDReaderUnsupported) read() (string, error) {
|
||||
return "<unknown>", nil
|
||||
}
|
||||
|
||||
var platformHostIDReader hostIDReader = &hostIDReaderUnsupported{}
|
37
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_windows.go
generated
vendored
Normal file
37
vendor/go.opentelemetry.io/otel/sdk/resource/host_id_windows.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
// implements hostIDReader
|
||||
type hostIDReaderWindows struct{}
|
||||
|
||||
// read reads MachineGuid from the windows registry key:
|
||||
// SOFTWARE\Microsoft\Cryptography
|
||||
func (*hostIDReaderWindows) read() (string, error) {
|
||||
k, err := registry.OpenKey(
|
||||
registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Cryptography`,
|
||||
registry.QUERY_VALUE|registry.WOW64_64KEY,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer k.Close()
|
||||
|
||||
guid, _, err := k.GetStringValue("MachineGuid")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return guid, nil
|
||||
}
|
||||
|
||||
var platformHostIDReader hostIDReader = &hostIDReaderWindows{}
|
89
vendor/go.opentelemetry.io/otel/sdk/resource/os.go
generated
vendored
Normal file
89
vendor/go.opentelemetry.io/otel/sdk/resource/os.go
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||
)
|
||||
|
||||
type osDescriptionProvider func() (string, error)
|
||||
|
||||
var defaultOSDescriptionProvider osDescriptionProvider = platformOSDescription
|
||||
|
||||
var osDescription = defaultOSDescriptionProvider
|
||||
|
||||
func setDefaultOSDescriptionProvider() {
|
||||
setOSDescriptionProvider(defaultOSDescriptionProvider)
|
||||
}
|
||||
|
||||
func setOSDescriptionProvider(osDescriptionProvider osDescriptionProvider) {
|
||||
osDescription = osDescriptionProvider
|
||||
}
|
||||
|
||||
type (
|
||||
osTypeDetector struct{}
|
||||
osDescriptionDetector struct{}
|
||||
)
|
||||
|
||||
// Detect returns a *Resource that describes the operating system type the
|
||||
// service is running on.
|
||||
func (osTypeDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
osType := runtimeOS()
|
||||
|
||||
osTypeAttribute := mapRuntimeOSToSemconvOSType(osType)
|
||||
|
||||
return NewWithAttributes(
|
||||
semconv.SchemaURL,
|
||||
osTypeAttribute,
|
||||
), nil
|
||||
}
|
||||
|
||||
// Detect returns a *Resource that describes the operating system the
|
||||
// service is running on.
|
||||
func (osDescriptionDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
description, err := osDescription()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewWithAttributes(
|
||||
semconv.SchemaURL,
|
||||
semconv.OSDescription(description),
|
||||
), nil
|
||||
}
|
||||
|
||||
// mapRuntimeOSToSemconvOSType translates the OS name as provided by the Go runtime
|
||||
// into an OS type attribute with the corresponding value defined by the semantic
|
||||
// conventions. In case the provided OS name isn't mapped, it's transformed to lowercase
|
||||
// and used as the value for the returned OS type attribute.
|
||||
func mapRuntimeOSToSemconvOSType(osType string) attribute.KeyValue {
|
||||
// the elements in this map are the intersection between
|
||||
// available GOOS values and defined semconv OS types
|
||||
osTypeAttributeMap := map[string]attribute.KeyValue{
|
||||
"aix": semconv.OSTypeAIX,
|
||||
"darwin": semconv.OSTypeDarwin,
|
||||
"dragonfly": semconv.OSTypeDragonflyBSD,
|
||||
"freebsd": semconv.OSTypeFreeBSD,
|
||||
"linux": semconv.OSTypeLinux,
|
||||
"netbsd": semconv.OSTypeNetBSD,
|
||||
"openbsd": semconv.OSTypeOpenBSD,
|
||||
"solaris": semconv.OSTypeSolaris,
|
||||
"windows": semconv.OSTypeWindows,
|
||||
"zos": semconv.OSTypeZOS,
|
||||
}
|
||||
|
||||
var osTypeAttribute attribute.KeyValue
|
||||
|
||||
if attr, ok := osTypeAttributeMap[osType]; ok {
|
||||
osTypeAttribute = attr
|
||||
} else {
|
||||
osTypeAttribute = semconv.OSTypeKey.String(strings.ToLower(osType))
|
||||
}
|
||||
|
||||
return osTypeAttribute
|
||||
}
|
91
vendor/go.opentelemetry.io/otel/sdk/resource/os_release_darwin.go
generated
vendored
Normal file
91
vendor/go.opentelemetry.io/otel/sdk/resource/os_release_darwin.go
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
type plist struct {
|
||||
XMLName xml.Name `xml:"plist"`
|
||||
Dict dict `xml:"dict"`
|
||||
}
|
||||
|
||||
type dict struct {
|
||||
Key []string `xml:"key"`
|
||||
String []string `xml:"string"`
|
||||
}
|
||||
|
||||
// osRelease builds a string describing the operating system release based on the
|
||||
// contents of the property list (.plist) system files. If no .plist files are found,
|
||||
// or if the required properties to build the release description string are missing,
|
||||
// an empty string is returned instead. The generated string resembles the output of
|
||||
// the `sw_vers` commandline program, but in a single-line string. For more information
|
||||
// about the `sw_vers` program, see: https://www.unix.com/man-page/osx/1/SW_VERS.
|
||||
func osRelease() string {
|
||||
file, err := getPlistFile()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
values, err := parsePlistFile(file)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return buildOSRelease(values)
|
||||
}
|
||||
|
||||
// getPlistFile returns a *os.File pointing to one of the well-known .plist files
|
||||
// available on macOS. If no file can be opened, it returns an error.
|
||||
func getPlistFile() (*os.File, error) {
|
||||
return getFirstAvailableFile([]string{
|
||||
"/System/Library/CoreServices/SystemVersion.plist",
|
||||
"/System/Library/CoreServices/ServerVersion.plist",
|
||||
})
|
||||
}
|
||||
|
||||
// parsePlistFile process the file pointed by `file` as a .plist file and returns
|
||||
// a map with the key-values for each pair of correlated <key> and <string> elements
|
||||
// contained in it.
|
||||
func parsePlistFile(file io.Reader) (map[string]string, error) {
|
||||
var v plist
|
||||
|
||||
err := xml.NewDecoder(file).Decode(&v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(v.Dict.Key) != len(v.Dict.String) {
|
||||
return nil, fmt.Errorf("the number of <key> and <string> elements doesn't match")
|
||||
}
|
||||
|
||||
properties := make(map[string]string, len(v.Dict.Key))
|
||||
for i, key := range v.Dict.Key {
|
||||
properties[key] = v.Dict.String[i]
|
||||
}
|
||||
|
||||
return properties, nil
|
||||
}
|
||||
|
||||
// buildOSRelease builds a string describing the OS release based on the properties
|
||||
// available on the provided map. It tries to find the `ProductName`, `ProductVersion`
|
||||
// and `ProductBuildVersion` properties. If some of these properties are not found,
|
||||
// it returns an empty string.
|
||||
func buildOSRelease(properties map[string]string) string {
|
||||
productName := properties["ProductName"]
|
||||
productVersion := properties["ProductVersion"]
|
||||
productBuildVersion := properties["ProductBuildVersion"]
|
||||
|
||||
if productName == "" || productVersion == "" || productBuildVersion == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s %s (%s)", productName, productVersion, productBuildVersion)
|
||||
}
|
143
vendor/go.opentelemetry.io/otel/sdk/resource/os_release_unix.go
generated
vendored
Normal file
143
vendor/go.opentelemetry.io/otel/sdk/resource/os_release_unix.go
generated
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build aix || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
||||
// +build aix dragonfly freebsd linux netbsd openbsd solaris zos
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// osRelease builds a string describing the operating system release based on the
|
||||
// properties of the os-release file. If no os-release file is found, or if the
|
||||
// required properties to build the release description string are missing, an empty
|
||||
// string is returned instead. For more information about os-release files, see:
|
||||
// https://www.freedesktop.org/software/systemd/man/os-release.html
|
||||
func osRelease() string {
|
||||
file, err := getOSReleaseFile()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
values := parseOSReleaseFile(file)
|
||||
|
||||
return buildOSRelease(values)
|
||||
}
|
||||
|
||||
// getOSReleaseFile returns a *os.File pointing to one of the well-known os-release
|
||||
// files, according to their order of preference. If no file can be opened, it
|
||||
// returns an error.
|
||||
func getOSReleaseFile() (*os.File, error) {
|
||||
return getFirstAvailableFile([]string{"/etc/os-release", "/usr/lib/os-release"})
|
||||
}
|
||||
|
||||
// parseOSReleaseFile process the file pointed by `file` as an os-release file and
|
||||
// returns a map with the key-values contained in it. Empty lines or lines starting
|
||||
// with a '#' character are ignored, as well as lines with the missing key=value
|
||||
// separator. Values are unquoted and unescaped.
|
||||
func parseOSReleaseFile(file io.Reader) map[string]string {
|
||||
values := make(map[string]string)
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
if skip(line) {
|
||||
continue
|
||||
}
|
||||
|
||||
key, value, ok := parse(line)
|
||||
if ok {
|
||||
values[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
// skip returns true if the line is blank or starts with a '#' character, and
|
||||
// therefore should be skipped from processing.
|
||||
func skip(line string) bool {
|
||||
line = strings.TrimSpace(line)
|
||||
|
||||
return len(line) == 0 || strings.HasPrefix(line, "#")
|
||||
}
|
||||
|
||||
// parse attempts to split the provided line on the first '=' character, and then
|
||||
// sanitize each side of the split before returning them as a key-value pair.
|
||||
func parse(line string) (string, string, bool) {
|
||||
k, v, found := strings.Cut(line, "=")
|
||||
|
||||
if !found || len(k) == 0 {
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
key := strings.TrimSpace(k)
|
||||
value := unescape(unquote(strings.TrimSpace(v)))
|
||||
|
||||
return key, value, true
|
||||
}
|
||||
|
||||
// unquote checks whether the string `s` is quoted with double or single quotes
|
||||
// and, if so, returns a version of the string without them. Otherwise it returns
|
||||
// the provided string unchanged.
|
||||
func unquote(s string) string {
|
||||
if len(s) < 2 {
|
||||
return s
|
||||
}
|
||||
|
||||
if (s[0] == '"' || s[0] == '\'') && s[0] == s[len(s)-1] {
|
||||
return s[1 : len(s)-1]
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// unescape removes the `\` prefix from some characters that are expected
|
||||
// to have it added in front of them for escaping purposes.
|
||||
func unescape(s string) string {
|
||||
return strings.NewReplacer(
|
||||
`\$`, `$`,
|
||||
`\"`, `"`,
|
||||
`\'`, `'`,
|
||||
`\\`, `\`,
|
||||
"\\`", "`",
|
||||
).Replace(s)
|
||||
}
|
||||
|
||||
// buildOSRelease builds a string describing the OS release based on the properties
|
||||
// available on the provided map. It favors a combination of the `NAME` and `VERSION`
|
||||
// properties as first option (falling back to `VERSION_ID` if `VERSION` isn't
|
||||
// found), and using `PRETTY_NAME` alone if some of the previous are not present. If
|
||||
// none of these properties are found, it returns an empty string.
|
||||
//
|
||||
// The rationale behind not using `PRETTY_NAME` as first choice was that, for some
|
||||
// Linux distributions, it doesn't include the same detail that can be found on the
|
||||
// individual `NAME` and `VERSION` properties, and combining `PRETTY_NAME` with
|
||||
// other properties can produce "pretty" redundant strings in some cases.
|
||||
func buildOSRelease(values map[string]string) string {
|
||||
var osRelease string
|
||||
|
||||
name := values["NAME"]
|
||||
version := values["VERSION"]
|
||||
|
||||
if version == "" {
|
||||
version = values["VERSION_ID"]
|
||||
}
|
||||
|
||||
if name != "" && version != "" {
|
||||
osRelease = fmt.Sprintf("%s %s", name, version)
|
||||
} else {
|
||||
osRelease = values["PRETTY_NAME"]
|
||||
}
|
||||
|
||||
return osRelease
|
||||
}
|
79
vendor/go.opentelemetry.io/otel/sdk/resource/os_unix.go
generated
vendored
Normal file
79
vendor/go.opentelemetry.io/otel/sdk/resource/os_unix.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type unameProvider func(buf *unix.Utsname) (err error)
|
||||
|
||||
var defaultUnameProvider unameProvider = unix.Uname
|
||||
|
||||
var currentUnameProvider = defaultUnameProvider
|
||||
|
||||
func setDefaultUnameProvider() {
|
||||
setUnameProvider(defaultUnameProvider)
|
||||
}
|
||||
|
||||
func setUnameProvider(unameProvider unameProvider) {
|
||||
currentUnameProvider = unameProvider
|
||||
}
|
||||
|
||||
// platformOSDescription returns a human readable OS version information string.
|
||||
// The final string combines OS release information (where available) and the
|
||||
// result of the `uname` system call.
|
||||
func platformOSDescription() (string, error) {
|
||||
uname, err := uname()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
osRelease := osRelease()
|
||||
if osRelease != "" {
|
||||
return fmt.Sprintf("%s (%s)", osRelease, uname), nil
|
||||
}
|
||||
|
||||
return uname, nil
|
||||
}
|
||||
|
||||
// uname issues a uname(2) system call (or equivalent on systems which doesn't
|
||||
// have one) and formats the output in a single string, similar to the output
|
||||
// of the `uname` commandline program. The final string resembles the one
|
||||
// obtained with a call to `uname -snrvm`.
|
||||
func uname() (string, error) {
|
||||
var utsName unix.Utsname
|
||||
|
||||
err := currentUnameProvider(&utsName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s %s %s %s %s",
|
||||
unix.ByteSliceToString(utsName.Sysname[:]),
|
||||
unix.ByteSliceToString(utsName.Nodename[:]),
|
||||
unix.ByteSliceToString(utsName.Release[:]),
|
||||
unix.ByteSliceToString(utsName.Version[:]),
|
||||
unix.ByteSliceToString(utsName.Machine[:]),
|
||||
), nil
|
||||
}
|
||||
|
||||
// getFirstAvailableFile returns an *os.File of the first available
|
||||
// file from a list of candidate file paths.
|
||||
func getFirstAvailableFile(candidates []string) (*os.File, error) {
|
||||
for _, c := range candidates {
|
||||
file, err := os.Open(c)
|
||||
if err == nil {
|
||||
return file, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no candidate file available: %v", candidates)
|
||||
}
|
15
vendor/go.opentelemetry.io/otel/sdk/resource/os_unsupported.go
generated
vendored
Normal file
15
vendor/go.opentelemetry.io/otel/sdk/resource/os_unsupported.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows,!zos
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
// platformOSDescription is a placeholder implementation for OSes
|
||||
// for which this project currently doesn't support os.description
|
||||
// attribute detection. See build tags declaration early on this file
|
||||
// for a list of unsupported OSes.
|
||||
func platformOSDescription() (string, error) {
|
||||
return "<unknown>", nil
|
||||
}
|
90
vendor/go.opentelemetry.io/otel/sdk/resource/os_windows.go
generated
vendored
Normal file
90
vendor/go.opentelemetry.io/otel/sdk/resource/os_windows.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
// platformOSDescription returns a human readable OS version information string.
|
||||
// It does so by querying registry values under the
|
||||
// `SOFTWARE\Microsoft\Windows NT\CurrentVersion` key. The final string
|
||||
// resembles the one displayed by the Version Reporter Applet (winver.exe).
|
||||
func platformOSDescription() (string, error) {
|
||||
k, err := registry.OpenKey(
|
||||
registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
defer k.Close()
|
||||
|
||||
var (
|
||||
productName = readProductName(k)
|
||||
displayVersion = readDisplayVersion(k)
|
||||
releaseID = readReleaseID(k)
|
||||
currentMajorVersionNumber = readCurrentMajorVersionNumber(k)
|
||||
currentMinorVersionNumber = readCurrentMinorVersionNumber(k)
|
||||
currentBuildNumber = readCurrentBuildNumber(k)
|
||||
ubr = readUBR(k)
|
||||
)
|
||||
|
||||
if displayVersion != "" {
|
||||
displayVersion += " "
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s %s(%s) [Version %s.%s.%s.%s]",
|
||||
productName,
|
||||
displayVersion,
|
||||
releaseID,
|
||||
currentMajorVersionNumber,
|
||||
currentMinorVersionNumber,
|
||||
currentBuildNumber,
|
||||
ubr,
|
||||
), nil
|
||||
}
|
||||
|
||||
func getStringValue(name string, k registry.Key) string {
|
||||
value, _, _ := k.GetStringValue(name)
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func getIntegerValue(name string, k registry.Key) uint64 {
|
||||
value, _, _ := k.GetIntegerValue(name)
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func readProductName(k registry.Key) string {
|
||||
return getStringValue("ProductName", k)
|
||||
}
|
||||
|
||||
func readDisplayVersion(k registry.Key) string {
|
||||
return getStringValue("DisplayVersion", k)
|
||||
}
|
||||
|
||||
func readReleaseID(k registry.Key) string {
|
||||
return getStringValue("ReleaseID", k)
|
||||
}
|
||||
|
||||
func readCurrentMajorVersionNumber(k registry.Key) string {
|
||||
return strconv.FormatUint(getIntegerValue("CurrentMajorVersionNumber", k), 10)
|
||||
}
|
||||
|
||||
func readCurrentMinorVersionNumber(k registry.Key) string {
|
||||
return strconv.FormatUint(getIntegerValue("CurrentMinorVersionNumber", k), 10)
|
||||
}
|
||||
|
||||
func readCurrentBuildNumber(k registry.Key) string {
|
||||
return getStringValue("CurrentBuildNumber", k)
|
||||
}
|
||||
|
||||
func readUBR(k registry.Key) string {
|
||||
return strconv.FormatUint(getIntegerValue("UBR", k), 10)
|
||||
}
|
173
vendor/go.opentelemetry.io/otel/sdk/resource/process.go
generated
vendored
Normal file
173
vendor/go.opentelemetry.io/otel/sdk/resource/process.go
generated
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||
)
|
||||
|
||||
type (
|
||||
pidProvider func() int
|
||||
executablePathProvider func() (string, error)
|
||||
commandArgsProvider func() []string
|
||||
ownerProvider func() (*user.User, error)
|
||||
runtimeNameProvider func() string
|
||||
runtimeVersionProvider func() string
|
||||
runtimeOSProvider func() string
|
||||
runtimeArchProvider func() string
|
||||
)
|
||||
|
||||
var (
|
||||
defaultPidProvider pidProvider = os.Getpid
|
||||
defaultExecutablePathProvider executablePathProvider = os.Executable
|
||||
defaultCommandArgsProvider commandArgsProvider = func() []string { return os.Args }
|
||||
defaultOwnerProvider ownerProvider = user.Current
|
||||
defaultRuntimeNameProvider runtimeNameProvider = func() string {
|
||||
if runtime.Compiler == "gc" {
|
||||
return "go"
|
||||
}
|
||||
return runtime.Compiler
|
||||
}
|
||||
defaultRuntimeVersionProvider runtimeVersionProvider = runtime.Version
|
||||
defaultRuntimeOSProvider runtimeOSProvider = func() string { return runtime.GOOS }
|
||||
defaultRuntimeArchProvider runtimeArchProvider = func() string { return runtime.GOARCH }
|
||||
)
|
||||
|
||||
var (
|
||||
pid = defaultPidProvider
|
||||
executablePath = defaultExecutablePathProvider
|
||||
commandArgs = defaultCommandArgsProvider
|
||||
owner = defaultOwnerProvider
|
||||
runtimeName = defaultRuntimeNameProvider
|
||||
runtimeVersion = defaultRuntimeVersionProvider
|
||||
runtimeOS = defaultRuntimeOSProvider
|
||||
runtimeArch = defaultRuntimeArchProvider
|
||||
)
|
||||
|
||||
func setDefaultOSProviders() {
|
||||
setOSProviders(
|
||||
defaultPidProvider,
|
||||
defaultExecutablePathProvider,
|
||||
defaultCommandArgsProvider,
|
||||
)
|
||||
}
|
||||
|
||||
func setOSProviders(
|
||||
pidProvider pidProvider,
|
||||
executablePathProvider executablePathProvider,
|
||||
commandArgsProvider commandArgsProvider,
|
||||
) {
|
||||
pid = pidProvider
|
||||
executablePath = executablePathProvider
|
||||
commandArgs = commandArgsProvider
|
||||
}
|
||||
|
||||
func setDefaultRuntimeProviders() {
|
||||
setRuntimeProviders(
|
||||
defaultRuntimeNameProvider,
|
||||
defaultRuntimeVersionProvider,
|
||||
defaultRuntimeOSProvider,
|
||||
defaultRuntimeArchProvider,
|
||||
)
|
||||
}
|
||||
|
||||
func setRuntimeProviders(
|
||||
runtimeNameProvider runtimeNameProvider,
|
||||
runtimeVersionProvider runtimeVersionProvider,
|
||||
runtimeOSProvider runtimeOSProvider,
|
||||
runtimeArchProvider runtimeArchProvider,
|
||||
) {
|
||||
runtimeName = runtimeNameProvider
|
||||
runtimeVersion = runtimeVersionProvider
|
||||
runtimeOS = runtimeOSProvider
|
||||
runtimeArch = runtimeArchProvider
|
||||
}
|
||||
|
||||
func setDefaultUserProviders() {
|
||||
setUserProviders(defaultOwnerProvider)
|
||||
}
|
||||
|
||||
func setUserProviders(ownerProvider ownerProvider) {
|
||||
owner = ownerProvider
|
||||
}
|
||||
|
||||
type (
|
||||
processPIDDetector struct{}
|
||||
processExecutableNameDetector struct{}
|
||||
processExecutablePathDetector struct{}
|
||||
processCommandArgsDetector struct{}
|
||||
processOwnerDetector struct{}
|
||||
processRuntimeNameDetector struct{}
|
||||
processRuntimeVersionDetector struct{}
|
||||
processRuntimeDescriptionDetector struct{}
|
||||
)
|
||||
|
||||
// Detect returns a *Resource that describes the process identifier (PID) of the
|
||||
// executing process.
|
||||
func (processPIDDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
return NewWithAttributes(semconv.SchemaURL, semconv.ProcessPID(pid())), nil
|
||||
}
|
||||
|
||||
// Detect returns a *Resource that describes the name of the process executable.
|
||||
func (processExecutableNameDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
executableName := filepath.Base(commandArgs()[0])
|
||||
|
||||
return NewWithAttributes(semconv.SchemaURL, semconv.ProcessExecutableName(executableName)), nil
|
||||
}
|
||||
|
||||
// Detect returns a *Resource that describes the full path of the process executable.
|
||||
func (processExecutablePathDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
executablePath, err := executablePath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewWithAttributes(semconv.SchemaURL, semconv.ProcessExecutablePath(executablePath)), nil
|
||||
}
|
||||
|
||||
// Detect returns a *Resource that describes all the command arguments as received
|
||||
// by the process.
|
||||
func (processCommandArgsDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
return NewWithAttributes(semconv.SchemaURL, semconv.ProcessCommandArgs(commandArgs()...)), nil
|
||||
}
|
||||
|
||||
// Detect returns a *Resource that describes the username of the user that owns the
|
||||
// process.
|
||||
func (processOwnerDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
owner, err := owner()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewWithAttributes(semconv.SchemaURL, semconv.ProcessOwner(owner.Username)), nil
|
||||
}
|
||||
|
||||
// Detect returns a *Resource that describes the name of the compiler used to compile
|
||||
// this process image.
|
||||
func (processRuntimeNameDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
return NewWithAttributes(semconv.SchemaURL, semconv.ProcessRuntimeName(runtimeName())), nil
|
||||
}
|
||||
|
||||
// Detect returns a *Resource that describes the version of the runtime of this process.
|
||||
func (processRuntimeVersionDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
return NewWithAttributes(semconv.SchemaURL, semconv.ProcessRuntimeVersion(runtimeVersion())), nil
|
||||
}
|
||||
|
||||
// Detect returns a *Resource that describes the runtime of this process.
|
||||
func (processRuntimeDescriptionDetector) Detect(ctx context.Context) (*Resource, error) {
|
||||
runtimeDescription := fmt.Sprintf(
|
||||
"go version %s %s/%s", runtimeVersion(), runtimeOS(), runtimeArch())
|
||||
|
||||
return NewWithAttributes(
|
||||
semconv.SchemaURL,
|
||||
semconv.ProcessRuntimeDescription(runtimeDescription),
|
||||
), nil
|
||||
}
|
294
vendor/go.opentelemetry.io/otel/sdk/resource/resource.go
generated
vendored
Normal file
294
vendor/go.opentelemetry.io/otel/sdk/resource/resource.go
generated
vendored
Normal file
@ -0,0 +1,294 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/sdk/internal/x"
|
||||
)
|
||||
|
||||
// Resource describes an entity about which identifying information
|
||||
// and metadata is exposed. Resource is an immutable object,
|
||||
// equivalent to a map from key to unique value.
|
||||
//
|
||||
// Resources should be passed and stored as pointers
|
||||
// (`*resource.Resource`). The `nil` value is equivalent to an empty
|
||||
// Resource.
|
||||
type Resource struct {
|
||||
attrs attribute.Set
|
||||
schemaURL string
|
||||
}
|
||||
|
||||
var (
|
||||
defaultResource *Resource
|
||||
defaultResourceOnce sync.Once
|
||||
)
|
||||
|
||||
// ErrSchemaURLConflict is an error returned when two Resources are merged
|
||||
// together that contain different, non-empty, schema URLs.
|
||||
var ErrSchemaURLConflict = errors.New("conflicting Schema URL")
|
||||
|
||||
// New returns a [Resource] built using opts.
|
||||
//
|
||||
// This may return a partial Resource along with an error containing
|
||||
// [ErrPartialResource] if options that provide a [Detector] are used and that
|
||||
// error is returned from one or more of the Detectors. It may also return a
|
||||
// merge-conflict Resource along with an error containing
|
||||
// [ErrSchemaURLConflict] if merging Resources from the opts results in a
|
||||
// schema URL conflict (see [Resource.Merge] for more information). It is up to
|
||||
// the caller to determine if this returned Resource should be used or not
|
||||
// based on these errors.
|
||||
func New(ctx context.Context, opts ...Option) (*Resource, error) {
|
||||
cfg := config{}
|
||||
for _, opt := range opts {
|
||||
cfg = opt.apply(cfg)
|
||||
}
|
||||
|
||||
r := &Resource{schemaURL: cfg.schemaURL}
|
||||
return r, detect(ctx, r, cfg.detectors)
|
||||
}
|
||||
|
||||
// NewWithAttributes creates a resource from attrs and associates the resource with a
|
||||
// schema URL. If attrs contains duplicate keys, the last value will be used. If attrs
|
||||
// contains any invalid items those items will be dropped. The attrs are assumed to be
|
||||
// in a schema identified by schemaURL.
|
||||
func NewWithAttributes(schemaURL string, attrs ...attribute.KeyValue) *Resource {
|
||||
resource := NewSchemaless(attrs...)
|
||||
resource.schemaURL = schemaURL
|
||||
return resource
|
||||
}
|
||||
|
||||
// NewSchemaless creates a resource from attrs. If attrs contains duplicate keys,
|
||||
// the last value will be used. If attrs contains any invalid items those items will
|
||||
// be dropped. The resource will not be associated with a schema URL. If the schema
|
||||
// of the attrs is known use NewWithAttributes instead.
|
||||
func NewSchemaless(attrs ...attribute.KeyValue) *Resource {
|
||||
if len(attrs) == 0 {
|
||||
return &Resource{}
|
||||
}
|
||||
|
||||
// Ensure attributes comply with the specification:
|
||||
// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/common/README.md#attribute
|
||||
s, _ := attribute.NewSetWithFiltered(attrs, func(kv attribute.KeyValue) bool {
|
||||
return kv.Valid()
|
||||
})
|
||||
|
||||
// If attrs only contains invalid entries do not allocate a new resource.
|
||||
if s.Len() == 0 {
|
||||
return &Resource{}
|
||||
}
|
||||
|
||||
return &Resource{attrs: s} //nolint
|
||||
}
|
||||
|
||||
// String implements the Stringer interface and provides a
|
||||
// human-readable form of the resource.
|
||||
//
|
||||
// Avoid using this representation as the key in a map of resources,
|
||||
// use Equivalent() as the key instead.
|
||||
func (r *Resource) String() string {
|
||||
if r == nil {
|
||||
return ""
|
||||
}
|
||||
return r.attrs.Encoded(attribute.DefaultEncoder())
|
||||
}
|
||||
|
||||
// MarshalLog is the marshaling function used by the logging system to represent this Resource.
|
||||
func (r *Resource) MarshalLog() interface{} {
|
||||
return struct {
|
||||
Attributes attribute.Set
|
||||
SchemaURL string
|
||||
}{
|
||||
Attributes: r.attrs,
|
||||
SchemaURL: r.schemaURL,
|
||||
}
|
||||
}
|
||||
|
||||
// Attributes returns a copy of attributes from the resource in a sorted order.
|
||||
// To avoid allocating a new slice, use an iterator.
|
||||
func (r *Resource) Attributes() []attribute.KeyValue {
|
||||
if r == nil {
|
||||
r = Empty()
|
||||
}
|
||||
return r.attrs.ToSlice()
|
||||
}
|
||||
|
||||
// SchemaURL returns the schema URL associated with Resource r.
|
||||
func (r *Resource) SchemaURL() string {
|
||||
if r == nil {
|
||||
return ""
|
||||
}
|
||||
return r.schemaURL
|
||||
}
|
||||
|
||||
// Iter returns an iterator of the Resource attributes.
|
||||
// This is ideal to use if you do not want a copy of the attributes.
|
||||
func (r *Resource) Iter() attribute.Iterator {
|
||||
if r == nil {
|
||||
r = Empty()
|
||||
}
|
||||
return r.attrs.Iter()
|
||||
}
|
||||
|
||||
// Equal returns true when a Resource is equivalent to this Resource.
|
||||
func (r *Resource) Equal(eq *Resource) bool {
|
||||
if r == nil {
|
||||
r = Empty()
|
||||
}
|
||||
if eq == nil {
|
||||
eq = Empty()
|
||||
}
|
||||
return r.Equivalent() == eq.Equivalent()
|
||||
}
|
||||
|
||||
// Merge creates a new [Resource] by merging a and b.
|
||||
//
|
||||
// If there are common keys between a and b, then the value from b will
|
||||
// overwrite the value from a, even if b's value is empty.
|
||||
//
|
||||
// The SchemaURL of the resources will be merged according to the
|
||||
// [OpenTelemetry specification rules]:
|
||||
//
|
||||
// - If a's schema URL is empty then the returned Resource's schema URL will
|
||||
// be set to the schema URL of b,
|
||||
// - Else if b's schema URL is empty then the returned Resource's schema URL
|
||||
// will be set to the schema URL of a,
|
||||
// - Else if the schema URLs of a and b are the same then that will be the
|
||||
// schema URL of the returned Resource,
|
||||
// - Else this is a merging error. If the resources have different,
|
||||
// non-empty, schema URLs an error containing [ErrSchemaURLConflict] will
|
||||
// be returned with the merged Resource. The merged Resource will have an
|
||||
// empty schema URL. It may be the case that some unintended attributes
|
||||
// have been overwritten or old semantic conventions persisted in the
|
||||
// returned Resource. It is up to the caller to determine if this returned
|
||||
// Resource should be used or not.
|
||||
//
|
||||
// [OpenTelemetry specification rules]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/resource/sdk.md#merge
|
||||
func Merge(a, b *Resource) (*Resource, error) {
|
||||
if a == nil && b == nil {
|
||||
return Empty(), nil
|
||||
}
|
||||
if a == nil {
|
||||
return b, nil
|
||||
}
|
||||
if b == nil {
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Note: 'b' attributes will overwrite 'a' with last-value-wins in attribute.Key()
|
||||
// Meaning this is equivalent to: append(a.Attributes(), b.Attributes()...)
|
||||
mi := attribute.NewMergeIterator(b.Set(), a.Set())
|
||||
combine := make([]attribute.KeyValue, 0, a.Len()+b.Len())
|
||||
for mi.Next() {
|
||||
combine = append(combine, mi.Attribute())
|
||||
}
|
||||
|
||||
switch {
|
||||
case a.schemaURL == "":
|
||||
return NewWithAttributes(b.schemaURL, combine...), nil
|
||||
case b.schemaURL == "":
|
||||
return NewWithAttributes(a.schemaURL, combine...), nil
|
||||
case a.schemaURL == b.schemaURL:
|
||||
return NewWithAttributes(a.schemaURL, combine...), nil
|
||||
}
|
||||
// Return the merged resource with an appropriate error. It is up to
|
||||
// the user to decide if the returned resource can be used or not.
|
||||
return NewSchemaless(combine...), fmt.Errorf(
|
||||
"%w: %s and %s",
|
||||
ErrSchemaURLConflict,
|
||||
a.schemaURL,
|
||||
b.schemaURL,
|
||||
)
|
||||
}
|
||||
|
||||
// Empty returns an instance of Resource with no attributes. It is
|
||||
// equivalent to a `nil` Resource.
|
||||
func Empty() *Resource {
|
||||
return &Resource{}
|
||||
}
|
||||
|
||||
// Default returns an instance of Resource with a default
|
||||
// "service.name" and OpenTelemetrySDK attributes.
|
||||
func Default() *Resource {
|
||||
defaultResourceOnce.Do(func() {
|
||||
var err error
|
||||
defaultDetectors := []Detector{
|
||||
defaultServiceNameDetector{},
|
||||
fromEnv{},
|
||||
telemetrySDK{},
|
||||
}
|
||||
if x.Resource.Enabled() {
|
||||
defaultDetectors = append([]Detector{defaultServiceInstanceIDDetector{}}, defaultDetectors...)
|
||||
}
|
||||
defaultResource, err = Detect(
|
||||
context.Background(),
|
||||
defaultDetectors...,
|
||||
)
|
||||
if err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
// If Detect did not return a valid resource, fall back to emptyResource.
|
||||
if defaultResource == nil {
|
||||
defaultResource = &Resource{}
|
||||
}
|
||||
})
|
||||
return defaultResource
|
||||
}
|
||||
|
||||
// Environment returns an instance of Resource with attributes
|
||||
// extracted from the OTEL_RESOURCE_ATTRIBUTES environment variable.
|
||||
func Environment() *Resource {
|
||||
detector := &fromEnv{}
|
||||
resource, err := detector.Detect(context.Background())
|
||||
if err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
return resource
|
||||
}
|
||||
|
||||
// Equivalent returns an object that can be compared for equality
|
||||
// between two resources. This value is suitable for use as a key in
|
||||
// a map.
|
||||
func (r *Resource) Equivalent() attribute.Distinct {
|
||||
return r.Set().Equivalent()
|
||||
}
|
||||
|
||||
// Set returns the equivalent *attribute.Set of this resource's attributes.
|
||||
func (r *Resource) Set() *attribute.Set {
|
||||
if r == nil {
|
||||
r = Empty()
|
||||
}
|
||||
return &r.attrs
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the resource attributes as a JSON list of { "Key":
|
||||
// "...", "Value": ... } pairs in order sorted by key.
|
||||
func (r *Resource) MarshalJSON() ([]byte, error) {
|
||||
if r == nil {
|
||||
r = Empty()
|
||||
}
|
||||
return r.attrs.MarshalJSON()
|
||||
}
|
||||
|
||||
// Len returns the number of unique key-values in this Resource.
|
||||
func (r *Resource) Len() int {
|
||||
if r == nil {
|
||||
return 0
|
||||
}
|
||||
return r.attrs.Len()
|
||||
}
|
||||
|
||||
// Encoded returns an encoded representation of the resource.
|
||||
func (r *Resource) Encoded(enc attribute.Encoder) string {
|
||||
if r == nil {
|
||||
return ""
|
||||
}
|
||||
return r.attrs.Encoded(enc)
|
||||
}
|
Reference in New Issue
Block a user