summaryrefslogtreecommitdiff
path: root/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace')
-rw-r--r--vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/LICENSE30
-rw-r--r--vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/doc.go3
-rw-r--r--vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/counter/counter.go31
-rw-r--r--vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x/README.md36
-rw-r--r--vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x/x.go63
-rw-r--r--vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/trace.go168
6 files changed, 323 insertions, 8 deletions
diff --git a/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/LICENSE b/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/LICENSE
index 261eeb9e9..f1aee0f11 100644
--- a/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/LICENSE
+++ b/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/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/exporters/stdout/stdouttrace/doc.go b/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/doc.go
index eff7730cd..648bc0749 100644
--- a/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/doc.go
+++ b/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/doc.go
@@ -3,4 +3,7 @@
// Package stdouttrace contains an OpenTelemetry exporter for tracing
// telemetry to be written to an output destination as JSON.
+//
+// See [go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x] for information about
+// the experimental features.
package stdouttrace // import "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
diff --git a/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/counter/counter.go b/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/counter/counter.go
new file mode 100644
index 000000000..8c780afb0
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/counter/counter.go
@@ -0,0 +1,31 @@
+// Code generated by gotmpl. DO NOT MODIFY.
+// source: internal/shared/counter/counter.go.tmpl
+
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+// Package counter provides a simple counter for generating unique IDs.
+//
+// This package is used to generate unique IDs while allowing testing packages
+// to reset the counter.
+package counter // import "go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/counter"
+
+import "sync/atomic"
+
+// exporterN is a global 0-based count of the number of exporters created.
+var exporterN atomic.Int64
+
+// NextExporterID returns the next unique ID for an exporter.
+func NextExporterID() int64 {
+ const inc = 1
+ return exporterN.Add(inc) - inc
+}
+
+// SetExporterID sets the exporter ID counter to v and returns the previous
+// value.
+//
+// This function is useful for testing purposes, allowing you to reset the
+// counter. It should not be used in production code.
+func SetExporterID(v int64) int64 {
+ return exporterN.Swap(v)
+}
diff --git a/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x/README.md b/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x/README.md
new file mode 100644
index 000000000..6b7d1aec8
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x/README.md
@@ -0,0 +1,36 @@
+# Experimental Features
+
+The `stdouttrace` exporter contains features that have not yet stabilized in the OpenTelemetry specification.
+These features are added to the `stdouttrace` exporter 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 `stdouttrace` exporter 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.exporter.span.inflight`
+- `otel.sdk.exporter.span.exported`
+- `otel.sdk.exporter.operation.duration`
+
+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/exporters/stdout/stdouttrace/internal/x/x.go b/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x/x.go
new file mode 100644
index 000000000..55bb98a96
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/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/exporters/stdout/stdouttrace].
+package x // import "go.opentelemetry.io/otel/exporters/stdout/stdouttrace/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/exporters/stdout/stdouttrace/trace.go b/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/trace.go
index bdb915ba8..d61324d2e 100644
--- a/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/trace.go
+++ b/vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/trace.go
@@ -6,13 +6,28 @@ package stdouttrace // import "go.opentelemetry.io/otel/exporters/stdout/stdoutt
import (
"context"
"encoding/json"
+ "errors"
+ "fmt"
"sync"
"time"
+ "go.opentelemetry.io/otel"
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/counter"
+ "go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x"
+ "go.opentelemetry.io/otel/metric"
+ "go.opentelemetry.io/otel/sdk"
"go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/sdk/trace/tracetest"
+ semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
+ "go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
)
+// otelComponentType is a name identifying the type of the OpenTelemetry
+// component. It is not a standardized OTel component type, so it uses the
+// Go package prefixed type name to ensure uniqueness and identity.
+const otelComponentType = "go.opentelemetry.io/otel/exporters/stdout/stdouttrace.Exporter"
+
var zeroTime time.Time
var _ trace.SpanExporter = &Exporter{}
@@ -26,10 +41,45 @@ func New(options ...Option) (*Exporter, error) {
enc.SetIndent("", "\t")
}
- return &Exporter{
+ exporter := &Exporter{
encoder: enc,
timestamps: cfg.Timestamps,
- }, nil
+ }
+
+ if !x.SelfObservability.Enabled() {
+ return exporter, nil
+ }
+
+ exporter.selfObservabilityEnabled = true
+ exporter.selfObservabilityAttrs = []attribute.KeyValue{
+ semconv.OTelComponentName(fmt.Sprintf("%s/%d", otelComponentType, counter.NextExporterID())),
+ semconv.OTelComponentTypeKey.String(otelComponentType),
+ }
+ s := attribute.NewSet(exporter.selfObservabilityAttrs...)
+ exporter.selfObservabilitySetOpt = metric.WithAttributeSet(s)
+
+ mp := otel.GetMeterProvider()
+ m := mp.Meter(
+ "go.opentelemetry.io/otel/exporters/stdout/stdouttrace",
+ metric.WithInstrumentationVersion(sdk.Version()),
+ metric.WithSchemaURL(semconv.SchemaURL),
+ )
+
+ var err, e error
+ if exporter.spanInflightMetric, e = otelconv.NewSDKExporterSpanInflight(m); e != nil {
+ e = fmt.Errorf("failed to create span inflight metric: %w", e)
+ err = errors.Join(err, e)
+ }
+ if exporter.spanExportedMetric, e = otelconv.NewSDKExporterSpanExported(m); e != nil {
+ e = fmt.Errorf("failed to create span exported metric: %w", e)
+ err = errors.Join(err, e)
+ }
+ if exporter.operationDurationMetric, e = otelconv.NewSDKExporterOperationDuration(m); e != nil {
+ e = fmt.Errorf("failed to create operation duration metric: %w", e)
+ err = errors.Join(err, e)
+ }
+
+ return exporter, err
}
// Exporter is an implementation of trace.SpanSyncer that writes spans to stdout.
@@ -40,10 +90,110 @@ type Exporter struct {
stoppedMu sync.RWMutex
stopped bool
+
+ selfObservabilityEnabled bool
+ selfObservabilityAttrs []attribute.KeyValue // selfObservability common attributes
+ selfObservabilitySetOpt metric.MeasurementOption
+ spanInflightMetric otelconv.SDKExporterSpanInflight
+ spanExportedMetric otelconv.SDKExporterSpanExported
+ operationDurationMetric otelconv.SDKExporterOperationDuration
}
+var (
+ measureAttrsPool = sync.Pool{
+ New: func() any {
+ // "component.name" + "component.type" + "error.type"
+ const n = 1 + 1 + 1
+ s := make([]attribute.KeyValue, 0, n)
+ // Return a pointer to a slice instead of a slice itself
+ // to avoid allocations on every call.
+ return &s
+ },
+ }
+
+ addOptPool = &sync.Pool{
+ New: func() any {
+ const n = 1 // WithAttributeSet
+ o := make([]metric.AddOption, 0, n)
+ return &o
+ },
+ }
+
+ recordOptPool = &sync.Pool{
+ New: func() any {
+ const n = 1 // WithAttributeSet
+ o := make([]metric.RecordOption, 0, n)
+ return &o
+ },
+ }
+)
+
// ExportSpans writes spans in json format to stdout.
-func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
+func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) (err error) {
+ var success int64
+ if e.selfObservabilityEnabled {
+ count := int64(len(spans))
+
+ addOpt := addOptPool.Get().(*[]metric.AddOption)
+ defer func() {
+ *addOpt = (*addOpt)[:0]
+ addOptPool.Put(addOpt)
+ }()
+
+ *addOpt = append(*addOpt, e.selfObservabilitySetOpt)
+
+ e.spanInflightMetric.Inst().Add(ctx, count, *addOpt...)
+ defer func(starting time.Time) {
+ e.spanInflightMetric.Inst().Add(ctx, -count, *addOpt...)
+
+ // Record the success and duration of the operation.
+ //
+ // Do not exclude 0 values, as they are valid and indicate no spans
+ // were exported which is meaningful for certain aggregations.
+ e.spanExportedMetric.Inst().Add(ctx, success, *addOpt...)
+
+ mOpt := e.selfObservabilitySetOpt
+ if err != nil {
+ // additional attributes for self-observability,
+ // only spanExportedMetric and operationDurationMetric are supported.
+ attrs := measureAttrsPool.Get().(*[]attribute.KeyValue)
+ defer func() {
+ *attrs = (*attrs)[:0] // reset the slice for reuse
+ measureAttrsPool.Put(attrs)
+ }()
+ *attrs = append(*attrs, e.selfObservabilityAttrs...)
+ *attrs = append(*attrs, semconv.ErrorType(err))
+
+ // Do not inefficiently make a copy of attrs by using
+ // WithAttributes instead of WithAttributeSet.
+ set := attribute.NewSet(*attrs...)
+ mOpt = metric.WithAttributeSet(set)
+
+ // Reset addOpt with new attribute set.
+ *addOpt = append((*addOpt)[:0], mOpt)
+
+ e.spanExportedMetric.Inst().Add(
+ ctx,
+ count-success,
+ *addOpt...,
+ )
+ }
+
+ recordOpt := recordOptPool.Get().(*[]metric.RecordOption)
+ defer func() {
+ *recordOpt = (*recordOpt)[:0]
+ recordOptPool.Put(recordOpt)
+ }()
+
+ *recordOpt = append(*recordOpt, mOpt)
+ e.operationDurationMetric.Inst().Record(
+ ctx,
+ time.Since(starting).Seconds(),
+ *recordOpt...,
+ )
+ }(time.Now())
+ }
+
if err := ctx.Err(); err != nil {
return err
}
@@ -75,15 +225,17 @@ func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan)
}
// Encode span stubs, one by one
- if err := e.encoder.Encode(stub); err != nil {
- return err
+ if e := e.encoder.Encode(stub); e != nil {
+ err = errors.Join(err, fmt.Errorf("failed to encode span %d: %w", i, e))
+ continue
}
+ success++
}
- return nil
+ return err
}
// Shutdown is called to stop the exporter, it performs no action.
-func (e *Exporter) Shutdown(ctx context.Context) error {
+func (e *Exporter) Shutdown(context.Context) error {
e.stoppedMu.Lock()
e.stopped = true
e.stoppedMu.Unlock()
@@ -92,7 +244,7 @@ func (e *Exporter) Shutdown(ctx context.Context) error {
}
// MarshalLog is the marshaling function used by the logging system to represent this Exporter.
-func (e *Exporter) MarshalLog() interface{} {
+func (e *Exporter) MarshalLog() any {
return struct {
Type string
WithTimestamps bool