@@ -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