summaryrefslogtreecommitdiff
path: root/vendor/go.opentelemetry.io/otel/sdk
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.opentelemetry.io/otel/sdk')
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/LICENSE30
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go4
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/log/LICENSE30
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/log/batch.go2
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/log/doc.go3
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/log/filter_processor.go2
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/log/internal/x/README.md34
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/log/internal/x/x.go63
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/log/logger.go34
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/log/provider.go21
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/log/record.go124
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/LICENSE30
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/config.go46
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/doc.go24
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/exemplar.go15
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/filter.go4
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/fixed_size_reservoir.go16
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/histogram_reservoir.go2
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go6
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/drop.go4
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/exponential_histogram.go18
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go8
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go16
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go16
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/README.md35
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/x.go22
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/manual_reader.go2
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/meter.go3
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go6
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go54
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/provider.go2
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/reader.go2
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/metric/version.go2
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go4
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/resource/container.go4
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/resource/env.go2
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go4
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/resource/os.go6
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/resource/os_release_unix.go6
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/resource/process.go18
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/resource/resource.go4
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go122
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/doc.go3
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/id_generator.go4
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/internal/x/README.md35
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/internal/x/x.go63
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/provider.go40
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go8
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go6
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go2
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/span.go19
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/tracer.go138
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/exporter.go4
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/recorder.go4
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/span.go2
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/version.go9
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/version.go2
57 files changed, 938 insertions, 251 deletions
diff --git a/vendor/go.opentelemetry.io/otel/sdk/LICENSE b/vendor/go.opentelemetry.io/otel/sdk/LICENSE
index 261eeb9e9..f1aee0f11 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/LICENSE
+++ b/vendor/go.opentelemetry.io/otel/sdk/LICENSE
@@ -199,3 +199,33 @@
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.
+
+--------------------------------------------------------------------------------
+
+Copyright 2009 The Go Authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google LLC nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go b/vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go
index 68d296cbe..1be472e91 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go
@@ -19,7 +19,7 @@ import (
// 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" {
+ if strings.EqualFold(v, "true") {
return v, true
}
return "", false
@@ -59,7 +59,7 @@ func (f Feature[T]) Lookup() (v T, ok bool) {
return f.parse(vRaw)
}
-// Enabled returns if the feature is enabled.
+// Enabled reports whether the feature is enabled.
func (f Feature[T]) Enabled() bool {
_, ok := f.Lookup()
return ok
diff --git a/vendor/go.opentelemetry.io/otel/sdk/log/LICENSE b/vendor/go.opentelemetry.io/otel/sdk/log/LICENSE
index 261eeb9e9..f1aee0f11 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/log/LICENSE
+++ b/vendor/go.opentelemetry.io/otel/sdk/log/LICENSE
@@ -199,3 +199,33 @@
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.
+
+--------------------------------------------------------------------------------
+
+Copyright 2009 The Go Authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google LLC nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/vendor/go.opentelemetry.io/otel/sdk/log/batch.go b/vendor/go.opentelemetry.io/otel/sdk/log/batch.go
index b91741d58..462eb1c3a 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/log/batch.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/log/batch.go
@@ -329,7 +329,7 @@ func (q *queue) TryDequeue(buf []Record, write func([]Record) bool) int {
origRead := q.read
n := min(len(buf), q.len)
- for i := 0; i < n; i++ {
+ for i := range n {
buf[i] = q.read.Value
q.read = q.read.Next()
}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/log/doc.go b/vendor/go.opentelemetry.io/otel/sdk/log/doc.go
index 78935de63..a27834a5b 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/log/doc.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/log/doc.go
@@ -30,6 +30,9 @@ should be used to describe the unique runtime environment instrumented code
is being run on. That way when multiple instances of the code are collected
at a single endpoint their origin is decipherable.
+See [go.opentelemetry.io/otel/sdk/log/internal/x] for information about
+the experimental features.
+
See [go.opentelemetry.io/otel/log] for more information about
the OpenTelemetry Logs API.
*/
diff --git a/vendor/go.opentelemetry.io/otel/sdk/log/filter_processor.go b/vendor/go.opentelemetry.io/otel/sdk/log/filter_processor.go
index 682f2eb2c..283133aba 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/log/filter_processor.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/log/filter_processor.go
@@ -30,7 +30,7 @@ import (
// It provides a Processor used to filter out [Record]
// that has a [log.Severity] below a threshold.
type FilterProcessor interface {
- // Enabled returns whether the Processor will process for the given context
+ // Enabled reports whether the Processor will process for the given context
// and param.
//
// The passed param is likely to be a partial record information being
diff --git a/vendor/go.opentelemetry.io/otel/sdk/log/internal/x/README.md b/vendor/go.opentelemetry.io/otel/sdk/log/internal/x/README.md
new file mode 100644
index 000000000..83e9e7b4c
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/sdk/log/internal/x/README.md
@@ -0,0 +1,34 @@
+# Experimental Features
+
+The Logs SDK contains features that have not yet stabilized in the OpenTelemetry specification.
+These features are added to the OpenTelemetry Go Logs 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
+
+- [Self-Observability](#self-observability)
+
+### Self-Observability
+
+The Logs SDK provides a self-observability feature that allows you to monitor the SDK itself.
+
+To opt-in, set the environment variable `OTEL_GO_X_SELF_OBSERVABILITY` to `true`.
+
+When enabled, the SDK will create the following metrics using the global `MeterProvider`:
+
+- `otel.sdk.log.created`
+
+Please see the [Semantic conventions for OpenTelemetry SDK metrics] documentation for more details on these metrics.
+
+[Semantic conventions for OpenTelemetry SDK metrics]: https://github.com/open-telemetry/semantic-conventions/blob/v1.36.0/docs/otel/sdk-metrics.md
+
+## 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.
diff --git a/vendor/go.opentelemetry.io/otel/sdk/log/internal/x/x.go b/vendor/go.opentelemetry.io/otel/sdk/log/internal/x/x.go
new file mode 100644
index 000000000..5f01b275d
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/sdk/log/internal/x/x.go
@@ -0,0 +1,63 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+// Package x documents experimental features for [go.opentelemetry.io/otel/sdk/log].
+package x // import "go.opentelemetry.io/otel/sdk/log/internal/x"
+
+import (
+ "os"
+ "strings"
+)
+
+// SelfObservability is an experimental feature flag that determines if SDK
+// self-observability metrics are enabled.
+//
+// To enable this feature set the OTEL_GO_X_SELF_OBSERVABILITY environment variable
+// to the case-insensitive string value of "true" (i.e. "True" and "TRUE"
+// will also enable this).
+var SelfObservability = newFeature("SELF_OBSERVABILITY", func(v string) (string, bool) {
+ if strings.EqualFold(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 reports whether the feature is enabled.
+func (f Feature[T]) Enabled() bool {
+ _, ok := f.Lookup()
+ return ok
+}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/log/logger.go b/vendor/go.opentelemetry.io/otel/sdk/log/logger.go
index 1ec8ff883..7dad98c92 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/log/logger.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/log/logger.go
@@ -5,12 +5,18 @@ package log // import "go.opentelemetry.io/otel/sdk/log"
import (
"context"
+ "fmt"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/embedded"
+ "go.opentelemetry.io/otel/metric"
+ "go.opentelemetry.io/otel/sdk"
"go.opentelemetry.io/otel/sdk/instrumentation"
+ "go.opentelemetry.io/otel/sdk/log/internal/x"
+ semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
+ "go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
"go.opentelemetry.io/otel/trace"
)
@@ -24,13 +30,31 @@ type logger struct {
provider *LoggerProvider
instrumentationScope instrumentation.Scope
+
+ selfObservabilityEnabled bool
+ logCreatedMetric otelconv.SDKLogCreated
}
func newLogger(p *LoggerProvider, scope instrumentation.Scope) *logger {
- return &logger{
+ l := &logger{
provider: p,
instrumentationScope: scope,
}
+ if !x.SelfObservability.Enabled() {
+ return l
+ }
+ l.selfObservabilityEnabled = true
+ mp := otel.GetMeterProvider()
+ m := mp.Meter("go.opentelemetry.io/otel/sdk/log",
+ metric.WithInstrumentationVersion(sdk.Version()),
+ metric.WithSchemaURL(semconv.SchemaURL))
+
+ var err error
+ if l.logCreatedMetric, err = otelconv.NewSDKLogCreated(m); err != nil {
+ err = fmt.Errorf("failed to create log created metric: %w", err)
+ otel.Handle(err)
+ }
+ return l
}
func (l *logger) Emit(ctx context.Context, r log.Record) {
@@ -84,7 +108,6 @@ func (l *logger) newRecord(ctx context.Context, r log.Record) Record {
observedTimestamp: r.ObservedTimestamp(),
severity: r.Severity(),
severityText: r.SeverityText(),
- body: r.Body(),
traceID: sc.TraceID(),
spanID: sc.SpanID(),
@@ -94,7 +117,14 @@ func (l *logger) newRecord(ctx context.Context, r log.Record) Record {
scope: &l.instrumentationScope,
attributeValueLengthLimit: l.provider.attributeValueLengthLimit,
attributeCountLimit: l.provider.attributeCountLimit,
+ allowDupKeys: l.provider.allowDupKeys,
}
+ if l.selfObservabilityEnabled {
+ l.logCreatedMetric.Add(ctx, 1)
+ }
+
+ // This ensures we deduplicate key-value collections in the log body
+ newRecord.SetBody(r.Body())
// This field SHOULD be set once the event is observed by OpenTelemetry.
if newRecord.observedTimestamp.IsZero() {
diff --git a/vendor/go.opentelemetry.io/otel/sdk/log/provider.go b/vendor/go.opentelemetry.io/otel/sdk/log/provider.go
index 359357b7e..c69422e12 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/log/provider.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/log/provider.go
@@ -32,6 +32,7 @@ type providerConfig struct {
fltrProcessors []FilterProcessor
attrCntLim setting[int]
attrValLenLim setting[int]
+ allowDupKeys setting[bool]
}
func newProviderConfig(opts []LoggerProviderOption) providerConfig {
@@ -67,6 +68,7 @@ type LoggerProvider struct {
fltrProcessors []FilterProcessor
attributeCountLimit int
attributeValueLengthLimit int
+ allowDupKeys bool
loggersMu sync.Mutex
loggers map[instrumentation.Scope]*logger
@@ -93,6 +95,7 @@ func NewLoggerProvider(opts ...LoggerProviderOption) *LoggerProvider {
fltrProcessors: cfg.fltrProcessors,
attributeCountLimit: cfg.attrCntLim.Value,
attributeValueLengthLimit: cfg.attrValLenLim.Value,
+ allowDupKeys: cfg.allowDupKeys.Value,
}
}
@@ -254,3 +257,21 @@ func WithAttributeValueLengthLimit(limit int) LoggerProviderOption {
return cfg
})
}
+
+// WithAllowKeyDuplication sets whether deduplication is skipped for log attributes or other key-value collections.
+//
+// By default, the key-value collections within a log record are deduplicated to comply with the OpenTelemetry Specification.
+// Deduplication means that if multiple key–value pairs with the same key are present, only a single pair
+// is retained and others are discarded.
+//
+// Disabling deduplication with this option can improve performance e.g. of adding attributes to the log record.
+//
+// Note that if you disable deduplication, you are responsible for ensuring that duplicate
+// key-value pairs within in a single collection are not emitted,
+// or that the telemetry receiver can handle such duplicates.
+func WithAllowKeyDuplication() LoggerProviderOption {
+ return loggerProviderOptionFunc(func(cfg providerConfig) providerConfig {
+ cfg.allowDupKeys = newSetting(true)
+ return cfg
+ })
+}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/log/record.go b/vendor/go.opentelemetry.io/otel/sdk/log/record.go
index 38fd65079..9dfd69b64 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/log/record.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/log/record.go
@@ -93,6 +93,9 @@ type Record struct {
attributeValueLengthLimit int
attributeCountLimit int
+ // specifies whether we should deduplicate any key value collections or not
+ allowDupKeys bool
+
noCmp [0]func() //nolint: unused // This is indeed used.
}
@@ -167,7 +170,11 @@ func (r *Record) Body() log.Value {
// SetBody sets the body of the log record.
func (r *Record) SetBody(v log.Value) {
- r.body = v
+ if !r.allowDupKeys {
+ r.body = r.dedupeBodyCollections(v)
+ } else {
+ r.body = v
+ }
}
// WalkAttributes walks all attributes the log record holds by calling f for
@@ -192,56 +199,60 @@ func (r *Record) AddAttributes(attrs ...log.KeyValue) {
if n == 0 {
// Avoid the more complex duplicate map lookups below.
var drop int
- attrs, drop = dedup(attrs)
- r.setDropped(drop)
+ if !r.allowDupKeys {
+ attrs, drop = dedup(attrs)
+ r.setDropped(drop)
+ }
- attrs, drop = head(attrs, r.attributeCountLimit)
+ attrs, drop := head(attrs, r.attributeCountLimit)
r.addDropped(drop)
r.addAttrs(attrs)
return
}
- // Used to find duplicates between attrs and existing attributes in r.
- rIndex := r.attrIndex()
- defer putIndex(rIndex)
+ if !r.allowDupKeys {
+ // Used to find duplicates between attrs and existing attributes in r.
+ rIndex := r.attrIndex()
+ defer putIndex(rIndex)
- // Unique attrs that need to be added to r. This uses the same underlying
- // array as attrs.
- //
- // Note, do not iterate attrs twice by just calling dedup(attrs) here.
- unique := attrs[:0]
- // Used to find duplicates within attrs itself. The index value is the
- // index of the element in unique.
- uIndex := getIndex()
- defer putIndex(uIndex)
-
- // Deduplicate attrs within the scope of all existing attributes.
- for _, a := range attrs {
- // Last-value-wins for any duplicates in attrs.
- idx, found := uIndex[a.Key]
- if found {
- r.addDropped(1)
- unique[idx] = a
- continue
- }
+ // Unique attrs that need to be added to r. This uses the same underlying
+ // array as attrs.
+ //
+ // Note, do not iterate attrs twice by just calling dedup(attrs) here.
+ unique := attrs[:0]
+ // Used to find duplicates within attrs itself. The index value is the
+ // index of the element in unique.
+ uIndex := getIndex()
+ defer putIndex(uIndex)
+
+ // Deduplicate attrs within the scope of all existing attributes.
+ for _, a := range attrs {
+ // Last-value-wins for any duplicates in attrs.
+ idx, found := uIndex[a.Key]
+ if found {
+ r.addDropped(1)
+ unique[idx] = a
+ continue
+ }
- idx, found = rIndex[a.Key]
- if found {
- // New attrs overwrite any existing with the same key.
- r.addDropped(1)
- if idx < 0 {
- r.front[-(idx + 1)] = a
+ idx, found = rIndex[a.Key]
+ if found {
+ // New attrs overwrite any existing with the same key.
+ r.addDropped(1)
+ if idx < 0 {
+ r.front[-(idx + 1)] = a
+ } else {
+ r.back[idx] = a
+ }
} else {
- r.back[idx] = a
+ // Unique attribute.
+ unique = append(unique, a)
+ uIndex[a.Key] = len(unique) - 1
}
- } else {
- // Unique attribute.
- unique = append(unique, a)
- uIndex[a.Key] = len(unique) - 1
}
+ attrs = unique
}
- attrs = unique
if r.attributeCountLimit > 0 && n+len(attrs) > r.attributeCountLimit {
// Truncate the now unique attributes to comply with limit.
@@ -297,8 +308,11 @@ func (r *Record) addAttrs(attrs []log.KeyValue) {
// SetAttributes sets (and overrides) attributes to the log record.
func (r *Record) SetAttributes(attrs ...log.KeyValue) {
var drop int
- attrs, drop = dedup(attrs)
- r.setDropped(drop)
+ r.setDropped(0)
+ if !r.allowDupKeys {
+ attrs, drop = dedup(attrs)
+ r.setDropped(drop)
+ }
attrs, drop = head(attrs, r.attributeCountLimit)
r.addDropped(drop)
@@ -426,10 +440,14 @@ func (r *Record) applyValueLimits(val log.Value) log.Value {
}
val = log.SliceValue(sl...)
case log.KindMap:
- // Deduplicate then truncate. Do not do at the same time to avoid
- // wasted truncation operations.
- kvs, dropped := dedup(val.AsMap())
- r.addDropped(dropped)
+ kvs := val.AsMap()
+ if !r.allowDupKeys {
+ // Deduplicate then truncate. Do not do at the same time to avoid
+ // wasted truncation operations.
+ var dropped int
+ kvs, dropped = dedup(kvs)
+ r.addDropped(dropped)
+ }
for i := range kvs {
kvs[i] = r.applyAttrLimits(kvs[i])
}
@@ -438,6 +456,24 @@ func (r *Record) applyValueLimits(val log.Value) log.Value {
return val
}
+func (r *Record) dedupeBodyCollections(val log.Value) log.Value {
+ switch val.Kind() {
+ case log.KindSlice:
+ sl := val.AsSlice()
+ for i := range sl {
+ sl[i] = r.dedupeBodyCollections(sl[i])
+ }
+ val = log.SliceValue(sl...)
+ case log.KindMap:
+ kvs, _ := dedup(val.AsMap())
+ for i := range kvs {
+ kvs[i].Value = r.dedupeBodyCollections(kvs[i].Value)
+ }
+ val = log.MapValue(kvs...)
+ }
+ return val
+}
+
// truncate returns a truncated version of s such that it contains less than
// the limit number of characters. Truncation is applied by returning the limit
// number of valid characters contained in s.
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/LICENSE b/vendor/go.opentelemetry.io/otel/sdk/metric/LICENSE
index 261eeb9e9..f1aee0f11 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/LICENSE
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/LICENSE
@@ -199,3 +199,33 @@
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.
+
+--------------------------------------------------------------------------------
+
+Copyright 2009 The Go Authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google LLC nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/config.go b/vendor/go.opentelemetry.io/otel/sdk/metric/config.go
index 203cd9d65..c6440a134 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/config.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/config.go
@@ -7,6 +7,7 @@ import (
"context"
"errors"
"os"
+ "strconv"
"strings"
"sync"
@@ -17,12 +18,15 @@ import (
// config contains configuration options for a MeterProvider.
type config struct {
- res *resource.Resource
- readers []Reader
- views []View
- exemplarFilter exemplar.Filter
+ res *resource.Resource
+ readers []Reader
+ views []View
+ exemplarFilter exemplar.Filter
+ cardinalityLimit int
}
+const defaultCardinalityLimit = 0
+
// readerSignals returns a force-flush and shutdown function for a
// MeterProvider to call in their respective options. All Readers c contains
// will have their force-flush and shutdown methods unified into returned
@@ -69,8 +73,9 @@ func unifyShutdown(funcs []func(context.Context) error) func(context.Context) er
// newConfig returns a config configured with options.
func newConfig(options []Option) config {
conf := config{
- res: resource.Default(),
- exemplarFilter: exemplar.TraceBasedFilter,
+ res: resource.Default(),
+ exemplarFilter: exemplar.TraceBasedFilter,
+ cardinalityLimit: cardinalityLimitFromEnv(),
}
for _, o := range meterProviderOptionsFromEnv() {
conf = o.apply(conf)
@@ -155,6 +160,21 @@ func WithExemplarFilter(filter exemplar.Filter) Option {
})
}
+// WithCardinalityLimit sets the cardinality limit for the MeterProvider.
+//
+// The cardinality limit is the hard limit on the number of metric datapoints
+// that can be collected for a single instrument in a single collect cycle.
+//
+// Setting this to a zero or negative value means no limit is applied.
+func WithCardinalityLimit(limit int) Option {
+ // For backward compatibility, the environment variable `OTEL_GO_X_CARDINALITY_LIMIT`
+ // can also be used to set this value.
+ return optionFunc(func(cfg config) config {
+ cfg.cardinalityLimit = limit
+ return cfg
+ })
+}
+
func meterProviderOptionsFromEnv() []Option {
var opts []Option
// https://github.com/open-telemetry/opentelemetry-specification/blob/d4b241f451674e8f611bb589477680341006ad2b/specification/configuration/sdk-environment-variables.md#exemplar
@@ -170,3 +190,17 @@ func meterProviderOptionsFromEnv() []Option {
}
return opts
}
+
+func cardinalityLimitFromEnv() int {
+ const cardinalityLimitKey = "OTEL_GO_X_CARDINALITY_LIMIT"
+ v := strings.TrimSpace(os.Getenv(cardinalityLimitKey))
+ if v == "" {
+ return defaultCardinalityLimit
+ }
+ n, err := strconv.Atoi(v)
+ if err != nil {
+ otel.Handle(err)
+ return defaultCardinalityLimit
+ }
+ return n
+}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/doc.go b/vendor/go.opentelemetry.io/otel/sdk/metric/doc.go
index 90a4ae16c..0f3b9d623 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/doc.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/doc.go
@@ -39,6 +39,30 @@
// Meter.RegisterCallback and Registration.Unregister to add and remove
// callbacks without leaking memory.
//
+// # Cardinality Limits
+//
+// Cardinality refers to the number of unique attributes collected. High cardinality can lead to
+// excessive memory usage, increased storage costs, and backend performance issues.
+//
+// Currently, the OpenTelemetry Go Metric SDK does not enforce a cardinality limit by default
+// (note that this may change in a future release). Use [WithCardinalityLimit] to set the
+// cardinality limit as desired.
+//
+// New attribute sets are dropped when the cardinality limit is reached. The measurement of
+// these sets are aggregated into
+// a special attribute set containing attribute.Bool("otel.metric.overflow", true).
+// This ensures total metric values (e.g., Sum, Count) remain correct for the
+// collection cycle, but information about the specific dropped sets
+// is not preserved.
+//
+// Recommendations:
+//
+// - Set the limit based on the theoretical maximum combinations or expected
+// active combinations. The OpenTelemetry Specification recommends a default of 2000.
+// - A too high of a limit increases worst-case memory overhead in the SDK and may cause downstream
+// issues for databases that cannot handle high cardinality.
+// - A too low of a limit causes loss of attribute detail as more data falls into overflow.
+//
// See [go.opentelemetry.io/otel/metric] for more information about
// the metric API.
//
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar.go b/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar.go
index 549d3bd5f..38b8745e6 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar.go
@@ -58,10 +58,7 @@ func DefaultExemplarReservoirProviderSelector(agg Aggregation) exemplar.Reservoi
// SimpleFixedSizeExemplarReservoir with a reservoir equal to the
// smaller of the maximum number of buckets configured on the
// aggregation or twenty (e.g. min(20, max_buckets)).
- n = int(a.MaxSize)
- if n > 20 {
- n = 20
- }
+ n = min(int(a.MaxSize), 20)
} else {
// https://github.com/open-telemetry/opentelemetry-specification/blob/e94af89e3d0c01de30127a0f423e912f6cda7bed/specification/metrics/sdk.md#simplefixedsizeexemplarreservoir
// This Exemplar reservoir MAY take a configuration parameter for
@@ -69,11 +66,11 @@ func DefaultExemplarReservoirProviderSelector(agg Aggregation) exemplar.Reservoi
// provided, the default size MAY be the number of possible
// concurrent threads (e.g. number of CPUs) to help reduce
// contention. Otherwise, a default size of 1 SHOULD be used.
- n = runtime.NumCPU()
- if n < 1 {
- // Should never be the case, but be defensive.
- n = 1
- }
+ //
+ // Use runtime.GOMAXPROCS instead of runtime.NumCPU to support
+ // containerized environments that may have less than the total number
+ // of logical CPUs available on the local machine allocated to it.
+ n = max(runtime.GOMAXPROCS(0), 1)
}
return exemplar.FixedSizeReservoirProvider(n)
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/filter.go b/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/filter.go
index b595e2ace..b50f5c153 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/filter.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/filter.go
@@ -24,11 +24,11 @@ func TraceBasedFilter(ctx context.Context) bool {
}
// AlwaysOnFilter is a [Filter] that always offers measurements.
-func AlwaysOnFilter(ctx context.Context) bool {
+func AlwaysOnFilter(context.Context) bool {
return true
}
// AlwaysOffFilter is a [Filter] that never offers measurements.
-func AlwaysOffFilter(ctx context.Context) bool {
+func AlwaysOffFilter(context.Context) bool {
return false
}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/fixed_size_reservoir.go b/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/fixed_size_reservoir.go
index 1fb1e0095..08e8f68fe 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/fixed_size_reservoir.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/fixed_size_reservoir.go
@@ -14,7 +14,7 @@ import (
// FixedSizeReservoirProvider returns a provider of [FixedSizeReservoir].
func FixedSizeReservoirProvider(k int) ReservoirProvider {
- return func(_ attribute.Set) Reservoir {
+ return func(attribute.Set) Reservoir {
return NewFixedSizeReservoir(k)
}
}
@@ -56,7 +56,7 @@ func newFixedSizeReservoir(s *storage) *FixedSizeReservoir {
// randomFloat64 returns, as a float64, a uniform pseudo-random number in the
// open interval (0.0,1.0).
-func (r *FixedSizeReservoir) randomFloat64() float64 {
+func (*FixedSizeReservoir) randomFloat64() float64 {
// TODO: Use an algorithm that avoids rejection sampling. For example:
//
// const precision = 1 << 53 // 2^53
@@ -125,13 +125,11 @@ func (r *FixedSizeReservoir) Offer(ctx context.Context, t time.Time, n Value, a
if int(r.count) < cap(r.store) {
r.store[r.count] = newMeasurement(ctx, t, n, a)
- } else {
- if r.count == r.next {
- // Overwrite a random existing measurement with the one offered.
- idx := int(rand.Int64N(int64(cap(r.store))))
- r.store[idx] = newMeasurement(ctx, t, n, a)
- r.advance()
- }
+ } else if r.count == r.next {
+ // Overwrite a random existing measurement with the one offered.
+ idx := int(rand.Int64N(int64(cap(r.store))))
+ r.store[idx] = newMeasurement(ctx, t, n, a)
+ r.advance()
}
r.count++
}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/histogram_reservoir.go b/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/histogram_reservoir.go
index 3b76cf305..decab613e 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/histogram_reservoir.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/histogram_reservoir.go
@@ -16,7 +16,7 @@ import (
func HistogramReservoirProvider(bounds []float64) ReservoirProvider {
cp := slices.Clone(bounds)
slices.Sort(cp)
- return func(_ attribute.Set) Reservoir {
+ return func(attribute.Set) Reservoir {
return NewHistogramReservoir(cp)
}
}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go b/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go
index 18891ed5b..63cccc508 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go
@@ -75,7 +75,7 @@ type Instrument struct {
nonComparable // nolint: unused
}
-// IsEmpty returns if all Instrument fields are their zero-value.
+// IsEmpty reports whether all Instrument fields are their zero-value.
func (i Instrument) IsEmpty() bool {
return i.Name == "" &&
i.Description == "" &&
@@ -204,7 +204,7 @@ func (i *int64Inst) Record(ctx context.Context, val int64, opts ...metric.Record
i.aggregate(ctx, val, c.Attributes())
}
-func (i *int64Inst) Enabled(_ context.Context) bool {
+func (i *int64Inst) Enabled(context.Context) bool {
return len(i.measures) != 0
}
@@ -245,7 +245,7 @@ func (i *float64Inst) Record(ctx context.Context, val float64, opts ...metric.Re
i.aggregate(ctx, val, c.Attributes())
}
-func (i *float64Inst) Enabled(_ context.Context) bool {
+func (i *float64Inst) Enabled(context.Context) bool {
return len(i.measures) != 0
}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/drop.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/drop.go
index 8396faaa4..129920cbd 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/drop.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/drop.go
@@ -18,10 +18,10 @@ func dropReservoir[N int64 | float64](attribute.Set) FilteredExemplarReservoir[N
type dropRes[N int64 | float64] struct{}
// Offer does nothing, all measurements offered will be dropped.
-func (r *dropRes[N]) Offer(context.Context, N, []attribute.KeyValue) {}
+func (*dropRes[N]) Offer(context.Context, N, []attribute.KeyValue) {}
// Collect resets dest. No exemplars will ever be returned.
-func (r *dropRes[N]) Collect(dest *[]exemplar.Exemplar) {
+func (*dropRes[N]) Collect(dest *[]exemplar.Exemplar) {
clear(*dest) // Erase elements to let GC collect objects
*dest = (*dest)[:0]
}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/exponential_histogram.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/exponential_histogram.go
index ae1f59344..857eddf30 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/exponential_histogram.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/exponential_histogram.go
@@ -183,8 +183,8 @@ func (p *expoHistogramDataPoint[N]) scaleChange(bin, startBin int32, length int)
var count int32
for high-low >= p.maxSize {
- low = low >> 1
- high = high >> 1
+ low >>= 1
+ high >>= 1
count++
if count > expoMaxScale-expoMinScale {
return count
@@ -225,7 +225,7 @@ func (b *expoBuckets) record(bin int32) {
b.counts = append(b.counts, make([]uint64, newLength-len(b.counts))...)
}
- copy(b.counts[shift:origLen+int(shift)], b.counts[:])
+ copy(b.counts[shift:origLen+int(shift)], b.counts)
b.counts = b.counts[:newLength]
for i := 1; i < int(shift); i++ {
b.counts[i] = 0
@@ -264,7 +264,7 @@ func (b *expoBuckets) downscale(delta int32) {
// new Counts: [4, 14, 30, 10]
if len(b.counts) <= 1 || delta < 1 {
- b.startBin = b.startBin >> delta
+ b.startBin >>= delta
return
}
@@ -282,7 +282,7 @@ func (b *expoBuckets) downscale(delta int32) {
lastIdx := (len(b.counts) - 1 + int(offset)) / int(steps)
b.counts = b.counts[:lastIdx+1]
- b.startBin = b.startBin >> delta
+ b.startBin >>= delta
}
// newExponentialHistogram returns an Aggregator that summarizes a set of
@@ -350,7 +350,9 @@ func (e *expoHistogram[N]) measure(
v.res.Offer(ctx, value, droppedAttr)
}
-func (e *expoHistogram[N]) delta(dest *metricdata.Aggregation) int {
+func (e *expoHistogram[N]) delta(
+ dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
+) int {
t := now()
// If *dest is not a metricdata.ExponentialHistogram, memory reuse is missed.
@@ -411,7 +413,9 @@ func (e *expoHistogram[N]) delta(dest *metricdata.Aggregation) int {
return n
}
-func (e *expoHistogram[N]) cumulative(dest *metricdata.Aggregation) int {
+func (e *expoHistogram[N]) cumulative(
+ dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
+) int {
t := now()
// If *dest is not a metricdata.ExponentialHistogram, memory reuse is missed.
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go
index d3068484c..736287e73 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go
@@ -140,7 +140,9 @@ type histogram[N int64 | float64] struct {
start time.Time
}
-func (s *histogram[N]) delta(dest *metricdata.Aggregation) int {
+func (s *histogram[N]) delta(
+ dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
+) int {
t := now()
// If *dest is not a metricdata.Histogram, memory reuse is missed. In that
@@ -190,7 +192,9 @@ func (s *histogram[N]) delta(dest *metricdata.Aggregation) int {
return n
}
-func (s *histogram[N]) cumulative(dest *metricdata.Aggregation) int {
+func (s *histogram[N]) cumulative(
+ dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
+) int {
t := now()
// If *dest is not a metricdata.Histogram, memory reuse is missed. In that
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go
index 350ccebdc..4bbe624c7 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go
@@ -55,7 +55,9 @@ func (s *lastValue[N]) measure(ctx context.Context, value N, fltrAttr attribute.
s.values[attr.Equivalent()] = d
}
-func (s *lastValue[N]) delta(dest *metricdata.Aggregation) int {
+func (s *lastValue[N]) delta(
+ dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
+) int {
t := now()
// Ignore if dest is not a metricdata.Gauge. The chance for memory reuse of
// the DataPoints is missed (better luck next time).
@@ -75,7 +77,9 @@ func (s *lastValue[N]) delta(dest *metricdata.Aggregation) int {
return n
}
-func (s *lastValue[N]) cumulative(dest *metricdata.Aggregation) int {
+func (s *lastValue[N]) cumulative(
+ dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
+) int {
t := now()
// Ignore if dest is not a metricdata.Gauge. The chance for memory reuse of
// the DataPoints is missed (better luck next time).
@@ -126,7 +130,9 @@ type precomputedLastValue[N int64 | float64] struct {
*lastValue[N]
}
-func (s *precomputedLastValue[N]) delta(dest *metricdata.Aggregation) int {
+func (s *precomputedLastValue[N]) delta(
+ dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
+) int {
t := now()
// Ignore if dest is not a metricdata.Gauge. The chance for memory reuse of
// the DataPoints is missed (better luck next time).
@@ -146,7 +152,9 @@ func (s *precomputedLastValue[N]) delta(dest *metricdata.Aggregation) int {
return n
}
-func (s *precomputedLastValue[N]) cumulative(dest *metricdata.Aggregation) int {
+func (s *precomputedLastValue[N]) cumulative(
+ dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
+) int {
t := now()
// Ignore if dest is not a metricdata.Gauge. The chance for memory reuse of
// the DataPoints is missed (better luck next time).
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go
index 612cde432..1b4b2304c 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go
@@ -70,7 +70,9 @@ type sum[N int64 | float64] struct {
start time.Time
}
-func (s *sum[N]) delta(dest *metricdata.Aggregation) int {
+func (s *sum[N]) delta(
+ dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
+) int {
t := now()
// If *dest is not a metricdata.Sum, memory reuse is missed. In that case,
@@ -105,7 +107,9 @@ func (s *sum[N]) delta(dest *metricdata.Aggregation) int {
return n
}
-func (s *sum[N]) cumulative(dest *metricdata.Aggregation) int {
+func (s *sum[N]) cumulative(
+ dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
+) int {
t := now()
// If *dest is not a metricdata.Sum, memory reuse is missed. In that case,
@@ -165,7 +169,9 @@ type precomputedSum[N int64 | float64] struct {
reported map[attribute.Distinct]N
}
-func (s *precomputedSum[N]) delta(dest *metricdata.Aggregation) int {
+func (s *precomputedSum[N]) delta(
+ dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
+) int {
t := now()
newReported := make(map[attribute.Distinct]N)
@@ -206,7 +212,9 @@ func (s *precomputedSum[N]) delta(dest *metricdata.Aggregation) int {
return n
}
-func (s *precomputedSum[N]) cumulative(dest *metricdata.Aggregation) int {
+func (s *precomputedSum[N]) cumulative(
+ dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
+) int {
t := now()
// If *dest is not a metricdata.Sum, memory reuse is missed. In that case,
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/README.md b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/README.md
index 59f736b73..be0714a5f 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/README.md
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/README.md
@@ -1,47 +1,16 @@
# Experimental Features
-The metric SDK contains features that have not yet stabilized in the OpenTelemetry specification.
-These features are added to the OpenTelemetry Go metric SDK prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
+The Metric SDK contains features that have not yet stabilized in the OpenTelemetry specification.
+These features are added to the OpenTelemetry Go Metric 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
-- [Cardinality Limit](#cardinality-limit)
- [Exemplars](#exemplars)
- [Instrument Enabled](#instrument-enabled)
-### Cardinality Limit
-
-The cardinality limit is the hard limit on the number of metric streams that can be collected for a single instrument.
-
-This experimental feature can be enabled by setting the `OTEL_GO_X_CARDINALITY_LIMIT` environment value.
-The value must be an integer value.
-All other values are ignored.
-
-If the value set is less than or equal to `0`, no limit will be applied.
-
-#### Examples
-
-Set the cardinality limit to 2000.
-
-```console
-export OTEL_GO_X_CARDINALITY_LIMIT=2000
-```
-
-Set an infinite cardinality limit (functionally equivalent to disabling the feature).
-
-```console
-export OTEL_GO_X_CARDINALITY_LIMIT=-1
-```
-
-Disable the cardinality limit.
-
-```console
-unset OTEL_GO_X_CARDINALITY_LIMIT
-```
-
### Exemplars
A sample of measurements made may be exported directly as a set of exemplars.
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/x.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/x.go
index a98606238..294dcf846 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/x.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/x.go
@@ -10,25 +10,8 @@ package x // import "go.opentelemetry.io/otel/sdk/metric/internal/x"
import (
"context"
"os"
- "strconv"
)
-// CardinalityLimit is an experimental feature flag that defines if
-// cardinality limits should be applied to the recorded metric data-points.
-//
-// To enable this feature set the OTEL_GO_X_CARDINALITY_LIMIT environment
-// variable to the integer limit value you want to use.
-//
-// Setting OTEL_GO_X_CARDINALITY_LIMIT to a value less than or equal to 0
-// will disable the cardinality limits.
-var CardinalityLimit = newFeature("CARDINALITY_LIMIT", func(v string) (int, bool) {
- n, err := strconv.Atoi(v)
- if err != nil {
- return 0, false
- }
- return n, true
-})
-
// 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 {
@@ -36,6 +19,7 @@ type Feature[T any] struct {
parse func(v string) (T, bool)
}
+//nolint:unused
func newFeature[T any](suffix string, parse func(string) (T, bool)) Feature[T] {
const envKeyRoot = "OTEL_GO_X_"
return Feature[T]{
@@ -63,7 +47,7 @@ func (f Feature[T]) Lookup() (v T, ok bool) {
return f.parse(vRaw)
}
-// Enabled returns if the feature is enabled.
+// Enabled reports whether the feature is enabled.
func (f Feature[T]) Enabled() bool {
_, ok := f.Lookup()
return ok
@@ -73,7 +57,7 @@ func (f Feature[T]) Enabled() bool {
//
// EnabledInstrument interface is implemented by synchronous instruments.
type EnabledInstrument interface {
- // Enabled returns whether the instrument will process measurements for the given context.
+ // Enabled reports whether the instrument will process measurements for the given context.
//
// This function can be used in places where measuring an instrument
// would result in computationally expensive operations.
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/manual_reader.go b/vendor/go.opentelemetry.io/otel/sdk/metric/manual_reader.go
index 96e779086..85d3dc207 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/manual_reader.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/manual_reader.go
@@ -129,7 +129,7 @@ func (mr *ManualReader) Collect(ctx context.Context, rm *metricdata.ResourceMetr
}
// MarshalLog returns logging data about the ManualReader.
-func (r *ManualReader) MarshalLog() interface{} {
+func (r *ManualReader) MarshalLog() any {
r.mu.Lock()
down := r.isShutdown
r.mu.Unlock()
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/meter.go b/vendor/go.opentelemetry.io/otel/sdk/metric/meter.go
index c500fd9f2..e0a1e90e7 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/meter.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/meter.go
@@ -12,7 +12,6 @@ import (
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/embedded"
"go.opentelemetry.io/otel/sdk/instrumentation"
-
"go.opentelemetry.io/otel/sdk/metric/internal/aggregate"
)
@@ -423,7 +422,7 @@ func (m *meter) Float64ObservableGauge(
}
func validateInstrumentName(name string) error {
- if len(name) == 0 {
+ if name == "" {
return fmt.Errorf("%w: %s: is empty", ErrInstrumentName, name)
}
if len(name) > 255 {
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go b/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go
index 0a48aed74..f08c771a6 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go
@@ -114,7 +114,7 @@ func NewPeriodicReader(exporter Exporter, options ...PeriodicReaderOption) *Peri
cancel: cancel,
done: make(chan struct{}),
rmPool: sync.Pool{
- New: func() interface{} {
+ New: func() any {
return &metricdata.ResourceMetrics{}
},
},
@@ -234,7 +234,7 @@ func (r *PeriodicReader) Collect(ctx context.Context, rm *metricdata.ResourceMet
}
// collect unwraps p as a produceHolder and returns its produce results.
-func (r *PeriodicReader) collect(ctx context.Context, p interface{}, rm *metricdata.ResourceMetrics) error {
+func (r *PeriodicReader) collect(ctx context.Context, p any, rm *metricdata.ResourceMetrics) error {
if p == nil {
return ErrReaderNotRegistered
}
@@ -349,7 +349,7 @@ func (r *PeriodicReader) Shutdown(ctx context.Context) error {
}
// MarshalLog returns logging data about the PeriodicReader.
-func (r *PeriodicReader) MarshalLog() interface{} {
+func (r *PeriodicReader) MarshalLog() any {
r.mu.Lock()
down := r.isShutdown
r.mu.Unlock()
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go b/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go
index 7bdb699ca..408fddc8d 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go
@@ -17,7 +17,6 @@ import (
"go.opentelemetry.io/otel/sdk/metric/exemplar"
"go.opentelemetry.io/otel/sdk/metric/internal"
"go.opentelemetry.io/otel/sdk/metric/internal/aggregate"
- "go.opentelemetry.io/otel/sdk/metric/internal/x"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
"go.opentelemetry.io/otel/sdk/resource"
)
@@ -37,17 +36,24 @@ type instrumentSync struct {
compAgg aggregate.ComputeAggregation
}
-func newPipeline(res *resource.Resource, reader Reader, views []View, exemplarFilter exemplar.Filter) *pipeline {
+func newPipeline(
+ res *resource.Resource,
+ reader Reader,
+ views []View,
+ exemplarFilter exemplar.Filter,
+ cardinalityLimit int,
+) *pipeline {
if res == nil {
res = resource.Empty()
}
return &pipeline{
- resource: res,
- reader: reader,
- views: views,
- int64Measures: map[observableID[int64]][]aggregate.Measure[int64]{},
- float64Measures: map[observableID[float64]][]aggregate.Measure[float64]{},
- exemplarFilter: exemplarFilter,
+ resource: res,
+ reader: reader,
+ views: views,
+ int64Measures: map[observableID[int64]][]aggregate.Measure[int64]{},
+ float64Measures: map[observableID[float64]][]aggregate.Measure[float64]{},
+ exemplarFilter: exemplarFilter,
+ cardinalityLimit: cardinalityLimit,
// aggregations is lazy allocated when needed.
}
}
@@ -65,12 +71,13 @@ type pipeline struct {
views []View
sync.Mutex
- int64Measures map[observableID[int64]][]aggregate.Measure[int64]
- float64Measures map[observableID[float64]][]aggregate.Measure[float64]
- aggregations map[instrumentation.Scope][]instrumentSync
- callbacks []func(context.Context) error
- multiCallbacks list.List
- exemplarFilter exemplar.Filter
+ int64Measures map[observableID[int64]][]aggregate.Measure[int64]
+ float64Measures map[observableID[float64]][]aggregate.Measure[float64]
+ aggregations map[instrumentation.Scope][]instrumentSync
+ callbacks []func(context.Context) error
+ multiCallbacks list.List
+ exemplarFilter exemplar.Filter
+ cardinalityLimit int
}
// addInt64Measure adds a new int64 measure to the pipeline for each observer.
@@ -388,10 +395,9 @@ func (i *inserter[N]) cachedAggregator(
b.Filter = stream.AttributeFilter
// A value less than or equal to zero will disable the aggregation
// limits for the builder (an all the created aggregates).
- // CardinalityLimit.Lookup returns 0 by default if unset (or
+ // cardinalityLimit will be 0 by default if unset (or
// unrecognized input). Use that value directly.
- b.AggregationLimit, _ = x.CardinalityLimit.Lookup()
-
+ b.AggregationLimit = i.pipeline.cardinalityLimit
in, out, err := i.aggregateFunc(b, stream.Aggregation, kind)
if err != nil {
return aggVal[N]{0, nil, err}
@@ -426,7 +432,7 @@ func (i *inserter[N]) logConflict(id instID) {
}
const msg = "duplicate metric stream definitions"
- args := []interface{}{
+ args := []any{
"names", fmt.Sprintf("%q, %q", existing.Name, id.Name),
"descriptions", fmt.Sprintf("%q, %q", existing.Description, id.Description),
"kinds", fmt.Sprintf("%s, %s", existing.Kind, id.Kind),
@@ -460,7 +466,7 @@ func (i *inserter[N]) logConflict(id instID) {
global.Warn(msg, args...)
}
-func (i *inserter[N]) instID(kind InstrumentKind, stream Stream) instID {
+func (*inserter[N]) instID(kind InstrumentKind, stream Stream) instID {
var zero N
return instID{
Name: stream.Name,
@@ -590,10 +596,16 @@ func isAggregatorCompatible(kind InstrumentKind, agg Aggregation) error {
// measurement.
type pipelines []*pipeline
-func newPipelines(res *resource.Resource, readers []Reader, views []View, exemplarFilter exemplar.Filter) pipelines {
+func newPipelines(
+ res *resource.Resource,
+ readers []Reader,
+ views []View,
+ exemplarFilter exemplar.Filter,
+ cardinalityLimit int,
+) pipelines {
pipes := make([]*pipeline, 0, len(readers))
for _, r := range readers {
- p := newPipeline(res, r, views, exemplarFilter)
+ p := newPipeline(res, r, views, exemplarFilter, cardinalityLimit)
r.register(p)
pipes = append(pipes, p)
}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go b/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go
index 2fca89e5a..b0a6ec580 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go
@@ -42,7 +42,7 @@ func NewMeterProvider(options ...Option) *MeterProvider {
flush, sdown := conf.readerSignals()
mp := &MeterProvider{
- pipes: newPipelines(conf.res, conf.readers, conf.views, conf.exemplarFilter),
+ pipes: newPipelines(conf.res, conf.readers, conf.views, conf.exemplarFilter, conf.cardinalityLimit),
forceFlush: flush,
shutdown: sdown,
}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/reader.go b/vendor/go.opentelemetry.io/otel/sdk/metric/reader.go
index c96e500a2..5c1cea825 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/reader.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/reader.go
@@ -117,7 +117,7 @@ type produceHolder struct {
type shutdownProducer struct{}
// produce returns an ErrReaderShutdown error.
-func (p shutdownProducer) produce(context.Context, *metricdata.ResourceMetrics) error {
+func (shutdownProducer) produce(context.Context, *metricdata.ResourceMetrics) error {
return ErrReaderShutdown
}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/version.go b/vendor/go.opentelemetry.io/otel/sdk/metric/version.go
index 0e5adc1a7..dd9051a76 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/metric/version.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/metric/version.go
@@ -5,5 +5,5 @@ package metric // import "go.opentelemetry.io/otel/sdk/metric"
// version is the current release version of the metric SDK in use.
func version() string {
- return "1.37.0"
+ return "1.38.0"
}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go b/vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go
index cefe4ab91..3f20eb7a5 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go
@@ -13,7 +13,7 @@ import (
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk"
- semconv "go.opentelemetry.io/otel/semconv/v1.34.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
)
type (
@@ -72,7 +72,7 @@ func StringDetector(schemaURL string, k attribute.Key, f func() (string, error))
// 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) {
+func (sd stringDetector) Detect(context.Context) (*Resource, error) {
value, err := sd.F()
if err != nil {
return nil, fmt.Errorf("%s: %w", string(sd.K), err)
diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/container.go b/vendor/go.opentelemetry.io/otel/sdk/resource/container.go
index 0d8619715..bbe142d20 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/resource/container.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/resource/container.go
@@ -11,7 +11,7 @@ import (
"os"
"regexp"
- semconv "go.opentelemetry.io/otel/semconv/v1.34.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
)
type containerIDProvider func() (string, error)
@@ -27,7 +27,7 @@ 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) {
+func (cgroupContainerIDDetector) Detect(context.Context) (*Resource, error) {
containerID, err := containerID()
if err != nil {
return nil, err
diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/env.go b/vendor/go.opentelemetry.io/otel/sdk/resource/env.go
index 16a062ad8..4a1b017ee 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/resource/env.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/resource/env.go
@@ -12,7 +12,7 @@ import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
- semconv "go.opentelemetry.io/otel/semconv/v1.34.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
)
const (
diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go
index 781903923..5fed33d4f 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go
@@ -8,7 +8,7 @@ import (
"errors"
"strings"
- semconv "go.opentelemetry.io/otel/semconv/v1.34.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
)
type hostIDProvider func() (string, error)
@@ -96,7 +96,7 @@ func (r *hostIDReaderLinux) read() (string, error) {
type hostIDDetector struct{}
// Detect returns a *Resource containing the platform specific host id.
-func (hostIDDetector) Detect(ctx context.Context) (*Resource, error) {
+func (hostIDDetector) Detect(context.Context) (*Resource, error) {
hostID, err := hostID()
if err != nil {
return nil, err
diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/os.go b/vendor/go.opentelemetry.io/otel/sdk/resource/os.go
index 01b4d27a0..51da76e80 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/resource/os.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/resource/os.go
@@ -8,7 +8,7 @@ import (
"strings"
"go.opentelemetry.io/otel/attribute"
- semconv "go.opentelemetry.io/otel/semconv/v1.34.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
)
type osDescriptionProvider func() (string, error)
@@ -32,7 +32,7 @@ type (
// Detect returns a *Resource that describes the operating system type the
// service is running on.
-func (osTypeDetector) Detect(ctx context.Context) (*Resource, error) {
+func (osTypeDetector) Detect(context.Context) (*Resource, error) {
osType := runtimeOS()
osTypeAttribute := mapRuntimeOSToSemconvOSType(osType)
@@ -45,7 +45,7 @@ func (osTypeDetector) Detect(ctx context.Context) (*Resource, error) {
// Detect returns a *Resource that describes the operating system the
// service is running on.
-func (osDescriptionDetector) Detect(ctx context.Context) (*Resource, error) {
+func (osDescriptionDetector) Detect(context.Context) (*Resource, error) {
description, err := osDescription()
if err != nil {
return nil, err
diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_unix.go b/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_unix.go
index f537e5ca5..7252af79f 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_unix.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/resource/os_release_unix.go
@@ -63,12 +63,12 @@ func parseOSReleaseFile(file io.Reader) map[string]string {
return values
}
-// skip returns true if the line is blank or starts with a '#' character, and
+// skip reports whether 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, "#")
+ return line == "" || strings.HasPrefix(line, "#")
}
// parse attempts to split the provided line on the first '=' character, and then
@@ -76,7 +76,7 @@ func skip(line string) bool {
func parse(line string) (string, string, bool) {
k, v, found := strings.Cut(line, "=")
- if !found || len(k) == 0 {
+ if !found || k == "" {
return "", "", false
}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/process.go b/vendor/go.opentelemetry.io/otel/sdk/resource/process.go
index 6712ce80d..138e57721 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/resource/process.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/resource/process.go
@@ -11,7 +11,7 @@ import (
"path/filepath"
"runtime"
- semconv "go.opentelemetry.io/otel/semconv/v1.34.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
)
type (
@@ -112,19 +112,19 @@ type (
// Detect returns a *Resource that describes the process identifier (PID) of the
// executing process.
-func (processPIDDetector) Detect(ctx context.Context) (*Resource, error) {
+func (processPIDDetector) Detect(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) {
+func (processExecutableNameDetector) Detect(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) {
+func (processExecutablePathDetector) Detect(context.Context) (*Resource, error) {
executablePath, err := executablePath()
if err != nil {
return nil, err
@@ -135,13 +135,13 @@ func (processExecutablePathDetector) Detect(ctx context.Context) (*Resource, err
// Detect returns a *Resource that describes all the command arguments as received
// by the process.
-func (processCommandArgsDetector) Detect(ctx context.Context) (*Resource, error) {
+func (processCommandArgsDetector) Detect(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) {
+func (processOwnerDetector) Detect(context.Context) (*Resource, error) {
owner, err := owner()
if err != nil {
return nil, err
@@ -152,17 +152,17 @@ func (processOwnerDetector) Detect(ctx context.Context) (*Resource, error) {
// 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) {
+func (processRuntimeNameDetector) Detect(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) {
+func (processRuntimeVersionDetector) Detect(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) {
+func (processRuntimeDescriptionDetector) Detect(context.Context) (*Resource, error) {
runtimeDescription := fmt.Sprintf(
"go version %s %s/%s", runtimeVersion(), runtimeOS(), runtimeArch())
diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go b/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go
index 09b91e1e1..28e1e4f7e 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go
@@ -112,7 +112,7 @@ func (r *Resource) String() string {
}
// MarshalLog is the marshaling function used by the logging system to represent this Resource.
-func (r *Resource) MarshalLog() interface{} {
+func (r *Resource) MarshalLog() any {
return struct {
Attributes attribute.Set
SchemaURL string
@@ -148,7 +148,7 @@ func (r *Resource) Iter() attribute.Iterator {
return r.attrs.Iter()
}
-// Equal returns whether r and o represent the same resource. Two resources can
+// Equal reports whether r and o represent the same resource. Two resources can
// be equal even if they have different schema URLs.
//
// See the documentation on the [Resource] type for the pitfalls of using ==
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go b/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go
index 6966ed861..9bc3e525d 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go
@@ -6,24 +6,35 @@ package trace // import "go.opentelemetry.io/otel/sdk/trace"
import (
"context"
"errors"
+ "fmt"
"sync"
"sync/atomic"
"time"
"go.opentelemetry.io/otel"
+ "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/internal/global"
+ "go.opentelemetry.io/otel/metric"
+ "go.opentelemetry.io/otel/sdk"
"go.opentelemetry.io/otel/sdk/internal/env"
+ "go.opentelemetry.io/otel/sdk/trace/internal/x"
+ semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
+ "go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
"go.opentelemetry.io/otel/trace"
)
// Defaults for BatchSpanProcessorOptions.
const (
- DefaultMaxQueueSize = 2048
- DefaultScheduleDelay = 5000
+ DefaultMaxQueueSize = 2048
+ // DefaultScheduleDelay is the delay interval between two consecutive exports, in milliseconds.
+ DefaultScheduleDelay = 5000
+ // DefaultExportTimeout is the duration after which an export is cancelled, in milliseconds.
DefaultExportTimeout = 30000
DefaultMaxExportBatchSize = 512
)
+var queueFull = otelconv.ErrorTypeAttr("queue_full")
+
// BatchSpanProcessorOption configures a BatchSpanProcessor.
type BatchSpanProcessorOption func(o *BatchSpanProcessorOptions)
@@ -67,6 +78,11 @@ type batchSpanProcessor struct {
queue chan ReadOnlySpan
dropped uint32
+ selfObservabilityEnabled bool
+ callbackRegistration metric.Registration
+ spansProcessedCounter otelconv.SDKProcessorSpanProcessed
+ componentNameAttr attribute.KeyValue
+
batch []ReadOnlySpan
batchMutex sync.Mutex
timer *time.Timer
@@ -87,11 +103,7 @@ func NewBatchSpanProcessor(exporter SpanExporter, options ...BatchSpanProcessorO
maxExportBatchSize := env.BatchSpanProcessorMaxExportBatchSize(DefaultMaxExportBatchSize)
if maxExportBatchSize > maxQueueSize {
- if DefaultMaxExportBatchSize > maxQueueSize {
- maxExportBatchSize = maxQueueSize
- } else {
- maxExportBatchSize = DefaultMaxExportBatchSize
- }
+ maxExportBatchSize = min(DefaultMaxExportBatchSize, maxQueueSize)
}
o := BatchSpanProcessorOptions{
@@ -112,6 +124,21 @@ func NewBatchSpanProcessor(exporter SpanExporter, options ...BatchSpanProcessorO
stopCh: make(chan struct{}),
}
+ if x.SelfObservability.Enabled() {
+ bsp.selfObservabilityEnabled = true
+ bsp.componentNameAttr = componentName()
+
+ var err error
+ bsp.spansProcessedCounter, bsp.callbackRegistration, err = newBSPObs(
+ bsp.componentNameAttr,
+ func() int64 { return int64(len(bsp.queue)) },
+ int64(bsp.o.MaxQueueSize),
+ )
+ if err != nil {
+ otel.Handle(err)
+ }
+ }
+
bsp.stopWait.Add(1)
go func() {
defer bsp.stopWait.Done()
@@ -122,8 +149,61 @@ func NewBatchSpanProcessor(exporter SpanExporter, options ...BatchSpanProcessorO
return bsp
}
+var processorIDCounter atomic.Int64
+
+// nextProcessorID returns an identifier for this batch span processor,
+// starting with 0 and incrementing by 1 each time it is called.
+func nextProcessorID() int64 {
+ return processorIDCounter.Add(1) - 1
+}
+
+func componentName() attribute.KeyValue {
+ id := nextProcessorID()
+ name := fmt.Sprintf("%s/%d", otelconv.ComponentTypeBatchingSpanProcessor, id)
+ return semconv.OTelComponentName(name)
+}
+
+// newBSPObs creates and returns a new set of metrics instruments and a
+// registration for a BatchSpanProcessor. It is the caller's responsibility
+// to unregister the registration when it is no longer needed.
+func newBSPObs(
+ cmpnt attribute.KeyValue,
+ qLen func() int64,
+ qMax int64,
+) (otelconv.SDKProcessorSpanProcessed, metric.Registration, error) {
+ meter := otel.GetMeterProvider().Meter(
+ selfObsScopeName,
+ metric.WithInstrumentationVersion(sdk.Version()),
+ metric.WithSchemaURL(semconv.SchemaURL),
+ )
+
+ qCap, err := otelconv.NewSDKProcessorSpanQueueCapacity(meter)
+
+ qSize, e := otelconv.NewSDKProcessorSpanQueueSize(meter)
+ err = errors.Join(err, e)
+
+ spansProcessed, e := otelconv.NewSDKProcessorSpanProcessed(meter)
+ err = errors.Join(err, e)
+
+ cmpntT := semconv.OTelComponentTypeBatchingSpanProcessor
+ attrs := metric.WithAttributes(cmpnt, cmpntT)
+
+ reg, e := meter.RegisterCallback(
+ func(_ context.Context, o metric.Observer) error {
+ o.ObserveInt64(qSize.Inst(), qLen(), attrs)
+ o.ObserveInt64(qCap.Inst(), qMax, attrs)
+ return nil
+ },
+ qSize.Inst(),
+ qCap.Inst(),
+ )
+ err = errors.Join(err, e)
+
+ return spansProcessed, reg, err
+}
+
// OnStart method does nothing.
-func (bsp *batchSpanProcessor) OnStart(parent context.Context, s ReadWriteSpan) {}
+func (*batchSpanProcessor) OnStart(context.Context, ReadWriteSpan) {}
// OnEnd method enqueues a ReadOnlySpan for later processing.
func (bsp *batchSpanProcessor) OnEnd(s ReadOnlySpan) {
@@ -162,6 +242,9 @@ func (bsp *batchSpanProcessor) Shutdown(ctx context.Context) error {
case <-ctx.Done():
err = ctx.Err()
}
+ if bsp.selfObservabilityEnabled {
+ err = errors.Join(err, bsp.callbackRegistration.Unregister())
+ }
})
return err
}
@@ -171,7 +254,7 @@ type forceFlushSpan struct {
flushed chan struct{}
}
-func (f forceFlushSpan) SpanContext() trace.SpanContext {
+func (forceFlushSpan) SpanContext() trace.SpanContext {
return trace.NewSpanContext(trace.SpanContextConfig{TraceFlags: trace.FlagsSampled})
}
@@ -274,6 +357,11 @@ func (bsp *batchSpanProcessor) exportSpans(ctx context.Context) error {
if l := len(bsp.batch); l > 0 {
global.Debug("exporting spans", "count", len(bsp.batch), "total_dropped", atomic.LoadUint32(&bsp.dropped))
+ if bsp.selfObservabilityEnabled {
+ bsp.spansProcessedCounter.Add(ctx, int64(l),
+ bsp.componentNameAttr,
+ bsp.spansProcessedCounter.AttrComponentType(otelconv.ComponentTypeBatchingSpanProcessor))
+ }
err := bsp.e.ExportSpans(ctx, bsp.batch)
// A new batch is always created after exporting, even if the batch failed to be exported.
@@ -382,11 +470,17 @@ func (bsp *batchSpanProcessor) enqueueBlockOnQueueFull(ctx context.Context, sd R
case bsp.queue <- sd:
return true
case <-ctx.Done():
+ if bsp.selfObservabilityEnabled {
+ bsp.spansProcessedCounter.Add(ctx, 1,
+ bsp.componentNameAttr,
+ bsp.spansProcessedCounter.AttrComponentType(otelconv.ComponentTypeBatchingSpanProcessor),
+ bsp.spansProcessedCounter.AttrErrorType(queueFull))
+ }
return false
}
}
-func (bsp *batchSpanProcessor) enqueueDrop(_ context.Context, sd ReadOnlySpan) bool {
+func (bsp *batchSpanProcessor) enqueueDrop(ctx context.Context, sd ReadOnlySpan) bool {
if !sd.SpanContext().IsSampled() {
return false
}
@@ -396,12 +490,18 @@ func (bsp *batchSpanProcessor) enqueueDrop(_ context.Context, sd ReadOnlySpan) b
return true
default:
atomic.AddUint32(&bsp.dropped, 1)
+ if bsp.selfObservabilityEnabled {
+ bsp.spansProcessedCounter.Add(ctx, 1,
+ bsp.componentNameAttr,
+ bsp.spansProcessedCounter.AttrComponentType(otelconv.ComponentTypeBatchingSpanProcessor),
+ bsp.spansProcessedCounter.AttrErrorType(queueFull))
+ }
}
return false
}
// MarshalLog is the marshaling function used by the logging system to represent this Span Processor.
-func (bsp *batchSpanProcessor) MarshalLog() interface{} {
+func (bsp *batchSpanProcessor) MarshalLog() any {
return struct {
Type string
SpanExporter SpanExporter
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/doc.go b/vendor/go.opentelemetry.io/otel/sdk/trace/doc.go
index 1f60524e3..e58e7f6ed 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/trace/doc.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/doc.go
@@ -6,5 +6,8 @@ Package trace contains support for OpenTelemetry distributed tracing.
The following assumes a basic familiarity with OpenTelemetry concepts.
See https://opentelemetry.io.
+
+See [go.opentelemetry.io/otel/sdk/trace/internal/x] for information about
+the experimental features.
*/
package trace // import "go.opentelemetry.io/otel/sdk/trace"
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/id_generator.go b/vendor/go.opentelemetry.io/otel/sdk/trace/id_generator.go
index c8d3fb7e3..3649322a6 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/trace/id_generator.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/id_generator.go
@@ -32,7 +32,7 @@ type randomIDGenerator struct{}
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 {
+func (*randomIDGenerator) NewSpanID(context.Context, trace.TraceID) trace.SpanID {
sid := trace.SpanID{}
for {
binary.NativeEndian.PutUint64(sid[:], rand.Uint64())
@@ -45,7 +45,7 @@ func (gen *randomIDGenerator) NewSpanID(ctx context.Context, traceID trace.Trace
// 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) {
+func (*randomIDGenerator) NewIDs(context.Context) (trace.TraceID, trace.SpanID) {
tid := trace.TraceID{}
sid := trace.SpanID{}
for {
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/internal/x/README.md b/vendor/go.opentelemetry.io/otel/sdk/trace/internal/x/README.md
new file mode 100644
index 000000000..feec16fa6
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/internal/x/README.md
@@ -0,0 +1,35 @@
+# Experimental Features
+
+The Trace SDK contains features that have not yet stabilized in the OpenTelemetry specification.
+These features are added to the OpenTelemetry Go Trace SDK prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
+
+These features may change in backwards incompatible ways as feedback is applied.
+See the [Compatibility and Stability](#compatibility-and-stability) section for more information.
+
+## Features
+
+- [Self-Observability](#self-observability)
+
+### Self-Observability
+
+The SDK provides a self-observability feature that allows you to monitor the SDK itself.
+
+To opt-in, set the environment variable `OTEL_GO_X_SELF_OBSERVABILITY` to `true`.
+
+When enabled, the SDK will create the following metrics using the global `MeterProvider`:
+
+- `otel.sdk.span.live`
+- `otel.sdk.span.started`
+
+Please see the [Semantic conventions for OpenTelemetry SDK metrics] documentation for more details on these metrics.
+
+[Semantic conventions for OpenTelemetry SDK metrics]: https://github.com/open-telemetry/semantic-conventions/blob/v1.36.0/docs/otel/sdk-metrics.md
+
+## 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.
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/internal/x/x.go b/vendor/go.opentelemetry.io/otel/sdk/trace/internal/x/x.go
new file mode 100644
index 000000000..2fcbbcc66
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/internal/x/x.go
@@ -0,0 +1,63 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+// Package x documents experimental features for [go.opentelemetry.io/otel/sdk/trace].
+package x // import "go.opentelemetry.io/otel/sdk/trace/internal/x"
+
+import (
+ "os"
+ "strings"
+)
+
+// SelfObservability is an experimental feature flag that determines if SDK
+// self-observability metrics are enabled.
+//
+// To enable this feature set the OTEL_GO_X_SELF_OBSERVABILITY environment variable
+// to the case-insensitive string value of "true" (i.e. "True" and "TRUE"
+// will also enable this).
+var SelfObservability = newFeature("SELF_OBSERVABILITY", func(v string) (string, bool) {
+ if strings.EqualFold(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 reports whether the feature is enabled.
+func (f Feature[T]) Enabled() bool {
+ _, ok := f.Lookup()
+ return ok
+}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go b/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go
index 0e2a2e7c6..37ce2ac87 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go
@@ -5,14 +5,20 @@ package trace // import "go.opentelemetry.io/otel/sdk/trace"
import (
"context"
+ "errors"
"fmt"
"sync"
"sync/atomic"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/internal/global"
+ "go.opentelemetry.io/otel/metric"
+ "go.opentelemetry.io/otel/sdk"
"go.opentelemetry.io/otel/sdk/instrumentation"
"go.opentelemetry.io/otel/sdk/resource"
+ "go.opentelemetry.io/otel/sdk/trace/internal/x"
+ semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
+ "go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/embedded"
"go.opentelemetry.io/otel/trace/noop"
@@ -20,6 +26,7 @@ import (
const (
defaultTracerName = "go.opentelemetry.io/otel/sdk/tracer"
+ selfObsScopeName = "go.opentelemetry.io/otel/sdk/trace"
)
// tracerProviderConfig.
@@ -45,7 +52,7 @@ type tracerProviderConfig struct {
}
// MarshalLog is the marshaling function used by the logging system to represent this Provider.
-func (cfg tracerProviderConfig) MarshalLog() interface{} {
+func (cfg tracerProviderConfig) MarshalLog() any {
return struct {
SpanProcessors []SpanProcessor
SamplerType string
@@ -156,8 +163,18 @@ func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T
t, ok := p.namedTracer[is]
if !ok {
t = &tracer{
- provider: p,
- instrumentationScope: is,
+ provider: p,
+ instrumentationScope: is,
+ selfObservabilityEnabled: x.SelfObservability.Enabled(),
+ }
+ if t.selfObservabilityEnabled {
+ var err error
+ t.spanLiveMetric, t.spanStartedMetric, err = newInst()
+ if err != nil {
+ msg := "failed to create self-observability metrics for tracer: %w"
+ err := fmt.Errorf(msg, err)
+ otel.Handle(err)
+ }
}
p.namedTracer[is] = t
}
@@ -184,6 +201,23 @@ func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T
return t
}
+func newInst() (otelconv.SDKSpanLive, otelconv.SDKSpanStarted, error) {
+ m := otel.GetMeterProvider().Meter(
+ selfObsScopeName,
+ metric.WithInstrumentationVersion(sdk.Version()),
+ metric.WithSchemaURL(semconv.SchemaURL),
+ )
+
+ var err error
+ spanLiveMetric, e := otelconv.NewSDKSpanLive(m)
+ err = errors.Join(err, e)
+
+ spanStartedMetric, e := otelconv.NewSDKSpanStarted(m)
+ err = errors.Join(err, e)
+
+ return spanLiveMetric, spanStartedMetric, err
+}
+
// RegisterSpanProcessor adds the given SpanProcessor to the list of SpanProcessors.
func (p *TracerProvider) RegisterSpanProcessor(sp SpanProcessor) {
// This check prevents calls during a shutdown.
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go b/vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go
index aa7b262d0..689663d48 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go
@@ -110,14 +110,14 @@ func TraceIDRatioBased(fraction float64) Sampler {
type alwaysOnSampler struct{}
-func (as alwaysOnSampler) ShouldSample(p SamplingParameters) SamplingResult {
+func (alwaysOnSampler) ShouldSample(p SamplingParameters) SamplingResult {
return SamplingResult{
Decision: RecordAndSample,
Tracestate: trace.SpanContextFromContext(p.ParentContext).TraceState(),
}
}
-func (as alwaysOnSampler) Description() string {
+func (alwaysOnSampler) Description() string {
return "AlwaysOnSampler"
}
@@ -131,14 +131,14 @@ func AlwaysSample() Sampler {
type alwaysOffSampler struct{}
-func (as alwaysOffSampler) ShouldSample(p SamplingParameters) SamplingResult {
+func (alwaysOffSampler) ShouldSample(p SamplingParameters) SamplingResult {
return SamplingResult{
Decision: Drop,
Tracestate: trace.SpanContextFromContext(p.ParentContext).TraceState(),
}
}
-func (as alwaysOffSampler) Description() string {
+func (alwaysOffSampler) Description() string {
return "AlwaysOffSampler"
}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go b/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go
index 664e13e03..411d9ccdd 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go
@@ -39,7 +39,7 @@ func NewSimpleSpanProcessor(exporter SpanExporter) SpanProcessor {
}
// OnStart does nothing.
-func (ssp *simpleSpanProcessor) OnStart(context.Context, ReadWriteSpan) {}
+func (*simpleSpanProcessor) OnStart(context.Context, ReadWriteSpan) {}
// OnEnd immediately exports a ReadOnlySpan.
func (ssp *simpleSpanProcessor) OnEnd(s ReadOnlySpan) {
@@ -104,13 +104,13 @@ func (ssp *simpleSpanProcessor) Shutdown(ctx context.Context) error {
}
// ForceFlush does nothing as there is no data to flush.
-func (ssp *simpleSpanProcessor) ForceFlush(context.Context) error {
+func (*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{} {
+func (ssp *simpleSpanProcessor) MarshalLog() any {
return struct {
Type string
Exporter SpanExporter
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go b/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go
index d511d0f27..63aa33780 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go
@@ -35,7 +35,7 @@ type snapshot struct {
var _ ReadOnlySpan = snapshot{}
-func (s snapshot) private() {}
+func (snapshot) private() {}
// Name returns the name of the span.
func (s snapshot) Name() string {
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/span.go b/vendor/go.opentelemetry.io/otel/sdk/trace/span.go
index 1785a4bbb..b376051fb 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/trace/span.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/span.go
@@ -20,7 +20,7 @@ import (
"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.34.0"
+ semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/embedded"
)
@@ -61,6 +61,7 @@ type ReadOnlySpan interface {
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.
@@ -165,7 +166,7 @@ func (s *recordingSpan) SpanContext() trace.SpanContext {
return s.spanContext
}
-// IsRecording returns if this span is being recorded. If this span has ended
+// IsRecording reports whether this span is being recorded. If this span has ended
// this will return false.
func (s *recordingSpan) IsRecording() bool {
if s == nil {
@@ -177,7 +178,7 @@ func (s *recordingSpan) IsRecording() bool {
return s.isRecording()
}
-// isRecording returns if this span is being recorded. If this span has ended
+// isRecording reports whether 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.
@@ -495,6 +496,16 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) {
}
s.mu.Unlock()
+ if s.tracer.selfObservabilityEnabled {
+ defer func() {
+ // Add the span to the context to ensure the metric is recorded
+ // with the correct span context.
+ ctx := trace.ContextWithSpan(context.Background(), s)
+ set := spanLiveSet(s.spanContext.IsSampled())
+ s.tracer.spanLiveMetric.AddSet(ctx, -1, set)
+ }()
+ }
+
sps := s.tracer.provider.getSpanProcessors()
if len(sps) == 0 {
return
@@ -545,7 +556,7 @@ func (s *recordingSpan) RecordError(err error, opts ...trace.EventOption) {
s.addEvent(semconv.ExceptionEventName, opts...)
}
-func typeStr(i interface{}) string {
+func typeStr(i any) string {
t := reflect.TypeOf(i)
if t.PkgPath() == "" && t.Name() == "" {
// Likely a builtin type.
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/tracer.go b/vendor/go.opentelemetry.io/otel/sdk/trace/tracer.go
index 0b65ae9ab..e965c4cce 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/trace/tracer.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/tracer.go
@@ -7,7 +7,9 @@ import (
"context"
"time"
+ "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/instrumentation"
+ "go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/embedded"
)
@@ -17,6 +19,10 @@ type tracer struct {
provider *TracerProvider
instrumentationScope instrumentation.Scope
+
+ selfObservabilityEnabled bool
+ spanLiveMetric otelconv.SDKSpanLive
+ spanStartedMetric otelconv.SDKSpanStarted
}
var _ trace.Tracer = &tracer{}
@@ -46,17 +52,25 @@ func (tr *tracer) Start(
}
s := tr.newSpan(ctx, name, &config)
+ newCtx := trace.ContextWithSpan(ctx, s)
+ if tr.selfObservabilityEnabled {
+ psc := trace.SpanContextFromContext(ctx)
+ set := spanStartedSet(psc, s)
+ tr.spanStartedMetric.AddSet(newCtx, 1, set)
+ }
+
if rw, ok := s.(ReadWriteSpan); ok && s.IsRecording() {
sps := tr.provider.getSpanProcessors()
for _, sp := range sps {
+ // Use original context.
sp.sp.OnStart(ctx, rw)
}
}
if rtt, ok := s.(runtimeTracer); ok {
- ctx = rtt.runtimeTrace(ctx)
+ newCtx = rtt.runtimeTrace(newCtx)
}
- return trace.ContextWithSpan(ctx, s), s
+ return newCtx, s
}
type runtimeTracer interface {
@@ -112,11 +126,12 @@ func (tr *tracer) newSpan(ctx context.Context, name string, config *trace.SpanCo
if !isRecording(samplingResult) {
return tr.newNonRecordingSpan(sc)
}
- return tr.newRecordingSpan(psc, sc, name, samplingResult, config)
+ return tr.newRecordingSpan(ctx, psc, sc, name, samplingResult, config)
}
// newRecordingSpan returns a new configured recordingSpan.
func (tr *tracer) newRecordingSpan(
+ ctx context.Context,
psc, sc trace.SpanContext,
name string,
sr SamplingResult,
@@ -153,6 +168,14 @@ func (tr *tracer) newRecordingSpan(
s.SetAttributes(sr.Attributes...)
s.SetAttributes(config.Attributes()...)
+ if tr.selfObservabilityEnabled {
+ // Propagate any existing values from the context with the new span to
+ // the measurement context.
+ ctx = trace.ContextWithSpan(ctx, s)
+ set := spanLiveSet(s.spanContext.IsSampled())
+ tr.spanLiveMetric.AddSet(ctx, 1, set)
+ }
+
return s
}
@@ -160,3 +183,112 @@ func (tr *tracer) newRecordingSpan(
func (tr *tracer) newNonRecordingSpan(sc trace.SpanContext) nonRecordingSpan {
return nonRecordingSpan{tracer: tr, sc: sc}
}
+
+type parentState int
+
+const (
+ parentStateNoParent parentState = iota
+ parentStateLocalParent
+ parentStateRemoteParent
+)
+
+type samplingState int
+
+const (
+ samplingStateDrop samplingState = iota
+ samplingStateRecordOnly
+ samplingStateRecordAndSample
+)
+
+type spanStartedSetKey struct {
+ parent parentState
+ sampling samplingState
+}
+
+var spanStartedSetCache = map[spanStartedSetKey]attribute.Set{
+ {parentStateNoParent, samplingStateDrop}: attribute.NewSet(
+ otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginNone),
+ otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultDrop),
+ ),
+ {parentStateLocalParent, samplingStateDrop}: attribute.NewSet(
+ otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginLocal),
+ otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultDrop),
+ ),
+ {parentStateRemoteParent, samplingStateDrop}: attribute.NewSet(
+ otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginRemote),
+ otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultDrop),
+ ),
+
+ {parentStateNoParent, samplingStateRecordOnly}: attribute.NewSet(
+ otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginNone),
+ otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultRecordOnly),
+ ),
+ {parentStateLocalParent, samplingStateRecordOnly}: attribute.NewSet(
+ otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginLocal),
+ otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultRecordOnly),
+ ),
+ {parentStateRemoteParent, samplingStateRecordOnly}: attribute.NewSet(
+ otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginRemote),
+ otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultRecordOnly),
+ ),
+
+ {parentStateNoParent, samplingStateRecordAndSample}: attribute.NewSet(
+ otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginNone),
+ otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultRecordAndSample),
+ ),
+ {parentStateLocalParent, samplingStateRecordAndSample}: attribute.NewSet(
+ otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginLocal),
+ otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultRecordAndSample),
+ ),
+ {parentStateRemoteParent, samplingStateRecordAndSample}: attribute.NewSet(
+ otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginRemote),
+ otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultRecordAndSample),
+ ),
+}
+
+func spanStartedSet(psc trace.SpanContext, span trace.Span) attribute.Set {
+ key := spanStartedSetKey{
+ parent: parentStateNoParent,
+ sampling: samplingStateDrop,
+ }
+
+ if psc.IsValid() {
+ if psc.IsRemote() {
+ key.parent = parentStateRemoteParent
+ } else {
+ key.parent = parentStateLocalParent
+ }
+ }
+
+ if span.IsRecording() {
+ if span.SpanContext().IsSampled() {
+ key.sampling = samplingStateRecordAndSample
+ } else {
+ key.sampling = samplingStateRecordOnly
+ }
+ }
+
+ return spanStartedSetCache[key]
+}
+
+type spanLiveSetKey struct {
+ sampled bool
+}
+
+var spanLiveSetCache = map[spanLiveSetKey]attribute.Set{
+ {true}: attribute.NewSet(
+ otelconv.SDKSpanLive{}.AttrSpanSamplingResult(
+ otelconv.SpanSamplingResultRecordAndSample,
+ ),
+ ),
+ {false}: attribute.NewSet(
+ otelconv.SDKSpanLive{}.AttrSpanSamplingResult(
+ otelconv.SpanSamplingResultRecordOnly,
+ ),
+ ),
+}
+
+func spanLiveSet(sampled bool) attribute.Set {
+ key := spanLiveSetKey{sampled: sampled}
+ return spanLiveSetCache[key]
+}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/exporter.go b/vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/exporter.go
index 07117495a..e12fa67e6 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/exporter.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/exporter.go
@@ -25,10 +25,10 @@ func NewNoopExporter() *NoopExporter {
type NoopExporter struct{}
// ExportSpans handles export of spans by dropping them.
-func (nsb *NoopExporter) ExportSpans(context.Context, []trace.ReadOnlySpan) error { return nil }
+func (*NoopExporter) ExportSpans(context.Context, []trace.ReadOnlySpan) error { return nil }
// Shutdown stops the exporter by doing nothing.
-func (nsb *NoopExporter) Shutdown(context.Context) error { return nil }
+func (*NoopExporter) Shutdown(context.Context) error { return nil }
var _ trace.SpanExporter = (*InMemoryExporter)(nil)
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/recorder.go b/vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/recorder.go
index 732669a17..ca63038f3 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/recorder.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/recorder.go
@@ -47,14 +47,14 @@ func (sr *SpanRecorder) OnEnd(s sdktrace.ReadOnlySpan) {
// Shutdown does nothing.
//
// This method is safe to be called concurrently.
-func (sr *SpanRecorder) Shutdown(context.Context) error {
+func (*SpanRecorder) Shutdown(context.Context) error {
return nil
}
// ForceFlush does nothing.
//
// This method is safe to be called concurrently.
-func (sr *SpanRecorder) ForceFlush(context.Context) error {
+func (*SpanRecorder) ForceFlush(context.Context) error {
return nil
}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/span.go b/vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/span.go
index cd2cc30ca..12b384b08 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/span.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/span.go
@@ -37,7 +37,7 @@ func (s SpanStubs) Snapshots() []tracesdk.ReadOnlySpan {
}
ro := make([]tracesdk.ReadOnlySpan, len(s))
- for i := 0; i < len(s); i++ {
+ for i := range s {
ro[i] = s[i].Snapshot()
}
return ro
diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/version.go b/vendor/go.opentelemetry.io/otel/sdk/trace/version.go
deleted file mode 100644
index b84dd2c5e..000000000
--- a/vendor/go.opentelemetry.io/otel/sdk/trace/version.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// 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"
-}
diff --git a/vendor/go.opentelemetry.io/otel/sdk/version.go b/vendor/go.opentelemetry.io/otel/sdk/version.go
index c0217af6b..7f97cc31e 100644
--- a/vendor/go.opentelemetry.io/otel/sdk/version.go
+++ b/vendor/go.opentelemetry.io/otel/sdk/version.go
@@ -6,5 +6,5 @@ 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.37.0"
+ return "1.38.0"
}