1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-10-08 23:21:56 +02:00
Files
opentelemetry-go/exporters/stdout/stdouttrace/trace.go
2025-09-09 12:11:08 -07:00

122 lines
2.6 KiB
Go

// 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 {
end := e.inst.ExportSpans(ctx, len(spans))
defer func() { 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,
}
}