@@ -5,6 +5,7 @@ use std::{collections::HashMap, sync::Arc};
55use quanta:: Instant ;
66
77use crate :: common:: Matcher ;
8+ use crate :: native_histogram:: { NativeHistogram , NativeHistogramConfig } ;
89
910use metrics_util:: {
1011 storage:: { Histogram , Summary } ,
@@ -32,6 +33,11 @@ pub enum Distribution {
3233 /// requests were faster than 200ms, and 99% of requests were faster than
3334 /// 1000ms, etc.
3435 Summary ( RollingSummary , Arc < Vec < Quantile > > , f64 ) ,
36+ /// A Prometheus native histogram.
37+ ///
38+ /// Uses exponential buckets to efficiently represent histogram data without
39+ /// requiring predefined bucket boundaries.
40+ NativeHistogram ( NativeHistogram ) ,
3541}
3642
3743impl Distribution {
@@ -54,6 +60,12 @@ impl Distribution {
5460 Distribution :: Summary ( RollingSummary :: new ( bucket_count, bucket_duration) , quantiles, 0.0 )
5561 }
5662
63+ /// Creates a native histogram distribution.
64+ pub fn new_native_histogram ( config : NativeHistogramConfig ) -> Distribution {
65+ let hist = NativeHistogram :: new ( config) ;
66+ Distribution :: NativeHistogram ( hist)
67+ }
68+
5769 /// Records the given `samples` in the current distribution.
5870 pub fn record_samples ( & mut self , samples : & [ ( f64 , Instant ) ] ) {
5971 match self {
@@ -66,6 +78,11 @@ impl Distribution {
6678 * sum += * sample;
6779 }
6880 }
81+ Distribution :: NativeHistogram ( hist) => {
82+ for ( sample, _ts) in samples {
83+ hist. observe ( * sample) ;
84+ }
85+ }
6986 }
7087 }
7188}
@@ -78,6 +95,7 @@ pub struct DistributionBuilder {
7895 bucket_duration : Option < Duration > ,
7996 bucket_count : Option < NonZeroU32 > ,
8097 bucket_overrides : Option < Vec < ( Matcher , Vec < f64 > ) > > ,
98+ native_histogram_overrides : Option < Vec < ( Matcher , NativeHistogramConfig ) > > ,
8199}
82100
83101impl DistributionBuilder {
@@ -88,6 +106,7 @@ impl DistributionBuilder {
88106 buckets : Option < Vec < f64 > > ,
89107 bucket_count : Option < NonZeroU32 > ,
90108 bucket_overrides : Option < HashMap < Matcher , Vec < f64 > > > ,
109+ native_histogram_overrides : Option < HashMap < Matcher , NativeHistogramConfig > > ,
91110 ) -> DistributionBuilder {
92111 DistributionBuilder {
93112 quantiles : Arc :: new ( quantiles) ,
@@ -99,11 +118,26 @@ impl DistributionBuilder {
99118 matchers. sort_by ( |a, b| a. 0 . cmp ( & b. 0 ) ) ;
100119 matchers
101120 } ) ,
121+ native_histogram_overrides : native_histogram_overrides. map ( |entries| {
122+ let mut matchers = entries. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
123+ matchers. sort_by ( |a, b| a. 0 . cmp ( & b. 0 ) ) ;
124+ matchers
125+ } ) ,
102126 }
103127 }
104128
105129 /// Returns a distribution for the given metric key.
106130 pub fn get_distribution ( & self , name : & str ) -> Distribution {
131+ // Check for native histogram overrides first (highest priority)
132+ if let Some ( ref overrides) = self . native_histogram_overrides {
133+ for ( matcher, config) in overrides {
134+ if matcher. matches ( name) {
135+ return Distribution :: new_native_histogram ( config. clone ( ) ) ;
136+ }
137+ }
138+ }
139+
140+ // Check for histogram bucket overrides
107141 if let Some ( ref overrides) = self . bucket_overrides {
108142 for ( matcher, buckets) in overrides {
109143 if matcher. matches ( name) {
@@ -112,10 +146,12 @@ impl DistributionBuilder {
112146 }
113147 }
114148
149+ // Check for global histogram buckets
115150 if let Some ( ref buckets) = self . buckets {
116151 return Distribution :: new_histogram ( buckets) ;
117152 }
118153
154+ // Default to summary
119155 let b_duration = self . bucket_duration . map_or ( DEFAULT_SUMMARY_BUCKET_DURATION , |d| d) ;
120156 let b_count = self . bucket_count . map_or ( DEFAULT_SUMMARY_BUCKET_COUNT , |c| c) ;
121157
@@ -124,6 +160,16 @@ impl DistributionBuilder {
124160
125161 /// Returns the distribution type for the given metric key.
126162 pub fn get_distribution_type ( & self , name : & str ) -> & ' static str {
163+ // Check for native histogram overrides first (highest priority)
164+ if let Some ( ref overrides) = self . native_histogram_overrides {
165+ for ( matcher, _) in overrides {
166+ if matcher. matches ( name) {
167+ return "native_histogram" ;
168+ }
169+ }
170+ }
171+
172+ // Check for regular histogram buckets
127173 if self . buckets . is_some ( ) {
128174 return "histogram" ;
129175 }
0 commit comments