@@ -472,6 +472,8 @@ type HistogramOpts struct {
472
472
NativeHistogramMaxBucketNumber uint32
473
473
NativeHistogramMinResetDuration time.Duration
474
474
NativeHistogramMaxZeroThreshold float64
475
+ NativeHistogramMaxExemplarCount uint32
476
+ NativeHistogramExemplarTTL time.Duration
475
477
476
478
// now is for testing purposes, by default it's time.Now.
477
479
now func () time.Time
@@ -556,6 +558,7 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
556
558
h .nativeHistogramZeroThreshold = DefNativeHistogramZeroThreshold
557
559
} // Leave h.nativeHistogramZeroThreshold at 0 otherwise.
558
560
h .nativeHistogramSchema = pickSchema (opts .NativeHistogramBucketFactor )
561
+ h .nativeExemplars = newNativeExemplars (opts .NativeHistogramExemplarTTL , opts .NativeHistogramMaxExemplarCount )
559
562
}
560
563
for i , upperBound := range h .upperBounds {
561
564
if i < len (h .upperBounds )- 1 {
@@ -732,6 +735,8 @@ type histogram struct {
732
735
733
736
// afterFunc is for testing purposes, by default it's time.AfterFunc.
734
737
afterFunc func (time.Duration , func ()) * time.Timer
738
+
739
+ nativeExemplars nativeExemplars
735
740
}
736
741
737
742
func (h * histogram ) Desc () * Desc {
@@ -821,6 +826,8 @@ func (h *histogram) Write(out *dto.Metric) error {
821
826
Length : proto .Uint32 (0 ),
822
827
}}
823
828
}
829
+
830
+ his .Exemplars = append (his .Exemplars , h .nativeExemplars .exemplars ... )
824
831
}
825
832
addAndResetCounts (hotCounts , coldCounts )
826
833
return nil
@@ -1102,6 +1109,10 @@ func (h *histogram) updateExemplar(v float64, bucket int, l Labels) {
1102
1109
panic (err )
1103
1110
}
1104
1111
h .exemplars [bucket ].Store (e )
1112
+ doSparse := h .nativeHistogramSchema > math .MinInt32 && ! math .IsNaN (v )
1113
+ if doSparse {
1114
+ h .nativeExemplars .addExemplar (e )
1115
+ }
1105
1116
}
1106
1117
1107
1118
// HistogramVec is a Collector that bundles a set of Histograms that all share the
@@ -1575,3 +1586,58 @@ func addAndResetCounts(hot, cold *histogramCounts) {
1575
1586
atomic .AddUint64 (& hot .nativeHistogramZeroBucket , atomic .LoadUint64 (& cold .nativeHistogramZeroBucket ))
1576
1587
atomic .StoreUint64 (& cold .nativeHistogramZeroBucket , 0 )
1577
1588
}
1589
+
1590
+ type nativeExemplars struct {
1591
+ nativeHistogramExemplarTTL time.Duration
1592
+ nativeHistogramMaxExemplarCount uint32
1593
+
1594
+ exemplars []* dto.Exemplar
1595
+
1596
+ lock sync.Mutex
1597
+ }
1598
+
1599
+ func newNativeExemplars (ttl time.Duration , count uint32 ) nativeExemplars {
1600
+ return nativeExemplars {
1601
+ nativeHistogramExemplarTTL : ttl ,
1602
+ nativeHistogramMaxExemplarCount : count ,
1603
+ exemplars : make ([]* dto.Exemplar , 0 ),
1604
+ lock : sync.Mutex {},
1605
+ }
1606
+ }
1607
+
1608
+ func (n * nativeExemplars ) addExemplar (e * dto.Exemplar ) {
1609
+ n .lock .Lock ()
1610
+ defer n .lock .Unlock ()
1611
+
1612
+ elogarithm := math .Log (e .GetValue ())
1613
+ if len (n .exemplars ) == int (n .nativeHistogramMaxExemplarCount ) {
1614
+ // check if oldestIndex is beyond TTL,
1615
+ // if so, find the oldest exemplar, and nearest exemplar
1616
+ oldestTimestamp := time .Now ()
1617
+ oldestIndex := - 1
1618
+ nearestValue := - 1.0
1619
+ nearestIndex := - 1
1620
+
1621
+ for i , exemplar := range n .exemplars {
1622
+ if exemplar .Timestamp .AsTime ().Before (oldestTimestamp ) {
1623
+ oldestTimestamp = exemplar .Timestamp .AsTime ()
1624
+ oldestIndex = i
1625
+ }
1626
+ logarithm := math .Log (exemplar .GetValue ())
1627
+ if nearestValue == - 1 || math .Abs (elogarithm - logarithm ) < nearestValue {
1628
+ fmt .Printf ("gap: %f" , math .Abs (elogarithm - logarithm ))
1629
+ nearestValue = math .Abs (elogarithm - logarithm )
1630
+ nearestIndex = i
1631
+ }
1632
+ }
1633
+
1634
+ if oldestIndex != - 1 && time .Since (oldestTimestamp ) > n .nativeHistogramExemplarTTL {
1635
+ n .exemplars [oldestIndex ] = e
1636
+ } else {
1637
+ n .exemplars [nearestIndex ] = e
1638
+ }
1639
+ return
1640
+ }
1641
+
1642
+ n .exemplars = append (n .exemplars , e )
1643
+ }
0 commit comments