diff --git a/trace/trace.go b/trace/trace.go index 68a45463..c606fb3a 100644 --- a/trace/trace.go +++ b/trace/trace.go @@ -120,41 +120,37 @@ func NewTrace(ctx context.Context, prop *propagation.PropagationContext) (contex return NewTraceFromPropagationContext(ctx, prop) } +type addFieldOptions struct { + isOverridable *bool +} + +func Overridable(overridable bool) addFieldOptions { + return addFieldOptions{isOverridable: &overridable} +} + // AddField adds a field to the trace. Every span in the trace will have this // field added to it. These fields are also passed along to downstream services. // It is useful to add fields here that pertain to the entire trace, to aid in // filtering spans at many different areas of the trace together. -func (t *Trace) AddField(key string, val interface{}) { +func (t *Trace) AddField(key string, val interface{}, opts ...addFieldOptions) { t.tlfLock.Lock() defer t.tlfLock.Unlock() - if t.traceLevelFields != nil { - t.traceLevelFields[key] = val + isOverridable := false + + for _, opt := range opts { + if opt.isOverridable != nil { + isOverridable = *opt.isOverridable + } } -} -// AddOverridableField adds a default field to the trace. -// It is similar to AddField, with two key differences: -// 1. Individual spans can override the value at a per-span level, using AddField on the Span. -// -// Overriding a field on a span does not override the entire subtree - in the following hypothetical -// trace, overriding a field on the parent span will not override that field in the child span. -// -// root -// parent -// child -// -// 2. Overridable fields are sent to downstream services, but we cannot encode the "overrideability" -// of the field in the propagation context, so the field will cease to be overrideable in the downstream -// service. -// -// AddOverridableField is best suited to niche cases where you are not propagating the span context, -// -// or cases where you only wish to overwrite the field in a small number of cases, usually in leaf spans. -func (t *Trace) AddOverridableField(key string, val interface{}) { - t.tlfLock.Lock() - defer t.tlfLock.Unlock() - if t.overridableTraceLevelFields != nil { - t.overridableTraceLevelFields[key] = val + if isOverridable { + if t.overridableTraceLevelFields != nil { + t.overridableTraceLevelFields[key] = val + } + } else { + if t.traceLevelFields != nil { + t.traceLevelFields[key] = val + } } } diff --git a/trace/trace_test.go b/trace/trace_test.go index 8a3fe4e6..c227469a 100644 --- a/trace/trace_test.go +++ b/trace/trace_test.go @@ -454,10 +454,10 @@ func TestTraceLevelFields(t *testing.T) { // span will attempt to override, but will fail to do so tr.AddField("overridden", 1) // span will attempt to override, and will succeed - tr.AddOverridableField("overridden_overridable", 1) + tr.AddField("overridden_overridable", 1, Overridable(true)) // span will leave these alone - tr.AddOverridableField("left_alone", 1) - tr.AddOverridableField("left_alone_overridable", 1) + tr.AddField("left_alone", 1) + tr.AddField("left_alone_overridable", 1, Overridable(true)) rs := tr.GetRootSpan() rs.AddField("overridden", 2)