@@ -29,6 +29,7 @@ use crate::metrics::exemplar::{CounterWithExemplar, Exemplar, HistogramWithExemp
2929use crate :: metrics:: family:: { Family , MetricConstructor } ;
3030use crate :: metrics:: gauge:: { self , Gauge } ;
3131use crate :: metrics:: histogram:: Histogram ;
32+ use crate :: metrics:: summary:: Summary ;
3233use crate :: metrics:: info:: Info ;
3334use crate :: metrics:: { MetricType , TypedMetric } ;
3435use crate :: registry:: { Registry , Unit } ;
@@ -332,6 +333,23 @@ impl<'a> BucketEncoder<'a> {
332333 } )
333334 }
334335
336+ /// Encode a quantile. Used for the [`Summary`] metric type.
337+ pub fn encode_quantile ( & mut self , quantile : f64 ) -> Result < ValueEncoder , std:: io:: Error > {
338+ if self . opened_curly_brackets {
339+ self . writer . write_all ( b"," ) ?;
340+ } else {
341+ self . writer . write_all ( b"{" ) ?;
342+ }
343+
344+ self . writer . write_all ( b"quantile=\" " ) ?;
345+ quantile. encode ( self . writer ) ?;
346+ self . writer . write_all ( b"\" }" ) ?;
347+
348+ Ok ( ValueEncoder {
349+ writer : self . writer ,
350+ } )
351+ }
352+
335353 /// Signal that the metric type has no bucket.
336354 pub fn no_bucket ( & mut self ) -> Result < ValueEncoder , std:: io:: Error > {
337355 if self . opened_curly_brackets {
@@ -581,6 +599,40 @@ fn encode_histogram_with_maybe_exemplars<S: Encode>(
581599 Ok ( ( ) )
582600}
583601
602+ /////////////////////////////////////////////////////////////////////////////////
603+ // Summary
604+
605+ impl EncodeMetric for Summary {
606+ fn encode ( & self , mut encoder : Encoder ) -> Result < ( ) , std:: io:: Error > {
607+ let ( sum, count, quantiles) = self . get ( ) ;
608+
609+ encoder
610+ . encode_suffix ( "sum" ) ?
611+ . no_bucket ( ) ?
612+ . encode_value ( sum) ?
613+ . no_exemplar ( ) ?;
614+ encoder
615+ . encode_suffix ( "count" ) ?
616+ . no_bucket ( ) ?
617+ . encode_value ( count) ?
618+ . no_exemplar ( ) ?;
619+
620+ for ( _, ( quantile, result) ) in quantiles. iter ( ) . enumerate ( ) {
621+ let mut bucket_encoder = encoder. no_suffix ( ) ?;
622+ let mut value_encoder = bucket_encoder. encode_quantile ( * quantile) ?;
623+ let mut exemplar_encoder = value_encoder. encode_value ( * result) ?;
624+ exemplar_encoder. no_exemplar ( ) ?
625+ }
626+
627+ Result :: Ok ( ( ) )
628+ }
629+
630+ fn metric_type ( & self ) -> MetricType {
631+ Self :: TYPE
632+ }
633+ }
634+
635+
584636/////////////////////////////////////////////////////////////////////////////////
585637// Info
586638
@@ -821,6 +873,30 @@ mod tests {
821873 parse_with_python_client ( String :: from_utf8 ( encoded) . unwrap ( ) ) ;
822874 }
823875
876+ #[ test]
877+ fn encode_summary ( ) {
878+ let mut registry = Registry :: default ( ) ;
879+ let summary = Summary :: new ( 3 , 10 , vec ! [ 0.5 , 0.9 , 0.99 ] , 0.0 ) ;
880+ registry. register ( "my_summary" , "My summary" , summary. clone ( ) ) ;
881+ summary. observe ( 0.10 ) ;
882+ summary. observe ( 0.20 ) ;
883+ summary. observe ( 0.30 ) ;
884+
885+ let mut encoded = Vec :: new ( ) ;
886+
887+ encode ( & mut encoded, & registry) . unwrap ( ) ;
888+
889+ let expected = "# HELP my_summary My summary.\n " . to_owned ( )
890+ + "# TYPE my_summary summary\n "
891+ + "my_summary_sum 0.6000000000000001\n "
892+ + "my_summary_count 3\n "
893+ + "my_summary{quantile=\" 0.5\" } 0.2\n "
894+ + "my_summary{quantile=\" 0.9\" } 0.3\n "
895+ + "my_summary{quantile=\" 0.99\" } 0.3\n "
896+ + "# EOF\n " ;
897+ assert_eq ! ( expected, String :: from_utf8( encoded. clone( ) ) . unwrap( ) ) ;
898+ }
899+
824900 fn parse_with_python_client ( input : String ) {
825901 pyo3:: prepare_freethreaded_python ( ) ;
826902
0 commit comments