@@ -6,6 +6,7 @@ package trace // import "go.opentelemetry.io/otel/sdk/trace"
6
6
import (
7
7
"context"
8
8
"fmt"
9
+ "go.opentelemetry.io/otel/internal/epoch"
9
10
"reflect"
10
11
"runtime"
11
12
rt "runtime/trace"
@@ -114,11 +115,11 @@ type recordingSpan struct {
114
115
name string
115
116
116
117
// startTime is the time at which this span was started.
117
- startTime time. Time
118
+ startTime epoch. Nanos
118
119
119
- // endTime is the time at which this span was ended. It contains the zero
120
- // value of time.Time until the span is ended.
121
- endTime time. Time
120
+ // endTime is the time at which this span was ended. It contains zero until
121
+ // the span is ended.
122
+ endTime epoch. Nanos
122
123
123
124
// status is the status of this span.
124
125
status Status
@@ -168,40 +169,19 @@ func (s *recordingSpan) SpanContext() trace.SpanContext {
168
169
// IsRecording returns if this span is being recorded. If this span has ended
169
170
// this will return false.
170
171
func (s * recordingSpan ) IsRecording () bool {
171
- if s == nil {
172
- return false
173
- }
174
- s .mu .Lock ()
175
- defer s .mu .Unlock ()
176
-
177
- return s .isRecording ()
178
- }
179
-
180
- // isRecording returns if this span is being recorded. If this span has ended
181
- // this will return false.
182
- //
183
- // This method assumes s.mu.Lock is held by the caller.
184
- func (s * recordingSpan ) isRecording () bool {
185
- if s == nil {
186
- return false
187
- }
188
- return s .endTime .IsZero ()
172
+ return s != nil && (& s .endTime ).Load () == 0
189
173
}
190
174
191
175
// SetStatus sets the status of the Span in the form of a code and a
192
176
// description, overriding previous values set. The description is only
193
177
// included in the set status when the code is for an error. If this span is
194
178
// not being recorded than this method does nothing.
195
179
func (s * recordingSpan ) SetStatus (code codes.Code , description string ) {
196
- if s == nil {
180
+ if ! s . IsRecording () {
197
181
return
198
182
}
199
-
200
183
s .mu .Lock ()
201
184
defer s .mu .Unlock ()
202
- if ! s .isRecording () {
203
- return
204
- }
205
185
if s .status .Code > code {
206
186
return
207
187
}
@@ -225,15 +205,12 @@ func (s *recordingSpan) SetStatus(code codes.Code, description string) {
225
205
// attributes the span is configured to have, the last added attributes will
226
206
// be dropped.
227
207
func (s * recordingSpan ) SetAttributes (attributes ... attribute.KeyValue ) {
228
- if s == nil || len (attributes ) == 0 {
208
+ if ! s . IsRecording () || len (attributes ) == 0 {
229
209
return
230
210
}
231
211
232
212
s .mu .Lock ()
233
213
defer s .mu .Unlock ()
234
- if ! s .isRecording () {
235
- return
236
- }
237
214
238
215
limit := s .tracer .provider .spanLimits .AttributeCountLimit
239
216
if limit == 0 {
@@ -444,24 +421,23 @@ func truncate(limit int, s string) string {
444
421
// If this method is called while panicking an error event is added to the
445
422
// Span before ending it and the panic is continued.
446
423
func (s * recordingSpan ) End (options ... trace.SpanEndOption ) {
447
- // Do not start by checking if the span is being recorded which requires
448
- // acquiring a lock. Make a minimal check that the span is not nil.
449
424
if s == nil {
450
425
return
451
426
}
452
427
453
- // Store the end time as soon as possible to avoid artificially increasing
454
- // the span's duration in case some operation below takes a while.
455
- et := monotonicEndTime (s .startTime )
428
+ config := trace .NewSpanEndConfig (options ... )
429
+ var endTime epoch.Nanos
430
+ if config .Timestamp ().IsZero () {
431
+ endTime = epoch .NanosNow ()
432
+ } else {
433
+ endTime = epoch .NewNanos (config .Timestamp ())
434
+ }
456
435
457
- // Lock the span now that we have an end time and see if we need to do any more processing.
458
- s .mu .Lock ()
459
- if ! s .isRecording () {
460
- s .mu .Unlock ()
436
+ // Only the first call to End sets the time using atomic compare-and-swap.
437
+ if ! (& s .endTime ).SwapIfZero (endTime ) {
461
438
return
462
439
}
463
440
464
- config := trace .NewSpanEndConfig (options ... )
465
441
if recovered := recover (); recovered != nil {
466
442
// Record but don't stop the panic.
467
443
defer panic (recovered )
@@ -482,19 +458,9 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) {
482
458
}
483
459
484
460
if s .executionTracerTaskEnd != nil {
485
- s .mu .Unlock ()
486
461
s .executionTracerTaskEnd ()
487
- s .mu .Lock ()
488
462
}
489
463
490
- // Setting endTime to non-zero marks the span as ended and not recording.
491
- if config .Timestamp ().IsZero () {
492
- s .endTime = et
493
- } else {
494
- s .endTime = config .Timestamp ()
495
- }
496
- s .mu .Unlock ()
497
-
498
464
sps := s .tracer .provider .getSpanProcessors ()
499
465
if len (sps ) == 0 {
500
466
return
@@ -505,30 +471,17 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) {
505
471
}
506
472
}
507
473
508
- // monotonicEndTime returns the end time at present but offset from start,
509
- // monotonically.
510
- //
511
- // The monotonic clock is used in subtractions hence the duration since start
512
- // added back to start gives end as a monotonic time. See
513
- // https://golang.org/pkg/time/#hdr-Monotonic_Clocks
514
- func monotonicEndTime (start time.Time ) time.Time {
515
- return start .Add (time .Since (start ))
516
- }
517
-
518
474
// RecordError will record err as a span event for this span. An additional call to
519
475
// SetStatus is required if the Status of the Span should be set to Error, this method
520
476
// does not change the Span status. If this span is not being recorded or err is nil
521
477
// than this method does nothing.
522
478
func (s * recordingSpan ) RecordError (err error , opts ... trace.EventOption ) {
523
- if s == nil || err == nil {
479
+ if err == nil || ! s . IsRecording () {
524
480
return
525
481
}
526
482
527
483
s .mu .Lock ()
528
484
defer s .mu .Unlock ()
529
- if ! s .isRecording () {
530
- return
531
- }
532
485
533
486
opts = append (opts , trace .WithAttributes (
534
487
semconv .ExceptionType (typeStr (err )),
@@ -564,15 +517,12 @@ func recordStackTrace() string {
564
517
// AddEvent adds an event with the provided name and options. If this span is
565
518
// not being recorded then this method does nothing.
566
519
func (s * recordingSpan ) AddEvent (name string , o ... trace.EventOption ) {
567
- if s == nil {
520
+ if ! s . IsRecording () {
568
521
return
569
522
}
570
523
571
524
s .mu .Lock ()
572
525
defer s .mu .Unlock ()
573
- if ! s .isRecording () {
574
- return
575
- }
576
526
s .addEvent (name , o ... )
577
527
}
578
528
@@ -601,15 +551,12 @@ func (s *recordingSpan) addEvent(name string, o ...trace.EventOption) {
601
551
// SetName sets the name of this span. If this span is not being recorded than
602
552
// this method does nothing.
603
553
func (s * recordingSpan ) SetName (name string ) {
604
- if s == nil {
554
+ if s == nil || ! s . IsRecording () {
605
555
return
606
556
}
607
557
608
558
s .mu .Lock ()
609
559
defer s .mu .Unlock ()
610
- if ! s .isRecording () {
611
- return
612
- }
613
560
s .name = name
614
561
}
615
562
@@ -638,15 +585,13 @@ func (s *recordingSpan) SpanKind() trace.SpanKind {
638
585
func (s * recordingSpan ) StartTime () time.Time {
639
586
s .mu .Lock ()
640
587
defer s .mu .Unlock ()
641
- return s .startTime
588
+ return s .startTime . ToTime ()
642
589
}
643
590
644
591
// EndTime returns the time this span ended. For spans that have not yet
645
592
// ended, the returned value will be the zero value of time.Time.
646
593
func (s * recordingSpan ) EndTime () time.Time {
647
- s .mu .Lock ()
648
- defer s .mu .Unlock ()
649
- return s .endTime
594
+ return (& s .endTime ).Load ().ToTime ()
650
595
}
651
596
652
597
// Attributes returns the attributes of this span.
@@ -740,7 +685,7 @@ func (s *recordingSpan) Resource() *resource.Resource {
740
685
}
741
686
742
687
func (s * recordingSpan ) AddLink (link trace.Link ) {
743
- if s == nil {
688
+ if ! s . IsRecording () {
744
689
return
745
690
}
746
691
if ! link .SpanContext .IsValid () && len (link .Attributes ) == 0 &&
@@ -750,9 +695,6 @@ func (s *recordingSpan) AddLink(link trace.Link) {
750
695
751
696
s .mu .Lock ()
752
697
defer s .mu .Unlock ()
753
- if ! s .isRecording () {
754
- return
755
- }
756
698
757
699
l := Link {SpanContext : link .SpanContext , Attributes : link .Attributes }
758
700
@@ -814,14 +756,14 @@ func (s *recordingSpan) snapshot() ReadOnlySpan {
814
756
s .mu .Lock ()
815
757
defer s .mu .Unlock ()
816
758
817
- sd .endTime = s .endTime
759
+ sd .endTime = s .endTime . ToTime ()
818
760
sd .instrumentationScope = s .tracer .instrumentationScope
819
761
sd .name = s .name
820
762
sd .parent = s .parent
821
763
sd .resource = s .tracer .provider .resource
822
764
sd .spanContext = s .spanContext
823
765
sd .spanKind = s .spanKind
824
- sd .startTime = s .startTime
766
+ sd .startTime = s .startTime . ToTime ()
825
767
sd .status = s .status
826
768
sd .childSpanCount = s .childSpanCount
827
769
@@ -842,15 +784,12 @@ func (s *recordingSpan) snapshot() ReadOnlySpan {
842
784
}
843
785
844
786
func (s * recordingSpan ) addChild () {
845
- if s == nil {
787
+ if ! s . IsRecording () {
846
788
return
847
789
}
848
790
849
791
s .mu .Lock ()
850
792
defer s .mu .Unlock ()
851
- if ! s .isRecording () {
852
- return
853
- }
854
793
s .childSpanCount ++
855
794
}
856
795
0 commit comments