diff --git a/metrics/honeycomb.go b/metrics/honeycomb.go index 43a2c6d944..790117e82d 100644 --- a/metrics/honeycomb.go +++ b/metrics/honeycomb.go @@ -138,9 +138,9 @@ func (h *HoneycombMetrics) initLibhoney(mc config.HoneycombMetricsConfig) error h.libhClient.AddDynamicField("memory_inuse", getAlloc) startTime := time.Now() h.libhClient.AddDynamicField("process_uptime_seconds", func() interface{} { - return time.Now().Sub(startTime) / time.Second + return time.Since(startTime) / time.Second }) - go h.reportToHoneycommb(ctx) + go h.reportToHoneycomb(ctx) return nil } @@ -213,7 +213,7 @@ func (h *HoneycombMetrics) readMemStats(mem *runtime.MemStats) { *mem = h.latestMemStats } -func (h *HoneycombMetrics) reportToHoneycommb(ctx context.Context) { +func (h *HoneycombMetrics) reportToHoneycomb(ctx context.Context) { tick := time.NewTicker(time.Duration(h.reportingFreq) * time.Second) for { select { @@ -284,7 +284,7 @@ func (h *HoneycombMetrics) Register(name string, metricType string) { case "histogram": getOrAdd(&h.lock, name, h.histograms, createHistogram) default: - h.Logger.Debug().Logf("unspported metric type %s", metricType) + h.Logger.Debug().Logf("unsupported metric type %s", metricType) } } @@ -308,7 +308,7 @@ func getOrAdd[T *counter | *gauge | *histogram](lock *sync.RWMutex, name string, metric, ok = metrics[name] if !ok { // create new metric using create function and add to map - metric := createMetric(name) + metric = createMetric(name) metrics[name] = metric } lock.Unlock() diff --git a/metrics/honeycomb_test.go b/metrics/honeycomb_test.go new file mode 100644 index 0000000000..3cd8af604c --- /dev/null +++ b/metrics/honeycomb_test.go @@ -0,0 +1,94 @@ +package metrics + +import ( + "sync" + "testing" + + "github.com/stretchr/testify/assert" +) + +// These tests do a concurrency check for the getOrAdd lock semantics, and generally verify that getOrAdd +// is functional under load. +func Test_getOrAdd_counter(t *testing.T) { + var lock *sync.RWMutex = &sync.RWMutex{} + var metrics map[string]*counter = make(map[string]*counter) + + const nthreads = 5 + + wg := sync.WaitGroup{} + + for i := 0; i < nthreads; i++ { + wg.Add(1) + go func() { + for j := 0; j < 1000; j++ { + name := "foo" + var ctr *counter = getOrAdd(lock, name, metrics, createCounter) + ctr.lock.Lock() + ctr.val++ + ctr.lock.Unlock() + } + wg.Done() + }() + } + wg.Wait() + + var ctr *counter = getOrAdd(lock, "foo", metrics, createCounter) + assert.Equal(t, nthreads*1000, ctr.val) +} + +func Test_getOrAdd_gauge(t *testing.T) { + var lock *sync.RWMutex = &sync.RWMutex{} + var metrics map[string]*gauge = make(map[string]*gauge) + + const nthreads = 5 + + wg := sync.WaitGroup{} + + for i := 0; i < nthreads; i++ { + wg.Add(1) + go func() { + for j := 0; j < 1000; j++ { + name := "foo" + var g *gauge = getOrAdd(lock, name, metrics, createGauge) + g.lock.Lock() + g.val++ + g.lock.Unlock() + } + wg.Done() + }() + } + wg.Wait() + + var g *gauge = getOrAdd(lock, "foo", metrics, createGauge) + assert.Equal(t, float64(nthreads*1000), g.val) +} + +func Test_getOrAdd_histogram(t *testing.T) { + var lock *sync.RWMutex = &sync.RWMutex{} + var metrics map[string]*histogram = make(map[string]*histogram) + + const nthreads = 5 + + wg := sync.WaitGroup{} + + for i := 0; i < nthreads; i++ { + wg.Add(1) + go func() { + for j := 0; j < 1000; j++ { + name := "foo" + var h *histogram = getOrAdd(lock, name, metrics, createHistogram) + h.lock.Lock() + if len(h.vals) == 0 { + h.vals = append(h.vals, 0) + } + h.vals[0]++ + h.lock.Unlock() + } + wg.Done() + }() + } + wg.Wait() + + var h *histogram = getOrAdd(lock, "foo", metrics, createHistogram) + assert.Equal(t, float64(nthreads*1000), h.vals[0]) +}