From 7be7ae3c9451fd0b5b7989082329afdc0e77837e Mon Sep 17 00:00:00 2001 From: Angith Jayan Date: Thu, 16 Oct 2025 15:41:41 +0530 Subject: [PATCH 1/2] fix: fix race conditions in the lambda_agent.go, logger.go --- lambda_agent.go | 16 +++++++++++++--- logger/logger.go | 18 ++++++++++-------- meter.go | 2 +- recorder.go | 3 ++- sensor.go | 9 ++++++++- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/lambda_agent.go b/lambda_agent.go index 9727caba9..60f704364 100644 --- a/lambda_agent.go +++ b/lambda_agent.go @@ -28,7 +28,7 @@ type lambdaAgent struct { snapshot serverlessSnapshot - mu sync.Mutex + mu sync.RWMutex spanQueue []Span client *http.Client @@ -144,7 +144,11 @@ func (a *lambdaAgent) enqueueSpans(spans []Span) { } func (a *lambdaAgent) sendRequest(req *http.Request) error { - req.Header.Set("X-Instana-Host", a.snapshot.Host) + a.mu.RLock() + host := a.snapshot.Host + a.mu.RUnlock() + + req.Header.Set("X-Instana-Host", host) req.Header.Set("X-Instana-Key", a.Key) req.Header.Set("X-Instana-Time", strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)) @@ -172,7 +176,11 @@ func (a *lambdaAgent) sendRequest(req *http.Request) error { } func (a *lambdaAgent) collectSnapshot(spans []Span) serverlessSnapshot { - if a.snapshot.EntityID != "" { + a.mu.RLock() + entityID := a.snapshot.EntityID + a.mu.RUnlock() + + if entityID != "" { return a.snapshot } @@ -184,10 +192,12 @@ func (a *lambdaAgent) collectSnapshot(spans []Span) serverlessSnapshot { continue } + a.mu.Lock() a.snapshot = serverlessSnapshot{ EntityID: sp.Snapshot.ARN, Host: sp.Snapshot.ARN, } + a.mu.Unlock() a.logger.Debug("collected snapshot") break diff --git a/logger/logger.go b/logger/logger.go index b0696e05f..5e51bd19a 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -9,6 +9,7 @@ import ( "os" "strings" "sync" + "sync/atomic" ) // Valid log levels to be used with (*logger.Logger).SetLevel() @@ -58,7 +59,7 @@ type Logger struct { p Printer mu sync.Mutex - lvl Level + lvl atomic.Uint32 prefix string } @@ -124,10 +125,11 @@ func (l *Logger) SetLevel(level Level) { level = DebugLevel } - l.mu.Lock() - defer l.mu.Unlock() + l.lvl.Store(uint32(level)) +} - l.lvl = level +func (l *Logger) GetLevel() Level { + return Level(l.lvl.Load()) } // SetPrefix sets the label that will be used as a prefix for each log line @@ -140,7 +142,7 @@ func (l *Logger) SetPrefix(prefix string) { // Debug appends a debug message to the log func (l *Logger) Debug(v ...interface{}) { - if l.lvl < DebugLevel { + if l.GetLevel() < DebugLevel { return } @@ -149,7 +151,7 @@ func (l *Logger) Debug(v ...interface{}) { // Info appends an info message to the log func (l *Logger) Info(v ...interface{}) { - if l.lvl < InfoLevel { + if l.GetLevel() < InfoLevel { return } @@ -158,7 +160,7 @@ func (l *Logger) Info(v ...interface{}) { // Warn appends a warning message to the log func (l *Logger) Warn(v ...interface{}) { - if l.lvl < WarnLevel { + if l.GetLevel() < WarnLevel { return } @@ -167,7 +169,7 @@ func (l *Logger) Warn(v ...interface{}) { // Error appends an error message to the log func (l *Logger) Error(v ...interface{}) { - if l.lvl < ErrorLevel { + if l.GetLevel() < ErrorLevel { return } diff --git a/meter.go b/meter.go index 8d41c1c74..bdc87e2ec 100644 --- a/meter.go +++ b/meter.go @@ -43,7 +43,7 @@ func (m *meterS) Run(collectInterval time.Duration) { case <-m.done: return case <-ticker.C: - if sensor.Agent().Ready() { + if isAgentReady() { go func() { _ = sensor.Agent().SendMetrics(m.collectMetrics()) }() diff --git a/recorder.go b/recorder.go index 44db7f6d3..6f294d6e8 100644 --- a/recorder.go +++ b/recorder.go @@ -35,7 +35,8 @@ func NewRecorder() *Recorder { ticker := time.NewTicker(1 * time.Second) go func() { for range ticker.C { - if sensor.Agent().Ready() { + + if isAgentReady() { go func() { if err := r.Flush(context.Background()); err != nil { sensor.logger.Error("failed to flush the spans: ", err.Error()) diff --git a/sensor.go b/sensor.go index c67ab8333..21e88f6c1 100644 --- a/sensor.go +++ b/sensor.go @@ -83,7 +83,7 @@ type sensorS struct { var ( sensor *sensorS - muSensor sync.Mutex + muSensor sync.RWMutex binaryName = filepath.Base(os.Args[0]) processStartedAt = time.Now() c TracerLogger @@ -286,6 +286,13 @@ func ShutdownSensor() { } } +func isAgentReady() bool { + muSensor.RLock() + defer muSensor.RUnlock() + + return sensor.Agent().Ready() +} + // ShutdownCollector cleans up the collector and sensor reference. // It will also reset the singleton as the next time that instana.InitCollector API is called, // collector and sensor will be reinitialized. From 923161d8a2a39554856a83591ff03d83f7c9909f Mon Sep 17 00:00:00 2001 From: Angith Jayan Date: Fri, 17 Oct 2025 12:32:36 +0530 Subject: [PATCH 2/2] fix: fix race conditions in the event.go, meter.go --- event.go | 2 +- meter.go | 2 +- sensor.go | 9 +++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/event.go b/event.go index 8fa4c345a..1ae79ccc6 100644 --- a/event.go +++ b/event.go @@ -80,6 +80,6 @@ func sendEvent(event *EventData) { // we do fire & forget here, because the whole pid dance isn't necessary to send events go func() { - _ = sensor.Agent().SendEvent(event) + _ = safeSensor().Agent().SendEvent(event) }() } diff --git a/meter.go b/meter.go index bdc87e2ec..0291ba287 100644 --- a/meter.go +++ b/meter.go @@ -45,7 +45,7 @@ func (m *meterS) Run(collectInterval time.Duration) { case <-ticker.C: if isAgentReady() { go func() { - _ = sensor.Agent().SendMetrics(m.collectMetrics()) + _ = safeSensor().Agent().SendMetrics(m.collectMetrics()) }() } } diff --git a/sensor.go b/sensor.go index 21e88f6c1..4e2084293 100644 --- a/sensor.go +++ b/sensor.go @@ -157,6 +157,15 @@ func newSensor(options *Options) *sensorS { return s } +// safeSensor safely returns the global sensor instance for concurrent access. +// It acquires a read lock and should only be used for read operations. +// Since the sensor is immutable after initialization, this provides sufficient protection against data races. +func safeSensor() *sensorS { + muSensor.RLock() + defer muSensor.RUnlock() + return sensor +} + func (r *sensorS) setLogger(l LeveledLogger) { r.logger = l