Skip to content

Commit 440d0b1

Browse files
committed
implement span processor's OnEnding
1 parent e47618f commit 440d0b1

File tree

3 files changed

+45
-4
lines changed

3 files changed

+45
-4
lines changed

sdk/trace/span.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ type recordingSpan struct {
120120
// value of time.Time until the span is ended.
121121
endTime time.Time
122122

123+
// hasEnded records whether the span is fully ended.
124+
hasEnded bool
125+
123126
// status is the status of this span.
124127
status Status
125128

@@ -171,10 +174,8 @@ func (s *recordingSpan) IsRecording() bool {
171174
if s == nil {
172175
return false
173176
}
174-
s.mu.Lock()
175-
defer s.mu.Unlock()
176177

177-
return s.endTime.IsZero()
178+
return !s.hasEnded
178179
}
179180

180181
// SetStatus sets the status of the Span in the form of a code and a
@@ -417,7 +418,6 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) {
417418
}
418419

419420
s.mu.Lock()
420-
// Setting endTime to non-zero marks the span as ended and not recording.
421421
if config.Timestamp().IsZero() {
422422
s.endTime = et
423423
} else {
@@ -426,6 +426,15 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) {
426426
s.mu.Unlock()
427427

428428
sps := s.tracer.provider.getSpanProcessors()
429+
for _, sp := range sps {
430+
if oesp, ok := sp.sp.(OnEndingSpanProcessor); ok {
431+
oesp.OnEnding(s)
432+
}
433+
}
434+
s.mu.Lock()
435+
s.hasEnded = true
436+
s.mu.Unlock()
437+
429438
if len(sps) == 0 {
430439
return
431440
}

sdk/trace/span_processor.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ type SpanProcessor interface {
4949
// must never be done outside of a new major release.
5050
}
5151

52+
// OnEndingSpanProcessor represents span processors that allow mutating spans
53+
// just before they are ended and made immutable.
54+
//
55+
// NOT STABLE: This interface still has a status of "development", and may have
56+
// breaking changes.
57+
type OnEndingSpanProcessor interface {
58+
// OnEnding is called while the span is finished, and while spans are still
59+
// mutable. It is called synchronously and cannot block.
60+
OnEnding(ReadWriteSpan)
61+
}
62+
5263
type spanProcessorState struct {
5364
sp SpanProcessor
5465
state sync.Once

sdk/trace/span_processor_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ func (t *testSpanProcessor) OnStart(parent context.Context, s sdktrace.ReadWrite
4646
t.spansStarted = append(t.spansStarted, s)
4747
}
4848

49+
func (t *testSpanProcessor) OnEnding(s sdktrace.ReadWriteSpan) {
50+
if t == nil {
51+
return
52+
}
53+
s.SetAttributes(attribute.Bool("OnEnding", true))
54+
}
55+
4956
func (t *testSpanProcessor) OnEnd(s sdktrace.ReadOnlySpan) {
5057
if t == nil {
5158
return
@@ -130,6 +137,17 @@ func TestRegisterSpanProcessor(t *testing.T) {
130137
}
131138
}
132139
}
140+
141+
onEndingOK := false
142+
for _, kv := range sp.spansEnded[0].Attributes() {
143+
switch kv.Key {
144+
case "OnEnding":
145+
onEndingOK = true
146+
default:
147+
continue
148+
}
149+
}
150+
133151
if c != len(spNames) {
134152
t.Errorf("%s: expected attributes(SpanProcessorName): got %d, want %d\n", name, c, len(spNames))
135153
}
@@ -139,6 +157,9 @@ func TestRegisterSpanProcessor(t *testing.T) {
139157
if !sidOK {
140158
t.Errorf("%s: expected attributes(ParentSpanID)\n", name)
141159
}
160+
if !onEndingOK {
161+
t.Errorf("%s: expected attributes(OnEnding)\n", name)
162+
}
142163
}
143164
}
144165

0 commit comments

Comments
 (0)