Skip to content

Commit 24f8859

Browse files
add mutex protection for float64Gauge and concurrent test
1 parent f0361cf commit 24f8859

File tree

2 files changed

+25
-0
lines changed

2 files changed

+25
-0
lines changed

pkg/gofr/metrics/register.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type metricsManager struct {
4242
// and otel/metric supports only asynchronous gauge (Float64ObservableGauge).
4343
// And if we use the otel/metric, we would not be able to have support for labels, Hence created a custom type to implement it.
4444
type float64Gauge struct {
45+
mu sync.RWMutex
4546
observations map[attribute.Set]float64
4647
}
4748

@@ -145,6 +146,9 @@ func (m *metricsManager) NewGauge(name, desc string) {
145146
// callbackFunc implements the callback function for the underlying asynchronous gauge
146147
// it observes the current state of all previous set() calls.
147148
func (f *float64Gauge) callbackFunc(_ context.Context, o metric.Float64Observer) error {
149+
f.mu.RLock()
150+
defer f.mu.RUnlock()
151+
148152
for attrs, val := range f.observations {
149153
o.Observe(val, metric.WithAttributeSet(attrs))
150154
}
@@ -242,7 +246,9 @@ func (m *metricsManager) SetGauge(name string, value float64, labels ...string)
242246
}
243247

244248
func (f *float64Gauge) set(val float64, attrs attribute.Set) {
249+
f.mu.Lock()
245250
f.observations[attrs] = val
251+
f.mu.Unlock()
246252
}
247253

248254
// getAttributes validates the given labels and convert them to corresponding otel attributes.

pkg/gofr/metrics/register_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"net/http"
66
"net/http/httptest"
77
"testing"
8+
"sync"
89

910
"github.com/stretchr/testify/assert"
1011

@@ -159,3 +160,21 @@ func Test_NewMetricsManagerLabelHighCardinality(t *testing.T) {
159160

160161
assert.Contains(t, log, `metrics counter-test has high cardinality: 24`, "TEST Failed. high cardinality of metrics")
161162
}
163+
164+
func Test_SetGauge_Concurrent(t *testing.T) {
165+
manager := NewMetricsManager(exporters.Prometheus("test-app", "v1.0.0"),
166+
logging.NewMockLogger(logging.INFO))
167+
168+
manager.NewGauge("conc-gauge", "concurrent gauge test")
169+
170+
var wg sync.WaitGroup
171+
for i := 0; i < 100; i++ {
172+
wg.Add(1)
173+
go func(v int) {
174+
defer wg.Done()
175+
manager.SetGauge("conc-gauge", float64(v))
176+
}(i)
177+
}
178+
179+
wg.Wait()
180+
}

0 commit comments

Comments
 (0)