mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
build: move e2e dependencies into e2e/go.mod
Several packages are only used while running the e2e suite. These packages are less important to update, as the they can not influence the final executable that is part of the Ceph-CSI container-image. By moving these dependencies out of the main Ceph-CSI go.mod, it is easier to identify if a reported CVE affects Ceph-CSI, or only the testing (like most of the Kubernetes CVEs). Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
committed by
mergify[bot]
parent
15da101b1b
commit
bec6090996
201
e2e/vendor/go.opentelemetry.io/otel/sdk/LICENSE
generated
vendored
Normal file
201
e2e/vendor/go.opentelemetry.io/otel/sdk/LICENSE
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
3
e2e/vendor/go.opentelemetry.io/otel/sdk/README.md
generated
vendored
Normal file
3
e2e/vendor/go.opentelemetry.io/otel/sdk/README.md
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# SDK
|
||||
|
||||
[](https://pkg.go.dev/go.opentelemetry.io/otel/sdk)
|
3
e2e/vendor/go.opentelemetry.io/otel/sdk/instrumentation/README.md
generated
vendored
Normal file
3
e2e/vendor/go.opentelemetry.io/otel/sdk/instrumentation/README.md
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# SDK Instrumentation
|
||||
|
||||
[](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/instrumentation)
|
13
e2e/vendor/go.opentelemetry.io/otel/sdk/instrumentation/doc.go
generated
vendored
Normal file
13
e2e/vendor/go.opentelemetry.io/otel/sdk/instrumentation/doc.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package instrumentation provides types to represent the code libraries that
|
||||
// provide OpenTelemetry instrumentation. These types are used in the
|
||||
// OpenTelemetry signal pipelines to identify the source of telemetry.
|
||||
//
|
||||
// See
|
||||
// https://github.com/open-telemetry/oteps/blob/d226b677d73a785523fe9b9701be13225ebc528d/text/0083-component.md
|
||||
// and
|
||||
// https://github.com/open-telemetry/oteps/blob/d226b677d73a785523fe9b9701be13225ebc528d/text/0201-scope-attributes.md
|
||||
// for more information.
|
||||
package instrumentation // import "go.opentelemetry.io/otel/sdk/instrumentation"
|
9
e2e/vendor/go.opentelemetry.io/otel/sdk/instrumentation/library.go
generated
vendored
Normal file
9
e2e/vendor/go.opentelemetry.io/otel/sdk/instrumentation/library.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package instrumentation // import "go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
|
||||
// Library represents the instrumentation library.
|
||||
//
|
||||
// Deprecated: use [Scope] instead.
|
||||
type Library = Scope
|
19
e2e/vendor/go.opentelemetry.io/otel/sdk/instrumentation/scope.go
generated
vendored
Normal file
19
e2e/vendor/go.opentelemetry.io/otel/sdk/instrumentation/scope.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package instrumentation // import "go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
|
||||
import "go.opentelemetry.io/otel/attribute"
|
||||
|
||||
// Scope represents the instrumentation scope.
|
||||
type Scope struct {
|
||||
// Name is the name of the instrumentation scope. This should be the
|
||||
// Go package name of that scope.
|
||||
Name string
|
||||
// Version is the version of the instrumentation scope.
|
||||
Version string
|
||||
// SchemaURL of the telemetry emitted by the scope.
|
||||
SchemaURL string
|
||||
// Attributes of the telemetry emitted by the scope.
|
||||
Attributes attribute.Set
|
||||
}
|
166
e2e/vendor/go.opentelemetry.io/otel/sdk/internal/env/env.go
generated
vendored
Normal file
166
e2e/vendor/go.opentelemetry.io/otel/sdk/internal/env/env.go
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package env // import "go.opentelemetry.io/otel/sdk/internal/env"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"go.opentelemetry.io/otel/internal/global"
|
||||
)
|
||||
|
||||
// Environment variable names.
|
||||
const (
|
||||
// BatchSpanProcessorScheduleDelayKey is the delay interval between two
|
||||
// consecutive exports (i.e. 5000).
|
||||
BatchSpanProcessorScheduleDelayKey = "OTEL_BSP_SCHEDULE_DELAY"
|
||||
// BatchSpanProcessorExportTimeoutKey is the maximum allowed time to
|
||||
// export data (i.e. 3000).
|
||||
BatchSpanProcessorExportTimeoutKey = "OTEL_BSP_EXPORT_TIMEOUT"
|
||||
// BatchSpanProcessorMaxQueueSizeKey is the maximum queue size (i.e. 2048).
|
||||
BatchSpanProcessorMaxQueueSizeKey = "OTEL_BSP_MAX_QUEUE_SIZE"
|
||||
// BatchSpanProcessorMaxExportBatchSizeKey is the maximum batch size (i.e.
|
||||
// 512). Note: it must be less than or equal to
|
||||
// BatchSpanProcessorMaxQueueSize.
|
||||
BatchSpanProcessorMaxExportBatchSizeKey = "OTEL_BSP_MAX_EXPORT_BATCH_SIZE"
|
||||
|
||||
// AttributeValueLengthKey is the maximum allowed attribute value size.
|
||||
AttributeValueLengthKey = "OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT"
|
||||
|
||||
// AttributeCountKey is the maximum allowed span attribute count.
|
||||
AttributeCountKey = "OTEL_ATTRIBUTE_COUNT_LIMIT"
|
||||
|
||||
// SpanAttributeValueLengthKey is the maximum allowed attribute value size
|
||||
// for a span.
|
||||
SpanAttributeValueLengthKey = "OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT"
|
||||
|
||||
// SpanAttributeCountKey is the maximum allowed span attribute count for a
|
||||
// span.
|
||||
SpanAttributeCountKey = "OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT"
|
||||
|
||||
// SpanEventCountKey is the maximum allowed span event count.
|
||||
SpanEventCountKey = "OTEL_SPAN_EVENT_COUNT_LIMIT"
|
||||
|
||||
// SpanEventAttributeCountKey is the maximum allowed attribute per span
|
||||
// event count.
|
||||
SpanEventAttributeCountKey = "OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT"
|
||||
|
||||
// SpanLinkCountKey is the maximum allowed span link count.
|
||||
SpanLinkCountKey = "OTEL_SPAN_LINK_COUNT_LIMIT"
|
||||
|
||||
// SpanLinkAttributeCountKey is the maximum allowed attribute per span
|
||||
// link count.
|
||||
SpanLinkAttributeCountKey = "OTEL_LINK_ATTRIBUTE_COUNT_LIMIT"
|
||||
)
|
||||
|
||||
// firstInt returns the value of the first matching environment variable from
|
||||
// keys. If the value is not an integer or no match is found, defaultValue is
|
||||
// returned.
|
||||
func firstInt(defaultValue int, keys ...string) int {
|
||||
for _, key := range keys {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
intValue, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
global.Info("Got invalid value, number value expected.", key, value)
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return intValue
|
||||
}
|
||||
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// IntEnvOr returns the int value of the environment variable with name key if
|
||||
// it exists, it is not empty, and the value is an int. Otherwise, defaultValue is returned.
|
||||
func IntEnvOr(key string, defaultValue int) int {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
intValue, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
global.Info("Got invalid value, number value expected.", key, value)
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return intValue
|
||||
}
|
||||
|
||||
// BatchSpanProcessorScheduleDelay returns the environment variable value for
|
||||
// the OTEL_BSP_SCHEDULE_DELAY key if it exists, otherwise defaultValue is
|
||||
// returned.
|
||||
func BatchSpanProcessorScheduleDelay(defaultValue int) int {
|
||||
return IntEnvOr(BatchSpanProcessorScheduleDelayKey, defaultValue)
|
||||
}
|
||||
|
||||
// BatchSpanProcessorExportTimeout returns the environment variable value for
|
||||
// the OTEL_BSP_EXPORT_TIMEOUT key if it exists, otherwise defaultValue is
|
||||
// returned.
|
||||
func BatchSpanProcessorExportTimeout(defaultValue int) int {
|
||||
return IntEnvOr(BatchSpanProcessorExportTimeoutKey, defaultValue)
|
||||
}
|
||||
|
||||
// BatchSpanProcessorMaxQueueSize returns the environment variable value for
|
||||
// the OTEL_BSP_MAX_QUEUE_SIZE key if it exists, otherwise defaultValue is
|
||||
// returned.
|
||||
func BatchSpanProcessorMaxQueueSize(defaultValue int) int {
|
||||
return IntEnvOr(BatchSpanProcessorMaxQueueSizeKey, defaultValue)
|
||||
}
|
||||
|
||||
// BatchSpanProcessorMaxExportBatchSize returns the environment variable value for
|
||||
// the OTEL_BSP_MAX_EXPORT_BATCH_SIZE key if it exists, otherwise defaultValue
|
||||
// is returned.
|
||||
func BatchSpanProcessorMaxExportBatchSize(defaultValue int) int {
|
||||
return IntEnvOr(BatchSpanProcessorMaxExportBatchSizeKey, defaultValue)
|
||||
}
|
||||
|
||||
// SpanAttributeValueLength returns the environment variable value for the
|
||||
// OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT key if it exists. Otherwise, the
|
||||
// environment variable value for OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT is
|
||||
// returned or defaultValue if that is not set.
|
||||
func SpanAttributeValueLength(defaultValue int) int {
|
||||
return firstInt(defaultValue, SpanAttributeValueLengthKey, AttributeValueLengthKey)
|
||||
}
|
||||
|
||||
// SpanAttributeCount returns the environment variable value for the
|
||||
// OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT key if it exists. Otherwise, the
|
||||
// environment variable value for OTEL_ATTRIBUTE_COUNT_LIMIT is returned or
|
||||
// defaultValue if that is not set.
|
||||
func SpanAttributeCount(defaultValue int) int {
|
||||
return firstInt(defaultValue, SpanAttributeCountKey, AttributeCountKey)
|
||||
}
|
||||
|
||||
// SpanEventCount returns the environment variable value for the
|
||||
// OTEL_SPAN_EVENT_COUNT_LIMIT key if it exists, otherwise defaultValue is
|
||||
// returned.
|
||||
func SpanEventCount(defaultValue int) int {
|
||||
return IntEnvOr(SpanEventCountKey, defaultValue)
|
||||
}
|
||||
|
||||
// SpanEventAttributeCount returns the environment variable value for the
|
||||
// OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT key if it exists, otherwise defaultValue
|
||||
// is returned.
|
||||
func SpanEventAttributeCount(defaultValue int) int {
|
||||
return IntEnvOr(SpanEventAttributeCountKey, defaultValue)
|
||||
}
|
||||
|
||||
// SpanLinkCount returns the environment variable value for the
|
||||
// OTEL_SPAN_LINK_COUNT_LIMIT key if it exists, otherwise defaultValue is
|
||||
// returned.
|
||||
func SpanLinkCount(defaultValue int) int {
|
||||
return IntEnvOr(SpanLinkCountKey, defaultValue)
|
||||
}
|
||||
|
||||
// SpanLinkAttributeCount returns the environment variable value for the
|
||||
// OTEL_LINK_ATTRIBUTE_COUNT_LIMIT key if it exists, otherwise defaultValue is
|
||||
// returned.
|
||||
func SpanLinkAttributeCount(defaultValue int) int {
|
||||
return IntEnvOr(SpanLinkAttributeCountKey, defaultValue)
|
||||
}
|
46
e2e/vendor/go.opentelemetry.io/otel/sdk/internal/x/README.md
generated
vendored
Normal file
46
e2e/vendor/go.opentelemetry.io/otel/sdk/internal/x/README.md
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
# Experimental Features
|
||||
|
||||
The SDK contains features that have not yet stabilized in the OpenTelemetry specification.
|
||||
These features are added to the OpenTelemetry Go SDK prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
|
||||
|
||||
These feature may change in backwards incompatible ways as feedback is applied.
|
||||
See the [Compatibility and Stability](#compatibility-and-stability) section for more information.
|
||||
|
||||
## Features
|
||||
|
||||
- [Resource](#resource)
|
||||
|
||||
### Resource
|
||||
|
||||
[OpenTelemetry resource semantic conventions] include many attribute definitions that are defined as experimental.
|
||||
To have experimental semantic conventions be added by [resource detectors] set the `OTEL_GO_X_RESOURCE` environment variable.
|
||||
The value set must be the case-insensitive string of `"true"` to enable the feature.
|
||||
All other values are ignored.
|
||||
|
||||
<!-- TODO: document what attributes are added by which detector -->
|
||||
|
||||
[OpenTelemetry resource semantic conventions]: https://opentelemetry.io/docs/specs/semconv/resource/
|
||||
[resource detectors]: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/resource#Detector
|
||||
|
||||
#### Examples
|
||||
|
||||
Enable experimental resource semantic conventions.
|
||||
|
||||
```console
|
||||
export OTEL_GO_X_RESOURCE=true
|
||||
```
|
||||
|
||||
Disable experimental resource semantic conventions.
|
||||
|
||||
```console
|
||||
unset OTEL_GO_X_RESOURCE
|
||||
```
|
||||
|
||||
## Compatibility and Stability
|
||||
|
||||
Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../VERSIONING.md).
|
||||
These features may be removed or modified in successive version releases, including patch versions.
|
||||
|
||||
When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
|
||||
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
|
||||
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.
|
66
e2e/vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go
generated
vendored
Normal file
66
e2e/vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package x contains support for OTel SDK experimental features.
|
||||
//
|
||||
// This package should only be used for features defined in the specification.
|
||||
// It should not be used for experiments or new project ideas.
|
||||
package x // import "go.opentelemetry.io/otel/sdk/internal/x"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Resource is an experimental feature flag that defines if resource detectors
|
||||
// should be included experimental semantic conventions.
|
||||
//
|
||||
// To enable this feature set the OTEL_GO_X_RESOURCE environment variable
|
||||
// to the case-insensitive string value of "true" (i.e. "True" and "TRUE"
|
||||
// will also enable this).
|
||||
var Resource = newFeature("RESOURCE", func(v string) (string, bool) {
|
||||
if strings.ToLower(v) == "true" {
|
||||
return v, true
|
||||
}
|
||||
return "", false
|
||||
})
|
||||
|
||||
// Feature is an experimental feature control flag. It provides a uniform way
|
||||
// to interact with these feature flags and parse their values.
|
||||
type Feature[T any] struct {
|
||||
key string
|
||||
parse func(v string) (T, bool)
|
||||
}
|
||||
|
||||
func newFeature[T any](suffix string, parse func(string) (T, bool)) Feature[T] {
|
||||
const envKeyRoot = "OTEL_GO_X_"
|
||||
return Feature[T]{
|
||||
key: envKeyRoot + suffix,
|
||||
parse: parse,
|
||||
}
|
||||
}
|
||||
|
||||
// Key returns the environment variable key that needs to be set to enable the
|
||||
// feature.
|
||||
func (f Feature[T]) Key() string { return f.key }
|
||||
|
||||
// Lookup returns the user configured value for the feature and true if the
|
||||
// user has enabled the feature. Otherwise, if the feature is not enabled, a
|
||||
// zero-value and false are returned.
|
||||
func (f Feature[T]) Lookup() (v T, ok bool) {
|
||||
// https://github.com/open-telemetry/opentelemetry-specification/blob/62effed618589a0bec416a87e559c0a9d96289bb/specification/configuration/sdk-environment-variables.md#parsing-empty-value
|
||||
//
|
||||
// > The SDK MUST interpret an empty value of an environment variable the
|
||||
// > same way as when the variable is unset.
|
||||
vRaw := os.Getenv(f.key)
|
||||
if vRaw == "" {
|
||||
return v, ok
|
||||
}
|
||||
return f.parse(vRaw)
|
||||
}
|
||||
|
||||
// Enabled returns if the feature is enabled.
|
||||
func (f Feature[T]) Enabled() bool {
|
||||
_, ok := f.Lookup()
|
||||
return ok
|
||||
}
|
3
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/README.md
generated
vendored
Normal file
3
e2e/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)
|
92
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/auto.go
generated
vendored
Normal file
92
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/auto.go
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// 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
|
||||
err error
|
||||
e error
|
||||
)
|
||||
|
||||
for _, detector := range detectors {
|
||||
if detector == nil {
|
||||
continue
|
||||
}
|
||||
r, e = detector.Detect(ctx)
|
||||
if e != nil {
|
||||
err = errors.Join(err, e)
|
||||
if !errors.Is(e, ErrPartialResource) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
r, e = Merge(res, r)
|
||||
if e != nil {
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
*res = *r
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrSchemaURLConflict) {
|
||||
// If there has been a merge conflict, ensure the resource has no
|
||||
// schema URL.
|
||||
res.schemaURL = ""
|
||||
}
|
||||
|
||||
err = fmt.Errorf("error detecting resource: %w", err)
|
||||
}
|
||||
return err
|
||||
}
|
116
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go
generated
vendored
Normal file
116
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go
generated
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
// 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
|
||||
// resource.New() 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
|
||||
// resource.New() 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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/config.go
generated
vendored
Normal file
195
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/container.go
generated
vendored
Normal file
89
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/doc.go
generated
vendored
Normal file
20
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/env.go
generated
vendored
Normal file
95
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go
generated
vendored
Normal file
109
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_bsd.go
generated
vendored
Normal file
12
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_darwin.go
generated
vendored
Normal file
8
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_exec.go
generated
vendored
Normal file
18
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_linux.go
generated
vendored
Normal file
11
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_readfile.go
generated
vendored
Normal file
17
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_unsupported.go
generated
vendored
Normal file
19
e2e/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{}
|
36
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_windows.go
generated
vendored
Normal file
36
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/host_id_windows.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// 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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/os.go
generated
vendored
Normal file
89
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_darwin.go
generated
vendored
Normal file
91
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_unix.go
generated
vendored
Normal file
143
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/os_unix.go
generated
vendored
Normal file
79
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/os_unsupported.go
generated
vendored
Normal file
15
e2e/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
|
||||
}
|
89
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/os_windows.go
generated
vendored
Normal file
89
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/os_windows.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 (
|
||||
"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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/process.go
generated
vendored
Normal file
173
e2e/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
e2e/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go
generated
vendored
Normal file
294
e2e/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)
|
||||
}
|
3
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/README.md
generated
vendored
Normal file
3
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/README.md
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# SDK Trace
|
||||
|
||||
[](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace)
|
414
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go
generated
vendored
Normal file
414
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go
generated
vendored
Normal file
@ -0,0 +1,414 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/internal/global"
|
||||
"go.opentelemetry.io/otel/sdk/internal/env"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// Defaults for BatchSpanProcessorOptions.
|
||||
const (
|
||||
DefaultMaxQueueSize = 2048
|
||||
DefaultScheduleDelay = 5000
|
||||
DefaultExportTimeout = 30000
|
||||
DefaultMaxExportBatchSize = 512
|
||||
)
|
||||
|
||||
// BatchSpanProcessorOption configures a BatchSpanProcessor.
|
||||
type BatchSpanProcessorOption func(o *BatchSpanProcessorOptions)
|
||||
|
||||
// BatchSpanProcessorOptions is configuration settings for a
|
||||
// BatchSpanProcessor.
|
||||
type BatchSpanProcessorOptions struct {
|
||||
// MaxQueueSize is the maximum queue size to buffer spans for delayed processing. If the
|
||||
// queue gets full it drops the spans. Use BlockOnQueueFull to change this behavior.
|
||||
// The default value of MaxQueueSize is 2048.
|
||||
MaxQueueSize int
|
||||
|
||||
// BatchTimeout is the maximum duration for constructing a batch. Processor
|
||||
// forcefully sends available spans when timeout is reached.
|
||||
// The default value of BatchTimeout is 5000 msec.
|
||||
BatchTimeout time.Duration
|
||||
|
||||
// ExportTimeout specifies the maximum duration for exporting spans. If the timeout
|
||||
// is reached, the export will be cancelled.
|
||||
// The default value of ExportTimeout is 30000 msec.
|
||||
ExportTimeout time.Duration
|
||||
|
||||
// MaxExportBatchSize is the maximum number of spans to process in a single batch.
|
||||
// If there are more than one batch worth of spans then it processes multiple batches
|
||||
// of spans one batch after the other without any delay.
|
||||
// The default value of MaxExportBatchSize is 512.
|
||||
MaxExportBatchSize int
|
||||
|
||||
// BlockOnQueueFull blocks onEnd() and onStart() method if the queue is full
|
||||
// AND if BlockOnQueueFull is set to true.
|
||||
// Blocking option should be used carefully as it can severely affect the performance of an
|
||||
// application.
|
||||
BlockOnQueueFull bool
|
||||
}
|
||||
|
||||
// batchSpanProcessor is a SpanProcessor that batches asynchronously-received
|
||||
// spans and sends them to a trace.Exporter when complete.
|
||||
type batchSpanProcessor struct {
|
||||
e SpanExporter
|
||||
o BatchSpanProcessorOptions
|
||||
|
||||
queue chan ReadOnlySpan
|
||||
dropped uint32
|
||||
|
||||
batch []ReadOnlySpan
|
||||
batchMutex sync.Mutex
|
||||
timer *time.Timer
|
||||
stopWait sync.WaitGroup
|
||||
stopOnce sync.Once
|
||||
stopCh chan struct{}
|
||||
stopped atomic.Bool
|
||||
}
|
||||
|
||||
var _ SpanProcessor = (*batchSpanProcessor)(nil)
|
||||
|
||||
// NewBatchSpanProcessor creates a new SpanProcessor that will send completed
|
||||
// span batches to the exporter with the supplied options.
|
||||
//
|
||||
// If the exporter is nil, the span processor will perform no action.
|
||||
func NewBatchSpanProcessor(exporter SpanExporter, options ...BatchSpanProcessorOption) SpanProcessor {
|
||||
maxQueueSize := env.BatchSpanProcessorMaxQueueSize(DefaultMaxQueueSize)
|
||||
maxExportBatchSize := env.BatchSpanProcessorMaxExportBatchSize(DefaultMaxExportBatchSize)
|
||||
|
||||
if maxExportBatchSize > maxQueueSize {
|
||||
if DefaultMaxExportBatchSize > maxQueueSize {
|
||||
maxExportBatchSize = maxQueueSize
|
||||
} else {
|
||||
maxExportBatchSize = DefaultMaxExportBatchSize
|
||||
}
|
||||
}
|
||||
|
||||
o := BatchSpanProcessorOptions{
|
||||
BatchTimeout: time.Duration(env.BatchSpanProcessorScheduleDelay(DefaultScheduleDelay)) * time.Millisecond,
|
||||
ExportTimeout: time.Duration(env.BatchSpanProcessorExportTimeout(DefaultExportTimeout)) * time.Millisecond,
|
||||
MaxQueueSize: maxQueueSize,
|
||||
MaxExportBatchSize: maxExportBatchSize,
|
||||
}
|
||||
for _, opt := range options {
|
||||
opt(&o)
|
||||
}
|
||||
bsp := &batchSpanProcessor{
|
||||
e: exporter,
|
||||
o: o,
|
||||
batch: make([]ReadOnlySpan, 0, o.MaxExportBatchSize),
|
||||
timer: time.NewTimer(o.BatchTimeout),
|
||||
queue: make(chan ReadOnlySpan, o.MaxQueueSize),
|
||||
stopCh: make(chan struct{}),
|
||||
}
|
||||
|
||||
bsp.stopWait.Add(1)
|
||||
go func() {
|
||||
defer bsp.stopWait.Done()
|
||||
bsp.processQueue()
|
||||
bsp.drainQueue()
|
||||
}()
|
||||
|
||||
return bsp
|
||||
}
|
||||
|
||||
// OnStart method does nothing.
|
||||
func (bsp *batchSpanProcessor) OnStart(parent context.Context, s ReadWriteSpan) {}
|
||||
|
||||
// OnEnd method enqueues a ReadOnlySpan for later processing.
|
||||
func (bsp *batchSpanProcessor) OnEnd(s ReadOnlySpan) {
|
||||
// Do not enqueue spans after Shutdown.
|
||||
if bsp.stopped.Load() {
|
||||
return
|
||||
}
|
||||
|
||||
// Do not enqueue spans if we are just going to drop them.
|
||||
if bsp.e == nil {
|
||||
return
|
||||
}
|
||||
bsp.enqueue(s)
|
||||
}
|
||||
|
||||
// Shutdown flushes the queue and waits until all spans are processed.
|
||||
// It only executes once. Subsequent call does nothing.
|
||||
func (bsp *batchSpanProcessor) Shutdown(ctx context.Context) error {
|
||||
var err error
|
||||
bsp.stopOnce.Do(func() {
|
||||
bsp.stopped.Store(true)
|
||||
wait := make(chan struct{})
|
||||
go func() {
|
||||
close(bsp.stopCh)
|
||||
bsp.stopWait.Wait()
|
||||
if bsp.e != nil {
|
||||
if err := bsp.e.Shutdown(ctx); err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
}
|
||||
close(wait)
|
||||
}()
|
||||
// Wait until the wait group is done or the context is cancelled
|
||||
select {
|
||||
case <-wait:
|
||||
case <-ctx.Done():
|
||||
err = ctx.Err()
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
type forceFlushSpan struct {
|
||||
ReadOnlySpan
|
||||
flushed chan struct{}
|
||||
}
|
||||
|
||||
func (f forceFlushSpan) SpanContext() trace.SpanContext {
|
||||
return trace.NewSpanContext(trace.SpanContextConfig{TraceFlags: trace.FlagsSampled})
|
||||
}
|
||||
|
||||
// ForceFlush exports all ended spans that have not yet been exported.
|
||||
func (bsp *batchSpanProcessor) ForceFlush(ctx context.Context) error {
|
||||
// Interrupt if context is already canceled.
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Do nothing after Shutdown.
|
||||
if bsp.stopped.Load() {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
if bsp.e != nil {
|
||||
flushCh := make(chan struct{})
|
||||
if bsp.enqueueBlockOnQueueFull(ctx, forceFlushSpan{flushed: flushCh}) {
|
||||
select {
|
||||
case <-bsp.stopCh:
|
||||
// The batchSpanProcessor is Shutdown.
|
||||
return nil
|
||||
case <-flushCh:
|
||||
// Processed any items in queue prior to ForceFlush being called
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
wait := make(chan error)
|
||||
go func() {
|
||||
wait <- bsp.exportSpans(ctx)
|
||||
close(wait)
|
||||
}()
|
||||
// Wait until the export is finished or the context is cancelled/timed out
|
||||
select {
|
||||
case err = <-wait:
|
||||
case <-ctx.Done():
|
||||
err = ctx.Err()
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// WithMaxQueueSize returns a BatchSpanProcessorOption that configures the
|
||||
// maximum queue size allowed for a BatchSpanProcessor.
|
||||
func WithMaxQueueSize(size int) BatchSpanProcessorOption {
|
||||
return func(o *BatchSpanProcessorOptions) {
|
||||
o.MaxQueueSize = size
|
||||
}
|
||||
}
|
||||
|
||||
// WithMaxExportBatchSize returns a BatchSpanProcessorOption that configures
|
||||
// the maximum export batch size allowed for a BatchSpanProcessor.
|
||||
func WithMaxExportBatchSize(size int) BatchSpanProcessorOption {
|
||||
return func(o *BatchSpanProcessorOptions) {
|
||||
o.MaxExportBatchSize = size
|
||||
}
|
||||
}
|
||||
|
||||
// WithBatchTimeout returns a BatchSpanProcessorOption that configures the
|
||||
// maximum delay allowed for a BatchSpanProcessor before it will export any
|
||||
// held span (whether the queue is full or not).
|
||||
func WithBatchTimeout(delay time.Duration) BatchSpanProcessorOption {
|
||||
return func(o *BatchSpanProcessorOptions) {
|
||||
o.BatchTimeout = delay
|
||||
}
|
||||
}
|
||||
|
||||
// WithExportTimeout returns a BatchSpanProcessorOption that configures the
|
||||
// amount of time a BatchSpanProcessor waits for an exporter to export before
|
||||
// abandoning the export.
|
||||
func WithExportTimeout(timeout time.Duration) BatchSpanProcessorOption {
|
||||
return func(o *BatchSpanProcessorOptions) {
|
||||
o.ExportTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// WithBlocking returns a BatchSpanProcessorOption that configures a
|
||||
// BatchSpanProcessor to wait for enqueue operations to succeed instead of
|
||||
// dropping data when the queue is full.
|
||||
func WithBlocking() BatchSpanProcessorOption {
|
||||
return func(o *BatchSpanProcessorOptions) {
|
||||
o.BlockOnQueueFull = true
|
||||
}
|
||||
}
|
||||
|
||||
// exportSpans is a subroutine of processing and draining the queue.
|
||||
func (bsp *batchSpanProcessor) exportSpans(ctx context.Context) error {
|
||||
bsp.timer.Reset(bsp.o.BatchTimeout)
|
||||
|
||||
bsp.batchMutex.Lock()
|
||||
defer bsp.batchMutex.Unlock()
|
||||
|
||||
if bsp.o.ExportTimeout > 0 {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(ctx, bsp.o.ExportTimeout)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
if l := len(bsp.batch); l > 0 {
|
||||
global.Debug("exporting spans", "count", len(bsp.batch), "total_dropped", atomic.LoadUint32(&bsp.dropped))
|
||||
err := bsp.e.ExportSpans(ctx, bsp.batch)
|
||||
|
||||
// A new batch is always created after exporting, even if the batch failed to be exported.
|
||||
//
|
||||
// It is up to the exporter to implement any type of retry logic if a batch is failing
|
||||
// to be exported, since it is specific to the protocol and backend being sent to.
|
||||
clear(bsp.batch) // Erase elements to let GC collect objects
|
||||
bsp.batch = bsp.batch[:0]
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// processQueue removes spans from the `queue` channel until processor
|
||||
// is shut down. It calls the exporter in batches of up to MaxExportBatchSize
|
||||
// waiting up to BatchTimeout to form a batch.
|
||||
func (bsp *batchSpanProcessor) processQueue() {
|
||||
defer bsp.timer.Stop()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
for {
|
||||
select {
|
||||
case <-bsp.stopCh:
|
||||
return
|
||||
case <-bsp.timer.C:
|
||||
if err := bsp.exportSpans(ctx); err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
case sd := <-bsp.queue:
|
||||
if ffs, ok := sd.(forceFlushSpan); ok {
|
||||
close(ffs.flushed)
|
||||
continue
|
||||
}
|
||||
bsp.batchMutex.Lock()
|
||||
bsp.batch = append(bsp.batch, sd)
|
||||
shouldExport := len(bsp.batch) >= bsp.o.MaxExportBatchSize
|
||||
bsp.batchMutex.Unlock()
|
||||
if shouldExport {
|
||||
if !bsp.timer.Stop() {
|
||||
// Handle both GODEBUG=asynctimerchan=[0|1] properly.
|
||||
select {
|
||||
case <-bsp.timer.C:
|
||||
default:
|
||||
}
|
||||
}
|
||||
if err := bsp.exportSpans(ctx); err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// drainQueue awaits the any caller that had added to bsp.stopWait
|
||||
// to finish the enqueue, then exports the final batch.
|
||||
func (bsp *batchSpanProcessor) drainQueue() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
for {
|
||||
select {
|
||||
case sd := <-bsp.queue:
|
||||
if _, ok := sd.(forceFlushSpan); ok {
|
||||
// Ignore flush requests as they are not valid spans.
|
||||
continue
|
||||
}
|
||||
|
||||
bsp.batchMutex.Lock()
|
||||
bsp.batch = append(bsp.batch, sd)
|
||||
shouldExport := len(bsp.batch) == bsp.o.MaxExportBatchSize
|
||||
bsp.batchMutex.Unlock()
|
||||
|
||||
if shouldExport {
|
||||
if err := bsp.exportSpans(ctx); err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
}
|
||||
default:
|
||||
// There are no more enqueued spans. Make final export.
|
||||
if err := bsp.exportSpans(ctx); err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (bsp *batchSpanProcessor) enqueue(sd ReadOnlySpan) {
|
||||
ctx := context.TODO()
|
||||
if bsp.o.BlockOnQueueFull {
|
||||
bsp.enqueueBlockOnQueueFull(ctx, sd)
|
||||
} else {
|
||||
bsp.enqueueDrop(ctx, sd)
|
||||
}
|
||||
}
|
||||
|
||||
func (bsp *batchSpanProcessor) enqueueBlockOnQueueFull(ctx context.Context, sd ReadOnlySpan) bool {
|
||||
if !sd.SpanContext().IsSampled() {
|
||||
return false
|
||||
}
|
||||
|
||||
select {
|
||||
case bsp.queue <- sd:
|
||||
return true
|
||||
case <-ctx.Done():
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (bsp *batchSpanProcessor) enqueueDrop(_ context.Context, sd ReadOnlySpan) bool {
|
||||
if !sd.SpanContext().IsSampled() {
|
||||
return false
|
||||
}
|
||||
|
||||
select {
|
||||
case bsp.queue <- sd:
|
||||
return true
|
||||
default:
|
||||
atomic.AddUint32(&bsp.dropped, 1)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MarshalLog is the marshaling function used by the logging system to represent this Span Processor.
|
||||
func (bsp *batchSpanProcessor) MarshalLog() interface{} {
|
||||
return struct {
|
||||
Type string
|
||||
SpanExporter SpanExporter
|
||||
Config BatchSpanProcessorOptions
|
||||
}{
|
||||
Type: "BatchSpanProcessor",
|
||||
SpanExporter: bsp.e,
|
||||
Config: bsp.o,
|
||||
}
|
||||
}
|
10
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/doc.go
generated
vendored
Normal file
10
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/doc.go
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/*
|
||||
Package trace contains support for OpenTelemetry distributed tracing.
|
||||
|
||||
The following assumes a basic familiarity with OpenTelemetry concepts.
|
||||
See https://opentelemetry.io.
|
||||
*/
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
26
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/event.go
generated
vendored
Normal file
26
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/event.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
)
|
||||
|
||||
// Event is a thing that happened during a Span's lifetime.
|
||||
type Event struct {
|
||||
// Name is the name of this event
|
||||
Name string
|
||||
|
||||
// Attributes describe the aspects of the event.
|
||||
Attributes []attribute.KeyValue
|
||||
|
||||
// DroppedAttributeCount is the number of attributes that were not
|
||||
// recorded due to configured limits being reached.
|
||||
DroppedAttributeCount int
|
||||
|
||||
// Time at which this event was recorded.
|
||||
Time time.Time
|
||||
}
|
64
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/evictedqueue.go
generated
vendored
Normal file
64
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/evictedqueue.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"go.opentelemetry.io/otel/internal/global"
|
||||
)
|
||||
|
||||
// evictedQueue is a FIFO queue with a configurable capacity.
|
||||
type evictedQueue[T any] struct {
|
||||
queue []T
|
||||
capacity int
|
||||
droppedCount int
|
||||
logDroppedMsg string
|
||||
logDroppedOnce sync.Once
|
||||
}
|
||||
|
||||
func newEvictedQueueEvent(capacity int) evictedQueue[Event] {
|
||||
// Do not pre-allocate queue, do this lazily.
|
||||
return evictedQueue[Event]{
|
||||
capacity: capacity,
|
||||
logDroppedMsg: "limit reached: dropping trace trace.Event",
|
||||
}
|
||||
}
|
||||
|
||||
func newEvictedQueueLink(capacity int) evictedQueue[Link] {
|
||||
// Do not pre-allocate queue, do this lazily.
|
||||
return evictedQueue[Link]{
|
||||
capacity: capacity,
|
||||
logDroppedMsg: "limit reached: dropping trace trace.Link",
|
||||
}
|
||||
}
|
||||
|
||||
// add adds value to the evictedQueue eq. If eq is at capacity, the oldest
|
||||
// queued value will be discarded and the drop count incremented.
|
||||
func (eq *evictedQueue[T]) add(value T) {
|
||||
if eq.capacity == 0 {
|
||||
eq.droppedCount++
|
||||
eq.logDropped()
|
||||
return
|
||||
}
|
||||
|
||||
if eq.capacity > 0 && len(eq.queue) == eq.capacity {
|
||||
// Drop first-in while avoiding allocating more capacity to eq.queue.
|
||||
copy(eq.queue[:eq.capacity-1], eq.queue[1:])
|
||||
eq.queue = eq.queue[:eq.capacity-1]
|
||||
eq.droppedCount++
|
||||
eq.logDropped()
|
||||
}
|
||||
eq.queue = append(eq.queue, value)
|
||||
}
|
||||
|
||||
func (eq *evictedQueue[T]) logDropped() {
|
||||
eq.logDroppedOnce.Do(func() { global.Warn(eq.logDroppedMsg) })
|
||||
}
|
||||
|
||||
// copy returns a copy of the evictedQueue.
|
||||
func (eq *evictedQueue[T]) copy() []T {
|
||||
return slices.Clone(eq.queue)
|
||||
}
|
81
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/id_generator.go
generated
vendored
Normal file
81
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/id_generator.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import (
|
||||
"context"
|
||||
crand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"math/rand"
|
||||
"sync"
|
||||
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// IDGenerator allows custom generators for TraceID and SpanID.
|
||||
type IDGenerator interface {
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
|
||||
// NewIDs returns a new trace and span ID.
|
||||
NewIDs(ctx context.Context) (trace.TraceID, trace.SpanID)
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
|
||||
// NewSpanID returns a ID for a new span in the trace with traceID.
|
||||
NewSpanID(ctx context.Context, traceID trace.TraceID) trace.SpanID
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
}
|
||||
|
||||
type randomIDGenerator struct {
|
||||
sync.Mutex
|
||||
randSource *rand.Rand
|
||||
}
|
||||
|
||||
var _ IDGenerator = &randomIDGenerator{}
|
||||
|
||||
// NewSpanID returns a non-zero span ID from a randomly-chosen sequence.
|
||||
func (gen *randomIDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) trace.SpanID {
|
||||
gen.Lock()
|
||||
defer gen.Unlock()
|
||||
sid := trace.SpanID{}
|
||||
for {
|
||||
_, _ = gen.randSource.Read(sid[:])
|
||||
if sid.IsValid() {
|
||||
break
|
||||
}
|
||||
}
|
||||
return sid
|
||||
}
|
||||
|
||||
// NewIDs returns a non-zero trace ID and a non-zero span ID from a
|
||||
// randomly-chosen sequence.
|
||||
func (gen *randomIDGenerator) NewIDs(ctx context.Context) (trace.TraceID, trace.SpanID) {
|
||||
gen.Lock()
|
||||
defer gen.Unlock()
|
||||
tid := trace.TraceID{}
|
||||
sid := trace.SpanID{}
|
||||
for {
|
||||
_, _ = gen.randSource.Read(tid[:])
|
||||
if tid.IsValid() {
|
||||
break
|
||||
}
|
||||
}
|
||||
for {
|
||||
_, _ = gen.randSource.Read(sid[:])
|
||||
if sid.IsValid() {
|
||||
break
|
||||
}
|
||||
}
|
||||
return tid, sid
|
||||
}
|
||||
|
||||
func defaultIDGenerator() IDGenerator {
|
||||
gen := &randomIDGenerator{}
|
||||
var rngSeed int64
|
||||
_ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed)
|
||||
gen.randSource = rand.New(rand.NewSource(rngSeed))
|
||||
return gen
|
||||
}
|
23
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/link.go
generated
vendored
Normal file
23
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/link.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import (
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// Link is the relationship between two Spans. The relationship can be within
|
||||
// the same Trace or across different Traces.
|
||||
type Link struct {
|
||||
// SpanContext of the linked Span.
|
||||
SpanContext trace.SpanContext
|
||||
|
||||
// Attributes describe the aspects of the link.
|
||||
Attributes []attribute.KeyValue
|
||||
|
||||
// DroppedAttributeCount is the number of attributes that were not
|
||||
// recorded due to configured limits being reached.
|
||||
DroppedAttributeCount int
|
||||
}
|
494
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go
generated
vendored
Normal file
494
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go
generated
vendored
Normal file
@ -0,0 +1,494 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/internal/global"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.opentelemetry.io/otel/trace/embedded"
|
||||
"go.opentelemetry.io/otel/trace/noop"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTracerName = "go.opentelemetry.io/otel/sdk/tracer"
|
||||
)
|
||||
|
||||
// tracerProviderConfig.
|
||||
type tracerProviderConfig struct {
|
||||
// processors contains collection of SpanProcessors that are processing pipeline
|
||||
// for spans in the trace signal.
|
||||
// SpanProcessors registered with a TracerProvider and are called at the start
|
||||
// and end of a Span's lifecycle, and are called in the order they are
|
||||
// registered.
|
||||
processors []SpanProcessor
|
||||
|
||||
// sampler is the default sampler used when creating new spans.
|
||||
sampler Sampler
|
||||
|
||||
// idGenerator is used to generate all Span and Trace IDs when needed.
|
||||
idGenerator IDGenerator
|
||||
|
||||
// spanLimits defines the attribute, event, and link limits for spans.
|
||||
spanLimits SpanLimits
|
||||
|
||||
// resource contains attributes representing an entity that produces telemetry.
|
||||
resource *resource.Resource
|
||||
}
|
||||
|
||||
// MarshalLog is the marshaling function used by the logging system to represent this Provider.
|
||||
func (cfg tracerProviderConfig) MarshalLog() interface{} {
|
||||
return struct {
|
||||
SpanProcessors []SpanProcessor
|
||||
SamplerType string
|
||||
IDGeneratorType string
|
||||
SpanLimits SpanLimits
|
||||
Resource *resource.Resource
|
||||
}{
|
||||
SpanProcessors: cfg.processors,
|
||||
SamplerType: fmt.Sprintf("%T", cfg.sampler),
|
||||
IDGeneratorType: fmt.Sprintf("%T", cfg.idGenerator),
|
||||
SpanLimits: cfg.spanLimits,
|
||||
Resource: cfg.resource,
|
||||
}
|
||||
}
|
||||
|
||||
// TracerProvider is an OpenTelemetry TracerProvider. It provides Tracers to
|
||||
// instrumentation so it can trace operational flow through a system.
|
||||
type TracerProvider struct {
|
||||
embedded.TracerProvider
|
||||
|
||||
mu sync.Mutex
|
||||
namedTracer map[instrumentation.Scope]*tracer
|
||||
spanProcessors atomic.Pointer[spanProcessorStates]
|
||||
|
||||
isShutdown atomic.Bool
|
||||
|
||||
// These fields are not protected by the lock mu. They are assumed to be
|
||||
// immutable after creation of the TracerProvider.
|
||||
sampler Sampler
|
||||
idGenerator IDGenerator
|
||||
spanLimits SpanLimits
|
||||
resource *resource.Resource
|
||||
}
|
||||
|
||||
var _ trace.TracerProvider = &TracerProvider{}
|
||||
|
||||
// NewTracerProvider returns a new and configured TracerProvider.
|
||||
//
|
||||
// By default the returned TracerProvider is configured with:
|
||||
// - a ParentBased(AlwaysSample) Sampler
|
||||
// - a random number IDGenerator
|
||||
// - the resource.Default() Resource
|
||||
// - the default SpanLimits.
|
||||
//
|
||||
// The passed opts are used to override these default values and configure the
|
||||
// returned TracerProvider appropriately.
|
||||
func NewTracerProvider(opts ...TracerProviderOption) *TracerProvider {
|
||||
o := tracerProviderConfig{
|
||||
spanLimits: NewSpanLimits(),
|
||||
}
|
||||
o = applyTracerProviderEnvConfigs(o)
|
||||
|
||||
for _, opt := range opts {
|
||||
o = opt.apply(o)
|
||||
}
|
||||
|
||||
o = ensureValidTracerProviderConfig(o)
|
||||
|
||||
tp := &TracerProvider{
|
||||
namedTracer: make(map[instrumentation.Scope]*tracer),
|
||||
sampler: o.sampler,
|
||||
idGenerator: o.idGenerator,
|
||||
spanLimits: o.spanLimits,
|
||||
resource: o.resource,
|
||||
}
|
||||
global.Info("TracerProvider created", "config", o)
|
||||
|
||||
spss := make(spanProcessorStates, 0, len(o.processors))
|
||||
for _, sp := range o.processors {
|
||||
spss = append(spss, newSpanProcessorState(sp))
|
||||
}
|
||||
tp.spanProcessors.Store(&spss)
|
||||
|
||||
return tp
|
||||
}
|
||||
|
||||
// Tracer returns a Tracer with the given name and options. If a Tracer for
|
||||
// the given name and options does not exist it is created, otherwise the
|
||||
// existing Tracer is returned.
|
||||
//
|
||||
// If name is empty, DefaultTracerName is used instead.
|
||||
//
|
||||
// This method is safe to be called concurrently.
|
||||
func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer {
|
||||
// This check happens before the mutex is acquired to avoid deadlocking if Tracer() is called from within Shutdown().
|
||||
if p.isShutdown.Load() {
|
||||
return noop.NewTracerProvider().Tracer(name, opts...)
|
||||
}
|
||||
c := trace.NewTracerConfig(opts...)
|
||||
if name == "" {
|
||||
name = defaultTracerName
|
||||
}
|
||||
is := instrumentation.Scope{
|
||||
Name: name,
|
||||
Version: c.InstrumentationVersion(),
|
||||
SchemaURL: c.SchemaURL(),
|
||||
Attributes: c.InstrumentationAttributes(),
|
||||
}
|
||||
|
||||
t, ok := func() (trace.Tracer, bool) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
// Must check the flag after acquiring the mutex to avoid returning a valid tracer if Shutdown() ran
|
||||
// after the first check above but before we acquired the mutex.
|
||||
if p.isShutdown.Load() {
|
||||
return noop.NewTracerProvider().Tracer(name, opts...), true
|
||||
}
|
||||
t, ok := p.namedTracer[is]
|
||||
if !ok {
|
||||
t = &tracer{
|
||||
provider: p,
|
||||
instrumentationScope: is,
|
||||
}
|
||||
p.namedTracer[is] = t
|
||||
}
|
||||
return t, ok
|
||||
}()
|
||||
if !ok {
|
||||
// This code is outside the mutex to not hold the lock while calling third party logging code:
|
||||
// - That code may do slow things like I/O, which would prolong the duration the lock is held,
|
||||
// slowing down all tracing consumers.
|
||||
// - Logging code may be instrumented with tracing and deadlock because it could try
|
||||
// acquiring the same non-reentrant mutex.
|
||||
global.Info("Tracer created", "name", name, "version", is.Version, "schemaURL", is.SchemaURL, "attributes", is.Attributes)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// RegisterSpanProcessor adds the given SpanProcessor to the list of SpanProcessors.
|
||||
func (p *TracerProvider) RegisterSpanProcessor(sp SpanProcessor) {
|
||||
// This check prevents calls during a shutdown.
|
||||
if p.isShutdown.Load() {
|
||||
return
|
||||
}
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
// This check prevents calls after a shutdown.
|
||||
if p.isShutdown.Load() {
|
||||
return
|
||||
}
|
||||
|
||||
current := p.getSpanProcessors()
|
||||
newSPS := make(spanProcessorStates, 0, len(current)+1)
|
||||
newSPS = append(newSPS, current...)
|
||||
newSPS = append(newSPS, newSpanProcessorState(sp))
|
||||
p.spanProcessors.Store(&newSPS)
|
||||
}
|
||||
|
||||
// UnregisterSpanProcessor removes the given SpanProcessor from the list of SpanProcessors.
|
||||
func (p *TracerProvider) UnregisterSpanProcessor(sp SpanProcessor) {
|
||||
// This check prevents calls during a shutdown.
|
||||
if p.isShutdown.Load() {
|
||||
return
|
||||
}
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
// This check prevents calls after a shutdown.
|
||||
if p.isShutdown.Load() {
|
||||
return
|
||||
}
|
||||
old := p.getSpanProcessors()
|
||||
if len(old) == 0 {
|
||||
return
|
||||
}
|
||||
spss := make(spanProcessorStates, len(old))
|
||||
copy(spss, old)
|
||||
|
||||
// stop the span processor if it is started and remove it from the list
|
||||
var stopOnce *spanProcessorState
|
||||
var idx int
|
||||
for i, sps := range spss {
|
||||
if sps.sp == sp {
|
||||
stopOnce = sps
|
||||
idx = i
|
||||
}
|
||||
}
|
||||
if stopOnce != nil {
|
||||
stopOnce.state.Do(func() {
|
||||
if err := sp.Shutdown(context.Background()); err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
if len(spss) > 1 {
|
||||
copy(spss[idx:], spss[idx+1:])
|
||||
}
|
||||
spss[len(spss)-1] = nil
|
||||
spss = spss[:len(spss)-1]
|
||||
|
||||
p.spanProcessors.Store(&spss)
|
||||
}
|
||||
|
||||
// ForceFlush immediately exports all spans that have not yet been exported for
|
||||
// all the registered span processors.
|
||||
func (p *TracerProvider) ForceFlush(ctx context.Context) error {
|
||||
spss := p.getSpanProcessors()
|
||||
if len(spss) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, sps := range spss {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err := sps.sp.ForceFlush(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shutdown shuts down TracerProvider. All registered span processors are shut down
|
||||
// in the order they were registered and any held computational resources are released.
|
||||
// After Shutdown is called, all methods are no-ops.
|
||||
func (p *TracerProvider) Shutdown(ctx context.Context) error {
|
||||
// This check prevents deadlocks in case of recursive shutdown.
|
||||
if p.isShutdown.Load() {
|
||||
return nil
|
||||
}
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
// This check prevents calls after a shutdown has already been done concurrently.
|
||||
if !p.isShutdown.CompareAndSwap(false, true) { // did toggle?
|
||||
return nil
|
||||
}
|
||||
|
||||
var retErr error
|
||||
for _, sps := range p.getSpanProcessors() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
var err error
|
||||
sps.state.Do(func() {
|
||||
err = sps.sp.Shutdown(ctx)
|
||||
})
|
||||
if err != nil {
|
||||
if retErr == nil {
|
||||
retErr = err
|
||||
} else {
|
||||
// Poor man's list of errors
|
||||
retErr = fmt.Errorf("%w; %w", retErr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
p.spanProcessors.Store(&spanProcessorStates{})
|
||||
return retErr
|
||||
}
|
||||
|
||||
func (p *TracerProvider) getSpanProcessors() spanProcessorStates {
|
||||
return *(p.spanProcessors.Load())
|
||||
}
|
||||
|
||||
// TracerProviderOption configures a TracerProvider.
|
||||
type TracerProviderOption interface {
|
||||
apply(tracerProviderConfig) tracerProviderConfig
|
||||
}
|
||||
|
||||
type traceProviderOptionFunc func(tracerProviderConfig) tracerProviderConfig
|
||||
|
||||
func (fn traceProviderOptionFunc) apply(cfg tracerProviderConfig) tracerProviderConfig {
|
||||
return fn(cfg)
|
||||
}
|
||||
|
||||
// WithSyncer registers the exporter with the TracerProvider using a
|
||||
// SimpleSpanProcessor.
|
||||
//
|
||||
// This is not recommended for production use. The synchronous nature of the
|
||||
// SimpleSpanProcessor that will wrap the exporter make it good for testing,
|
||||
// debugging, or showing examples of other feature, but it will be slow and
|
||||
// have a high computation resource usage overhead. The WithBatcher option is
|
||||
// recommended for production use instead.
|
||||
func WithSyncer(e SpanExporter) TracerProviderOption {
|
||||
return WithSpanProcessor(NewSimpleSpanProcessor(e))
|
||||
}
|
||||
|
||||
// WithBatcher registers the exporter with the TracerProvider using a
|
||||
// BatchSpanProcessor configured with the passed opts.
|
||||
func WithBatcher(e SpanExporter, opts ...BatchSpanProcessorOption) TracerProviderOption {
|
||||
return WithSpanProcessor(NewBatchSpanProcessor(e, opts...))
|
||||
}
|
||||
|
||||
// WithSpanProcessor registers the SpanProcessor with a TracerProvider.
|
||||
func WithSpanProcessor(sp SpanProcessor) TracerProviderOption {
|
||||
return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
|
||||
cfg.processors = append(cfg.processors, sp)
|
||||
return cfg
|
||||
})
|
||||
}
|
||||
|
||||
// WithResource returns a TracerProviderOption that will configure the
|
||||
// Resource r as a TracerProvider's Resource. The configured Resource is
|
||||
// referenced by all the Tracers the TracerProvider creates. It represents the
|
||||
// entity producing telemetry.
|
||||
//
|
||||
// If this option is not used, the TracerProvider will use the
|
||||
// resource.Default() Resource by default.
|
||||
func WithResource(r *resource.Resource) TracerProviderOption {
|
||||
return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
|
||||
var err error
|
||||
cfg.resource, err = resource.Merge(resource.Environment(), r)
|
||||
if err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
return cfg
|
||||
})
|
||||
}
|
||||
|
||||
// WithIDGenerator returns a TracerProviderOption that will configure the
|
||||
// IDGenerator g as a TracerProvider's IDGenerator. The configured IDGenerator
|
||||
// is used by the Tracers the TracerProvider creates to generate new Span and
|
||||
// Trace IDs.
|
||||
//
|
||||
// If this option is not used, the TracerProvider will use a random number
|
||||
// IDGenerator by default.
|
||||
func WithIDGenerator(g IDGenerator) TracerProviderOption {
|
||||
return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
|
||||
if g != nil {
|
||||
cfg.idGenerator = g
|
||||
}
|
||||
return cfg
|
||||
})
|
||||
}
|
||||
|
||||
// WithSampler returns a TracerProviderOption that will configure the Sampler
|
||||
// s as a TracerProvider's Sampler. The configured Sampler is used by the
|
||||
// Tracers the TracerProvider creates to make their sampling decisions for the
|
||||
// Spans they create.
|
||||
//
|
||||
// This option overrides the Sampler configured through the OTEL_TRACES_SAMPLER
|
||||
// and OTEL_TRACES_SAMPLER_ARG environment variables. If this option is not used
|
||||
// and the sampler is not configured through environment variables or the environment
|
||||
// contains invalid/unsupported configuration, the TracerProvider will use a
|
||||
// ParentBased(AlwaysSample) Sampler by default.
|
||||
func WithSampler(s Sampler) TracerProviderOption {
|
||||
return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
|
||||
if s != nil {
|
||||
cfg.sampler = s
|
||||
}
|
||||
return cfg
|
||||
})
|
||||
}
|
||||
|
||||
// WithSpanLimits returns a TracerProviderOption that configures a
|
||||
// TracerProvider to use the SpanLimits sl. These SpanLimits bound any Span
|
||||
// created by a Tracer from the TracerProvider.
|
||||
//
|
||||
// If any field of sl is zero or negative it will be replaced with the default
|
||||
// value for that field.
|
||||
//
|
||||
// If this or WithRawSpanLimits are not provided, the TracerProvider will use
|
||||
// the limits defined by environment variables, or the defaults if unset.
|
||||
// Refer to the NewSpanLimits documentation for information about this
|
||||
// relationship.
|
||||
//
|
||||
// Deprecated: Use WithRawSpanLimits instead which allows setting unlimited
|
||||
// and zero limits. This option will be kept until the next major version
|
||||
// incremented release.
|
||||
func WithSpanLimits(sl SpanLimits) TracerProviderOption {
|
||||
if sl.AttributeValueLengthLimit <= 0 {
|
||||
sl.AttributeValueLengthLimit = DefaultAttributeValueLengthLimit
|
||||
}
|
||||
if sl.AttributeCountLimit <= 0 {
|
||||
sl.AttributeCountLimit = DefaultAttributeCountLimit
|
||||
}
|
||||
if sl.EventCountLimit <= 0 {
|
||||
sl.EventCountLimit = DefaultEventCountLimit
|
||||
}
|
||||
if sl.AttributePerEventCountLimit <= 0 {
|
||||
sl.AttributePerEventCountLimit = DefaultAttributePerEventCountLimit
|
||||
}
|
||||
if sl.LinkCountLimit <= 0 {
|
||||
sl.LinkCountLimit = DefaultLinkCountLimit
|
||||
}
|
||||
if sl.AttributePerLinkCountLimit <= 0 {
|
||||
sl.AttributePerLinkCountLimit = DefaultAttributePerLinkCountLimit
|
||||
}
|
||||
return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
|
||||
cfg.spanLimits = sl
|
||||
return cfg
|
||||
})
|
||||
}
|
||||
|
||||
// WithRawSpanLimits returns a TracerProviderOption that configures a
|
||||
// TracerProvider to use these limits. These limits bound any Span created by
|
||||
// a Tracer from the TracerProvider.
|
||||
//
|
||||
// The limits will be used as-is. Zero or negative values will not be changed
|
||||
// to the default value like WithSpanLimits does. Setting a limit to zero will
|
||||
// effectively disable the related resource it limits and setting to a
|
||||
// negative value will mean that resource is unlimited. Consequentially, this
|
||||
// means that the zero-value SpanLimits will disable all span resources.
|
||||
// Because of this, limits should be constructed using NewSpanLimits and
|
||||
// updated accordingly.
|
||||
//
|
||||
// If this or WithSpanLimits are not provided, the TracerProvider will use the
|
||||
// limits defined by environment variables, or the defaults if unset. Refer to
|
||||
// the NewSpanLimits documentation for information about this relationship.
|
||||
func WithRawSpanLimits(limits SpanLimits) TracerProviderOption {
|
||||
return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
|
||||
cfg.spanLimits = limits
|
||||
return cfg
|
||||
})
|
||||
}
|
||||
|
||||
func applyTracerProviderEnvConfigs(cfg tracerProviderConfig) tracerProviderConfig {
|
||||
for _, opt := range tracerProviderOptionsFromEnv() {
|
||||
cfg = opt.apply(cfg)
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
func tracerProviderOptionsFromEnv() []TracerProviderOption {
|
||||
var opts []TracerProviderOption
|
||||
|
||||
sampler, err := samplerFromEnv()
|
||||
if err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
|
||||
if sampler != nil {
|
||||
opts = append(opts, WithSampler(sampler))
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
// ensureValidTracerProviderConfig ensures that given TracerProviderConfig is valid.
|
||||
func ensureValidTracerProviderConfig(cfg tracerProviderConfig) tracerProviderConfig {
|
||||
if cfg.sampler == nil {
|
||||
cfg.sampler = ParentBased(AlwaysSample())
|
||||
}
|
||||
if cfg.idGenerator == nil {
|
||||
cfg.idGenerator = defaultIDGenerator()
|
||||
}
|
||||
if cfg.resource == nil {
|
||||
cfg.resource = resource.Default()
|
||||
}
|
||||
return cfg
|
||||
}
|
97
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go
generated
vendored
Normal file
97
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
tracesSamplerKey = "OTEL_TRACES_SAMPLER"
|
||||
tracesSamplerArgKey = "OTEL_TRACES_SAMPLER_ARG"
|
||||
|
||||
samplerAlwaysOn = "always_on"
|
||||
samplerAlwaysOff = "always_off"
|
||||
samplerTraceIDRatio = "traceidratio"
|
||||
samplerParentBasedAlwaysOn = "parentbased_always_on"
|
||||
samplerParsedBasedAlwaysOff = "parentbased_always_off"
|
||||
samplerParentBasedTraceIDRatio = "parentbased_traceidratio"
|
||||
)
|
||||
|
||||
type errUnsupportedSampler string
|
||||
|
||||
func (e errUnsupportedSampler) Error() string {
|
||||
return fmt.Sprintf("unsupported sampler: %s", string(e))
|
||||
}
|
||||
|
||||
var (
|
||||
errNegativeTraceIDRatio = errors.New("invalid trace ID ratio: less than 0.0")
|
||||
errGreaterThanOneTraceIDRatio = errors.New("invalid trace ID ratio: greater than 1.0")
|
||||
)
|
||||
|
||||
type samplerArgParseError struct {
|
||||
parseErr error
|
||||
}
|
||||
|
||||
func (e samplerArgParseError) Error() string {
|
||||
return fmt.Sprintf("parsing sampler argument: %s", e.parseErr.Error())
|
||||
}
|
||||
|
||||
func (e samplerArgParseError) Unwrap() error {
|
||||
return e.parseErr
|
||||
}
|
||||
|
||||
func samplerFromEnv() (Sampler, error) {
|
||||
sampler, ok := os.LookupEnv(tracesSamplerKey)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sampler = strings.ToLower(strings.TrimSpace(sampler))
|
||||
samplerArg, hasSamplerArg := os.LookupEnv(tracesSamplerArgKey)
|
||||
samplerArg = strings.TrimSpace(samplerArg)
|
||||
|
||||
switch sampler {
|
||||
case samplerAlwaysOn:
|
||||
return AlwaysSample(), nil
|
||||
case samplerAlwaysOff:
|
||||
return NeverSample(), nil
|
||||
case samplerTraceIDRatio:
|
||||
if !hasSamplerArg {
|
||||
return TraceIDRatioBased(1.0), nil
|
||||
}
|
||||
return parseTraceIDRatio(samplerArg)
|
||||
case samplerParentBasedAlwaysOn:
|
||||
return ParentBased(AlwaysSample()), nil
|
||||
case samplerParsedBasedAlwaysOff:
|
||||
return ParentBased(NeverSample()), nil
|
||||
case samplerParentBasedTraceIDRatio:
|
||||
if !hasSamplerArg {
|
||||
return ParentBased(TraceIDRatioBased(1.0)), nil
|
||||
}
|
||||
ratio, err := parseTraceIDRatio(samplerArg)
|
||||
return ParentBased(ratio), err
|
||||
default:
|
||||
return nil, errUnsupportedSampler(sampler)
|
||||
}
|
||||
}
|
||||
|
||||
func parseTraceIDRatio(arg string) (Sampler, error) {
|
||||
v, err := strconv.ParseFloat(arg, 64)
|
||||
if err != nil {
|
||||
return TraceIDRatioBased(1.0), samplerArgParseError{err}
|
||||
}
|
||||
if v < 0.0 {
|
||||
return TraceIDRatioBased(1.0), errNegativeTraceIDRatio
|
||||
}
|
||||
if v > 1.0 {
|
||||
return TraceIDRatioBased(1.0), errGreaterThanOneTraceIDRatio
|
||||
}
|
||||
|
||||
return TraceIDRatioBased(v), nil
|
||||
}
|
282
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go
generated
vendored
Normal file
282
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go
generated
vendored
Normal file
@ -0,0 +1,282 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// Sampler decides whether a trace should be sampled and exported.
|
||||
type Sampler interface {
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
|
||||
// ShouldSample returns a SamplingResult based on a decision made from the
|
||||
// passed parameters.
|
||||
ShouldSample(parameters SamplingParameters) SamplingResult
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
|
||||
// Description returns information describing the Sampler.
|
||||
Description() string
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
}
|
||||
|
||||
// SamplingParameters contains the values passed to a Sampler.
|
||||
type SamplingParameters struct {
|
||||
ParentContext context.Context
|
||||
TraceID trace.TraceID
|
||||
Name string
|
||||
Kind trace.SpanKind
|
||||
Attributes []attribute.KeyValue
|
||||
Links []trace.Link
|
||||
}
|
||||
|
||||
// SamplingDecision indicates whether a span is dropped, recorded and/or sampled.
|
||||
type SamplingDecision uint8
|
||||
|
||||
// Valid sampling decisions.
|
||||
const (
|
||||
// Drop will not record the span and all attributes/events will be dropped.
|
||||
Drop SamplingDecision = iota
|
||||
|
||||
// Record indicates the span's `IsRecording() == true`, but `Sampled` flag
|
||||
// *must not* be set.
|
||||
RecordOnly
|
||||
|
||||
// RecordAndSample has span's `IsRecording() == true` and `Sampled` flag
|
||||
// *must* be set.
|
||||
RecordAndSample
|
||||
)
|
||||
|
||||
// SamplingResult conveys a SamplingDecision, set of Attributes and a Tracestate.
|
||||
type SamplingResult struct {
|
||||
Decision SamplingDecision
|
||||
Attributes []attribute.KeyValue
|
||||
Tracestate trace.TraceState
|
||||
}
|
||||
|
||||
type traceIDRatioSampler struct {
|
||||
traceIDUpperBound uint64
|
||||
description string
|
||||
}
|
||||
|
||||
func (ts traceIDRatioSampler) ShouldSample(p SamplingParameters) SamplingResult {
|
||||
psc := trace.SpanContextFromContext(p.ParentContext)
|
||||
x := binary.BigEndian.Uint64(p.TraceID[8:16]) >> 1
|
||||
if x < ts.traceIDUpperBound {
|
||||
return SamplingResult{
|
||||
Decision: RecordAndSample,
|
||||
Tracestate: psc.TraceState(),
|
||||
}
|
||||
}
|
||||
return SamplingResult{
|
||||
Decision: Drop,
|
||||
Tracestate: psc.TraceState(),
|
||||
}
|
||||
}
|
||||
|
||||
func (ts traceIDRatioSampler) Description() string {
|
||||
return ts.description
|
||||
}
|
||||
|
||||
// TraceIDRatioBased samples a given fraction of traces. Fractions >= 1 will
|
||||
// always sample. Fractions < 0 are treated as zero. To respect the
|
||||
// parent trace's `SampledFlag`, the `TraceIDRatioBased` sampler should be used
|
||||
// as a delegate of a `Parent` sampler.
|
||||
//
|
||||
//nolint:revive // revive complains about stutter of `trace.TraceIDRatioBased`
|
||||
func TraceIDRatioBased(fraction float64) Sampler {
|
||||
if fraction >= 1 {
|
||||
return AlwaysSample()
|
||||
}
|
||||
|
||||
if fraction <= 0 {
|
||||
fraction = 0
|
||||
}
|
||||
|
||||
return &traceIDRatioSampler{
|
||||
traceIDUpperBound: uint64(fraction * (1 << 63)),
|
||||
description: fmt.Sprintf("TraceIDRatioBased{%g}", fraction),
|
||||
}
|
||||
}
|
||||
|
||||
type alwaysOnSampler struct{}
|
||||
|
||||
func (as alwaysOnSampler) ShouldSample(p SamplingParameters) SamplingResult {
|
||||
return SamplingResult{
|
||||
Decision: RecordAndSample,
|
||||
Tracestate: trace.SpanContextFromContext(p.ParentContext).TraceState(),
|
||||
}
|
||||
}
|
||||
|
||||
func (as alwaysOnSampler) Description() string {
|
||||
return "AlwaysOnSampler"
|
||||
}
|
||||
|
||||
// AlwaysSample returns a Sampler that samples every trace.
|
||||
// Be careful about using this sampler in a production application with
|
||||
// significant traffic: a new trace will be started and exported for every
|
||||
// request.
|
||||
func AlwaysSample() Sampler {
|
||||
return alwaysOnSampler{}
|
||||
}
|
||||
|
||||
type alwaysOffSampler struct{}
|
||||
|
||||
func (as alwaysOffSampler) ShouldSample(p SamplingParameters) SamplingResult {
|
||||
return SamplingResult{
|
||||
Decision: Drop,
|
||||
Tracestate: trace.SpanContextFromContext(p.ParentContext).TraceState(),
|
||||
}
|
||||
}
|
||||
|
||||
func (as alwaysOffSampler) Description() string {
|
||||
return "AlwaysOffSampler"
|
||||
}
|
||||
|
||||
// NeverSample returns a Sampler that samples no traces.
|
||||
func NeverSample() Sampler {
|
||||
return alwaysOffSampler{}
|
||||
}
|
||||
|
||||
// ParentBased returns a sampler decorator which behaves differently,
|
||||
// based on the parent of the span. If the span has no parent,
|
||||
// the decorated sampler is used to make sampling decision. If the span has
|
||||
// a parent, depending on whether the parent is remote and whether it
|
||||
// is sampled, one of the following samplers will apply:
|
||||
// - remoteParentSampled(Sampler) (default: AlwaysOn)
|
||||
// - remoteParentNotSampled(Sampler) (default: AlwaysOff)
|
||||
// - localParentSampled(Sampler) (default: AlwaysOn)
|
||||
// - localParentNotSampled(Sampler) (default: AlwaysOff)
|
||||
func ParentBased(root Sampler, samplers ...ParentBasedSamplerOption) Sampler {
|
||||
return parentBased{
|
||||
root: root,
|
||||
config: configureSamplersForParentBased(samplers),
|
||||
}
|
||||
}
|
||||
|
||||
type parentBased struct {
|
||||
root Sampler
|
||||
config samplerConfig
|
||||
}
|
||||
|
||||
func configureSamplersForParentBased(samplers []ParentBasedSamplerOption) samplerConfig {
|
||||
c := samplerConfig{
|
||||
remoteParentSampled: AlwaysSample(),
|
||||
remoteParentNotSampled: NeverSample(),
|
||||
localParentSampled: AlwaysSample(),
|
||||
localParentNotSampled: NeverSample(),
|
||||
}
|
||||
|
||||
for _, so := range samplers {
|
||||
c = so.apply(c)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// samplerConfig is a group of options for parentBased sampler.
|
||||
type samplerConfig struct {
|
||||
remoteParentSampled, remoteParentNotSampled Sampler
|
||||
localParentSampled, localParentNotSampled Sampler
|
||||
}
|
||||
|
||||
// ParentBasedSamplerOption configures the sampler for a particular sampling case.
|
||||
type ParentBasedSamplerOption interface {
|
||||
apply(samplerConfig) samplerConfig
|
||||
}
|
||||
|
||||
// WithRemoteParentSampled sets the sampler for the case of sampled remote parent.
|
||||
func WithRemoteParentSampled(s Sampler) ParentBasedSamplerOption {
|
||||
return remoteParentSampledOption{s}
|
||||
}
|
||||
|
||||
type remoteParentSampledOption struct {
|
||||
s Sampler
|
||||
}
|
||||
|
||||
func (o remoteParentSampledOption) apply(config samplerConfig) samplerConfig {
|
||||
config.remoteParentSampled = o.s
|
||||
return config
|
||||
}
|
||||
|
||||
// WithRemoteParentNotSampled sets the sampler for the case of remote parent
|
||||
// which is not sampled.
|
||||
func WithRemoteParentNotSampled(s Sampler) ParentBasedSamplerOption {
|
||||
return remoteParentNotSampledOption{s}
|
||||
}
|
||||
|
||||
type remoteParentNotSampledOption struct {
|
||||
s Sampler
|
||||
}
|
||||
|
||||
func (o remoteParentNotSampledOption) apply(config samplerConfig) samplerConfig {
|
||||
config.remoteParentNotSampled = o.s
|
||||
return config
|
||||
}
|
||||
|
||||
// WithLocalParentSampled sets the sampler for the case of sampled local parent.
|
||||
func WithLocalParentSampled(s Sampler) ParentBasedSamplerOption {
|
||||
return localParentSampledOption{s}
|
||||
}
|
||||
|
||||
type localParentSampledOption struct {
|
||||
s Sampler
|
||||
}
|
||||
|
||||
func (o localParentSampledOption) apply(config samplerConfig) samplerConfig {
|
||||
config.localParentSampled = o.s
|
||||
return config
|
||||
}
|
||||
|
||||
// WithLocalParentNotSampled sets the sampler for the case of local parent
|
||||
// which is not sampled.
|
||||
func WithLocalParentNotSampled(s Sampler) ParentBasedSamplerOption {
|
||||
return localParentNotSampledOption{s}
|
||||
}
|
||||
|
||||
type localParentNotSampledOption struct {
|
||||
s Sampler
|
||||
}
|
||||
|
||||
func (o localParentNotSampledOption) apply(config samplerConfig) samplerConfig {
|
||||
config.localParentNotSampled = o.s
|
||||
return config
|
||||
}
|
||||
|
||||
func (pb parentBased) ShouldSample(p SamplingParameters) SamplingResult {
|
||||
psc := trace.SpanContextFromContext(p.ParentContext)
|
||||
if psc.IsValid() {
|
||||
if psc.IsRemote() {
|
||||
if psc.IsSampled() {
|
||||
return pb.config.remoteParentSampled.ShouldSample(p)
|
||||
}
|
||||
return pb.config.remoteParentNotSampled.ShouldSample(p)
|
||||
}
|
||||
|
||||
if psc.IsSampled() {
|
||||
return pb.config.localParentSampled.ShouldSample(p)
|
||||
}
|
||||
return pb.config.localParentNotSampled.ShouldSample(p)
|
||||
}
|
||||
return pb.root.ShouldSample(p)
|
||||
}
|
||||
|
||||
func (pb parentBased) Description() string {
|
||||
return fmt.Sprintf("ParentBased{root:%s,remoteParentSampled:%s,"+
|
||||
"remoteParentNotSampled:%s,localParentSampled:%s,localParentNotSampled:%s}",
|
||||
pb.root.Description(),
|
||||
pb.config.remoteParentSampled.Description(),
|
||||
pb.config.remoteParentNotSampled.Description(),
|
||||
pb.config.localParentSampled.Description(),
|
||||
pb.config.localParentNotSampled.Description(),
|
||||
)
|
||||
}
|
121
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go
generated
vendored
Normal file
121
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/internal/global"
|
||||
)
|
||||
|
||||
// simpleSpanProcessor is a SpanProcessor that synchronously sends all
|
||||
// completed Spans to a trace.Exporter immediately.
|
||||
type simpleSpanProcessor struct {
|
||||
exporterMu sync.Mutex
|
||||
exporter SpanExporter
|
||||
stopOnce sync.Once
|
||||
}
|
||||
|
||||
var _ SpanProcessor = (*simpleSpanProcessor)(nil)
|
||||
|
||||
// NewSimpleSpanProcessor returns a new SpanProcessor that will synchronously
|
||||
// send completed spans to the exporter immediately.
|
||||
//
|
||||
// This SpanProcessor is not recommended for production use. The synchronous
|
||||
// nature of this SpanProcessor makes it good for testing, debugging, or showing
|
||||
// examples of other features, but it will be slow and have a high computation
|
||||
// resource usage overhead. The BatchSpanProcessor is recommended for production
|
||||
// use instead.
|
||||
func NewSimpleSpanProcessor(exporter SpanExporter) SpanProcessor {
|
||||
ssp := &simpleSpanProcessor{
|
||||
exporter: exporter,
|
||||
}
|
||||
global.Warn("SimpleSpanProcessor is not recommended for production use, consider using BatchSpanProcessor instead.")
|
||||
|
||||
return ssp
|
||||
}
|
||||
|
||||
// OnStart does nothing.
|
||||
func (ssp *simpleSpanProcessor) OnStart(context.Context, ReadWriteSpan) {}
|
||||
|
||||
// OnEnd immediately exports a ReadOnlySpan.
|
||||
func (ssp *simpleSpanProcessor) OnEnd(s ReadOnlySpan) {
|
||||
ssp.exporterMu.Lock()
|
||||
defer ssp.exporterMu.Unlock()
|
||||
|
||||
if ssp.exporter != nil && s.SpanContext().TraceFlags().IsSampled() {
|
||||
if err := ssp.exporter.ExportSpans(context.Background(), []ReadOnlySpan{s}); err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown shuts down the exporter this SimpleSpanProcessor exports to.
|
||||
func (ssp *simpleSpanProcessor) Shutdown(ctx context.Context) error {
|
||||
var err error
|
||||
ssp.stopOnce.Do(func() {
|
||||
stopFunc := func(exp SpanExporter) (<-chan error, func()) {
|
||||
done := make(chan error)
|
||||
return done, func() { done <- exp.Shutdown(ctx) }
|
||||
}
|
||||
|
||||
// The exporter field of the simpleSpanProcessor needs to be zeroed to
|
||||
// signal it is shut down, meaning all subsequent calls to OnEnd will
|
||||
// be gracefully ignored. This needs to be done synchronously to avoid
|
||||
// any race condition.
|
||||
//
|
||||
// A closure is used to keep reference to the exporter and then the
|
||||
// field is zeroed. This ensures the simpleSpanProcessor is shut down
|
||||
// before the exporter. This order is important as it avoids a potential
|
||||
// deadlock. If the exporter shut down operation generates a span, that
|
||||
// span would need to be exported. Meaning, OnEnd would be called and
|
||||
// try acquiring the lock that is held here.
|
||||
ssp.exporterMu.Lock()
|
||||
done, shutdown := stopFunc(ssp.exporter)
|
||||
ssp.exporter = nil
|
||||
ssp.exporterMu.Unlock()
|
||||
|
||||
go shutdown()
|
||||
|
||||
// Wait for the exporter to shut down or the deadline to expire.
|
||||
select {
|
||||
case err = <-done:
|
||||
case <-ctx.Done():
|
||||
// It is possible for the exporter to have immediately shut down and
|
||||
// the context to be done simultaneously. In that case this outer
|
||||
// select statement will randomly choose a case. This will result in
|
||||
// a different returned error for similar scenarios. Instead, double
|
||||
// check if the exporter shut down at the same time and return that
|
||||
// error if so. This will ensure consistency as well as ensure
|
||||
// the caller knows the exporter shut down successfully (they can
|
||||
// already determine if the deadline is expired given they passed
|
||||
// the context).
|
||||
select {
|
||||
case err = <-done:
|
||||
default:
|
||||
err = ctx.Err()
|
||||
}
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// ForceFlush does nothing as there is no data to flush.
|
||||
func (ssp *simpleSpanProcessor) ForceFlush(context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalLog is the marshaling function used by the logging system to represent
|
||||
// this Span Processor.
|
||||
func (ssp *simpleSpanProcessor) MarshalLog() interface{} {
|
||||
return struct {
|
||||
Type string
|
||||
Exporter SpanExporter
|
||||
}{
|
||||
Type: "SimpleSpanProcessor",
|
||||
Exporter: ssp.exporter,
|
||||
}
|
||||
}
|
133
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go
generated
vendored
Normal file
133
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// snapshot is an record of a spans state at a particular checkpointed time.
|
||||
// It is used as a read-only representation of that state.
|
||||
type snapshot struct {
|
||||
name string
|
||||
spanContext trace.SpanContext
|
||||
parent trace.SpanContext
|
||||
spanKind trace.SpanKind
|
||||
startTime time.Time
|
||||
endTime time.Time
|
||||
attributes []attribute.KeyValue
|
||||
events []Event
|
||||
links []Link
|
||||
status Status
|
||||
childSpanCount int
|
||||
droppedAttributeCount int
|
||||
droppedEventCount int
|
||||
droppedLinkCount int
|
||||
resource *resource.Resource
|
||||
instrumentationScope instrumentation.Scope
|
||||
}
|
||||
|
||||
var _ ReadOnlySpan = snapshot{}
|
||||
|
||||
func (s snapshot) private() {}
|
||||
|
||||
// Name returns the name of the span.
|
||||
func (s snapshot) Name() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
// SpanContext returns the unique SpanContext that identifies the span.
|
||||
func (s snapshot) SpanContext() trace.SpanContext {
|
||||
return s.spanContext
|
||||
}
|
||||
|
||||
// Parent returns the unique SpanContext that identifies the parent of the
|
||||
// span if one exists. If the span has no parent the returned SpanContext
|
||||
// will be invalid.
|
||||
func (s snapshot) Parent() trace.SpanContext {
|
||||
return s.parent
|
||||
}
|
||||
|
||||
// SpanKind returns the role the span plays in a Trace.
|
||||
func (s snapshot) SpanKind() trace.SpanKind {
|
||||
return s.spanKind
|
||||
}
|
||||
|
||||
// StartTime returns the time the span started recording.
|
||||
func (s snapshot) StartTime() time.Time {
|
||||
return s.startTime
|
||||
}
|
||||
|
||||
// EndTime returns the time the span stopped recording. It will be zero if
|
||||
// the span has not ended.
|
||||
func (s snapshot) EndTime() time.Time {
|
||||
return s.endTime
|
||||
}
|
||||
|
||||
// Attributes returns the defining attributes of the span.
|
||||
func (s snapshot) Attributes() []attribute.KeyValue {
|
||||
return s.attributes
|
||||
}
|
||||
|
||||
// Links returns all the links the span has to other spans.
|
||||
func (s snapshot) Links() []Link {
|
||||
return s.links
|
||||
}
|
||||
|
||||
// Events returns all the events that occurred within in the spans
|
||||
// lifetime.
|
||||
func (s snapshot) Events() []Event {
|
||||
return s.events
|
||||
}
|
||||
|
||||
// Status returns the spans status.
|
||||
func (s snapshot) Status() Status {
|
||||
return s.status
|
||||
}
|
||||
|
||||
// InstrumentationScope returns information about the instrumentation
|
||||
// scope that created the span.
|
||||
func (s snapshot) InstrumentationScope() instrumentation.Scope {
|
||||
return s.instrumentationScope
|
||||
}
|
||||
|
||||
// InstrumentationLibrary returns information about the instrumentation
|
||||
// library that created the span.
|
||||
func (s snapshot) InstrumentationLibrary() instrumentation.Library { //nolint:staticcheck // This method needs to be define for backwards compatibility
|
||||
return s.instrumentationScope
|
||||
}
|
||||
|
||||
// Resource returns information about the entity that produced the span.
|
||||
func (s snapshot) Resource() *resource.Resource {
|
||||
return s.resource
|
||||
}
|
||||
|
||||
// DroppedAttributes returns the number of attributes dropped by the span
|
||||
// due to limits being reached.
|
||||
func (s snapshot) DroppedAttributes() int {
|
||||
return s.droppedAttributeCount
|
||||
}
|
||||
|
||||
// DroppedLinks returns the number of links dropped by the span due to limits
|
||||
// being reached.
|
||||
func (s snapshot) DroppedLinks() int {
|
||||
return s.droppedLinkCount
|
||||
}
|
||||
|
||||
// DroppedEvents returns the number of events dropped by the span due to
|
||||
// limits being reached.
|
||||
func (s snapshot) DroppedEvents() int {
|
||||
return s.droppedEventCount
|
||||
}
|
||||
|
||||
// ChildSpanCount returns the count of spans that consider the span a
|
||||
// direct parent.
|
||||
func (s snapshot) ChildSpanCount() int {
|
||||
return s.childSpanCount
|
||||
}
|
892
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/span.go
generated
vendored
Normal file
892
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/span.go
generated
vendored
Normal file
@ -0,0 +1,892 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
rt "runtime/trace"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/internal/global"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.opentelemetry.io/otel/trace/embedded"
|
||||
)
|
||||
|
||||
// ReadOnlySpan allows reading information from the data structure underlying a
|
||||
// trace.Span. It is used in places where reading information from a span is
|
||||
// necessary but changing the span isn't necessary or allowed.
|
||||
//
|
||||
// Warning: methods may be added to this interface in minor releases.
|
||||
type ReadOnlySpan interface {
|
||||
// Name returns the name of the span.
|
||||
Name() string
|
||||
// SpanContext returns the unique SpanContext that identifies the span.
|
||||
SpanContext() trace.SpanContext
|
||||
// Parent returns the unique SpanContext that identifies the parent of the
|
||||
// span if one exists. If the span has no parent the returned SpanContext
|
||||
// will be invalid.
|
||||
Parent() trace.SpanContext
|
||||
// SpanKind returns the role the span plays in a Trace.
|
||||
SpanKind() trace.SpanKind
|
||||
// StartTime returns the time the span started recording.
|
||||
StartTime() time.Time
|
||||
// EndTime returns the time the span stopped recording. It will be zero if
|
||||
// the span has not ended.
|
||||
EndTime() time.Time
|
||||
// Attributes returns the defining attributes of the span.
|
||||
// The order of the returned attributes is not guaranteed to be stable across invocations.
|
||||
Attributes() []attribute.KeyValue
|
||||
// Links returns all the links the span has to other spans.
|
||||
Links() []Link
|
||||
// Events returns all the events that occurred within in the spans
|
||||
// lifetime.
|
||||
Events() []Event
|
||||
// Status returns the spans status.
|
||||
Status() Status
|
||||
// InstrumentationScope returns information about the instrumentation
|
||||
// scope that created the span.
|
||||
InstrumentationScope() instrumentation.Scope
|
||||
// InstrumentationLibrary returns information about the instrumentation
|
||||
// library that created the span.
|
||||
// Deprecated: please use InstrumentationScope instead.
|
||||
InstrumentationLibrary() instrumentation.Library //nolint:staticcheck // This method needs to be define for backwards compatibility
|
||||
// Resource returns information about the entity that produced the span.
|
||||
Resource() *resource.Resource
|
||||
// DroppedAttributes returns the number of attributes dropped by the span
|
||||
// due to limits being reached.
|
||||
DroppedAttributes() int
|
||||
// DroppedLinks returns the number of links dropped by the span due to
|
||||
// limits being reached.
|
||||
DroppedLinks() int
|
||||
// DroppedEvents returns the number of events dropped by the span due to
|
||||
// limits being reached.
|
||||
DroppedEvents() int
|
||||
// ChildSpanCount returns the count of spans that consider the span a
|
||||
// direct parent.
|
||||
ChildSpanCount() int
|
||||
|
||||
// A private method to prevent users implementing the
|
||||
// interface and so future additions to it will not
|
||||
// violate compatibility.
|
||||
private()
|
||||
}
|
||||
|
||||
// ReadWriteSpan exposes the same methods as trace.Span and in addition allows
|
||||
// reading information from the underlying data structure.
|
||||
// This interface exposes the union of the methods of trace.Span (which is a
|
||||
// "write-only" span) and ReadOnlySpan. New methods for writing or reading span
|
||||
// information should be added under trace.Span or ReadOnlySpan, respectively.
|
||||
//
|
||||
// Warning: methods may be added to this interface in minor releases.
|
||||
type ReadWriteSpan interface {
|
||||
trace.Span
|
||||
ReadOnlySpan
|
||||
}
|
||||
|
||||
// recordingSpan is an implementation of the OpenTelemetry Span API
|
||||
// representing the individual component of a trace that is sampled.
|
||||
type recordingSpan struct {
|
||||
embedded.Span
|
||||
|
||||
// mu protects the contents of this span.
|
||||
mu sync.Mutex
|
||||
|
||||
// parent holds the parent span of this span as a trace.SpanContext.
|
||||
parent trace.SpanContext
|
||||
|
||||
// spanKind represents the kind of this span as a trace.SpanKind.
|
||||
spanKind trace.SpanKind
|
||||
|
||||
// name is the name of this span.
|
||||
name string
|
||||
|
||||
// startTime is the time at which this span was started.
|
||||
startTime time.Time
|
||||
|
||||
// endTime is the time at which this span was ended. It contains the zero
|
||||
// value of time.Time until the span is ended.
|
||||
endTime time.Time
|
||||
|
||||
// status is the status of this span.
|
||||
status Status
|
||||
|
||||
// childSpanCount holds the number of child spans created for this span.
|
||||
childSpanCount int
|
||||
|
||||
// spanContext holds the SpanContext of this span.
|
||||
spanContext trace.SpanContext
|
||||
|
||||
// attributes is a collection of user provided key/values. The collection
|
||||
// is constrained by a configurable maximum held by the parent
|
||||
// TracerProvider. When additional attributes are added after this maximum
|
||||
// is reached these attributes the user is attempting to add are dropped.
|
||||
// This dropped number of attributes is tracked and reported in the
|
||||
// ReadOnlySpan exported when the span ends.
|
||||
attributes []attribute.KeyValue
|
||||
droppedAttributes int
|
||||
logDropAttrsOnce sync.Once
|
||||
|
||||
// events are stored in FIFO queue capped by configured limit.
|
||||
events evictedQueue[Event]
|
||||
|
||||
// links are stored in FIFO queue capped by configured limit.
|
||||
links evictedQueue[Link]
|
||||
|
||||
// executionTracerTaskEnd ends the execution tracer span.
|
||||
executionTracerTaskEnd func()
|
||||
|
||||
// tracer is the SDK tracer that created this span.
|
||||
tracer *tracer
|
||||
}
|
||||
|
||||
var (
|
||||
_ ReadWriteSpan = (*recordingSpan)(nil)
|
||||
_ runtimeTracer = (*recordingSpan)(nil)
|
||||
)
|
||||
|
||||
// SpanContext returns the SpanContext of this span.
|
||||
func (s *recordingSpan) SpanContext() trace.SpanContext {
|
||||
if s == nil {
|
||||
return trace.SpanContext{}
|
||||
}
|
||||
return s.spanContext
|
||||
}
|
||||
|
||||
// IsRecording returns if this span is being recorded. If this span has ended
|
||||
// this will return false.
|
||||
func (s *recordingSpan) IsRecording() bool {
|
||||
if s == nil {
|
||||
return false
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return s.isRecording()
|
||||
}
|
||||
|
||||
// isRecording returns if this span is being recorded. If this span has ended
|
||||
// this will return false.
|
||||
//
|
||||
// This method assumes s.mu.Lock is held by the caller.
|
||||
func (s *recordingSpan) isRecording() bool {
|
||||
if s == nil {
|
||||
return false
|
||||
}
|
||||
return s.endTime.IsZero()
|
||||
}
|
||||
|
||||
// SetStatus sets the status of the Span in the form of a code and a
|
||||
// description, overriding previous values set. The description is only
|
||||
// included in the set status when the code is for an error. If this span is
|
||||
// not being recorded than this method does nothing.
|
||||
func (s *recordingSpan) SetStatus(code codes.Code, description string) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if !s.isRecording() {
|
||||
return
|
||||
}
|
||||
if s.status.Code > code {
|
||||
return
|
||||
}
|
||||
|
||||
status := Status{Code: code}
|
||||
if code == codes.Error {
|
||||
status.Description = description
|
||||
}
|
||||
|
||||
s.status = status
|
||||
}
|
||||
|
||||
// SetAttributes sets attributes of this span.
|
||||
//
|
||||
// If a key from attributes already exists the value associated with that key
|
||||
// will be overwritten with the value contained in attributes.
|
||||
//
|
||||
// If this span is not being recorded than this method does nothing.
|
||||
//
|
||||
// If adding attributes to the span would exceed the maximum amount of
|
||||
// attributes the span is configured to have, the last added attributes will
|
||||
// be dropped.
|
||||
func (s *recordingSpan) SetAttributes(attributes ...attribute.KeyValue) {
|
||||
if s == nil || len(attributes) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if !s.isRecording() {
|
||||
return
|
||||
}
|
||||
|
||||
limit := s.tracer.provider.spanLimits.AttributeCountLimit
|
||||
if limit == 0 {
|
||||
// No attributes allowed.
|
||||
s.addDroppedAttr(len(attributes))
|
||||
return
|
||||
}
|
||||
|
||||
// If adding these attributes could exceed the capacity of s perform a
|
||||
// de-duplication and truncation while adding to avoid over allocation.
|
||||
if limit > 0 && len(s.attributes)+len(attributes) > limit {
|
||||
s.addOverCapAttrs(limit, attributes)
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, add without deduplication. When attributes are read they
|
||||
// will be deduplicated, optimizing the operation.
|
||||
s.attributes = slices.Grow(s.attributes, len(attributes))
|
||||
for _, a := range attributes {
|
||||
if !a.Valid() {
|
||||
// Drop all invalid attributes.
|
||||
s.addDroppedAttr(1)
|
||||
continue
|
||||
}
|
||||
a = truncateAttr(s.tracer.provider.spanLimits.AttributeValueLengthLimit, a)
|
||||
s.attributes = append(s.attributes, a)
|
||||
}
|
||||
}
|
||||
|
||||
// Declared as a var so tests can override.
|
||||
var logDropAttrs = func() {
|
||||
global.Warn("limit reached: dropping trace Span attributes")
|
||||
}
|
||||
|
||||
// addDroppedAttr adds incr to the count of dropped attributes.
|
||||
//
|
||||
// The first, and only the first, time this method is called a warning will be
|
||||
// logged.
|
||||
//
|
||||
// This method assumes s.mu.Lock is held by the caller.
|
||||
func (s *recordingSpan) addDroppedAttr(incr int) {
|
||||
s.droppedAttributes += incr
|
||||
s.logDropAttrsOnce.Do(logDropAttrs)
|
||||
}
|
||||
|
||||
// addOverCapAttrs adds the attributes attrs to the span s while
|
||||
// de-duplicating the attributes of s and attrs and dropping attributes that
|
||||
// exceed the limit.
|
||||
//
|
||||
// This method assumes s.mu.Lock is held by the caller.
|
||||
//
|
||||
// This method should only be called when there is a possibility that adding
|
||||
// attrs to s will exceed the limit. Otherwise, attrs should be added to s
|
||||
// without checking for duplicates and all retrieval methods of the attributes
|
||||
// for s will de-duplicate as needed.
|
||||
//
|
||||
// This method assumes limit is a value > 0. The argument should be validated
|
||||
// by the caller.
|
||||
func (s *recordingSpan) addOverCapAttrs(limit int, attrs []attribute.KeyValue) {
|
||||
// In order to not allocate more capacity to s.attributes than needed,
|
||||
// prune and truncate this addition of attributes while adding.
|
||||
|
||||
// Do not set a capacity when creating this map. Benchmark testing has
|
||||
// showed this to only add unused memory allocations in general use.
|
||||
exists := make(map[attribute.Key]int, len(s.attributes))
|
||||
s.dedupeAttrsFromRecord(exists)
|
||||
|
||||
// Now that s.attributes is deduplicated, adding unique attributes up to
|
||||
// the capacity of s will not over allocate s.attributes.
|
||||
|
||||
// max size = limit
|
||||
maxCap := min(len(attrs)+len(s.attributes), limit)
|
||||
if cap(s.attributes) < maxCap {
|
||||
s.attributes = slices.Grow(s.attributes, maxCap-cap(s.attributes))
|
||||
}
|
||||
for _, a := range attrs {
|
||||
if !a.Valid() {
|
||||
// Drop all invalid attributes.
|
||||
s.addDroppedAttr(1)
|
||||
continue
|
||||
}
|
||||
|
||||
if idx, ok := exists[a.Key]; ok {
|
||||
// Perform all updates before dropping, even when at capacity.
|
||||
a = truncateAttr(s.tracer.provider.spanLimits.AttributeValueLengthLimit, a)
|
||||
s.attributes[idx] = a
|
||||
continue
|
||||
}
|
||||
|
||||
if len(s.attributes) >= limit {
|
||||
// Do not just drop all of the remaining attributes, make sure
|
||||
// updates are checked and performed.
|
||||
s.addDroppedAttr(1)
|
||||
} else {
|
||||
a = truncateAttr(s.tracer.provider.spanLimits.AttributeValueLengthLimit, a)
|
||||
s.attributes = append(s.attributes, a)
|
||||
exists[a.Key] = len(s.attributes) - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// truncateAttr returns a truncated version of attr. Only string and string
|
||||
// slice attribute values are truncated. String values are truncated to at
|
||||
// most a length of limit. Each string slice value is truncated in this fashion
|
||||
// (the slice length itself is unaffected).
|
||||
//
|
||||
// No truncation is performed for a negative limit.
|
||||
func truncateAttr(limit int, attr attribute.KeyValue) attribute.KeyValue {
|
||||
if limit < 0 {
|
||||
return attr
|
||||
}
|
||||
switch attr.Value.Type() {
|
||||
case attribute.STRING:
|
||||
if v := attr.Value.AsString(); len(v) > limit {
|
||||
return attr.Key.String(safeTruncate(v, limit))
|
||||
}
|
||||
case attribute.STRINGSLICE:
|
||||
v := attr.Value.AsStringSlice()
|
||||
for i := range v {
|
||||
if len(v[i]) > limit {
|
||||
v[i] = safeTruncate(v[i], limit)
|
||||
}
|
||||
}
|
||||
return attr.Key.StringSlice(v)
|
||||
}
|
||||
return attr
|
||||
}
|
||||
|
||||
// safeTruncate truncates the string and guarantees valid UTF-8 is returned.
|
||||
func safeTruncate(input string, limit int) string {
|
||||
if trunc, ok := safeTruncateValidUTF8(input, limit); ok {
|
||||
return trunc
|
||||
}
|
||||
trunc, _ := safeTruncateValidUTF8(strings.ToValidUTF8(input, ""), limit)
|
||||
return trunc
|
||||
}
|
||||
|
||||
// safeTruncateValidUTF8 returns a copy of the input string safely truncated to
|
||||
// limit. The truncation is ensured to occur at the bounds of complete UTF-8
|
||||
// characters. If invalid encoding of UTF-8 is encountered, input is returned
|
||||
// with false, otherwise, the truncated input will be returned with true.
|
||||
func safeTruncateValidUTF8(input string, limit int) (string, bool) {
|
||||
for cnt := 0; cnt <= limit; {
|
||||
r, size := utf8.DecodeRuneInString(input[cnt:])
|
||||
if r == utf8.RuneError {
|
||||
return input, false
|
||||
}
|
||||
|
||||
if cnt+size > limit {
|
||||
return input[:cnt], true
|
||||
}
|
||||
cnt += size
|
||||
}
|
||||
return input, true
|
||||
}
|
||||
|
||||
// End ends the span. This method does nothing if the span is already ended or
|
||||
// is not being recorded.
|
||||
//
|
||||
// The only SpanOption currently supported is WithTimestamp which will set the
|
||||
// end time for a Span's life-cycle.
|
||||
//
|
||||
// If this method is called while panicking an error event is added to the
|
||||
// Span before ending it and the panic is continued.
|
||||
func (s *recordingSpan) End(options ...trace.SpanEndOption) {
|
||||
// Do not start by checking if the span is being recorded which requires
|
||||
// acquiring a lock. Make a minimal check that the span is not nil.
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Store the end time as soon as possible to avoid artificially increasing
|
||||
// the span's duration in case some operation below takes a while.
|
||||
et := monotonicEndTime(s.startTime)
|
||||
|
||||
// Lock the span now that we have an end time and see if we need to do any more processing.
|
||||
s.mu.Lock()
|
||||
if !s.isRecording() {
|
||||
s.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
config := trace.NewSpanEndConfig(options...)
|
||||
if recovered := recover(); recovered != nil {
|
||||
// Record but don't stop the panic.
|
||||
defer panic(recovered)
|
||||
opts := []trace.EventOption{
|
||||
trace.WithAttributes(
|
||||
semconv.ExceptionType(typeStr(recovered)),
|
||||
semconv.ExceptionMessage(fmt.Sprint(recovered)),
|
||||
),
|
||||
}
|
||||
|
||||
if config.StackTrace() {
|
||||
opts = append(opts, trace.WithAttributes(
|
||||
semconv.ExceptionStacktrace(recordStackTrace()),
|
||||
))
|
||||
}
|
||||
|
||||
s.addEvent(semconv.ExceptionEventName, opts...)
|
||||
}
|
||||
|
||||
if s.executionTracerTaskEnd != nil {
|
||||
s.mu.Unlock()
|
||||
s.executionTracerTaskEnd()
|
||||
s.mu.Lock()
|
||||
}
|
||||
|
||||
// Setting endTime to non-zero marks the span as ended and not recording.
|
||||
if config.Timestamp().IsZero() {
|
||||
s.endTime = et
|
||||
} else {
|
||||
s.endTime = config.Timestamp()
|
||||
}
|
||||
s.mu.Unlock()
|
||||
|
||||
sps := s.tracer.provider.getSpanProcessors()
|
||||
if len(sps) == 0 {
|
||||
return
|
||||
}
|
||||
snap := s.snapshot()
|
||||
for _, sp := range sps {
|
||||
sp.sp.OnEnd(snap)
|
||||
}
|
||||
}
|
||||
|
||||
// monotonicEndTime returns the end time at present but offset from start,
|
||||
// monotonically.
|
||||
//
|
||||
// The monotonic clock is used in subtractions hence the duration since start
|
||||
// added back to start gives end as a monotonic time. See
|
||||
// https://golang.org/pkg/time/#hdr-Monotonic_Clocks
|
||||
func monotonicEndTime(start time.Time) time.Time {
|
||||
return start.Add(time.Since(start))
|
||||
}
|
||||
|
||||
// RecordError will record err as a span event for this span. An additional call to
|
||||
// SetStatus is required if the Status of the Span should be set to Error, this method
|
||||
// does not change the Span status. If this span is not being recorded or err is nil
|
||||
// than this method does nothing.
|
||||
func (s *recordingSpan) RecordError(err error, opts ...trace.EventOption) {
|
||||
if s == nil || err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if !s.isRecording() {
|
||||
return
|
||||
}
|
||||
|
||||
opts = append(opts, trace.WithAttributes(
|
||||
semconv.ExceptionType(typeStr(err)),
|
||||
semconv.ExceptionMessage(err.Error()),
|
||||
))
|
||||
|
||||
c := trace.NewEventConfig(opts...)
|
||||
if c.StackTrace() {
|
||||
opts = append(opts, trace.WithAttributes(
|
||||
semconv.ExceptionStacktrace(recordStackTrace()),
|
||||
))
|
||||
}
|
||||
|
||||
s.addEvent(semconv.ExceptionEventName, opts...)
|
||||
}
|
||||
|
||||
func typeStr(i interface{}) string {
|
||||
t := reflect.TypeOf(i)
|
||||
if t.PkgPath() == "" && t.Name() == "" {
|
||||
// Likely a builtin type.
|
||||
return t.String()
|
||||
}
|
||||
return fmt.Sprintf("%s.%s", t.PkgPath(), t.Name())
|
||||
}
|
||||
|
||||
func recordStackTrace() string {
|
||||
stackTrace := make([]byte, 2048)
|
||||
n := runtime.Stack(stackTrace, false)
|
||||
|
||||
return string(stackTrace[0:n])
|
||||
}
|
||||
|
||||
// AddEvent adds an event with the provided name and options. If this span is
|
||||
// not being recorded then this method does nothing.
|
||||
func (s *recordingSpan) AddEvent(name string, o ...trace.EventOption) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if !s.isRecording() {
|
||||
return
|
||||
}
|
||||
s.addEvent(name, o...)
|
||||
}
|
||||
|
||||
// addEvent adds an event with the provided name and options.
|
||||
//
|
||||
// This method assumes s.mu.Lock is held by the caller.
|
||||
func (s *recordingSpan) addEvent(name string, o ...trace.EventOption) {
|
||||
c := trace.NewEventConfig(o...)
|
||||
e := Event{Name: name, Attributes: c.Attributes(), Time: c.Timestamp()}
|
||||
|
||||
// Discard attributes over limit.
|
||||
limit := s.tracer.provider.spanLimits.AttributePerEventCountLimit
|
||||
if limit == 0 {
|
||||
// Drop all attributes.
|
||||
e.DroppedAttributeCount = len(e.Attributes)
|
||||
e.Attributes = nil
|
||||
} else if limit > 0 && len(e.Attributes) > limit {
|
||||
// Drop over capacity.
|
||||
e.DroppedAttributeCount = len(e.Attributes) - limit
|
||||
e.Attributes = e.Attributes[:limit]
|
||||
}
|
||||
|
||||
s.events.add(e)
|
||||
}
|
||||
|
||||
// SetName sets the name of this span. If this span is not being recorded than
|
||||
// this method does nothing.
|
||||
func (s *recordingSpan) SetName(name string) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if !s.isRecording() {
|
||||
return
|
||||
}
|
||||
s.name = name
|
||||
}
|
||||
|
||||
// Name returns the name of this span.
|
||||
func (s *recordingSpan) Name() string {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.name
|
||||
}
|
||||
|
||||
// Name returns the SpanContext of this span's parent span.
|
||||
func (s *recordingSpan) Parent() trace.SpanContext {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.parent
|
||||
}
|
||||
|
||||
// SpanKind returns the SpanKind of this span.
|
||||
func (s *recordingSpan) SpanKind() trace.SpanKind {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.spanKind
|
||||
}
|
||||
|
||||
// StartTime returns the time this span started.
|
||||
func (s *recordingSpan) StartTime() time.Time {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.startTime
|
||||
}
|
||||
|
||||
// EndTime returns the time this span ended. For spans that have not yet
|
||||
// ended, the returned value will be the zero value of time.Time.
|
||||
func (s *recordingSpan) EndTime() time.Time {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.endTime
|
||||
}
|
||||
|
||||
// Attributes returns the attributes of this span.
|
||||
//
|
||||
// The order of the returned attributes is not guaranteed to be stable.
|
||||
func (s *recordingSpan) Attributes() []attribute.KeyValue {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.dedupeAttrs()
|
||||
return s.attributes
|
||||
}
|
||||
|
||||
// dedupeAttrs deduplicates the attributes of s to fit capacity.
|
||||
//
|
||||
// This method assumes s.mu.Lock is held by the caller.
|
||||
func (s *recordingSpan) dedupeAttrs() {
|
||||
// Do not set a capacity when creating this map. Benchmark testing has
|
||||
// showed this to only add unused memory allocations in general use.
|
||||
exists := make(map[attribute.Key]int, len(s.attributes))
|
||||
s.dedupeAttrsFromRecord(exists)
|
||||
}
|
||||
|
||||
// dedupeAttrsFromRecord deduplicates the attributes of s to fit capacity
|
||||
// using record as the record of unique attribute keys to their index.
|
||||
//
|
||||
// This method assumes s.mu.Lock is held by the caller.
|
||||
func (s *recordingSpan) dedupeAttrsFromRecord(record map[attribute.Key]int) {
|
||||
// Use the fact that slices share the same backing array.
|
||||
unique := s.attributes[:0]
|
||||
for _, a := range s.attributes {
|
||||
if idx, ok := record[a.Key]; ok {
|
||||
unique[idx] = a
|
||||
} else {
|
||||
unique = append(unique, a)
|
||||
record[a.Key] = len(unique) - 1
|
||||
}
|
||||
}
|
||||
clear(s.attributes[len(unique):]) // Erase unneeded elements to let GC collect objects.
|
||||
s.attributes = unique
|
||||
}
|
||||
|
||||
// Links returns the links of this span.
|
||||
func (s *recordingSpan) Links() []Link {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if len(s.links.queue) == 0 {
|
||||
return []Link{}
|
||||
}
|
||||
return s.links.copy()
|
||||
}
|
||||
|
||||
// Events returns the events of this span.
|
||||
func (s *recordingSpan) Events() []Event {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if len(s.events.queue) == 0 {
|
||||
return []Event{}
|
||||
}
|
||||
return s.events.copy()
|
||||
}
|
||||
|
||||
// Status returns the status of this span.
|
||||
func (s *recordingSpan) Status() Status {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.status
|
||||
}
|
||||
|
||||
// InstrumentationScope returns the instrumentation.Scope associated with
|
||||
// the Tracer that created this span.
|
||||
func (s *recordingSpan) InstrumentationScope() instrumentation.Scope {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.tracer.instrumentationScope
|
||||
}
|
||||
|
||||
// InstrumentationLibrary returns the instrumentation.Library associated with
|
||||
// the Tracer that created this span.
|
||||
func (s *recordingSpan) InstrumentationLibrary() instrumentation.Library { //nolint:staticcheck // This method needs to be define for backwards compatibility
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.tracer.instrumentationScope
|
||||
}
|
||||
|
||||
// Resource returns the Resource associated with the Tracer that created this
|
||||
// span.
|
||||
func (s *recordingSpan) Resource() *resource.Resource {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.tracer.provider.resource
|
||||
}
|
||||
|
||||
func (s *recordingSpan) AddLink(link trace.Link) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
if !link.SpanContext.IsValid() && len(link.Attributes) == 0 &&
|
||||
link.SpanContext.TraceState().Len() == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if !s.isRecording() {
|
||||
return
|
||||
}
|
||||
|
||||
l := Link{SpanContext: link.SpanContext, Attributes: link.Attributes}
|
||||
|
||||
// Discard attributes over limit.
|
||||
limit := s.tracer.provider.spanLimits.AttributePerLinkCountLimit
|
||||
if limit == 0 {
|
||||
// Drop all attributes.
|
||||
l.DroppedAttributeCount = len(l.Attributes)
|
||||
l.Attributes = nil
|
||||
} else if limit > 0 && len(l.Attributes) > limit {
|
||||
l.DroppedAttributeCount = len(l.Attributes) - limit
|
||||
l.Attributes = l.Attributes[:limit]
|
||||
}
|
||||
|
||||
s.links.add(l)
|
||||
}
|
||||
|
||||
// DroppedAttributes returns the number of attributes dropped by the span
|
||||
// due to limits being reached.
|
||||
func (s *recordingSpan) DroppedAttributes() int {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.droppedAttributes
|
||||
}
|
||||
|
||||
// DroppedLinks returns the number of links dropped by the span due to limits
|
||||
// being reached.
|
||||
func (s *recordingSpan) DroppedLinks() int {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.links.droppedCount
|
||||
}
|
||||
|
||||
// DroppedEvents returns the number of events dropped by the span due to
|
||||
// limits being reached.
|
||||
func (s *recordingSpan) DroppedEvents() int {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.events.droppedCount
|
||||
}
|
||||
|
||||
// ChildSpanCount returns the count of spans that consider the span a
|
||||
// direct parent.
|
||||
func (s *recordingSpan) ChildSpanCount() int {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.childSpanCount
|
||||
}
|
||||
|
||||
// TracerProvider returns a trace.TracerProvider that can be used to generate
|
||||
// additional Spans on the same telemetry pipeline as the current Span.
|
||||
func (s *recordingSpan) TracerProvider() trace.TracerProvider {
|
||||
return s.tracer.provider
|
||||
}
|
||||
|
||||
// snapshot creates a read-only copy of the current state of the span.
|
||||
func (s *recordingSpan) snapshot() ReadOnlySpan {
|
||||
var sd snapshot
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
sd.endTime = s.endTime
|
||||
sd.instrumentationScope = s.tracer.instrumentationScope
|
||||
sd.name = s.name
|
||||
sd.parent = s.parent
|
||||
sd.resource = s.tracer.provider.resource
|
||||
sd.spanContext = s.spanContext
|
||||
sd.spanKind = s.spanKind
|
||||
sd.startTime = s.startTime
|
||||
sd.status = s.status
|
||||
sd.childSpanCount = s.childSpanCount
|
||||
|
||||
if len(s.attributes) > 0 {
|
||||
s.dedupeAttrs()
|
||||
sd.attributes = s.attributes
|
||||
}
|
||||
sd.droppedAttributeCount = s.droppedAttributes
|
||||
if len(s.events.queue) > 0 {
|
||||
sd.events = s.events.copy()
|
||||
sd.droppedEventCount = s.events.droppedCount
|
||||
}
|
||||
if len(s.links.queue) > 0 {
|
||||
sd.links = s.links.copy()
|
||||
sd.droppedLinkCount = s.links.droppedCount
|
||||
}
|
||||
return &sd
|
||||
}
|
||||
|
||||
func (s *recordingSpan) addChild() {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if !s.isRecording() {
|
||||
return
|
||||
}
|
||||
s.childSpanCount++
|
||||
}
|
||||
|
||||
func (*recordingSpan) private() {}
|
||||
|
||||
// runtimeTrace starts a "runtime/trace".Task for the span and returns a
|
||||
// context containing the task.
|
||||
func (s *recordingSpan) runtimeTrace(ctx context.Context) context.Context {
|
||||
if !rt.IsEnabled() {
|
||||
// Avoid additional overhead if runtime/trace is not enabled.
|
||||
return ctx
|
||||
}
|
||||
nctx, task := rt.NewTask(ctx, s.name)
|
||||
|
||||
s.mu.Lock()
|
||||
s.executionTracerTaskEnd = task.End
|
||||
s.mu.Unlock()
|
||||
|
||||
return nctx
|
||||
}
|
||||
|
||||
// nonRecordingSpan is a minimal implementation of the OpenTelemetry Span API
|
||||
// that wraps a SpanContext. It performs no operations other than to return
|
||||
// the wrapped SpanContext or TracerProvider that created it.
|
||||
type nonRecordingSpan struct {
|
||||
embedded.Span
|
||||
|
||||
// tracer is the SDK tracer that created this span.
|
||||
tracer *tracer
|
||||
sc trace.SpanContext
|
||||
}
|
||||
|
||||
var _ trace.Span = nonRecordingSpan{}
|
||||
|
||||
// SpanContext returns the wrapped SpanContext.
|
||||
func (s nonRecordingSpan) SpanContext() trace.SpanContext { return s.sc }
|
||||
|
||||
// IsRecording always returns false.
|
||||
func (nonRecordingSpan) IsRecording() bool { return false }
|
||||
|
||||
// SetStatus does nothing.
|
||||
func (nonRecordingSpan) SetStatus(codes.Code, string) {}
|
||||
|
||||
// SetError does nothing.
|
||||
func (nonRecordingSpan) SetError(bool) {}
|
||||
|
||||
// SetAttributes does nothing.
|
||||
func (nonRecordingSpan) SetAttributes(...attribute.KeyValue) {}
|
||||
|
||||
// End does nothing.
|
||||
func (nonRecordingSpan) End(...trace.SpanEndOption) {}
|
||||
|
||||
// RecordError does nothing.
|
||||
func (nonRecordingSpan) RecordError(error, ...trace.EventOption) {}
|
||||
|
||||
// AddEvent does nothing.
|
||||
func (nonRecordingSpan) AddEvent(string, ...trace.EventOption) {}
|
||||
|
||||
// AddLink does nothing.
|
||||
func (nonRecordingSpan) AddLink(trace.Link) {}
|
||||
|
||||
// SetName does nothing.
|
||||
func (nonRecordingSpan) SetName(string) {}
|
||||
|
||||
// TracerProvider returns the trace.TracerProvider that provided the Tracer
|
||||
// that created this span.
|
||||
func (s nonRecordingSpan) TracerProvider() trace.TracerProvider { return s.tracer.provider }
|
||||
|
||||
func isRecording(s SamplingResult) bool {
|
||||
return s.Decision == RecordOnly || s.Decision == RecordAndSample
|
||||
}
|
||||
|
||||
func isSampled(s SamplingResult) bool {
|
||||
return s.Decision == RecordAndSample
|
||||
}
|
||||
|
||||
// Status is the classified state of a Span.
|
||||
type Status struct {
|
||||
// Code is an identifier of a Spans state classification.
|
||||
Code codes.Code
|
||||
// Description is a user hint about why that status was set. It is only
|
||||
// applicable when Code is Error.
|
||||
Description string
|
||||
}
|
36
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/span_exporter.go
generated
vendored
Normal file
36
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/span_exporter.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import "context"
|
||||
|
||||
// SpanExporter handles the delivery of spans to external receivers. This is
|
||||
// the final component in the trace export pipeline.
|
||||
type SpanExporter interface {
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
|
||||
// ExportSpans exports a batch of spans.
|
||||
//
|
||||
// This function is called synchronously, so there is no concurrency
|
||||
// safety requirement. However, due to the synchronous calling pattern,
|
||||
// it is critical that all timeouts and cancellations contained in the
|
||||
// passed context must be honored.
|
||||
//
|
||||
// Any retry logic must be contained in this function. The SDK that
|
||||
// calls this function will not implement any retry logic. All errors
|
||||
// returned by this function are considered unrecoverable and will be
|
||||
// reported to a configured error Handler.
|
||||
ExportSpans(ctx context.Context, spans []ReadOnlySpan) error
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
|
||||
// Shutdown notifies the exporter of a pending halt to operations. The
|
||||
// exporter is expected to perform any cleanup or synchronization it
|
||||
// requires while honoring all timeouts and cancellations contained in
|
||||
// the passed context.
|
||||
Shutdown(ctx context.Context) error
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
}
|
114
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/span_limits.go
generated
vendored
Normal file
114
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/span_limits.go
generated
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import "go.opentelemetry.io/otel/sdk/internal/env"
|
||||
|
||||
const (
|
||||
// DefaultAttributeValueLengthLimit is the default maximum allowed
|
||||
// attribute value length, unlimited.
|
||||
DefaultAttributeValueLengthLimit = -1
|
||||
|
||||
// DefaultAttributeCountLimit is the default maximum number of attributes
|
||||
// a span can have.
|
||||
DefaultAttributeCountLimit = 128
|
||||
|
||||
// DefaultEventCountLimit is the default maximum number of events a span
|
||||
// can have.
|
||||
DefaultEventCountLimit = 128
|
||||
|
||||
// DefaultLinkCountLimit is the default maximum number of links a span can
|
||||
// have.
|
||||
DefaultLinkCountLimit = 128
|
||||
|
||||
// DefaultAttributePerEventCountLimit is the default maximum number of
|
||||
// attributes a span event can have.
|
||||
DefaultAttributePerEventCountLimit = 128
|
||||
|
||||
// DefaultAttributePerLinkCountLimit is the default maximum number of
|
||||
// attributes a span link can have.
|
||||
DefaultAttributePerLinkCountLimit = 128
|
||||
)
|
||||
|
||||
// SpanLimits represents the limits of a span.
|
||||
type SpanLimits struct {
|
||||
// AttributeValueLengthLimit is the maximum allowed attribute value length.
|
||||
//
|
||||
// This limit only applies to string and string slice attribute values.
|
||||
// Any string longer than this value will be truncated to this length.
|
||||
//
|
||||
// Setting this to a negative value means no limit is applied.
|
||||
AttributeValueLengthLimit int
|
||||
|
||||
// AttributeCountLimit is the maximum allowed span attribute count. Any
|
||||
// attribute added to a span once this limit is reached will be dropped.
|
||||
//
|
||||
// Setting this to zero means no attributes will be recorded.
|
||||
//
|
||||
// Setting this to a negative value means no limit is applied.
|
||||
AttributeCountLimit int
|
||||
|
||||
// EventCountLimit is the maximum allowed span event count. Any event
|
||||
// added to a span once this limit is reached means it will be added but
|
||||
// the oldest event will be dropped.
|
||||
//
|
||||
// Setting this to zero means no events we be recorded.
|
||||
//
|
||||
// Setting this to a negative value means no limit is applied.
|
||||
EventCountLimit int
|
||||
|
||||
// LinkCountLimit is the maximum allowed span link count. Any link added
|
||||
// to a span once this limit is reached means it will be added but the
|
||||
// oldest link will be dropped.
|
||||
//
|
||||
// Setting this to zero means no links we be recorded.
|
||||
//
|
||||
// Setting this to a negative value means no limit is applied.
|
||||
LinkCountLimit int
|
||||
|
||||
// AttributePerEventCountLimit is the maximum number of attributes allowed
|
||||
// per span event. Any attribute added after this limit reached will be
|
||||
// dropped.
|
||||
//
|
||||
// Setting this to zero means no attributes will be recorded for events.
|
||||
//
|
||||
// Setting this to a negative value means no limit is applied.
|
||||
AttributePerEventCountLimit int
|
||||
|
||||
// AttributePerLinkCountLimit is the maximum number of attributes allowed
|
||||
// per span link. Any attribute added after this limit reached will be
|
||||
// dropped.
|
||||
//
|
||||
// Setting this to zero means no attributes will be recorded for links.
|
||||
//
|
||||
// Setting this to a negative value means no limit is applied.
|
||||
AttributePerLinkCountLimit int
|
||||
}
|
||||
|
||||
// NewSpanLimits returns a SpanLimits with all limits set to the value their
|
||||
// corresponding environment variable holds, or the default if unset.
|
||||
//
|
||||
// • AttributeValueLengthLimit: OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT
|
||||
// (default: unlimited)
|
||||
//
|
||||
// • AttributeCountLimit: OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT (default: 128)
|
||||
//
|
||||
// • EventCountLimit: OTEL_SPAN_EVENT_COUNT_LIMIT (default: 128)
|
||||
//
|
||||
// • AttributePerEventCountLimit: OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT (default:
|
||||
// 128)
|
||||
//
|
||||
// • LinkCountLimit: OTEL_SPAN_LINK_COUNT_LIMIT (default: 128)
|
||||
//
|
||||
// • AttributePerLinkCountLimit: OTEL_LINK_ATTRIBUTE_COUNT_LIMIT (default: 128)
|
||||
func NewSpanLimits() SpanLimits {
|
||||
return SpanLimits{
|
||||
AttributeValueLengthLimit: env.SpanAttributeValueLength(DefaultAttributeValueLengthLimit),
|
||||
AttributeCountLimit: env.SpanAttributeCount(DefaultAttributeCountLimit),
|
||||
EventCountLimit: env.SpanEventCount(DefaultEventCountLimit),
|
||||
LinkCountLimit: env.SpanLinkCount(DefaultLinkCountLimit),
|
||||
AttributePerEventCountLimit: env.SpanEventAttributeCount(DefaultAttributePerEventCountLimit),
|
||||
AttributePerLinkCountLimit: env.SpanLinkAttributeCount(DefaultAttributePerLinkCountLimit),
|
||||
}
|
||||
}
|
61
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/span_processor.go
generated
vendored
Normal file
61
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/span_processor.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// SpanProcessor is a processing pipeline for spans in the trace signal.
|
||||
// SpanProcessors registered with a TracerProvider and are called at the start
|
||||
// and end of a Span's lifecycle, and are called in the order they are
|
||||
// registered.
|
||||
type SpanProcessor interface {
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
|
||||
// OnStart is called when a span is started. It is called synchronously
|
||||
// and should not block.
|
||||
OnStart(parent context.Context, s ReadWriteSpan)
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
|
||||
// OnEnd is called when span is finished. It is called synchronously and
|
||||
// hence not block.
|
||||
OnEnd(s ReadOnlySpan)
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
|
||||
// Shutdown is called when the SDK shuts down. Any cleanup or release of
|
||||
// resources held by the processor should be done in this call.
|
||||
//
|
||||
// Calls to OnStart, OnEnd, or ForceFlush after this has been called
|
||||
// should be ignored.
|
||||
//
|
||||
// All timeouts and cancellations contained in ctx must be honored, this
|
||||
// should not block indefinitely.
|
||||
Shutdown(ctx context.Context) error
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
|
||||
// ForceFlush exports all ended spans to the configured Exporter that have not yet
|
||||
// been exported. It should only be called when absolutely necessary, such as when
|
||||
// using a FaaS provider that may suspend the process after an invocation, but before
|
||||
// the Processor can export the completed spans.
|
||||
ForceFlush(ctx context.Context) error
|
||||
// DO NOT CHANGE: any modification will not be backwards compatible and
|
||||
// must never be done outside of a new major release.
|
||||
}
|
||||
|
||||
type spanProcessorState struct {
|
||||
sp SpanProcessor
|
||||
state sync.Once
|
||||
}
|
||||
|
||||
func newSpanProcessorState(sp SpanProcessor) *spanProcessorState {
|
||||
return &spanProcessorState{sp: sp}
|
||||
}
|
||||
|
||||
type spanProcessorStates []*spanProcessorState
|
153
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/tracer.go
generated
vendored
Normal file
153
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/tracer.go
generated
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.opentelemetry.io/otel/trace/embedded"
|
||||
)
|
||||
|
||||
type tracer struct {
|
||||
embedded.Tracer
|
||||
|
||||
provider *TracerProvider
|
||||
instrumentationScope instrumentation.Scope
|
||||
}
|
||||
|
||||
var _ trace.Tracer = &tracer{}
|
||||
|
||||
// Start starts a Span and returns it along with a context containing it.
|
||||
//
|
||||
// The Span is created with the provided name and as a child of any existing
|
||||
// span context found in the passed context. The created Span will be
|
||||
// configured appropriately by any SpanOption passed.
|
||||
func (tr *tracer) Start(ctx context.Context, name string, options ...trace.SpanStartOption) (context.Context, trace.Span) {
|
||||
config := trace.NewSpanStartConfig(options...)
|
||||
|
||||
if ctx == nil {
|
||||
// Prevent trace.ContextWithSpan from panicking.
|
||||
ctx = context.Background()
|
||||
}
|
||||
|
||||
// For local spans created by this SDK, track child span count.
|
||||
if p := trace.SpanFromContext(ctx); p != nil {
|
||||
if sdkSpan, ok := p.(*recordingSpan); ok {
|
||||
sdkSpan.addChild()
|
||||
}
|
||||
}
|
||||
|
||||
s := tr.newSpan(ctx, name, &config)
|
||||
if rw, ok := s.(ReadWriteSpan); ok && s.IsRecording() {
|
||||
sps := tr.provider.getSpanProcessors()
|
||||
for _, sp := range sps {
|
||||
sp.sp.OnStart(ctx, rw)
|
||||
}
|
||||
}
|
||||
if rtt, ok := s.(runtimeTracer); ok {
|
||||
ctx = rtt.runtimeTrace(ctx)
|
||||
}
|
||||
|
||||
return trace.ContextWithSpan(ctx, s), s
|
||||
}
|
||||
|
||||
type runtimeTracer interface {
|
||||
// runtimeTrace starts a "runtime/trace".Task for the span and
|
||||
// returns a context containing the task.
|
||||
runtimeTrace(ctx context.Context) context.Context
|
||||
}
|
||||
|
||||
// newSpan returns a new configured span.
|
||||
func (tr *tracer) newSpan(ctx context.Context, name string, config *trace.SpanConfig) trace.Span {
|
||||
// If told explicitly to make this a new root use a zero value SpanContext
|
||||
// as a parent which contains an invalid trace ID and is not remote.
|
||||
var psc trace.SpanContext
|
||||
if config.NewRoot() {
|
||||
ctx = trace.ContextWithSpanContext(ctx, psc)
|
||||
} else {
|
||||
psc = trace.SpanContextFromContext(ctx)
|
||||
}
|
||||
|
||||
// If there is a valid parent trace ID, use it to ensure the continuity of
|
||||
// the trace. Always generate a new span ID so other components can rely
|
||||
// on a unique span ID, even if the Span is non-recording.
|
||||
var tid trace.TraceID
|
||||
var sid trace.SpanID
|
||||
if !psc.TraceID().IsValid() {
|
||||
tid, sid = tr.provider.idGenerator.NewIDs(ctx)
|
||||
} else {
|
||||
tid = psc.TraceID()
|
||||
sid = tr.provider.idGenerator.NewSpanID(ctx, tid)
|
||||
}
|
||||
|
||||
samplingResult := tr.provider.sampler.ShouldSample(SamplingParameters{
|
||||
ParentContext: ctx,
|
||||
TraceID: tid,
|
||||
Name: name,
|
||||
Kind: config.SpanKind(),
|
||||
Attributes: config.Attributes(),
|
||||
Links: config.Links(),
|
||||
})
|
||||
|
||||
scc := trace.SpanContextConfig{
|
||||
TraceID: tid,
|
||||
SpanID: sid,
|
||||
TraceState: samplingResult.Tracestate,
|
||||
}
|
||||
if isSampled(samplingResult) {
|
||||
scc.TraceFlags = psc.TraceFlags() | trace.FlagsSampled
|
||||
} else {
|
||||
scc.TraceFlags = psc.TraceFlags() &^ trace.FlagsSampled
|
||||
}
|
||||
sc := trace.NewSpanContext(scc)
|
||||
|
||||
if !isRecording(samplingResult) {
|
||||
return tr.newNonRecordingSpan(sc)
|
||||
}
|
||||
return tr.newRecordingSpan(psc, sc, name, samplingResult, config)
|
||||
}
|
||||
|
||||
// newRecordingSpan returns a new configured recordingSpan.
|
||||
func (tr *tracer) newRecordingSpan(psc, sc trace.SpanContext, name string, sr SamplingResult, config *trace.SpanConfig) *recordingSpan {
|
||||
startTime := config.Timestamp()
|
||||
if startTime.IsZero() {
|
||||
startTime = time.Now()
|
||||
}
|
||||
|
||||
s := &recordingSpan{
|
||||
// Do not pre-allocate the attributes slice here! Doing so will
|
||||
// allocate memory that is likely never going to be used, or if used,
|
||||
// will be over-sized. The default Go compiler has been tested to
|
||||
// dynamically allocate needed space very well. Benchmarking has shown
|
||||
// it to be more performant than what we can predetermine here,
|
||||
// especially for the common use case of few to no added
|
||||
// attributes.
|
||||
|
||||
parent: psc,
|
||||
spanContext: sc,
|
||||
spanKind: trace.ValidateSpanKind(config.SpanKind()),
|
||||
name: name,
|
||||
startTime: startTime,
|
||||
events: newEvictedQueueEvent(tr.provider.spanLimits.EventCountLimit),
|
||||
links: newEvictedQueueLink(tr.provider.spanLimits.LinkCountLimit),
|
||||
tracer: tr,
|
||||
}
|
||||
|
||||
for _, l := range config.Links() {
|
||||
s.AddLink(l)
|
||||
}
|
||||
|
||||
s.SetAttributes(sr.Attributes...)
|
||||
s.SetAttributes(config.Attributes()...)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// newNonRecordingSpan returns a new configured nonRecordingSpan.
|
||||
func (tr *tracer) newNonRecordingSpan(sc trace.SpanContext) nonRecordingSpan {
|
||||
return nonRecordingSpan{tracer: tr, sc: sc}
|
||||
}
|
9
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/version.go
generated
vendored
Normal file
9
e2e/vendor/go.opentelemetry.io/otel/sdk/trace/version.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/sdk/trace"
|
||||
|
||||
// version is the current release version of the metric SDK in use.
|
||||
func version() string {
|
||||
return "1.16.0-rc.1"
|
||||
}
|
9
e2e/vendor/go.opentelemetry.io/otel/sdk/version.go
generated
vendored
Normal file
9
e2e/vendor/go.opentelemetry.io/otel/sdk/version.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk // import "go.opentelemetry.io/otel/sdk"
|
||||
|
||||
// Version is the current release version of the OpenTelemetry SDK in use.
|
||||
func Version() string {
|
||||
return "1.32.0"
|
||||
}
|
Reference in New Issue
Block a user