@@ -32,15 +32,30 @@ type Recorder struct {
3232func NewRecorder () * Recorder {
3333 r := & Recorder {}
3434
35- ticker := time .NewTicker (1 * time .Second )
35+ // Create a reference to r that will be captured by the goroutine
36+ recorder := r
37+
3638 go func () {
39+ ticker := time .NewTicker (1 * time .Second )
40+ defer ticker .Stop () // Ensure ticker is stopped when goroutine exits
41+
3742 for range ticker .C {
38- if sensor .Agent ().Ready () {
39- go func () {
40- if err := r .Flush (context .Background ()); err != nil {
41- sensor .logger .Error ("failed to flush the spans: " , err .Error ())
43+ muSensor .Lock ()
44+ agentReady := sensor != nil && sensor .Agent ().Ready ()
45+ muSensor .Unlock ()
46+
47+ if agentReady {
48+ // Create a new reference to recorder for this goroutine to avoid race conditions
49+ r := recorder
50+ go func (rec * Recorder ) {
51+ if err := rec .Flush (context .Background ()); err != nil {
52+ muSensor .Lock ()
53+ if sensor != nil {
54+ sensor .logger .Error ("failed to flush the spans: " , err .Error ())
55+ }
56+ muSensor .Unlock ()
4257 }
43- }()
58+ }(r )
4459 }
4560 }
4661 }()
@@ -59,32 +74,51 @@ func NewTestRecorder() *Recorder {
5974// RecordSpan accepts spans to be recorded and added to the span queue
6075// for eventual reporting to the host agent.
6176func (r * Recorder ) RecordSpan (span * spanS ) {
77+ // Get all sensor-related values under a single lock to minimize contention
78+ muSensor .Lock ()
79+ if sensor == nil {
80+ muSensor .Unlock ()
81+ return
82+ }
83+
84+ agentReady := sensor .Agent ().Ready ()
85+ maxBufferedSpans := sensor .options .MaxBufferedSpans
86+ forceTransmissionAt := sensor .options .ForceTransmissionStartingAt
87+ logger := sensor .logger
88+ muSensor .Unlock ()
89+
6290 // If we're not announced and not in test mode then just
6391 // return
64- if ! r .testMode && ! sensor . Agent (). Ready () {
92+ if ! r .testMode && ! agentReady {
6593 return
6694 }
6795
6896 r .Lock ()
6997 defer r .Unlock ()
7098
71- if len (r .spans ) == sensor . options . MaxBufferedSpans {
99+ if len (r .spans ) == maxBufferedSpans {
72100 r .spans = r .spans [1 :]
73101 }
74102
75103 r .spans = append (r .spans , newSpan (span ))
76104
77- if r .testMode || ! sensor . Agent (). Ready () {
105+ if r .testMode || ! agentReady {
78106 return
79107 }
80108
81- if len (r .spans ) >= sensor .options .ForceTransmissionStartingAt {
82- sensor .logger .Debug ("forcing " , len (r .spans ), "span(s) to the agent" )
83- go func () {
84- if err := r .Flush (context .Background ()); err != nil {
85- sensor .logger .Error ("failed to flush the spans: " , err .Error ())
109+ if len (r .spans ) >= forceTransmissionAt {
110+ logger .Debug ("forcing " , len (r .spans ), "span(s) to the agent" )
111+ // Create a reference to r for this goroutine to avoid race conditions
112+ rec := r
113+ go func (recorder * Recorder ) {
114+ if err := recorder .Flush (context .Background ()); err != nil {
115+ muSensor .Lock ()
116+ if sensor != nil {
117+ sensor .logger .Error ("failed to flush the spans: " , err .Error ())
118+ }
119+ muSensor .Unlock ()
86120 }
87- }()
121+ }(rec )
88122 }
89123}
90124
@@ -118,7 +152,15 @@ func (r *Recorder) Flush(ctx context.Context) error {
118152 return nil
119153 }
120154
121- if err := sensor .Agent ().SendSpans (spansToSend ); err != nil {
155+ muSensor .Lock ()
156+ if sensor == nil {
157+ muSensor .Unlock ()
158+ return nil
159+ }
160+ agent := sensor .Agent ()
161+ muSensor .Unlock ()
162+
163+ if err := agent .SendSpans (spansToSend ); err != nil {
122164 r .Lock ()
123165 defer r .Unlock ()
124166
0 commit comments