feat(telemetry): instrument inference duration and frame age

This commit is contained in:
2021-12-02 09:16:50 +01:00
parent 85fe69dcaa
commit bb99d3b7c9
450 changed files with 201257 additions and 2 deletions

72
vendor/go.opentelemetry.io/otel/sdk/resource/auto.go generated vendored Normal file
View File

@ -0,0 +1,72 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package resource // import "go.opentelemetry.io/otel/sdk/resource"
import (
"context"
"errors"
"fmt"
)
var (
// 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.
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 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
for _, detector := range detectors {
if detector == nil {
continue
}
res, err := detector.Detect(ctx)
if err != nil {
errInfo = append(errInfo, err.Error())
if !errors.Is(err, ErrPartialResource) {
continue
}
}
autoDetectedRes, err = Merge(autoDetectedRes, res)
if err != nil {
errInfo = append(errInfo, err.Error())
}
}
var aggregatedError error
if len(errInfo) > 0 {
aggregatedError = fmt.Errorf("detecting resources: %s", errInfo)
}
return autoDetectedRes, aggregatedError
}

108
vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go generated vendored Normal file
View File

@ -0,0 +1,108 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package resource // import "go.opentelemetry.io/otel/sdk/resource"
import (
"context"
"fmt"
"os"
"path/filepath"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.7.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{}
)
var (
_ Detector = telemetrySDK{}
_ Detector = host{}
_ Detector = stringDetector{}
_ Detector = defaultServiceNameDetector{}
)
// Detect returns a *Resource that describes the OpenTelemetry SDK used.
func (telemetrySDK) Detect(context.Context) (*Resource, error) {
return NewWithAttributes(
semconv.SchemaURL,
semconv.TelemetrySDKNameKey.String("opentelemetry"),
semconv.TelemetrySDKLanguageKey.String("go"),
semconv.TelemetrySDKVersionKey.String(otel.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)
}

171
vendor/go.opentelemetry.io/otel/sdk/resource/config.go generated vendored Normal file
View File

@ -0,0 +1,171 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
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)
}
// 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) {
cfg.detectors = append(cfg.detectors, o.detectors...)
}
// 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{})
}
// 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) {
cfg.schemaURL = string(o)
}
// 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.
// See individual WithProcess* functions to configure specific attributes.
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 the configured 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{})
}

28
vendor/go.opentelemetry.io/otel/sdk/resource/doc.go generated vendored Normal file
View File

@ -0,0 +1,28 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// 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>,...`).
package resource // import "go.opentelemetry.io/otel/sdk/resource"

99
vendor/go.opentelemetry.io/otel/sdk/resource/env.go generated vendored Normal file
View File

@ -0,0 +1,99 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package resource // import "go.opentelemetry.io/otel/sdk/resource"
import (
"context"
"fmt"
"os"
"strings"
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
)
const (
// resourceAttrKey is the environment variable name OpenTelemetry Resource information will be read from.
resourceAttrKey = "OTEL_RESOURCE_ATTRIBUTES"
// svcNameKey is the environment variable name that Service Name information will be read from.
svcNameKey = "OTEL_SERVICE_NAME"
)
var (
// errMissingValue is returned when a resource value is missing.
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.ServiceNameKey.String(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, ",")
attrs := []attribute.KeyValue{}
var invalid []string
for _, p := range pairs {
field := strings.SplitN(p, "=", 2)
if len(field) != 2 {
invalid = append(invalid, p)
continue
}
k, v := strings.TrimSpace(field[0]), strings.TrimSpace(field[1])
attrs = append(attrs, attribute.String(k, v))
}
var err error
if len(invalid) > 0 {
err = fmt.Errorf("%w: %v", errMissingValue, invalid)
}
return NewSchemaless(attrs...), err
}

97
vendor/go.opentelemetry.io/otel/sdk/resource/os.go generated vendored Normal file
View File

@ -0,0 +1,97 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package resource // import "go.opentelemetry.io/otel/sdk/resource"
import (
"context"
"strings"
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.7.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{}
type 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.OSDescriptionKey.String(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{
"darwin": semconv.OSTypeDarwin,
"dragonfly": semconv.OSTypeDragonflyBSD,
"freebsd": semconv.OSTypeFreeBSD,
"linux": semconv.OSTypeLinux,
"netbsd": semconv.OSTypeNetBSD,
"openbsd": semconv.OSTypeOpenBSD,
"solaris": semconv.OSTypeSolaris,
"windows": semconv.OSTypeWindows,
}
var osTypeAttribute attribute.KeyValue
if attr, ok := osTypeAttributeMap[osType]; ok {
osTypeAttribute = attr
} else {
osTypeAttribute = semconv.OSTypeKey.String(strings.ToLower(osType))
}
return osTypeAttribute
}

View File

@ -0,0 +1,102 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
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)
}

