Skip to content

Commit 718d2b0

Browse files
bborehampstibrany
authored andcommitted
Fixed panic while collecting Prometheus metrics (cortexproject#4483)
`HistogramData.buckets` must be immutable after `HistogramData.Metric()` has been called, so take an extra copy. Signed-off-by: Bryan Boreham <[email protected]> Co-authored-by: Marco Pracucci <[email protected]> Co-authored-by: Peter Štibraný <[email protected]> Signed-off-by: Alvin Lin <[email protected]>
1 parent 66635c3 commit 718d2b0

File tree

2 files changed

+28
-6
lines changed

2 files changed

+28
-6
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@
8282
>>>>>>> Clean up some changelog entries (#4458)
8383
=======
8484
* [BUGFIX] Querier: fixed panic when querying exemplars and using `-distributor.shard-by-all-labels=false`. #4473
85+
<<<<<<< HEAD
8586
>>>>>>> fix querier panics when query exemplars (#4473)
87+
=======
88+
* [BUGFIX] Compactor: fixed panic while collecting Prometheus metrics. #4483
89+
>>>>>>> Fixed panic while collecting Prometheus metrics (#4483)
8690
8791
## 1.10.0 / 2021-08-03
8892

pkg/util/metrics_helper.go

+24-6
Original file line numberDiff line numberDiff line change
@@ -454,14 +454,17 @@ func (s *SummaryData) Metric(desc *prometheus.Desc, labelValues ...string) prome
454454
return prometheus.MustNewConstSummary(desc, s.sampleCount, s.sampleSum, s.quantiles, labelValues...)
455455
}
456456

457-
// HistogramData keeps data required to build histogram Metric
457+
// HistogramData keeps data required to build histogram Metric.
458458
type HistogramData struct {
459459
sampleCount uint64
460460
sampleSum float64
461461
buckets map[float64]uint64
462462
}
463463

464-
// Adds histogram from gathered metrics to this histogram data.
464+
// AddHistogram adds histogram from gathered metrics to this histogram data.
465+
// Do not call this function after Metric() has been invoked, because histogram created by Metric
466+
// is using the buckets map (doesn't make a copy), and it's not allowed to change the buckets
467+
// after they've been passed to a prometheus.Metric.
465468
func (d *HistogramData) AddHistogram(histo *dto.Histogram) {
466469
d.sampleCount += histo.GetSampleCount()
467470
d.sampleSum += histo.GetSampleSum()
@@ -477,7 +480,10 @@ func (d *HistogramData) AddHistogram(histo *dto.Histogram) {
477480
}
478481
}
479482

480-
// Merged another histogram data into this one.
483+
// AddHistogramData merges another histogram data into this one.
484+
// Do not call this function after Metric() has been invoked, because histogram created by Metric
485+
// is using the buckets map (doesn't make a copy), and it's not allowed to change the buckets
486+
// after they've been passed to a prometheus.Metric.
481487
func (d *HistogramData) AddHistogramData(histo HistogramData) {
482488
d.sampleCount += histo.sampleCount
483489
d.sampleSum += histo.sampleSum
@@ -492,12 +498,22 @@ func (d *HistogramData) AddHistogramData(histo HistogramData) {
492498
}
493499
}
494500

495-
// Return prometheus metric from this histogram data.
501+
// Metric returns prometheus metric from this histogram data.
502+
//
503+
// Note that returned metric shares bucket with this HistogramData, so avoid
504+
// doing more modifications to this HistogramData after calling Metric.
496505
func (d *HistogramData) Metric(desc *prometheus.Desc, labelValues ...string) prometheus.Metric {
497506
return prometheus.MustNewConstHistogram(desc, d.sampleCount, d.sampleSum, d.buckets, labelValues...)
498507
}
499508

500-
// Creates new histogram data collector.
509+
// Copy returns a copy of this histogram data.
510+
func (d *HistogramData) Copy() *HistogramData {
511+
cp := &HistogramData{}
512+
cp.AddHistogramData(*d)
513+
return cp
514+
}
515+
516+
// NewHistogramDataCollector creates new histogram data collector.
501517
func NewHistogramDataCollector(desc *prometheus.Desc) *HistogramDataCollector {
502518
return &HistogramDataCollector{
503519
desc: desc,
@@ -522,7 +538,9 @@ func (h *HistogramDataCollector) Collect(out chan<- prometheus.Metric) {
522538
h.dataMu.RLock()
523539
defer h.dataMu.RUnlock()
524540

525-
out <- h.data.Metric(h.desc)
541+
// We must create a copy of the HistogramData data structure before calling Metric()
542+
// to honor its contract.
543+
out <- h.data.Copy().Metric(h.desc)
526544
}
527545

528546
func (h *HistogramDataCollector) Add(hd HistogramData) {

0 commit comments

Comments
 (0)