1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-11-25 22:41:46 +02:00
Files
opentelemetry-go/exporters/stdout/stdouttrace/trace.go

122 lines
2.6 KiB
Go
Raw Normal View History

// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package stdouttrace // import "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
import (
"context"
"encoding/json"
"errors"
"fmt"
"sync"
"time"
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/counter"
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/observ"
"go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/sdk/trace/tracetest"
)
var zeroTime time.Time
var _ trace.SpanExporter = &Exporter{}
// New creates an Exporter with the passed options.
func New(options ...Option) (*Exporter, error) {
cfg := newConfig(options...)
enc := json.NewEncoder(cfg.Writer)
if cfg.PrettyPrint {
enc.SetIndent("", "\t")
}
exporter := &Exporter{
encoder: enc,
timestamps: cfg.Timestamps,
}
var err error
exporter.inst, err = observ.NewInstrumentation(counter.NextExporterID())
return exporter, err
}
// Exporter is an implementation of trace.SpanSyncer that writes spans to stdout.
type Exporter struct {
encoder *json.Encoder
encoderMu sync.Mutex
timestamps bool
stoppedMu sync.RWMutex
stopped bool
inst *observ.Instrumentation
}
// ExportSpans writes spans in json format to stdout.
func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) (err error) {
var success int64
if e.inst != nil {
Optimize the return type of ExportSpans (#7405) Do not allocate a return function from `ExportSpans` to the heap. Use the added `ExportOp` type instead. ### Benchmarks #### `stdouttrace` ```terminal goos: linux goarch: amd64 pkg: go.opentelemetry.io/otel/exporters/stdout/stdouttrace cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz │ main.bmark.results │ stdouttrace-optimize-end.bmark.results │ │ sec/op │ sec/op vs base │ ExporterExportSpans/Observability-8 23.37µ ± 2% 22.79µ ± 3% -2.50% (p=0.025 n=10) ExporterExportSpans/NoObservability-8 23.07µ ± 7% 22.29µ ± 1% -3.38% (p=0.000 n=10) geomean 23.22µ 22.54µ -2.94% │ main.bmark.results │ stdouttrace-optimize-end.bmark.results │ │ B/op │ B/op vs base │ ExporterExportSpans/Observability-8 4.253Ki ± 0% 4.190Ki ± 0% -1.47% (p=0.000 n=10) ExporterExportSpans/NoObservability-8 3.975Ki ± 0% 3.975Ki ± 0% ~ (p=0.474 n=10) geomean 4.111Ki 4.081Ki -0.74% │ main.bmark.results │ stdouttrace-optimize-end.bmark.results │ │ allocs/op │ allocs/op vs base │ ExporterExportSpans/Observability-8 67.00 ± 0% 66.00 ± 0% -1.49% (p=0.000 n=10) ExporterExportSpans/NoObservability-8 64.00 ± 0% 64.00 ± 0% ~ (p=1.000 n=10) ¹ geomean 65.48 64.99 -0.75% ¹ all samples are equal ``` #### `stdouttrace/internal/observ` ```terminal goos: linux goarch: amd64 pkg: go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/observ cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz │ main.bmark.results │ stdouttrace-optimize-end.bmark.results │ │ sec/op │ sec/op vs base │ InstrumentationExportSpans/NoError-8 197.9n ± 7% 153.3n ± 5% -22.51% (p=0.000 n=10) InstrumentationExportSpans/PartialError-8 754.4n ± 6% 663.2n ± 6% -12.08% (p=0.001 n=10) InstrumentationExportSpans/FullError-8 772.8n ± 4% 669.2n ± 4% -13.39% (p=0.000 n=10) geomean 486.8n 408.3n -16.13% │ main.bmark.results │ stdouttrace-optimize-end.bmark.results │ │ B/op │ B/op vs base │ InstrumentationExportSpans/NoError-8 64.00 ± 0% 0.00 ± 0% -100.00% (p=0.000 n=10) InstrumentationExportSpans/PartialError-8 280.0 ± 0% 216.0 ± 0% -22.86% (p=0.000 n=10) InstrumentationExportSpans/FullError-8 280.0 ± 0% 216.0 ± 0% -22.86% (p=0.000 n=10) geomean 171.2 ? ¹ ² ¹ summaries must be >0 to compute geomean ² ratios must be >0 to compute geomean │ main.bmark.results │ stdouttrace-optimize-end.bmark.results │ │ allocs/op │ allocs/op vs base │ InstrumentationExportSpans/NoError-8 1.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10) InstrumentationExportSpans/PartialError-8 3.000 ± 0% 2.000 ± 0% -33.33% (p=0.000 n=10) InstrumentationExportSpans/FullError-8 3.000 ± 0% 2.000 ± 0% -33.33% (p=0.000 n=10) geomean 2.080 ? ¹ ² ¹ summaries must be >0 to compute geomean ² ratios must be >0 to compute geomean ```
2025-09-25 09:07:15 -07:00
op := e.inst.ExportSpans(ctx, len(spans))
defer func() { op.End(success, err) }()
}
if err := ctx.Err(); err != nil {
return err
}
e.stoppedMu.RLock()
stopped := e.stopped
e.stoppedMu.RUnlock()
if stopped {
return nil
}
if len(spans) == 0 {
return nil
}
stubs := tracetest.SpanStubsFromReadOnlySpans(spans)
e.encoderMu.Lock()
defer e.encoderMu.Unlock()
for i := range stubs {
stub := &stubs[i]
// Remove timestamps
if !e.timestamps {
stub.StartTime = zeroTime
stub.EndTime = zeroTime
for j := range stub.Events {
ev := &stub.Events[j]
ev.Time = zeroTime
}
}
// Encode span stubs, one by one
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 err
}
// Shutdown is called to stop the exporter, it performs no action.
func (e *Exporter) Shutdown(context.Context) error {
e.stoppedMu.Lock()
e.stopped = true
e.stoppedMu.Unlock()
return nil
}
// MarshalLog is the marshaling function used by the logging system to represent this Exporter.
func (e *Exporter) MarshalLog() any {
return struct {
Type string
WithTimestamps bool
}{
Type: "stdout",
WithTimestamps: e.timestamps,
}
}