View File

@ -0,0 +1,154 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//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) {
parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 || len(parts[0]) == 0 {
return "", "", false
}
key := strings.TrimSpace(parts[0])
value := unescape(unquote(strings.TrimSpace(parts[1])))
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
}

100
vendor/go.opentelemetry.io/otel/sdk/resource/os_unix.go generated vendored Normal file
View File

@ -0,0 +1,100 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//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 (
"bytes"
"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",
charsToString(utsName.Sysname[:]),
charsToString(utsName.Nodename[:]),
charsToString(utsName.Release[:]),
charsToString(utsName.Version[:]),
charsToString(utsName.Machine[:]),
), nil
}
// charsToString converts a C-like null-terminated char array to a Go string.
func charsToString(charArray []byte) string {
if i := bytes.IndexByte(charArray, 0); i >= 0 {
charArray = charArray[:i]
}
return string(charArray)
}
// 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)
}

View File

@ -0,0 +1,34 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !aix
// +build !darwin
// +build !dragonfly
// +build !freebsd
// +build !linux
// +build !netbsd
// +build !openbsd
// +build !solaris
// +build !windows
// +build !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
}

View File

@ -0,0 +1,101 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
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)
}

175
vendor/go.opentelemetry.io/otel/sdk/resource/process.go generated vendored Normal file
View File

@ -0,0 +1,175 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
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.7.0"
)
type pidProvider func() int
type executablePathProvider func() (string, error)
type commandArgsProvider func() []string
type ownerProvider func() (*user.User, error)
type runtimeNameProvider func() string
type runtimeVersionProvider func() string
type runtimeOSProvider func() string
type 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 { 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{}
type processExecutableNameDetector struct{}
type processExecutablePathDetector struct{}
type processCommandArgsDetector struct{}
type processOwnerDetector struct{}
type processRuntimeNameDetector struct{}
type processRuntimeVersionDetector struct{}
type 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.ProcessPIDKey.Int(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.ProcessExecutableNameKey.String(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.ProcessExecutablePathKey.String(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.ProcessCommandArgsKey.StringSlice(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.ProcessOwnerKey.String(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.ProcessRuntimeNameKey.String(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.ProcessRuntimeVersionKey.String(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.ProcessRuntimeDescriptionKey.String(runtimeDescription),
), nil
}

View File

@ -0,0 +1,266 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package resource // import "go.opentelemetry.io/otel/sdk/resource"
import (
"context"
"errors"
"fmt"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
)
// 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 (
emptyResource Resource
defaultResource = func(r *Resource, err error) *Resource {
if err != nil {
otel.Handle(err)
}
return r
}(
Detect(
context.Background(),
defaultServiceNameDetector{},
fromEnv{},
telemetrySDK{},
),
)
)
var (
errMergeConflictSchemaURL = errors.New("cannot merge resource due to conflicting Schema URL")
)
// New returns a Resource combined from the user-provided detectors.
func New(ctx context.Context, opts ...Option) (*Resource, error) {
cfg := config{}
for _, opt := range opts {
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
}
// 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 &emptyResource
}
// Ensure attributes comply with the specification:
// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.0.1/specification/common/common.md#attributes
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 &emptyResource
}
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())
}
// 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()
}
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 combining resource a and b.
//
// If there are common keys between resource a and b, then the value
// from resource b will overwrite the value from resource a, even
// if resource b's value is empty.
//
// The SchemaURL of the resources will be merged according to the spec rules:
// https://github.com/open-telemetry/opentelemetry-specification/blob/bad49c714a62da5493f2d1d9bafd7ebe8c8ce7eb/specification/resource/sdk.md#merge
// If the resources have different non-empty schemaURL an empty resource and an error
// will be returned.
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
}
// Merge the schema URL.
var schemaURL string
if a.schemaURL == "" {
schemaURL = b.schemaURL
} else if b.schemaURL == "" {
schemaURL = a.schemaURL
} else if a.schemaURL == b.schemaURL {
schemaURL = a.schemaURL
} else {
return Empty(), errMergeConflictSchemaURL
}
// 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.Label())
}
merged := NewWithAttributes(schemaURL, combine...)
return merged, nil
}
// Empty returns an instance of Resource with no attributes. It is
// equivalent to a `nil` Resource.
func Empty() *Resource {
return &emptyResource
}
// Default returns an instance of Resource with a default
// "service.name" and OpenTelemetrySDK attributes.
func Default() *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)
}