Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Add support for per-series start time tracking for cumulative metrics in `go.opentelemetry.io/otel/sdk/metric`.
Set `OTEL_GO_X_PER_SERIES_START_TIMESTAMPS=true` to enable. (#8060)
- Add `WithCardinalityLimitSelector` for metric reader for configuring cardinality limits specific to the instrument kind. (#7855)
- Add `WithStackTrace` option for TracerProvider to add stackTraces to all spans. (#8094)

### Changed

Expand Down
81 changes: 72 additions & 9 deletions sdk/trace/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,32 @@ import (

const defaultTracerName = "go.opentelemetry.io/otel/sdk/tracer"

// StackTraceMode configures how the TracerProvider adds stack traces to
// exception events for recorded errors and panics.
type StackTraceMode int

const (
// StackTraceModeDefault does not add stack traces unless the span or event
// uses trace.WithStackTrace(true).
StackTraceModeDefault StackTraceMode = iota
// StackTraceModeAlways adds stack traces for all recorded errors and panics.
StackTraceModeAlways
// StackTraceModeNever never adds stack traces, even when
// trace.WithStackTrace(true) is used.
StackTraceModeNever
)

func (m StackTraceMode) String() string {
switch m {
case StackTraceModeAlways:
return "Always"
case StackTraceModeNever:
return "Never"
default:
return "Default"
}
}

// tracerProviderConfig.
type tracerProviderConfig struct {
// processors contains collection of SpanProcessors that are processing pipeline
Expand All @@ -42,6 +68,9 @@ type tracerProviderConfig struct {

// resource contains attributes representing an entity that produces telemetry.
resource *resource.Resource

// stackTraceMode configures stack trace capture for recorded errors and panics.
stackTraceMode StackTraceMode
}

// MarshalLog is the marshaling function used by the logging system to represent this Provider.
Expand All @@ -52,12 +81,14 @@ func (cfg tracerProviderConfig) MarshalLog() any {
IDGeneratorType string
SpanLimits SpanLimits
Resource *resource.Resource
StackTraceMode string
}{
SpanProcessors: cfg.processors,
SamplerType: fmt.Sprintf("%T", cfg.sampler),
IDGeneratorType: fmt.Sprintf("%T", cfg.idGenerator),
SpanLimits: cfg.spanLimits,
Resource: cfg.resource,
StackTraceMode: cfg.stackTraceMode.String(),
}
}

Expand All @@ -74,10 +105,11 @@ type TracerProvider struct {

// These fields are not protected by the lock mu. They are assumed to be
// immutable after creation of the TracerProvider.
sampler Sampler
idGenerator IDGenerator
spanLimits SpanLimits
resource *resource.Resource
sampler Sampler
idGenerator IDGenerator
spanLimits SpanLimits
resource *resource.Resource
stackTraceMode StackTraceMode
}

var _ trace.TracerProvider = &TracerProvider{}
Expand Down Expand Up @@ -105,11 +137,12 @@ func NewTracerProvider(opts ...TracerProviderOption) *TracerProvider {
o = ensureValidTracerProviderConfig(o)

tp := &TracerProvider{
namedTracer: make(map[instrumentation.Scope]*tracer),
sampler: o.sampler,
idGenerator: o.idGenerator,
spanLimits: o.spanLimits,
resource: o.resource,
namedTracer: make(map[instrumentation.Scope]*tracer),
sampler: o.sampler,
idGenerator: o.idGenerator,
spanLimits: o.spanLimits,
resource: o.resource,
stackTraceMode: o.stackTraceMode,
}
global.Info("TracerProvider created", "config", o)

Expand Down Expand Up @@ -384,6 +417,36 @@ func WithIDGenerator(g IDGenerator) TracerProviderOption {
})
}

// WithAlwaysStackTrace configures the TracerProvider to capture a stack trace
// for all recorded errors and panics.
func WithAlwaysStackTrace() TracerProviderOption {
return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
cfg.stackTraceMode = StackTraceModeAlways
return cfg
})
}

// WithNeverStackTrace configures the TracerProvider to never capture stack
// traces for recorded errors and panics, including when trace.WithStackTrace(true)
// is passed on a span or event.
func WithNeverStackTrace() TracerProviderOption {
return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
cfg.stackTraceMode = StackTraceModeNever
return cfg
})
}

func (p *TracerProvider) shouldRecordExceptionStackTrace(spanRequested bool) bool {
switch p.stackTraceMode {
case StackTraceModeNever:
return false
case StackTraceModeAlways:
return true
default:
return spanRequested
}
}

// WithSampler returns a TracerProviderOption that will configure the Sampler
// s as a TracerProvider's Sampler. The configured Sampler is used by the
// Tracers the TracerProvider creates to make their sampling decisions for the
Expand Down
4 changes: 2 additions & 2 deletions sdk/trace/span.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) {
),
}

if config.StackTrace() {
if s.tracer.provider.shouldRecordExceptionStackTrace(config.StackTrace()) {
opts = append(opts, trace.WithAttributes(
semconv.ExceptionStacktrace(recordStackTrace()),
))
Expand Down Expand Up @@ -558,7 +558,7 @@ func (s *recordingSpan) RecordError(err error, opts ...trace.EventOption) {
))

c := trace.NewEventConfig(opts...)
if c.StackTrace() {
if s.tracer.provider.shouldRecordExceptionStackTrace(c.StackTrace()) {
opts = append(opts, trace.WithAttributes(
semconv.ExceptionStacktrace(recordStackTrace()),
))
Expand Down
Loading
Loading