diff --git a/histogram.go b/histogram.go index bd023d8..47af50c 100644 --- a/histogram.go +++ b/histogram.go @@ -152,10 +152,10 @@ func (h *Histogram) VisitNonZeroBuckets(f func(vmrange string, count uint64)) { // // The returned histogram is safe to use from concurrent goroutines. func NewHistogram(name string) *Histogram { - return defaultSet.NewHistogram(name, false) + return defaultSet.NewHistogram(name) } func NewCompatibleHistogram(name string) *Histogram { - return defaultSet.NewHistogram(name, true) + return defaultSet.NewCompatibleHistogram(name) } // GetOrCreateHistogram returns registered histogram with the given name @@ -173,10 +173,10 @@ func NewCompatibleHistogram(name string) *Histogram { // // Performance tip: prefer NewHistogram instead of GetOrCreateHistogram. func GetOrCreateHistogram(name string) *Histogram { - return defaultSet.GetOrCreateHistogram(name, false) + return defaultSet.GetOrCreateHistogram(name) } func GetOrCreateCompatibleHistogram(name string) *Histogram { - return defaultSet.GetOrCreateHistogram(name, true) + return defaultSet.GetOrCreateCompatibleHistogram(name) } // UpdateDuration updates request duration based on the given startTime. diff --git a/push.go b/push.go index f878408..4215f48 100644 --- a/push.go +++ b/push.go @@ -115,8 +115,8 @@ func InitPushExt(pushURL string, interval time.Duration, extraLabels string, wri pushesTotal := pushMetrics.GetOrCreateCounter(fmt.Sprintf(`metrics_push_total{url=%q}`, pushURLRedacted)) pushErrorsTotal := pushMetrics.GetOrCreateCounter(fmt.Sprintf(`metrics_push_errors_total{url=%q}`, pushURLRedacted)) bytesPushedTotal := pushMetrics.GetOrCreateCounter(fmt.Sprintf(`metrics_push_bytes_pushed_total{url=%q}`, pushURLRedacted)) - pushDuration := pushMetrics.GetOrCreateHistogram(fmt.Sprintf(`metrics_push_duration_seconds{url=%q}`, pushURLRedacted), false) - pushBlockSize := pushMetrics.GetOrCreateHistogram(fmt.Sprintf(`metrics_push_block_size_bytes{url=%q}`, pushURLRedacted), false) + pushDuration := pushMetrics.GetOrCreateHistogram(fmt.Sprintf(`metrics_push_duration_seconds{url=%q}`, pushURLRedacted)) + pushBlockSize := pushMetrics.GetOrCreateHistogram(fmt.Sprintf(`metrics_push_block_size_bytes{url=%q}`, pushURLRedacted)) pushMetrics.GetOrCreateFloatCounter(fmt.Sprintf(`metrics_push_interval_seconds{url=%q}`, pushURLRedacted)).Set(interval.Seconds()) go func() { ticker := time.NewTicker(interval) diff --git a/set.go b/set.go index 6ecbfe2..d7bc371 100644 --- a/set.go +++ b/set.go @@ -65,8 +65,13 @@ func (s *Set) WritePrometheus(w io.Writer) { // - foo{bar="baz",aaa="b"} // // The returned histogram is safe to use from concurrent goroutines. -func (s *Set) NewHistogram(name string, compatible bool) *Histogram { - h := &Histogram{compatible: compatible} +func (s *Set) NewHistogram(name string) *Histogram { + h := &Histogram{} + s.registerMetric(name, h) + return h +} +func (s *Set) NewCompatibleHistogram(name string) *Histogram { + h := &Histogram{compatible: true} s.registerMetric(name, h) return h } @@ -84,7 +89,7 @@ func (s *Set) NewHistogram(name string, compatible bool) *Histogram { // The returned histogram is safe to use from concurrent goroutines. // // Performance tip: prefer NewHistogram instead of GetOrCreateHistogram. -func (s *Set) GetOrCreateHistogram(name string, compatible bool) *Histogram { +func (s *Set) GetOrCreateHistogram(name string) *Histogram { s.mu.Lock() nm := s.m[name] s.mu.Unlock() @@ -95,7 +100,35 @@ func (s *Set) GetOrCreateHistogram(name string, compatible bool) *Histogram { } nmNew := &namedMetric{ name: name, - metric: &Histogram{compatible: compatible}, + metric: &Histogram{}, + } + s.mu.Lock() + nm = s.m[name] + if nm == nil { + nm = nmNew + s.m[name] = nm + s.a = append(s.a, nm) + } + s.mu.Unlock() + } + h, ok := nm.metric.(*Histogram) + if !ok { + panic(fmt.Errorf("BUG: metric %q isn't a Histogram. It is %T", name, nm.metric)) + } + return h +} +func (s *Set) GetOrCreateCompatibleHistogram(name string) *Histogram { + s.mu.Lock() + nm := s.m[name] + s.mu.Unlock() + if nm == nil { + // Slow path - create and register missing histogram. + if err := validateMetric(name); err != nil { + panic(fmt.Errorf("BUG: invalid metric name %q: %s", name, err)) + } + nmNew := &namedMetric{ + name: name, + metric: &Histogram{compatible: true}, } s.mu.Lock() nm = s.m[name] diff --git a/set_test.go b/set_test.go index 4ddba29..66ed07a 100644 --- a/set_test.go +++ b/set_test.go @@ -29,7 +29,7 @@ func TestNewSet(t *testing.T) { if sm == nil { t.Fatalf("NewSummary returned nil") } - h := s.NewHistogram(fmt.Sprintf("histogram_%d", j), false) + h := s.NewHistogram(fmt.Sprintf("histogram_%d", j)) if h == nil { t.Fatalf("NewHistogram returned nil") } @@ -71,7 +71,7 @@ func TestSetUnregisterAllMetrics(t *testing.T) { for i := 0; i < 10; i++ { _ = s.NewCounter(fmt.Sprintf("counter_%d", i)) _ = s.NewSummary(fmt.Sprintf("summary_%d", i)) - _ = s.NewHistogram(fmt.Sprintf("histogram_%d", i), false) + _ = s.NewHistogram(fmt.Sprintf("histogram_%d", i)) _ = s.NewGauge(fmt.Sprintf("gauge_%d", i), func() float64 { return 0 }) expectedMetricsCount += 4 }