@@ -454,14 +454,17 @@ func (s *SummaryData) Metric(desc *prometheus.Desc, labelValues ...string) prome
454
454
return prometheus .MustNewConstSummary (desc , s .sampleCount , s .sampleSum , s .quantiles , labelValues ... )
455
455
}
456
456
457
- // HistogramData keeps data required to build histogram Metric
457
+ // HistogramData keeps data required to build histogram Metric.
458
458
type HistogramData struct {
459
459
sampleCount uint64
460
460
sampleSum float64
461
461
buckets map [float64 ]uint64
462
462
}
463
463
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.
465
468
func (d * HistogramData ) AddHistogram (histo * dto.Histogram ) {
466
469
d .sampleCount += histo .GetSampleCount ()
467
470
d .sampleSum += histo .GetSampleSum ()
@@ -477,7 +480,10 @@ func (d *HistogramData) AddHistogram(histo *dto.Histogram) {
477
480
}
478
481
}
479
482
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.
481
487
func (d * HistogramData ) AddHistogramData (histo HistogramData ) {
482
488
d .sampleCount += histo .sampleCount
483
489
d .sampleSum += histo .sampleSum
@@ -492,12 +498,22 @@ func (d *HistogramData) AddHistogramData(histo HistogramData) {
492
498
}
493
499
}
494
500
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.
496
505
func (d * HistogramData ) Metric (desc * prometheus.Desc , labelValues ... string ) prometheus.Metric {
497
506
return prometheus .MustNewConstHistogram (desc , d .sampleCount , d .sampleSum , d .buckets , labelValues ... )
498
507
}
499
508
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.
501
517
func NewHistogramDataCollector (desc * prometheus.Desc ) * HistogramDataCollector {
502
518
return & HistogramDataCollector {
503
519
desc : desc ,
@@ -522,7 +538,9 @@ func (h *HistogramDataCollector) Collect(out chan<- prometheus.Metric) {
522
538
h .dataMu .RLock ()
523
539
defer h .dataMu .RUnlock ()
524
540
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 )
526
544
}
527
545
528
546
func (h * HistogramDataCollector ) Add (hd HistogramData ) {
0 commit comments