From dca8b24dbd0abb6961db5139f8818bbfb421d71f Mon Sep 17 00:00:00 2001 From: Yingrong Zhao <22300958+VinozzZ@users.noreply.github.com> Date: Tue, 24 Sep 2024 18:55:03 -0400 Subject: [PATCH 1/3] feat: declare metrics before register --- app/app.go | 20 +++++++- cmd/refinery/main.go | 60 +++++++++++++++++++----- collect/cache/cache.go | 18 +++++--- collect/cache/cuckoo.go | 9 ++++ collect/cache/cuckooSentCache.go | 8 +++- collect/cache/kept_reasons_cache.go | 12 +++-- collect/collect.go | 72 +++++++++++++++-------------- collect/stressRelief.go | 14 ++++-- collect/stress_relief_test.go | 6 +-- internal/health/health.go | 8 ++++ internal/peer/file.go | 8 +++- internal/peer/pubsub_redis.go | 12 +++-- metrics/legacy.go | 18 ++++---- metrics/legacy_test.go | 5 +- metrics/metrics.go | 20 +++++++- metrics/metricsnamer.go | 7 ++- metrics/mock.go | 6 ++- metrics/multi_metrics.go | 8 ++-- metrics/multi_metrics_test.go | 15 ++++-- metrics/nullmetrics.go | 20 ++++---- metrics/otel_metrics.go | 55 +++++++++++++++------- metrics/prometheus.go | 28 ++++++----- metrics/prometheus_test.go | 22 +++++++-- pubsub/pubsub_goredis.go | 10 +++- pubsub/pubsub_local.go | 11 ++++- route/route.go | 16 ++++--- sample/deterministic.go | 11 +++-- sample/dynamic.go | 37 ++++----------- sample/dynamic_ema.go | 56 +++++++++------------- sample/ema_throughput.go | 35 ++++---------- sample/rules.go | 23 +++++---- sample/sample.go | 56 ++++++++++++++++++++-- sample/totalthroughput.go | 37 ++++----------- sample/windowed_throughput.go | 37 ++++----------- transmit/transmit.go | 16 +++++-- 35 files changed, 494 insertions(+), 302 deletions(-) diff --git a/app/app.go b/app/app.go index de1ee309a3..e90dc888c4 100644 --- a/app/app.go +++ b/app/app.go @@ -42,8 +42,9 @@ func (a *App) Start() error { } a.Logger.Debug().Logf("Starting up App...") - a.Metrics.Register("config_hash", "gauge") - a.Metrics.Register("rule_config_hash", "gauge") + for _, metric := range configHashMetrics { + a.Metrics.Register(metric) + } a.IncomingRouter.SetVersion(a.Version) a.PeerRouter.SetVersion(a.Version) @@ -64,3 +65,18 @@ func (a *App) Stop() error { a.Logger.Debug().Logf("Shutting down App...") return nil } + +var configHashMetrics = []metrics.Metadata{ + metrics.Metadata{ + Name: "config_hash", + Type: metrics.Gauge, + Unit: "hash", + Description: "The hash of the current configuration", + }, + metrics.Metadata{ + Name: "rule_config_hash", + Type: metrics.Gauge, + Unit: "hash", + Description: "The hash of the current rules configuration", + }, +} diff --git a/cmd/refinery/main.go b/cmd/refinery/main.go index 01f283c319..5240224da1 100644 --- a/cmd/refinery/main.go +++ b/cmd/refinery/main.go @@ -307,18 +307,9 @@ func main() { // these have to be done after the injection (of metrics) // these are the metrics that libhoney will emit; we preregister them so that they always appear - libhoneyMetricsName := map[string]string{ - "queue_length": "gauge", - "queue_overflow": "counter", - "send_errors": "counter", - "send_retries": "counter", - "batches_sent": "counter", - "messages_sent": "counter", - "response_decode_errors": "counter", - } - for name, typ := range libhoneyMetricsName { - upstreamMetricsRecorder.Register(name, typ) - peerMetricsRecorder.Register(name, typ) + for _, metric := range libhoneyMetrics { + upstreamMetricsRecorder.Register(metric) + peerMetricsRecorder.Register(metric) } metricsSingleton.Store("UPSTREAM_BUFFER_SIZE", float64(c.GetUpstreamBufferSize())) @@ -376,3 +367,48 @@ func main() { close(monitorDone) close(sigsToExit) } + +var libhoneyMetrics = []metrics.Metadata{ + metrics.Metadata{ + Name: "queue_length", + Type: metrics.Gauge, + Unit: "count", + Description: "number of events waiting to be sent to destination", + }, + metrics.Metadata{ + Name: "queue_overflow", + Type: metrics.Counter, + Unit: "count", + Description: "number of events dropped due to queue overflow", + }, + metrics.Metadata{ + Name: "send_errors", + Type: metrics.Counter, + Unit: "count", + Description: "number of errors encountered while sending events to destination", + }, + metrics.Metadata{ + Name: "send_retries", + Type: metrics.Counter, + Unit: "count", + Description: "number of times a batch of events was retried", + }, + metrics.Metadata{ + Name: "batches_sent", + Type: metrics.Counter, + Unit: "count", + Description: "number of batches of events sent to destination", + }, + metrics.Metadata{ + Name: "messages_sent", + Type: metrics.Counter, + Unit: "count", + Description: "number of messages sent to destination", + }, + metrics.Metadata{ + Name: "response_decode_errors", + Type: metrics.Counter, + Unit: "count", + Description: "number of errors encountered while decoding responses from destination", + }, +} diff --git a/collect/cache/cache.go b/collect/cache/cache.go index 1c7c3ca12d..ffe042fc06 100644 --- a/collect/cache/cache.go +++ b/collect/cache/cache.go @@ -49,26 +49,30 @@ type DefaultInMemCache struct { const DefaultInMemCacheCapacity = 10000 +var collectCacheMetrics = []metrics.Metadata{ + {Name: "collect_cache_buffer_overrun", Type: metrics.Counter, Unit: "count", Description: "The number of times the trace overwritten in the circular buffer has not yet been sent"}, + {Name: "collect_cache_capacity", Type: metrics.Gauge, Unit: "count", Description: "The number of traces that can be stored in the cache"}, + {Name: "collect_cache_entries", Type: metrics.Histogram, Unit: "count", Description: "The number of traces currently stored in the cache"}, +} + func NewInMemCache( capacity int, - metrics metrics.Metrics, + met metrics.Metrics, logger logger.Logger, ) *DefaultInMemCache { logger.Debug().Logf("Starting DefaultInMemCache") defer func() { logger.Debug().Logf("Finished starting DefaultInMemCache") }() - // buffer_overrun increments when the trace overwritten in the circular - // buffer has not yet been sent - metrics.Register("collect_cache_buffer_overrun", "counter") - metrics.Register("collect_cache_capacity", "gauge") - metrics.Register("collect_cache_entries", "histogram") + for _, metadata := range collectCacheMetrics { + met.Register(metadata) + } if capacity == 0 { capacity = DefaultInMemCacheCapacity } return &DefaultInMemCache{ - Metrics: metrics, + Metrics: met, Logger: logger, cache: make(map[string]*types.Trace, capacity), traceBuffer: make([]*types.Trace, capacity), diff --git a/collect/cache/cuckoo.go b/collect/cache/cuckoo.go index e6c4e4774d..ad12b5b2b7 100644 --- a/collect/cache/cuckoo.go +++ b/collect/cache/cuckoo.go @@ -44,6 +44,12 @@ const ( AddQueueSleepTime = 100 * time.Microsecond ) +var cuckooTraceCheckerMetrics = []metrics.Metadata{ + {Name: CurrentCapacity, Type: metrics.Gauge, Unit: "trace", Description: "current capacity of the cuckoo filter"}, + {Name: FutureLoadFactor, Type: metrics.Gauge, Unit: "percentage", Description: "the fraction of slots occupied in the future cuckoo filter"}, + {Name: CurrentLoadFactor, Type: metrics.Gauge, Unit: "percentage", Description: "the fraction of slots occupied in the current cuckoo filter"}, +} + func NewCuckooTraceChecker(capacity uint, m metrics.Metrics) *CuckooTraceChecker { c := &CuckooTraceChecker{ capacity: capacity, @@ -52,6 +58,9 @@ func NewCuckooTraceChecker(capacity uint, m metrics.Metrics) *CuckooTraceChecker met: m, addch: make(chan string, AddQueueDepth), } + for _, metric := range cuckooTraceCheckerMetrics { + m.Register(metric) + } // To try to avoid blocking on Add, we have a goroutine that pulls from a // channel and adds to the filter. diff --git a/collect/cache/cuckooSentCache.go b/collect/cache/cuckooSentCache.go index df592c261c..1825e6982a 100644 --- a/collect/cache/cuckooSentCache.go +++ b/collect/cache/cuckooSentCache.go @@ -161,6 +161,10 @@ type cuckooSentCache struct { // Make sure it implements TraceSentCache var _ TraceSentCache = (*cuckooSentCache)(nil) +var cuckooSentCacheMetrics = []metrics.Metadata{ + {Name: "cache_recent_dropped_traces", Type: metrics.Gauge, Unit: "traces", Description: "the current size of the most recent dropped trace cache"}, +} + func NewCuckooSentCache(cfg config.SampleCacheConfig, met metrics.Metrics) (TraceSentCache, error) { stc, err := lru.New[string, *keptTraceCacheEntry](int(cfg.KeptSize)) if err != nil { @@ -180,7 +184,9 @@ func NewCuckooSentCache(cfg config.SampleCacheConfig, met metrics.Metrics) (Trac // request. recentDroppedIDs := generics.NewSetWithTTL[string](3 * time.Second) - met.Register("cache_recent_dropped_traces", "gauge") + for _, metric := range cuckooSentCacheMetrics { + met.Register(metric) + } cache := &cuckooSentCache{ met: met, diff --git a/collect/cache/kept_reasons_cache.go b/collect/cache/kept_reasons_cache.go index 69469dfd7d..2e8c69de4c 100644 --- a/collect/cache/kept_reasons_cache.go +++ b/collect/cache/kept_reasons_cache.go @@ -22,12 +22,18 @@ type KeptReasonsCache struct { hashSeed uint64 } +var keptReasonCacheMetrics = []metrics.Metadata{ + {Name: "collect_sent_reasons_cache_entries", Type: metrics.Histogram, Unit: "count", Description: "Number of entries in the sent reasons cache"}, +} + // NewKeptReasonsCache returns a new SentReasonsCache. -func NewKeptReasonsCache(metrics metrics.Metrics) *KeptReasonsCache { - metrics.Register("collect_sent_reasons_cache_entries", "histogram") +func NewKeptReasonsCache(met metrics.Metrics) *KeptReasonsCache { + for _, metric := range keptReasonCacheMetrics { + met.Register(metric) + } return &KeptReasonsCache{ - Metrics: metrics, + Metrics: met, keys: make(map[uint64]uint32), hashSeed: rand.Uint64(), } diff --git a/collect/collect.go b/collect/collect.go index 6c3d31fc3d..3b1b25f77f 100644 --- a/collect/collect.go +++ b/collect/collect.go @@ -95,6 +95,39 @@ type InMemCollector struct { hostname string } +var inMemCollectorMetrics = []metrics.Metadata{ + {Name: "trace_duration_ms", Type: metrics.Histogram}, + {Name: "trace_span_count", Type: metrics.Histogram}, + {Name: "collector_incoming_queue", Type: metrics.Histogram}, + {Name: "collector_peer_queue_length", Type: metrics.Gauge}, + {Name: "collector_incoming_queue_length", Type: metrics.Gauge}, + {Name: "collector_peer_queue", Type: metrics.Histogram}, + {Name: "collector_cache_size", Type: metrics.Gauge}, + {Name: "memory_heap_allocation", Type: metrics.Gauge}, + {Name: "span_received", Type: metrics.Counter}, + {Name: "span_processed", Type: metrics.Counter}, + {Name: "spans_waiting", Type: metrics.UpDown}, + {Name: "trace_sent_cache_hit", Type: metrics.Counter}, + {Name: "trace_accepted", Type: metrics.Counter}, + {Name: "trace_send_kept", Type: metrics.Counter}, + {Name: "trace_send_dropped", Type: metrics.Counter}, + {Name: "trace_send_has_root", Type: metrics.Counter}, + {Name: "trace_send_no_root", Type: metrics.Counter}, + {Name: "trace_forwarded_on_peer_change", Type: metrics.Gauge}, + {Name: "trace_redistribution_count", Type: metrics.Gauge}, + {Name: "trace_send_on_shutdown", Type: metrics.Counter}, + {Name: "trace_forwarded_on_shutdown", Type: metrics.Counter}, + + {Name: TraceSendGotRoot, Type: metrics.Counter}, + {Name: TraceSendExpired, Type: metrics.Counter}, + {Name: TraceSendSpanLimit, Type: metrics.Counter}, + {Name: TraceSendEjectedFull, Type: metrics.Counter}, + {Name: TraceSendEjectedMemsize, Type: metrics.Counter}, + {Name: TraceSendLateSpan, Type: metrics.Counter}, + + {Name: "dropped_from_stress", Type: metrics.Counter}, +} + func (i *InMemCollector) Start() error { i.Logger.Debug().Logf("Starting InMemCollector") defer func() { i.Logger.Debug().Logf("Finished starting InMemCollector") }() @@ -107,39 +140,11 @@ func (i *InMemCollector) Start() error { i.Health.Register(CollectorHealthKey, 3*time.Second) - i.Metrics.Register("trace_duration_ms", "histogram") - i.Metrics.Register("trace_span_count", "histogram") - i.Metrics.Register("collector_incoming_queue", "histogram") - i.Metrics.Register("collector_peer_queue_length", "gauge") - i.Metrics.Register("collector_incoming_queue_length", "gauge") - i.Metrics.Register("collector_peer_queue", "histogram") - i.Metrics.Register("collector_cache_size", "gauge") - i.Metrics.Register("memory_heap_allocation", "gauge") - i.Metrics.Register("span_received", "counter") - i.Metrics.Register("span_processed", "counter") - i.Metrics.Register("spans_waiting", "updown") - i.Metrics.Register("trace_sent_cache_hit", "counter") - i.Metrics.Register("trace_accepted", "counter") - i.Metrics.Register("trace_send_kept", "counter") - i.Metrics.Register("trace_send_dropped", "counter") - i.Metrics.Register("trace_send_has_root", "counter") - i.Metrics.Register("trace_send_no_root", "counter") - i.Metrics.Register("trace_forwarded_on_peer_change", "gauge") - i.Metrics.Register("trace_redistribution_count", "gauge") - i.Metrics.Register("trace_send_on_shutdown", "counter") - i.Metrics.Register("trace_forwarded_on_shutdown", "counter") - - i.Metrics.Register(TraceSendGotRoot, "counter") - i.Metrics.Register(TraceSendExpired, "counter") - i.Metrics.Register(TraceSendSpanLimit, "counter") - i.Metrics.Register(TraceSendEjectedFull, "counter") - i.Metrics.Register(TraceSendEjectedMemsize, "counter") - i.Metrics.Register(TraceSendLateSpan, "counter") + for _, metric := range inMemCollectorMetrics { + i.Metrics.Register(metric) + } sampleCacheConfig := i.Config.GetSampleCacheConfig() - i.Metrics.Register(cache.CurrentCapacity, "gauge") - i.Metrics.Register(cache.FutureLoadFactor, "gauge") - i.Metrics.Register(cache.CurrentLoadFactor, "gauge") var err error i.sampleTraceCache, err = cache.NewCuckooSentCache(sampleCacheConfig, i.Metrics) if err != nil { @@ -1061,7 +1066,7 @@ func (i *InMemCollector) addAdditionalAttributes(sp *types.Span) { } } -func newRedistributeNotifier(logger logger.Logger, metrics metrics.Metrics, clock clockwork.Clock) *redistributeNotifier { +func newRedistributeNotifier(logger logger.Logger, met metrics.Metrics, clock clockwork.Clock) *redistributeNotifier { r := &redistributeNotifier{ initialDelay: 3 * time.Second, maxDelay: 30 * time.Second, @@ -1069,11 +1074,10 @@ func newRedistributeNotifier(logger logger.Logger, metrics metrics.Metrics, cloc done: make(chan struct{}), clock: clock, logger: logger, - metrics: metrics, + metrics: met, triggered: make(chan struct{}), reset: make(chan struct{}), } - r.metrics.Register("trace_redistribution_count", "gauge") return r } diff --git a/collect/stressRelief.go b/collect/stressRelief.go index 893d43b7ba..5c52507c31 100644 --- a/collect/stressRelief.go +++ b/collect/stressRelief.go @@ -107,6 +107,13 @@ type StressRelief struct { const StressReliefHealthKey = "stress_relief" +var stressReliefMetrics = []metrics.Metadata{ + {Name: "cluster_stress_level", Type: metrics.Gauge}, + {Name: "individual_stress_level", Type: metrics.Gauge}, + {Name: "stress_level", Type: metrics.Gauge}, + {Name: "stress_relief_activated", Type: metrics.Gauge}, +} + func (s *StressRelief) Start() error { s.Logger.Debug().Logf("Starting StressRelief system") defer func() { s.Logger.Debug().Logf("Finished starting StressRelief system") }() @@ -115,10 +122,9 @@ func (s *StressRelief) Start() error { s.Health.Register(StressReliefHealthKey, 3*time.Second) // register stress level metrics - s.RefineryMetrics.Register("cluster_stress_level", "gauge") - s.RefineryMetrics.Register("individual_stress_level", "gauge") - s.RefineryMetrics.Register("stress_level", "gauge") - s.RefineryMetrics.Register("stress_relief_activated", "gauge") + for _, m := range stressReliefMetrics { + s.RefineryMetrics.Register(m) + } // We use an algorithms map so that we can name these algorithms, which makes it easier for several things: // - change our mind about which algorithm to use diff --git a/collect/stress_relief_test.go b/collect/stress_relief_test.go index 45b57a9958..709dd56a55 100644 --- a/collect/stress_relief_test.go +++ b/collect/stress_relief_test.go @@ -27,7 +27,7 @@ func TestStressRelief_Monitor(t *testing.T) { defer stop() require.NoError(t, sr.Start()) - sr.RefineryMetrics.Register("collector_incoming_queue_length", "gauge") + sr.RefineryMetrics.Register("collector_incoming_queue_length", "gauge", metrics.Metadata{}) sr.RefineryMetrics.Store("INCOMING_CAP", 1200) @@ -81,7 +81,7 @@ func TestStressRelief_Peer(t *testing.T) { defer stop() require.NoError(t, sr.Start()) - sr.RefineryMetrics.Register("collector_incoming_queue_length", "gauge") + sr.RefineryMetrics.Register("collector_incoming_queue_length", "gauge", metrics.Metadata{}) sr.RefineryMetrics.Store("INCOMING_CAP", 1200) @@ -139,7 +139,7 @@ func TestStressRelief_OverallStressLevel(t *testing.T) { sr.disableStressLevelReport = true sr.Start() - sr.RefineryMetrics.Register("collector_incoming_queue_length", "gauge") + sr.RefineryMetrics.Register("collector_incoming_queue_length", "gauge", metrics.Metadata{}) sr.RefineryMetrics.Store("INCOMING_CAP", 1200) diff --git a/internal/health/health.go b/internal/health/health.go index 96794388b5..7c69a3db18 100644 --- a/internal/health/health.go +++ b/internal/health/health.go @@ -68,6 +68,11 @@ type Health struct { Reporter } +var healthMetrics = []metrics.Metadata{ + {Name: "is_ready", Type: metrics.Gauge, Unit: "bool", Description: "Whether the system is ready to receive traffic"}, + {Name: "is_alive", Type: metrics.Gauge, Unit: "bool", Description: "Whether the system is alive and reporting in"}, +} + func (h *Health) Start() error { // if we don't have a logger or metrics object, we'll use the null ones (makes testing easier) if h.Logger == nil { @@ -76,6 +81,9 @@ func (h *Health) Start() error { if h.Metrics == nil { h.Metrics = &metrics.NullMetrics{} } + for _, metric := range healthMetrics { + h.Metrics.Register(metric) + } h.timeouts = make(map[string]time.Duration) h.timeLeft = make(map[string]time.Duration) h.readies = make(map[string]bool) diff --git a/internal/peer/file.go b/internal/peer/file.go index b995183152..04bd23c955 100644 --- a/internal/peer/file.go +++ b/internal/peer/file.go @@ -45,8 +45,14 @@ func (p *FilePeers) RegisterUpdatedPeersCallback(callback func()) { callback() } +var filePeersMetrics = []metrics.Metadata{ + {Name: "num_file_peers", Type: metrics.Gauge, Unit: "peers", Description: "Number of peers in the file peer list"}, +} + func (p *FilePeers) Start() (err error) { - p.Metrics.Register("num_file_peers", "gauge") + for _, metric := range filePeersMetrics { + p.Metrics.Register(metric) + } p.id, err = p.publicAddr() if err != nil { diff --git a/internal/peer/pubsub_redis.go b/internal/peer/pubsub_redis.go index 99d656b40b..61ed73f04a 100644 --- a/internal/peer/pubsub_redis.go +++ b/internal/peer/pubsub_redis.go @@ -120,6 +120,12 @@ func (p *RedisPubsubPeers) listen(ctx context.Context, msg string) { p.checkHash() } +var redisPubSubPeersMetrics = []metrics.Metadata{ + {Name: "num_peers", Type: metrics.Gauge, Unit: "peers", Description: "the active number of peers in the cluster"}, + {Name: "peer_hash", Type: metrics.Gauge, Unit: "hash", Description: "the hash of the current list of peers"}, + {Name: "peer_messages", Type: metrics.Counter, Unit: "messages", Description: "the number of messages received by the peers service"}, +} + func (p *RedisPubsubPeers) Start() error { if p.PubSub == nil { return errors.New("injected pubsub is nil") @@ -137,9 +143,9 @@ func (p *RedisPubsubPeers) Start() error { p.Logger.Info().Logf("subscribing to pubsub peers channel") p.sub = p.PubSub.Subscribe(context.Background(), "peers", p.listen) - p.Metrics.Register("num_peers", "gauge") - p.Metrics.Register("peer_hash", "gauge") - p.Metrics.Register("peer_messages", "counter") + for _, metric := range redisPubSubPeersMetrics { + p.Metrics.Register(metric) + } myaddr, err := p.publicAddr() if err != nil { diff --git a/metrics/legacy.go b/metrics/legacy.go index 8df829d355..55003921ca 100644 --- a/metrics/legacy.go +++ b/metrics/legacy.go @@ -17,6 +17,8 @@ import ( "github.com/honeycombio/refinery/logger" ) +var _ Metrics = (*LegacyMetrics)(nil) + type LegacyMetrics struct { Config config.Config `inject:""` Logger logger.Logger `inject:""` @@ -304,19 +306,19 @@ func average(vals []float64) float64 { return total / float64(len(vals)) } -func (h *LegacyMetrics) Register(name string, metricType string) { - h.Logger.Debug().Logf("metrics registering %s with name %s", metricType, name) - switch metricType { +func (h *LegacyMetrics) Register(metadata Metadata) { + h.Logger.Debug().Logf("metrics registering %s with name %s", metadata.MetricType, metadata.Name) + switch metadata.MetricType { case "counter": - getOrAdd(&h.lock, name, h.counters, createCounter) + getOrAdd(&h.lock, metadata.Name, h.counters, createCounter) case "gauge": - getOrAdd(&h.lock, name, h.gauges, createGauge) + getOrAdd(&h.lock, metadata.Name, h.gauges, createGauge) case "histogram": - getOrAdd(&h.lock, name, h.histograms, createHistogram) + getOrAdd(&h.lock, metadata.Name, h.histograms, createHistogram) case "updown": - getOrAdd(&h.lock, name, h.updowns, createUpdown) + getOrAdd(&h.lock, metadata.Name, h.updowns, createUpdown) default: - h.Logger.Debug().Logf("unsupported metric type %s", metricType) + h.Logger.Debug().Logf("unsupported metric type %s", metadata.MetricType) } } diff --git a/metrics/legacy_test.go b/metrics/legacy_test.go index 2ccca10971..187067490f 100644 --- a/metrics/legacy_test.go +++ b/metrics/legacy_test.go @@ -133,7 +133,10 @@ func TestMetricsUpdown(t *testing.T) { Logger: &logger.NullLogger{}, } m.Start() - m.Register("foo", "updown") + m.Register(Metadata{ + Name: "foo", + MetricType: "updown", + }) m.Up("foo") m.Up("foo") m.Down("foo") diff --git a/metrics/metrics.go b/metrics/metrics.go index 32fbf83258..4220e53cc8 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -34,7 +34,7 @@ import ( // StressRelief. type Metrics interface { // Register declares a metric; metricType should be one of counter, gauge, histogram, updown - Register(name string, metricType string) + Register(metadata Metadata) Increment(name string) // for counters Gauge(name string, val interface{}) // for gauges Count(name string, n interface{}) // for counters @@ -89,3 +89,21 @@ func PrefixMetricName(prefix string, name string) string { } return name } + +type Metadata struct { + Name string + Type MetricType + // Unit is the unit of the metric, e.g. "bytes", "seconds", "count" + Unit string + // Description is a human-readable description of the metric + Description string +} + +type MetricType int + +const ( + Counter MetricType = iota + Gauge + Histogram + UpDown +) diff --git a/metrics/metricsnamer.go b/metrics/metricsnamer.go index 9cabf5c5dd..7bdb263cde 100644 --- a/metrics/metricsnamer.go +++ b/metrics/metricsnamer.go @@ -1,5 +1,7 @@ package metrics +var _ Metrics = (*MetricsPrefixer)(nil) + // This wraps a Metrics object and is a Metrics object itself, but adds a prefix // to all uses of its name. The point is that we can have a singleton Metrics // object that collects and reports all metrics rather than 3-5 different @@ -24,8 +26,9 @@ func (p *MetricsPrefixer) Start() error { return nil } -func (p *MetricsPrefixer) Register(name string, metricType string) { - p.Metrics.Register(p.prefix+name, metricType) +func (p *MetricsPrefixer) Register(metadata Metadata) { + metadata.Name = p.prefix + metadata.Name + p.Metrics.Register(metadata) } func (p *MetricsPrefixer) Increment(name string) { diff --git a/metrics/mock.go b/metrics/mock.go index 7d73306ed3..ae6b9a520e 100644 --- a/metrics/mock.go +++ b/metrics/mock.go @@ -2,6 +2,8 @@ package metrics import "sync" +var _ Metrics = (*MockMetrics)(nil) + // MockMetrics collects metrics that were registered and changed to allow tests to // verify expected behavior type MockMetrics struct { @@ -25,11 +27,11 @@ func (m *MockMetrics) Start() { m.Constants = make(map[string]float64) } -func (m *MockMetrics) Register(name string, metricType string) { +func (m *MockMetrics) Register(metadata Metadata) { m.lock.Lock() defer m.lock.Unlock() - m.Registrations[name] = metricType + m.Registrations[metadata.Name] = metadata.MetricType } func (m *MockMetrics) Increment(name string) { m.lock.Lock() diff --git a/metrics/multi_metrics.go b/metrics/multi_metrics.go index d773f3f805..3f94c46781 100644 --- a/metrics/multi_metrics.go +++ b/metrics/multi_metrics.go @@ -6,6 +6,8 @@ import ( "github.com/honeycombio/refinery/config" ) +var _ Metrics = (*MultiMetrics)(nil) + // MultiMetrics is a metrics provider that sends metrics to at least one // underlying metrics provider (StoreMetrics). It can be configured to send // metrics to multiple providers at once. @@ -61,13 +63,13 @@ func (m *MultiMetrics) Children() []Metrics { return m.children } -func (m *MultiMetrics) Register(name string, metricType string) { +func (m *MultiMetrics) Register(metadata Metadata) { for _, ch := range m.children { - ch.Register(name, metricType) + ch.Register(metadata) } m.lock.Lock() defer m.lock.Unlock() - m.values[name] = 0 + m.values[metadata.Name] = 0 } func (m *MultiMetrics) Increment(name string) { // for counters diff --git a/metrics/multi_metrics_test.go b/metrics/multi_metrics_test.go index bd3b2ca339..b22b465671 100644 --- a/metrics/multi_metrics_test.go +++ b/metrics/multi_metrics_test.go @@ -71,9 +71,18 @@ func TestMultiMetrics_Register(t *testing.T) { // that are important to StressRelief. mm, err := getAndStartMultiMetrics() assert.NoError(t, err) - mm.Register("updown", "updowncounter") - mm.Register("counter", "counter") - mm.Register("gauge", "gauge") + mm.Register(Metadata{ + Name: "updown", + MetricType: "updowncounter", + }) + mm.Register(Metadata{ + Name: "counter", + MetricType: "counter", + }) + mm.Register(Metadata{ + Name: "gauge", + MetricType: "gauge", + }) mm.Count("counter", 1) mm.Up("updown") diff --git a/metrics/nullmetrics.go b/metrics/nullmetrics.go index 028742f5c6..411b2ac617 100644 --- a/metrics/nullmetrics.go +++ b/metrics/nullmetrics.go @@ -1,17 +1,19 @@ package metrics +var _ Metrics = (*NullMetrics)(nil) + // NullMetrics discards all metrics type NullMetrics struct{} // Start initializes all metrics or resets all metrics to zero func (n *NullMetrics) Start() {} -func (n *NullMetrics) Register(name string, metricType string) {} -func (n *NullMetrics) Increment(name string) {} -func (n *NullMetrics) Gauge(name string, val interface{}) {} -func (n *NullMetrics) Count(name string, val interface{}) {} -func (n *NullMetrics) Histogram(name string, obs interface{}) {} -func (n *NullMetrics) Up(name string) {} -func (n *NullMetrics) Down(name string) {} -func (n *NullMetrics) Store(name string, value float64) {} -func (n *NullMetrics) Get(name string) (float64, bool) { return 0, true } +func (n *NullMetrics) Register(metadata Metadata) {} +func (n *NullMetrics) Increment(name string) {} +func (n *NullMetrics) Gauge(name string, val interface{}) {} +func (n *NullMetrics) Count(name string, val interface{}) {} +func (n *NullMetrics) Histogram(name string, obs interface{}) {} +func (n *NullMetrics) Up(name string) {} +func (n *NullMetrics) Down(name string) {} +func (n *NullMetrics) Store(name string, value float64) {} +func (n *NullMetrics) Get(name string) (float64, bool) { return 0, true } diff --git a/metrics/otel_metrics.go b/metrics/otel_metrics.go index 7688e1ecf0..3bdd7b44e1 100644 --- a/metrics/otel_metrics.go +++ b/metrics/otel_metrics.go @@ -18,6 +18,8 @@ import ( "go.opentelemetry.io/otel/sdk/resource" ) +var _ Metrics = (*OTelMetrics)(nil) + // OTelMetrics sends metrics to Honeycomb using the OpenTelemetry protocol. One // particular thing to note is that OTel metrics treats histograms very // differently than Honeycomb's Legacy metrics. In particular, Legacy metrics @@ -181,18 +183,27 @@ func (o *OTelMetrics) Start() error { return nil } -func (o *OTelMetrics) Register(name string, metricType string) { +// Register creates a new metric with the given metadata +// and initialize it with zero value. +func (o *OTelMetrics) Register(metadata Metadata) { o.lock.Lock() defer o.lock.Unlock() - switch metricType { + ctx := context.Background() + + switch metadata.MetricType { case "counter": - ctr, err := o.meter.Int64Counter(name) + ctr, err := o.meter.Int64Counter(metadata.Name, + metric.WithUnit(metadata.Unit), + metric.WithDescription(metadata.Description), + ) if err != nil { - o.Logger.Error().WithString("name", name).Logf("failed to create counter") + o.Logger.Error().WithString("name", metadata.Name).Logf("failed to create counter") return } - o.counters[name] = ctr + // Give the counter an initial value of 0 so that OTel will send it + ctr.Add(ctx, 0) + o.counters[metadata.Name] = ctr case "gauge": var f metric.Float64Callback = func(_ context.Context, result metric.Float64Observer) error { // this callback is invoked from outside this function call, so we @@ -200,36 +211,48 @@ func (o *OTelMetrics) Register(name string, metricType string) { // Observe() takes, so we make a copy of the value and unlock before // calling Observe. o.lock.RLock() - v := o.values[name] + v := o.values[metadata.Name] o.lock.RUnlock() result.Observe(v) return nil } - g, err := o.meter.Float64ObservableGauge(name, + g, err := o.meter.Float64ObservableGauge(metadata.Name, + metric.WithUnit(metadata.Unit), + metric.WithDescription(metadata.Description), metric.WithFloat64Callback(f), ) if err != nil { - o.Logger.Error().WithString("name", name).Logf("failed to create gauge") + o.Logger.Error().WithString("name", metadata.Name).Logf("failed to create gauge") return } - o.gauges[name] = g + + o.values[metadata.Name] = 0 + o.gauges[metadata.Name] = g case "histogram": - h, err := o.meter.Float64Histogram(name) + h, err := o.meter.Float64Histogram(metadata.Name, + metric.WithUnit(metadata.Unit), + metric.WithDescription(metadata.Description), + ) if err != nil { - o.Logger.Error().WithString("name", name).Logf("failed to create histogram") + o.Logger.Error().WithString("name", metadata.Name).Logf("failed to create histogram") return } - o.histograms[name] = h + h.Record(ctx, 0) + o.histograms[metadata.Name] = h case "updown": - ud, err := o.meter.Int64UpDownCounter(name) + ud, err := o.meter.Int64UpDownCounter(metadata.Name, + metric.WithUnit(metadata.Unit), + metric.WithDescription(metadata.Description), + ) if err != nil { - o.Logger.Error().WithString("name", name).Logf("failed to create updown counter") + o.Logger.Error().WithString("name", metadata.Name).Logf("failed to create updown counter") return } - o.updowns[name] = ud + ud.Add(ctx, 0) + o.updowns[metadata.Name] = ud default: - o.Logger.Error().WithString("type", metricType).Logf("unknown metric type") + o.Logger.Error().WithString("type", metadata.MetricType).Logf("unknown metric type") return } } diff --git a/metrics/prometheus.go b/metrics/prometheus.go index 8b54a11d62..18992643ad 100644 --- a/metrics/prometheus.go +++ b/metrics/prometheus.go @@ -13,6 +13,8 @@ import ( "github.com/honeycombio/refinery/logger" ) +var _ Metrics = (*PromMetrics)(nil) + type PromMetrics struct { Config config.Config `inject:""` Logger logger.Logger `inject:""` @@ -45,40 +47,44 @@ func (p *PromMetrics) Start() error { // Register takes a name and a metric type. The type should be one of "counter", // "gauge", or "histogram" -func (p *PromMetrics) Register(name string, metricType string) { +func (p *PromMetrics) Register(metadata Metadata) { p.lock.Lock() defer p.lock.Unlock() - newmet, exists := p.metrics[name] + newmet, exists := p.metrics[metadata.Name] // don't attempt to add the metric again as this will cause a panic if exists { return } - switch metricType { + help := metadata.Description + if help == "" { + help = metadata.Name + } + switch metadata.MetricType { case "counter": newmet = promauto.NewCounter(prometheus.CounterOpts{ - Name: name, - Help: name, + Name: metadata.Name, + Help: help, }) case "gauge", "updown": // updown is a special gauge newmet = promauto.NewGauge(prometheus.GaugeOpts{ - Name: name, - Help: name, + Name: metadata.Name, + Help: help, }) case "histogram": newmet = promauto.NewHistogram(prometheus.HistogramOpts{ - Name: name, - Help: name, + Name: metadata.Name, + Help: help, // This is an attempt at a usable set of buckets for a wide range of metrics // 16 buckets, first upper bound of 1, each following upper bound is 4x the previous Buckets: prometheus.ExponentialBuckets(1, 4, 16), }) } - p.metrics[name] = newmet - p.values[name] = 0 + p.metrics[metadata.Name] = newmet + p.values[metadata.Name] = 0 } func (p *PromMetrics) Get(name string) (float64, bool) { diff --git a/metrics/prometheus_test.go b/metrics/prometheus_test.go index 6ff27073e7..5a254fbad0 100644 --- a/metrics/prometheus_test.go +++ b/metrics/prometheus_test.go @@ -19,9 +19,15 @@ func TestMultipleRegistrations(t *testing.T) { assert.NoError(t, err) - p.Register("test", "counter") - - p.Register("test", "counter") + p.Register(Metadata{ + Name: "test", + MetricType: "counter", + }) + + p.Register(Metadata{ + Name: "test", + MetricType: "counter", + }) } func TestRaciness(t *testing.T) { @@ -34,14 +40,20 @@ func TestRaciness(t *testing.T) { assert.NoError(t, err) - p.Register("race", "counter") + p.Register(Metadata{ + Name: "race", + MetricType: "counter", + }) // this loop modifying the metric registry and reading it to increment // a counter should not trigger a race condition for i := 0; i < 50; i++ { go func(j int) { metricName := fmt.Sprintf("metric%d", j) - p.Register(metricName, "counter") + p.Register(Metadata{ + Name: metricName, + MetricType: "counter", + }) }(i) go func(j int) { diff --git a/pubsub/pubsub_goredis.go b/pubsub/pubsub_goredis.go index 33a3a471e0..ae47dae90c 100644 --- a/pubsub/pubsub_goredis.go +++ b/pubsub/pubsub_goredis.go @@ -48,6 +48,11 @@ type GoRedisSubscription struct { // Ensure that GoRedisSubscription implements Subscription var _ Subscription = (*GoRedisSubscription)(nil) +var goredisPubSubMetrics = []metrics.Metadata{ + {Name: "redis_pubsub_published", Type: metrics.Counter, Unit: "count", Description: "Number of messages published to Redis PubSub"}, + {Name: "redis_pubsub_received", Type: metrics.Counter, Unit: "count", Description: "Number of messages received from Redis PubSub"}, +} + func (ps *GoRedisPubSub) Start() error { options := new(redis.UniversalOptions) var ( @@ -100,8 +105,9 @@ func (ps *GoRedisPubSub) Start() error { } } - ps.Metrics.Register("redis_pubsub_published", "counter") - ps.Metrics.Register("redis_pubsub_received", "counter") + for _, metric := range goredisPubSubMetrics { + ps.Metrics.Register(metric) + } ps.client = client ps.subs = make([]*GoRedisSubscription, 0) diff --git a/pubsub/pubsub_local.go b/pubsub/pubsub_local.go index ec9012aabf..d8876df43c 100644 --- a/pubsub/pubsub_local.go +++ b/pubsub/pubsub_local.go @@ -31,14 +31,21 @@ type LocalSubscription struct { // Ensure that LocalSubscription implements Subscription var _ Subscription = (*LocalSubscription)(nil) +var localPubSubMetrics = []metrics.Metadata{ + {Name: "local_pubsub_published", Type: metrics.Counter, Unit: "messages", Description: "The total number of messages sent via the local pubsub implementation"}, + {Name: "local_pubsub_received", Type: metrics.Counter, Unit: "messages", Description: "The total number of messages received via the local pubsub implementation"}, +} + // Start initializes the LocalPubSub func (ps *LocalPubSub) Start() error { ps.topics = make(map[string][]*LocalSubscription) if ps.Metrics == nil { ps.Metrics = &metrics.NullMetrics{} } - ps.Metrics.Register("local_pubsub_published", "counter") - ps.Metrics.Register("local_pubsub_received", "counter") + + for _, metric := range localPubSubMetrics { + ps.Metrics.Register(metric) + } return nil } diff --git a/route/route.go b/route/route.go index 249d727917..891823f347 100644 --- a/route/route.go +++ b/route/route.go @@ -121,6 +121,11 @@ func (r *Router) SetVersion(ver string) { r.versionStr = ver } +var routerMetrics = []metrics.Metadata{ + {Name: "_router_proxied", Type: metrics.Counter, Unit: "count", Description: "the number of events proxied to another refinery"}, + {Name: "_router_event", Type: metrics.Counter, Unit: "count", Description: "the number of events received"}, +} + // LnS spins up the Listen and Serve portion of the router. A router is // initialized as being for either incoming traffic from clients or traffic from // a peer. They listen on different addresses so peer traffic can be @@ -145,13 +150,10 @@ func (r *Router) LnS(incomingOrPeer string) { return } - r.Metrics.Register(r.incomingOrPeer+"_router_proxied", "counter") - r.Metrics.Register(r.incomingOrPeer+"_router_event", "counter") - r.Metrics.Register(r.incomingOrPeer+"_router_batch", "counter") - r.Metrics.Register(r.incomingOrPeer+"_router_nonspan", "counter") - r.Metrics.Register(r.incomingOrPeer+"_router_span", "counter") - r.Metrics.Register(r.incomingOrPeer+"_router_peer", "counter") - r.Metrics.Register(r.incomingOrPeer+"_router_dropped", "counter") + for _, metric := range routerMetrics { + metric.Name = r.incomingOrPeer + metric.Name + r.Metrics.Register(metric) + } muxxer := mux.NewRouter() diff --git a/sample/deterministic.go b/sample/deterministic.go index c51500ddfe..4a52d611d1 100644 --- a/sample/deterministic.go +++ b/sample/deterministic.go @@ -29,11 +29,16 @@ func (d *DeterministicSampler) Start() error { d.Logger.Debug().Logf("Starting DeterministicSampler") defer func() { d.Logger.Debug().Logf("Finished starting DeterministicSampler") }() d.sampleRate = d.Config.SampleRate - d.prefix = "deterministic_" + d.prefix = "deterministic" if d.Metrics == nil { d.Metrics = &metrics.NullMetrics{} } + for _, metric := range samplerMetrics { + metric.Name = d.prefix + metric.Name + d.Metrics.Register(metric) + } + // Get the actual upper bound - the largest possible value divided by // the sample rate. In the case where the sample rate is 1, this should // sample every value. @@ -50,9 +55,9 @@ func (d *DeterministicSampler) GetSampleRate(trace *types.Trace) (rate uint, kee v := binary.BigEndian.Uint32(sum[:4]) shouldKeep := v <= d.upperBound if shouldKeep { - d.Metrics.Increment(d.prefix + "num_kept") + d.Metrics.Increment(d.prefix + "_num_kept") } else { - d.Metrics.Increment(d.prefix + "num_dropped") + d.Metrics.Increment(d.prefix + "_num_dropped") } return uint(d.sampleRate), shouldKeep, "deterministic/chance", "" diff --git a/sample/dynamic.go b/sample/dynamic.go index a8a77b1c6d..450700c053 100644 --- a/sample/dynamic.go +++ b/sample/dynamic.go @@ -21,12 +21,12 @@ type DynamicSampler struct { clearFrequency config.Duration maxKeys int prefix string - lastMetrics map[string]int64 key *traceKey keyFields []string - dynsampler dynsampler.Sampler + dynsampler dynsampler.Sampler + metricsRecorder dynsamplerMetricsRecorder } func (d *DynamicSampler) Start() error { @@ -42,9 +42,9 @@ func (d *DynamicSampler) Start() error { if d.maxKeys == 0 { d.maxKeys = 500 } - d.prefix = "dynamic_" d.keyFields = d.Config.GetSamplingFields() + d.prefix = "dynamic" // spin up the actual dynamic sampler d.dynsampler = &dynsampler.AvgSampleRate{ GoalSampleRate: int(d.sampleRate), @@ -53,14 +53,12 @@ func (d *DynamicSampler) Start() error { } d.dynsampler.Start() - // Register statistics this package will produce - d.lastMetrics = d.dynsampler.GetMetrics(d.prefix) - for name := range d.lastMetrics { - d.Metrics.Register(name, getMetricType(name)) + // Register statistics from the dynsampler-go package + d.metricsRecorder = dynsamplerMetricsRecorder{ + met: d.Metrics, + prefix: d.prefix, } - d.Metrics.Register(d.prefix+"num_dropped", "counter") - d.Metrics.Register(d.prefix+"num_kept", "counter") - d.Metrics.Register(d.prefix+"sample_rate", "histogram") + d.metricsRecorder.RegisterMetrics(d.dynsampler) return nil } @@ -80,23 +78,8 @@ func (d *DynamicSampler) GetSampleRate(trace *types.Trace) (rate uint, keep bool "trace_id": trace.TraceID, "span_count": count, }).Logf("got sample rate and decision") - if shouldKeep { - d.Metrics.Increment(d.prefix + "num_kept") - } else { - d.Metrics.Increment(d.prefix + "num_dropped") - } - d.Metrics.Histogram(d.prefix+"sample_rate", float64(rate)) - for name, val := range d.dynsampler.GetMetrics(d.prefix) { - switch getMetricType(name) { - case "counter": - delta := val - d.lastMetrics[name] - d.Metrics.Count(name, delta) - d.lastMetrics[name] = val - case "gauge": - d.Metrics.Gauge(name, val) - } - } - return rate, shouldKeep, "dynamic", key + d.metricsRecorder.RecordMetrics(d.dynsampler, shouldKeep, rate) + return rate, shouldKeep, d.prefix, key } func (d *DynamicSampler) GetKeyFields() []string { diff --git a/sample/dynamic_ema.go b/sample/dynamic_ema.go index ce13e6b2f6..6792308f94 100644 --- a/sample/dynamic_ema.go +++ b/sample/dynamic_ema.go @@ -30,7 +30,8 @@ type EMADynamicSampler struct { key *traceKey keyFields []string - dynsampler dynsampler.Sampler + dynsampler *dynsampler.EMASampleRate + metricsRecorder *dynsamplerMetricsRecorder } func (d *EMADynamicSampler) Start() error { @@ -47,29 +48,32 @@ func (d *EMADynamicSampler) Start() error { if d.maxKeys == 0 { d.maxKeys = 500 } - d.prefix = "emadynamic_" + d.prefix = "emadynamic" d.keyFields = d.Config.GetSamplingFields() // spin up the actual dynamic sampler - d.dynsampler = &dynsampler.EMASampleRate{ - GoalSampleRate: d.goalSampleRate, - AdjustmentIntervalDuration: time.Duration(d.adjustmentInterval), - Weight: d.weight, - AgeOutValue: d.ageOutValue, - BurstDetectionDelay: d.burstDetectionDelay, - BurstMultiple: d.burstMultiple, - MaxKeys: d.maxKeys, + d.dynsampler = &baseSampler{ + Sampler: &dynsampler.EMASampleRate{ + GoalSampleRate: d.goalSampleRate, + AdjustmentIntervalDuration: time.Duration(d.adjustmentInterval), + Weight: d.weight, + AgeOutValue: d.ageOutValue, + BurstDetectionDelay: d.burstDetectionDelay, + BurstMultiple: d.burstMultiple, + MaxKeys: d.maxKeys, + }, + prefix: d.prefix, + met: d.Metrics, } d.dynsampler.Start() // Register statistics this package will produce - d.lastMetrics = d.dynsampler.GetMetrics(d.prefix) - for name := range d.lastMetrics { - d.Metrics.Register(name, getMetricType(name)) + d.metricsRecorder = &dynsamplerMetricsRecorder{ + prefix: d.prefix, + met: d.Metrics, } - d.Metrics.Register(d.prefix+"num_dropped", "counter") - d.Metrics.Register(d.prefix+"num_kept", "counter") - d.Metrics.Register(d.prefix+"sample_rate", "histogram") + + d.metricsRecorder.RegisterMetrics(d.dynsampler) return nil } @@ -88,23 +92,9 @@ func (d *EMADynamicSampler) GetSampleRate(trace *types.Trace) (rate uint, keep b "trace_id": trace.TraceID, "span_count": count, }).Logf("got sample rate and decision") - if shouldKeep { - d.Metrics.Increment(d.prefix + "num_kept") - } else { - d.Metrics.Increment(d.prefix + "num_dropped") - } - d.Metrics.Histogram(d.prefix+"sample_rate", float64(rate)) - for name, val := range d.dynsampler.GetMetrics(d.prefix) { - switch getMetricType(name) { - case "counter": - delta := val - d.lastMetrics[name] - d.Metrics.Count(name, delta) - d.lastMetrics[name] = val - case "gauge": - d.Metrics.Gauge(name, val) - } - } - return rate, shouldKeep, "emadynamic", key + d.metricsRecorder.RecordMetrics(d.dynsampler, shouldKeep, rate) + + return rate, shouldKeep, d.prefix, key } func (d *EMADynamicSampler) GetKeyFields() []string { diff --git a/sample/ema_throughput.go b/sample/ema_throughput.go index 2814641851..6e6ced77aa 100644 --- a/sample/ema_throughput.go +++ b/sample/ema_throughput.go @@ -28,12 +28,12 @@ type EMAThroughputSampler struct { burstDetectionDelay uint maxKeys int prefix string - lastMetrics map[string]int64 key *traceKey keyFields []string - dynsampler *dynsampler.EMAThroughput + dynsampler *dynsampler.EMAThroughput + metricsRecorder *dynsamplerMetricsRecorder } func (d *EMAThroughputSampler) Start() error { @@ -55,7 +55,7 @@ func (d *EMAThroughputSampler) Start() error { if d.maxKeys == 0 { d.maxKeys = 500 } - d.prefix = "emathroughput_" + d.prefix = "emathroughput" d.keyFields = d.Config.GetSamplingFields() // spin up the actual dynamic sampler @@ -72,13 +72,11 @@ func (d *EMAThroughputSampler) Start() error { d.dynsampler.Start() // Register statistics this package will produce - d.lastMetrics = d.dynsampler.GetMetrics(d.prefix) - for name := range d.lastMetrics { - d.Metrics.Register(name, getMetricType(name)) + d.metricsRecorder = &dynsamplerMetricsRecorder{ + prefix: d.prefix, + met: d.Metrics, } - d.Metrics.Register(d.prefix+"num_dropped", "counter") - d.Metrics.Register(d.prefix+"num_kept", "counter") - d.Metrics.Register(d.prefix+"sample_rate", "histogram") + d.metricsRecorder.RegisterMetrics(d.dynsampler) return nil } @@ -105,23 +103,8 @@ func (d *EMAThroughputSampler) GetSampleRate(trace *types.Trace) (rate uint, kee "trace_id": trace.TraceID, "span_count": count, }).Logf("got sample rate and decision") - if shouldKeep { - d.Metrics.Increment(d.prefix + "num_kept") - } else { - d.Metrics.Increment(d.prefix + "num_dropped") - } - d.Metrics.Histogram(d.prefix+"sample_rate", float64(rate)) - for name, val := range d.dynsampler.GetMetrics(d.prefix) { - switch getMetricType(name) { - case "counter": - delta := val - d.lastMetrics[name] - d.Metrics.Count(name, delta) - d.lastMetrics[name] = val - case "gauge": - d.Metrics.Gauge(name, val) - } - } - return rate, shouldKeep, "emathroughput", key + d.metricsRecorder.RecordMetrics(d.dynsampler, shouldKeep, rate) + return rate, shouldKeep, d.prefix, key } func (d *EMAThroughputSampler) GetKeyFields() []string { diff --git a/sample/rules.go b/sample/rules.go index cd87f8f3a8..db490c41c1 100644 --- a/sample/rules.go +++ b/sample/rules.go @@ -25,15 +25,20 @@ type RulesBasedSampler struct { const RootPrefix = "root." +var ruleBasedSamplerMetrics = []metrics.Metadata{ + {Name: "_num_dropped_by_drop_rule", Type: metrics.Counter, Unit: "count", Description: "Number of traces dropped by the drop rule"}, +} + func (s *RulesBasedSampler) Start() error { s.Logger.Debug().Logf("Starting RulesBasedSampler") defer func() { s.Logger.Debug().Logf("Finished starting RulesBasedSampler") }() - s.prefix = "rulesbased_" + s.prefix = "rulesbased" - s.Metrics.Register(s.prefix+"num_dropped", "counter") - s.Metrics.Register(s.prefix+"num_dropped_by_drop_rule", "counter") - s.Metrics.Register(s.prefix+"num_kept", "counter") - s.Metrics.Register(s.prefix+"sample_rate", "histogram") + ruleBasedSamplerMetrics = append(ruleBasedSamplerMetrics, samplerMetrics...) + for _, metric := range ruleBasedSamplerMetrics { + metric.Name = s.prefix + metric.Name + s.Metrics.Register(metric) + } s.samplers = make(map[string]Sampler) s.keyFields = s.Config.GetSamplingFields() @@ -137,16 +142,16 @@ func (s *RulesBasedSampler) GetSampleRate(trace *types.Trace) (rate uint, keep b rate = uint(rule.SampleRate) keep = !rule.Drop && rule.SampleRate > 0 && rand.Intn(rule.SampleRate) == 0 reason += rule.Name - s.Metrics.Histogram(s.prefix+"sample_rate", float64(rate)) + s.Metrics.Histogram(s.prefix+"_sample_rate", float64(rate)) } if keep { - s.Metrics.Increment(s.prefix + "num_kept") + s.Metrics.Increment(s.prefix + "_num_kept") } else { - s.Metrics.Increment(s.prefix + "num_dropped") + s.Metrics.Increment(s.prefix + "_num_dropped") if rule.Drop { // If we dropped because of an explicit drop rule, then increment that too. - s.Metrics.Increment(s.prefix + "num_dropped_by_drop_rule") + s.Metrics.Increment(s.prefix + "_num_dropped_by_drop_rule") } } logger.WithFields(map[string]interface{}{ diff --git a/sample/sample.go b/sample/sample.go index 0e7d6e9c63..65690af1e8 100644 --- a/sample/sample.go +++ b/sample/sample.go @@ -5,6 +5,7 @@ import ( "os" "strings" + dynsampler "github.com/honeycombio/dynsampler-go" "github.com/honeycombio/refinery/config" "github.com/honeycombio/refinery/internal/peer" "github.com/honeycombio/refinery/logger" @@ -107,9 +108,58 @@ func (s *SamplerFactory) GetSamplerImplementationForKey(samplerKey string, isLeg return sampler } -func getMetricType(name string) string { +var samplerMetrics = []metrics.Metadata{ + {Name: "_num_dropped", Type: metrics.Counter, Unit: "count", Description: "Number of traces dropped by configured sampler"}, + {Name: "_num_kept", Type: metrics.Counter, Unit: "count", Description: "Number of traces kept by configured sampler"}, + {Name: "_sample_rate", Type: metrics.Histogram, Unit: "count", Description: "Sample rate for traces"}, +} + +func getMetricType(name string) metrics.MetricType { if strings.HasSuffix(name, "_count") { - return "counter" + return metrics.Counter + } + return metrics.Gauge +} + +type dynsamplerMetricsRecorder struct { + prefix string + lastMetrics map[string]int64 + met metrics.Metrics +} + +func (d *dynsamplerMetricsRecorder) RegisterMetrics(sampler dynsampler.Sampler) { + // Register statistics this package will produce + d.lastMetrics = sampler.GetMetrics(d.prefix + "_") + for name := range d.lastMetrics { + d.met.Register(metrics.Metadata{ + Name: name, + Type: getMetricType(name), + }) + } + + for _, metric := range samplerMetrics { + metric.Name = d.prefix + metric.Name + d.met.Register(metric) + } + +} + +func (d *dynsamplerMetricsRecorder) RecordMetrics(sampler dynsampler.Sampler, kept bool, rate uint) { + for name, val := range sampler.GetMetrics(d.prefix + "_") { + switch getMetricType(name) { + case metrics.Counter: + delta := val - d.lastMetrics[name] + d.met.Count(name, delta) + d.lastMetrics[name] = val + case metrics.Gauge: + d.met.Gauge(name, val) + } + } + + if kept { + d.met.Increment(d.prefix + "_num_kept") + } else { + d.met.Increment(d.prefix + "_num_dropped") } - return "gauge" + d.met.Histogram(d.prefix+"_sample_rate", float64(rate)) } diff --git a/sample/totalthroughput.go b/sample/totalthroughput.go index b82d5b85c6..bcff0fd1ef 100644 --- a/sample/totalthroughput.go +++ b/sample/totalthroughput.go @@ -23,12 +23,12 @@ type TotalThroughputSampler struct { clearFrequency config.Duration maxKeys int prefix string - lastMetrics map[string]int64 key *traceKey keyFields []string - dynsampler *dynsampler.TotalThroughput + dynsampler *dynsampler.TotalThroughput + metricsRecorder *dynsamplerMetricsRecorder } func (d *TotalThroughputSampler) Start() error { @@ -52,7 +52,7 @@ func (d *TotalThroughputSampler) Start() error { if d.maxKeys == 0 { d.maxKeys = 500 } - d.prefix = "totalthroughput_" + d.prefix = "totalthroughput" d.keyFields = d.Config.GetSamplingFields() // spin up the actual dynamic sampler @@ -64,14 +64,11 @@ func (d *TotalThroughputSampler) Start() error { d.dynsampler.Start() // Register statistics this package will produce - d.lastMetrics = d.dynsampler.GetMetrics(d.prefix) - for name := range d.lastMetrics { - d.Metrics.Register(name, getMetricType(name)) + d.metricsRecorder = &dynsamplerMetricsRecorder{ + prefix: d.prefix, + met: d.Metrics, } - d.Metrics.Register(d.prefix+"num_dropped", "counter") - d.Metrics.Register(d.prefix+"num_kept", "counter") - d.Metrics.Register(d.prefix+"sample_rate", "histogram") - + d.metricsRecorder.RegisterMetrics(d.dynsampler) return nil } @@ -97,23 +94,9 @@ func (d *TotalThroughputSampler) GetSampleRate(trace *types.Trace) (rate uint, k "trace_id": trace.TraceID, "span_count": count, }).Logf("got sample rate and decision") - if shouldKeep { - d.Metrics.Increment(d.prefix + "num_kept") - } else { - d.Metrics.Increment(d.prefix + "num_dropped") - } - d.Metrics.Histogram(d.prefix+"sample_rate", float64(rate)) - for name, val := range d.dynsampler.GetMetrics(d.prefix) { - switch getMetricType(name) { - case "counter": - delta := val - d.lastMetrics[name] - d.Metrics.Count(name, delta) - d.lastMetrics[name] = val - case "gauge": - d.Metrics.Gauge(name, val) - } - } - return rate, shouldKeep, "totalthroughput", key + + d.metricsRecorder.RecordMetrics(d.dynsampler, shouldKeep, rate) + return rate, shouldKeep, d.prefix, key } func (d *TotalThroughputSampler) GetKeyFields() []string { diff --git a/sample/windowed_throughput.go b/sample/windowed_throughput.go index cb8cc8612a..c5b5889be3 100644 --- a/sample/windowed_throughput.go +++ b/sample/windowed_throughput.go @@ -24,12 +24,12 @@ type WindowedThroughputSampler struct { useClusterSize bool maxKeys int prefix string - lastMetrics map[string]int64 key *traceKey keyFields []string - dynsampler *dynsampler.WindowedThroughput + dynsampler *dynsampler.WindowedThroughput + metricsRecorder *dynsamplerMetricsRecorder } func (d *WindowedThroughputSampler) Start() error { @@ -47,7 +47,7 @@ func (d *WindowedThroughputSampler) Start() error { if d.maxKeys == 0 { d.maxKeys = 500 } - d.prefix = "windowedthroughput_" + d.prefix = "windowedthroughput" d.keyFields = d.Config.GetSamplingFields() // spin up the actual dynamic sampler @@ -60,14 +60,11 @@ func (d *WindowedThroughputSampler) Start() error { d.dynsampler.Start() // Register statistics this package will produce - d.lastMetrics = d.dynsampler.GetMetrics(d.prefix) - for name := range d.lastMetrics { - d.Metrics.Register(name, getMetricType(name)) + d.metricsRecorder = &dynsamplerMetricsRecorder{ + prefix: d.prefix, + met: d.Metrics, } - d.Metrics.Register(d.prefix+"num_dropped", "counter") - d.Metrics.Register(d.prefix+"num_kept", "counter") - d.Metrics.Register(d.prefix+"sample_rate", "histogram") - + d.metricsRecorder.RegisterMetrics(d.dynsampler) return nil } @@ -93,23 +90,9 @@ func (d *WindowedThroughputSampler) GetSampleRate(trace *types.Trace) (rate uint "trace_id": trace.TraceID, "span_count": count, }).Logf("got sample rate and decision") - if shouldKeep { - d.Metrics.Increment(d.prefix + "num_kept") - } else { - d.Metrics.Increment(d.prefix + "num_dropped") - } - d.Metrics.Histogram(d.prefix+"sample_rate", float64(rate)) - for name, val := range d.dynsampler.GetMetrics(d.prefix) { - switch getMetricType(name) { - case "counter": - delta := val - d.lastMetrics[name] - d.Metrics.Count(name, delta) - d.lastMetrics[name] = val - case "gauge": - d.Metrics.Gauge(name, val) - } - } - return rate, shouldKeep, "Windowedthroughput", key + d.metricsRecorder.RecordMetrics(d.dynsampler, shouldKeep, rate) + + return rate, shouldKeep, d.prefix, key } func (d *WindowedThroughputSampler) GetKeyFields() []string { return d.keyFields diff --git a/transmit/transmit.go b/transmit/transmit.go index 6a5790646e..a90b0c1d95 100644 --- a/transmit/transmit.go +++ b/transmit/transmit.go @@ -50,6 +50,14 @@ func NewDefaultTransmission(client *libhoney.Client, m metrics.Metrics, name str return &DefaultTransmission{LibhClient: client, Metrics: m, Name: name} } +var transmissionMetrics = []metrics.Metadata{ + {Name: counterEnqueueErrors, Type: metrics.Counter, Unit: "count", Description: "The number of errors encountered when enqueueing events"}, + {Name: counterResponse20x, Type: metrics.Counter, Unit: "count", Description: "The number of successful responses from Honeycomb"}, + {Name: counterResponseErrors, Type: metrics.Counter, Unit: "count", Description: "The number of errors encountered when sending events to Honeycomb"}, + {Name: updownQueuedItems, Type: metrics.UpDown, Unit: "count", Description: "The number of events queued for transmission to Honeycomb"}, + {Name: histogramQueueTime, Type: metrics.Histogram, Unit: "microsecond", Description: "The time spent in the queue before being sent to Honeycomb"}, +} + func (d *DefaultTransmission) Start() error { d.Logger.Debug().Logf("Starting DefaultTransmission: %s type", d.Name) defer func() { d.Logger.Debug().Logf("Finished starting DefaultTransmission: %s type", d.Name) }() @@ -65,11 +73,9 @@ func (d *DefaultTransmission) Start() error { libhoney.UserAgentAddition = "refinery/" + d.Version }) - d.Metrics.Register(counterEnqueueErrors, "counter") - d.Metrics.Register(counterResponse20x, "counter") - d.Metrics.Register(counterResponseErrors, "counter") - d.Metrics.Register(updownQueuedItems, "updown") - d.Metrics.Register(histogramQueueTime, "histogram") + for _, m := range transmissionMetrics { + d.Metrics.Register(m) + } processCtx, canceler := context.WithCancel(context.Background()) d.responseCanceler = canceler From 8f47f6fc46a3f2a0181eeb43e4310e5caf6a9da5 Mon Sep 17 00:00:00 2001 From: Yingrong Zhao <22300958+VinozzZ@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:42:10 -0400 Subject: [PATCH 2/3] fix tests --- collect/stress_relief_test.go | 15 ++++++++++++--- metrics/legacy.go | 14 +++++++------- metrics/legacy_test.go | 4 ++-- metrics/metrics.go | 14 ++++++++++++++ metrics/mock.go | 2 +- metrics/multi_metrics_test.go | 12 ++++++------ metrics/otel_metrics.go | 12 ++++++------ metrics/prometheus.go | 8 ++++---- metrics/prometheus_test.go | 16 ++++++++-------- sample/dynamic_ema.go | 20 ++++++++------------ sample/windowed_throughput_test.go | 2 +- 11 files changed, 69 insertions(+), 50 deletions(-) diff --git a/collect/stress_relief_test.go b/collect/stress_relief_test.go index 709dd56a55..6db1ee848b 100644 --- a/collect/stress_relief_test.go +++ b/collect/stress_relief_test.go @@ -27,7 +27,10 @@ func TestStressRelief_Monitor(t *testing.T) { defer stop() require.NoError(t, sr.Start()) - sr.RefineryMetrics.Register("collector_incoming_queue_length", "gauge", metrics.Metadata{}) + sr.RefineryMetrics.Register(metrics.Metadata{ + Name: "collector_incoming_queue_length", + Type: metrics.Gauge, + }) sr.RefineryMetrics.Store("INCOMING_CAP", 1200) @@ -81,7 +84,10 @@ func TestStressRelief_Peer(t *testing.T) { defer stop() require.NoError(t, sr.Start()) - sr.RefineryMetrics.Register("collector_incoming_queue_length", "gauge", metrics.Metadata{}) + sr.RefineryMetrics.Register(metrics.Metadata{ + Name: "collector_incoming_queue_length", + Type: metrics.Gauge, + }) sr.RefineryMetrics.Store("INCOMING_CAP", 1200) @@ -139,7 +145,10 @@ func TestStressRelief_OverallStressLevel(t *testing.T) { sr.disableStressLevelReport = true sr.Start() - sr.RefineryMetrics.Register("collector_incoming_queue_length", "gauge", metrics.Metadata{}) + sr.RefineryMetrics.Register(metrics.Metadata{ + Name: "collector_incoming_queue_length", + Type: metrics.Gauge, + }) sr.RefineryMetrics.Store("INCOMING_CAP", 1200) diff --git a/metrics/legacy.go b/metrics/legacy.go index 55003921ca..e2bec8cbd2 100644 --- a/metrics/legacy.go +++ b/metrics/legacy.go @@ -307,18 +307,18 @@ func average(vals []float64) float64 { } func (h *LegacyMetrics) Register(metadata Metadata) { - h.Logger.Debug().Logf("metrics registering %s with name %s", metadata.MetricType, metadata.Name) - switch metadata.MetricType { - case "counter": + h.Logger.Debug().Logf("metrics registering %s with name %s", metadata.Type, metadata.Name) + switch metadata.Type { + case Counter: getOrAdd(&h.lock, metadata.Name, h.counters, createCounter) - case "gauge": + case Gauge: getOrAdd(&h.lock, metadata.Name, h.gauges, createGauge) - case "histogram": + case Histogram: getOrAdd(&h.lock, metadata.Name, h.histograms, createHistogram) - case "updown": + case UpDown: getOrAdd(&h.lock, metadata.Name, h.updowns, createUpdown) default: - h.Logger.Debug().Logf("unsupported metric type %s", metadata.MetricType) + h.Logger.Debug().Logf("unsupported metric type %s", metadata.Type) } } diff --git a/metrics/legacy_test.go b/metrics/legacy_test.go index 187067490f..4ae6a47c3e 100644 --- a/metrics/legacy_test.go +++ b/metrics/legacy_test.go @@ -134,8 +134,8 @@ func TestMetricsUpdown(t *testing.T) { } m.Start() m.Register(Metadata{ - Name: "foo", - MetricType: "updown", + Name: "foo", + Type: UpDown, }) m.Up("foo") m.Up("foo") diff --git a/metrics/metrics.go b/metrics/metrics.go index 4220e53cc8..6d46976428 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -101,6 +101,20 @@ type Metadata struct { type MetricType int +func (m MetricType) String() string { + switch m { + case Counter: + return "counter" + case Gauge: + return "gauge" + case Histogram: + return "histogram" + case UpDown: + return "updown" + } + return "unknown" +} + const ( Counter MetricType = iota Gauge diff --git a/metrics/mock.go b/metrics/mock.go index ae6b9a520e..937fe44bb1 100644 --- a/metrics/mock.go +++ b/metrics/mock.go @@ -31,7 +31,7 @@ func (m *MockMetrics) Register(metadata Metadata) { m.lock.Lock() defer m.lock.Unlock() - m.Registrations[metadata.Name] = metadata.MetricType + m.Registrations[metadata.Name] = metadata.Type.String() } func (m *MockMetrics) Increment(name string) { m.lock.Lock() diff --git a/metrics/multi_metrics_test.go b/metrics/multi_metrics_test.go index b22b465671..ef530445cc 100644 --- a/metrics/multi_metrics_test.go +++ b/metrics/multi_metrics_test.go @@ -72,16 +72,16 @@ func TestMultiMetrics_Register(t *testing.T) { mm, err := getAndStartMultiMetrics() assert.NoError(t, err) mm.Register(Metadata{ - Name: "updown", - MetricType: "updowncounter", + Name: "updown", + Type: UpDown, }) mm.Register(Metadata{ - Name: "counter", - MetricType: "counter", + Name: "counter", + Type: Counter, }) mm.Register(Metadata{ - Name: "gauge", - MetricType: "gauge", + Name: "gauge", + Type: Gauge, }) mm.Count("counter", 1) diff --git a/metrics/otel_metrics.go b/metrics/otel_metrics.go index 3bdd7b44e1..e51f86768a 100644 --- a/metrics/otel_metrics.go +++ b/metrics/otel_metrics.go @@ -191,8 +191,8 @@ func (o *OTelMetrics) Register(metadata Metadata) { ctx := context.Background() - switch metadata.MetricType { - case "counter": + switch metadata.Type { + case Counter: ctr, err := o.meter.Int64Counter(metadata.Name, metric.WithUnit(metadata.Unit), metric.WithDescription(metadata.Description), @@ -204,7 +204,7 @@ func (o *OTelMetrics) Register(metadata Metadata) { // Give the counter an initial value of 0 so that OTel will send it ctr.Add(ctx, 0) o.counters[metadata.Name] = ctr - case "gauge": + case Gauge: var f metric.Float64Callback = func(_ context.Context, result metric.Float64Observer) error { // this callback is invoked from outside this function call, so we // need to Rlock when we read the values map. We don't know how long @@ -229,7 +229,7 @@ func (o *OTelMetrics) Register(metadata Metadata) { o.values[metadata.Name] = 0 o.gauges[metadata.Name] = g - case "histogram": + case Histogram: h, err := o.meter.Float64Histogram(metadata.Name, metric.WithUnit(metadata.Unit), metric.WithDescription(metadata.Description), @@ -240,7 +240,7 @@ func (o *OTelMetrics) Register(metadata Metadata) { } h.Record(ctx, 0) o.histograms[metadata.Name] = h - case "updown": + case UpDown: ud, err := o.meter.Int64UpDownCounter(metadata.Name, metric.WithUnit(metadata.Unit), metric.WithDescription(metadata.Description), @@ -252,7 +252,7 @@ func (o *OTelMetrics) Register(metadata Metadata) { ud.Add(ctx, 0) o.updowns[metadata.Name] = ud default: - o.Logger.Error().WithString("type", metadata.MetricType).Logf("unknown metric type") + o.Logger.Error().WithString("type", metadata.Type.String()).Logf("unknown metric type") return } } diff --git a/metrics/prometheus.go b/metrics/prometheus.go index 18992643ad..e0c25725bd 100644 --- a/metrics/prometheus.go +++ b/metrics/prometheus.go @@ -62,18 +62,18 @@ func (p *PromMetrics) Register(metadata Metadata) { if help == "" { help = metadata.Name } - switch metadata.MetricType { - case "counter": + switch metadata.Type { + case Counter: newmet = promauto.NewCounter(prometheus.CounterOpts{ Name: metadata.Name, Help: help, }) - case "gauge", "updown": // updown is a special gauge + case Gauge, UpDown: // updown is a special gauge newmet = promauto.NewGauge(prometheus.GaugeOpts{ Name: metadata.Name, Help: help, }) - case "histogram": + case Histogram: newmet = promauto.NewHistogram(prometheus.HistogramOpts{ Name: metadata.Name, Help: help, diff --git a/metrics/prometheus_test.go b/metrics/prometheus_test.go index 5a254fbad0..eb889e61c0 100644 --- a/metrics/prometheus_test.go +++ b/metrics/prometheus_test.go @@ -20,13 +20,13 @@ func TestMultipleRegistrations(t *testing.T) { assert.NoError(t, err) p.Register(Metadata{ - Name: "test", - MetricType: "counter", + Name: "test", + Type: Counter, }) p.Register(Metadata{ - Name: "test", - MetricType: "counter", + Name: "test", + Type: Counter, }) } @@ -41,8 +41,8 @@ func TestRaciness(t *testing.T) { assert.NoError(t, err) p.Register(Metadata{ - Name: "race", - MetricType: "counter", + Name: "race", + Type: Counter, }) // this loop modifying the metric registry and reading it to increment @@ -51,8 +51,8 @@ func TestRaciness(t *testing.T) { go func(j int) { metricName := fmt.Sprintf("metric%d", j) p.Register(Metadata{ - Name: metricName, - MetricType: "counter", + Name: metricName, + Type: Counter, }) }(i) diff --git a/sample/dynamic_ema.go b/sample/dynamic_ema.go index 6792308f94..a1acf6ccf3 100644 --- a/sample/dynamic_ema.go +++ b/sample/dynamic_ema.go @@ -52,18 +52,14 @@ func (d *EMADynamicSampler) Start() error { d.keyFields = d.Config.GetSamplingFields() // spin up the actual dynamic sampler - d.dynsampler = &baseSampler{ - Sampler: &dynsampler.EMASampleRate{ - GoalSampleRate: d.goalSampleRate, - AdjustmentIntervalDuration: time.Duration(d.adjustmentInterval), - Weight: d.weight, - AgeOutValue: d.ageOutValue, - BurstDetectionDelay: d.burstDetectionDelay, - BurstMultiple: d.burstMultiple, - MaxKeys: d.maxKeys, - }, - prefix: d.prefix, - met: d.Metrics, + d.dynsampler = &dynsampler.EMASampleRate{ + GoalSampleRate: d.goalSampleRate, + AdjustmentIntervalDuration: time.Duration(d.adjustmentInterval), + Weight: d.weight, + AgeOutValue: d.ageOutValue, + BurstDetectionDelay: d.burstDetectionDelay, + BurstMultiple: d.burstMultiple, + MaxKeys: d.maxKeys, } d.dynsampler.Start() diff --git a/sample/windowed_throughput_test.go b/sample/windowed_throughput_test.go index 9fb7d9894b..ec81bb61ad 100644 --- a/sample/windowed_throughput_test.go +++ b/sample/windowed_throughput_test.go @@ -45,7 +45,7 @@ func TestWindowedThroughputAddSampleRateKeyToTrace(t *testing.T) { assert.Len(t, spans, spanCount, "should have the same number of spans as input") assert.Equal(t, uint(1), rate, "sample rate should be 1") - assert.Equal(t, "Windowedthroughput", reason) + assert.Equal(t, "windowedthroughput", reason) assert.Equal(t, "4•,200•,true•,/{slug}/fun•,", key) } From 3ddb0faab82218b816f30e4cdec6dbdb3d407fa4 Mon Sep 17 00:00:00 2001 From: Yingrong Zhao <22300958+VinozzZ@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:36:46 -0400 Subject: [PATCH 3/3] use UCUM units for three more spots --- collect/cache/kept_reasons_cache.go | 2 +- pubsub/pubsub_local.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/collect/cache/kept_reasons_cache.go b/collect/cache/kept_reasons_cache.go index 2e8c69de4c..22fe39f882 100644 --- a/collect/cache/kept_reasons_cache.go +++ b/collect/cache/kept_reasons_cache.go @@ -23,7 +23,7 @@ type KeptReasonsCache struct { } var keptReasonCacheMetrics = []metrics.Metadata{ - {Name: "collect_sent_reasons_cache_entries", Type: metrics.Histogram, Unit: "count", Description: "Number of entries in the sent reasons cache"}, + {Name: "collect_sent_reasons_cache_entries", Type: metrics.Histogram, Unit: metrics.Dimensionless, Description: "Number of entries in the sent reasons cache"}, } // NewKeptReasonsCache returns a new SentReasonsCache. diff --git a/pubsub/pubsub_local.go b/pubsub/pubsub_local.go index d8876df43c..28669facf2 100644 --- a/pubsub/pubsub_local.go +++ b/pubsub/pubsub_local.go @@ -32,8 +32,8 @@ type LocalSubscription struct { var _ Subscription = (*LocalSubscription)(nil) var localPubSubMetrics = []metrics.Metadata{ - {Name: "local_pubsub_published", Type: metrics.Counter, Unit: "messages", Description: "The total number of messages sent via the local pubsub implementation"}, - {Name: "local_pubsub_received", Type: metrics.Counter, Unit: "messages", Description: "The total number of messages received via the local pubsub implementation"}, + {Name: "local_pubsub_published", Type: metrics.Counter, Unit: metrics.Dimensionless, Description: "The total number of messages sent via the local pubsub implementation"}, + {Name: "local_pubsub_received", Type: metrics.Counter, Unit: metrics.Dimensionless, Description: "The total number of messages received via the local pubsub implementation"}, } // Start initializes the LocalPubSub