Skip to content

Commit 473720d

Browse files
committed
Add native histograms
Signed-off-by: Shivanth <[email protected]>
1 parent 9c67f61 commit 473720d

File tree

2 files changed

+669
-0
lines changed

2 files changed

+669
-0
lines changed

prometheus/histogram.go

+126
Original file line numberDiff line numberDiff line change
@@ -1835,3 +1835,129 @@ func (n *nativeExemplars) addExemplar(e *dto.Exemplar) {
18351835
n.exemplars = append(n.exemplars[:nIdx], append([]*dto.Exemplar{e}, append(n.exemplars[nIdx:rIdx], n.exemplars[rIdx+1:]...)...)...)
18361836
}
18371837
}
1838+
1839+
type constNativeHistogram struct {
1840+
desc *Desc
1841+
count uint64
1842+
sum float64
1843+
labelPairs []*dto.LabelPair
1844+
nativeHistogramSchema int32
1845+
nativeHistogramZeroThreshold float64
1846+
nativeHistogramMaxZeroThreshold float64
1847+
nativeHistogramMaxBuckets uint32
1848+
nativeHistogramMinResetDuration time.Duration
1849+
timeStamp time.Time
1850+
nativeExemplars []*dto.Exemplar
1851+
1852+
positiveBuckets map[int]int64
1853+
negativeBuckets map[int]int64
1854+
zeroBucket uint64
1855+
}
1856+
1857+
func NewconstNativeHistogram(desc *Desc, count uint64, sum float64, postiveBuckets, negativeBuckets map[int]int64, zeroBucket uint64,
1858+
labelPairs []*dto.LabelPair, nativeHistogramSchema int32, nativeHistogramZeroThreshold float64,
1859+
nativeHistogramMaxZeroThreshold float64, nativeHistogramMaxBuckets uint32,
1860+
nativeHistogramMinResetDuration time.Duration,
1861+
timeStamp time.Time,
1862+
nativeExemplars []*dto.Exemplar,
1863+
) constNativeHistogram {
1864+
return constNativeHistogram{
1865+
desc: desc,
1866+
count: count,
1867+
sum: sum,
1868+
positiveBuckets: postiveBuckets,
1869+
negativeBuckets: negativeBuckets,
1870+
zeroBucket: zeroBucket,
1871+
labelPairs: labelPairs,
1872+
nativeHistogramSchema: nativeHistogramSchema,
1873+
nativeHistogramZeroThreshold: nativeHistogramZeroThreshold,
1874+
nativeHistogramMaxZeroThreshold: nativeHistogramMaxZeroThreshold,
1875+
nativeHistogramMaxBuckets: nativeHistogramMaxBuckets,
1876+
nativeHistogramMinResetDuration: nativeHistogramMinResetDuration,
1877+
timeStamp: timeStamp,
1878+
nativeExemplars: nativeExemplars,
1879+
}
1880+
}
1881+
1882+
func (h *constNativeHistogram) Desc() *Desc {
1883+
return h.desc
1884+
}
1885+
1886+
func (h *constNativeHistogram) Write(out *dto.Metric) error {
1887+
his := &dto.Histogram{
1888+
CreatedTimestamp: timestamppb.New(h.timeStamp),
1889+
Schema: &h.nativeHistogramSchema,
1890+
ZeroThreshold: &h.nativeHistogramZeroThreshold,
1891+
Exemplars: h.nativeExemplars,
1892+
SampleCount: &h.count,
1893+
SampleSum: &h.sum,
1894+
}
1895+
his.ZeroThreshold = proto.Float64(h.nativeHistogramZeroThreshold)
1896+
his.ZeroCount = proto.Uint64(h.zeroBucket)
1897+
his.NegativeSpan, his.NegativeDelta = makeBucketsAny(h.negativeBuckets)
1898+
his.PositiveSpan, his.PositiveDelta = makeBucketsAny(h.positiveBuckets)
1899+
if *his.ZeroThreshold == 0 && *his.ZeroCount == 0 && len(his.PositiveSpan) == 0 && len(his.NegativeSpan) == 0 {
1900+
his.PositiveSpan = []*dto.BucketSpan{{
1901+
Offset: proto.Int32(0),
1902+
Length: proto.Uint32(0),
1903+
}}
1904+
}
1905+
his.Exemplars = append(his.Exemplars, h.nativeExemplars...)
1906+
out.Histogram = his
1907+
out.Label = h.labelPairs
1908+
return nil
1909+
}
1910+
1911+
func makeBucketsAny(buckets map[int]int64) ([]*dto.BucketSpan, []int64) {
1912+
var ii []int
1913+
1914+
for k := range buckets {
1915+
ii = append(ii, k)
1916+
}
1917+
sort.Ints(ii)
1918+
1919+
if len(ii) == 0 {
1920+
return nil, nil
1921+
}
1922+
1923+
var (
1924+
spans []*dto.BucketSpan
1925+
deltas []int64
1926+
prevCount int64
1927+
nextI int
1928+
)
1929+
1930+
appendDelta := func(count int64) {
1931+
*spans[len(spans)-1].Length++
1932+
deltas = append(deltas, count-prevCount)
1933+
prevCount = count
1934+
}
1935+
1936+
for n, i := range ii {
1937+
count := buckets[i]
1938+
// Multiple spans with only small gaps in between are probably
1939+
// encoded more efficiently as one larger span with a few empty
1940+
// buckets. Needs some research to find the sweet spot. For now,
1941+
// we assume that gaps of one or two buckets should not create
1942+
// a new span.
1943+
iDelta := int32(i - nextI)
1944+
if n == 0 || iDelta > 2 {
1945+
// We have to create a new span, either because we are
1946+
// at the very beginning, or because we have found a gap
1947+
// of more than two buckets.
1948+
spans = append(spans, &dto.BucketSpan{
1949+
Offset: proto.Int32(iDelta),
1950+
Length: proto.Uint32(0),
1951+
})
1952+
} else {
1953+
// We have found a small gap (or no gap at all).
1954+
// Insert empty buckets as needed.
1955+
for j := int32(0); j < iDelta; j++ {
1956+
appendDelta(0)
1957+
}
1958+
}
1959+
appendDelta(count)
1960+
nextI = i + 1
1961+
}
1962+
return spans, deltas
1963+
}

0 commit comments

Comments
 (0)