11use std:: collections:: { HashMap , HashSet } ;
22
3- use chrono:: DateTime ;
43use serde:: ser:: { SerializeSeq , Serializer } ;
54use serde:: Serialize ;
65
6+ use super :: counter:: Counter ;
7+ use super :: gauge:: Gauge ;
78use super :: label_set:: LabelSet ;
9+ use super :: metric:: Metric ;
810use super :: MetricName ;
11+ use crate :: metrics:: sample_collection:: SampleCollection ;
912use crate :: DurationSinceUnixEpoch ;
1013
1114#[ derive( Debug , Clone , Default , PartialEq ) ]
@@ -217,160 +220,12 @@ impl MetricKindCollection<Gauge> {
217220 }
218221}
219222
220- #[ derive( Debug , Clone , Default , PartialEq ) ]
221- pub struct Metric < T > {
222- pub name : MetricName ,
223- pub samples : SampleCollection < T > ,
224- }
225-
226- impl < T : Serialize > Serialize for SampleCollection < T > {
227- fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
228- where
229- S : Serializer ,
230- {
231- let samples: Vec < & Sample < T > > = self . samples . values ( ) . collect ( ) ;
232- samples. serialize ( serializer)
233- }
234- }
235-
236- #[ derive( Debug , Clone , Default , PartialEq ) ]
237- pub struct SampleCollection < T > {
238- samples : HashMap < LabelSet , Sample < T > > ,
239- }
240-
241- impl < T > SampleCollection < T > {
242- /// # Panics
243- ///
244- /// Panics if there are duplicate `LabelSets` in the provided samples.
245- #[ must_use]
246- pub fn new ( samples : Vec < Sample < T > > ) -> Self {
247- let mut map = HashMap :: with_capacity ( samples. len ( ) ) ;
248- for sample in samples {
249- assert ! (
250- map. insert( sample. labels( ) . clone( ) , sample) . is_none( ) ,
251- "Duplicate LabelSet found in SampleCollection"
252- ) ;
253- }
254- Self { samples : map }
255- }
256-
257- #[ must_use]
258- pub fn get ( & self , label : & LabelSet ) -> Option < & Sample < T > > {
259- self . samples . get ( label)
260- }
261-
262- #[ must_use]
263- pub fn get_mut ( & mut self , label : & LabelSet ) -> Option < & mut Sample < T > > {
264- self . samples . get_mut ( label)
265- }
266- }
267-
268- #[ derive( Debug , Clone , Serialize , PartialEq ) ]
269- pub struct Sample < T > {
270- value : T ,
271-
272- #[ serde( serialize_with = "serialize_duration" ) ]
273- update_at : DurationSinceUnixEpoch ,
274-
275- labels : LabelSet ,
276- }
277-
278- impl < T > Sample < T > {
279- #[ must_use]
280- pub fn new ( value : T , update_at : DurationSinceUnixEpoch , labels : LabelSet ) -> Self {
281- Self {
282- value,
283- update_at,
284- labels,
285- }
286- }
287-
288- #[ must_use]
289- pub fn labels ( & self ) -> & LabelSet {
290- & self . labels
291- }
292-
293- #[ must_use]
294- pub fn value ( & self ) -> & T {
295- & self . value
296- }
297-
298- pub fn value_mut ( & mut self ) -> & mut T {
299- & mut self . value
300- }
301-
302- #[ must_use]
303- pub fn update_at ( & self ) -> DurationSinceUnixEpoch {
304- self . update_at
305- }
306-
307- pub fn set_update_at ( & mut self , time : DurationSinceUnixEpoch ) {
308- self . update_at = time;
309- }
310- }
311-
312- /// Serializes the `update_at` field as a string in ISO 8601 format (RFC 3339).
313- ///
314- /// # Errors
315- ///
316- /// Returns an error if:
317- /// - The conversion from `u64` to `i64` fails.
318- /// - The timestamp is invalid.
319- fn serialize_duration < S > ( duration : & DurationSinceUnixEpoch , serializer : S ) -> Result < S :: Ok , S :: Error >
320- where
321- S : Serializer ,
322- {
323- let secs = i64:: try_from ( duration. as_secs ( ) ) . map_err ( |_| serde:: ser:: Error :: custom ( "Timestamp too large" ) ) ?;
324- let nanos = duration. subsec_nanos ( ) ;
325-
326- let datetime = DateTime :: from_timestamp ( secs, nanos) . ok_or_else ( || serde:: ser:: Error :: custom ( "Invalid timestamp" ) ) ?;
327-
328- serializer. serialize_str ( & datetime. to_rfc3339 ( ) ) // Serializes as ISO 8601 (RFC 3339)
329- }
330-
331- #[ derive( Debug , Clone , Serialize , Default , PartialEq ) ]
332- pub struct Counter ( u64 ) ;
333-
334- impl Counter {
335- #[ must_use]
336- pub fn new ( value : u64 ) -> Self {
337- Self ( value)
338- }
339-
340- #[ must_use]
341- pub fn value ( & self ) -> u64 {
342- self . 0
343- }
344-
345- pub fn increment ( & mut self , value : u64 ) {
346- self . 0 += value;
347- }
348- }
349-
350- #[ derive( Debug , Clone , Serialize , Default , PartialEq ) ]
351- pub struct Gauge ( f64 ) ;
352-
353- impl Gauge {
354- #[ must_use]
355- pub fn new ( value : f64 ) -> Self {
356- Self ( value)
357- }
358-
359- #[ must_use]
360- pub fn value ( & self ) -> f64 {
361- self . 0
362- }
363-
364- pub fn set ( & mut self , value : f64 ) {
365- self . 0 = value;
366- }
367- }
368-
369223#[ cfg( test) ]
370224mod tests {
371225 use pretty_assertions:: assert_eq;
372226
373227 use super :: * ;
228+ use crate :: metrics:: sample:: Sample ;
374229 use crate :: metrics:: { LabelName , LabelValue } ;
375230
376231 #[ test]
@@ -381,11 +236,7 @@ mod tests {
381236 let mut metric_collection = MetricCollection {
382237 counters : MetricKindCollection :: new ( vec ! [ Metric {
383238 name: MetricName :: new( "test_counter" ) ,
384- samples: SampleCollection :: new( vec![ Sample {
385- value: Counter :: new( 0 ) ,
386- update_at: time,
387- labels: label_set. clone( ) ,
388- } ] ) ,
239+ samples: SampleCollection :: new( vec![ Sample :: new( Counter :: new( 0 ) , time, label_set. clone( ) ) ] ) ,
389240 } ] ) ,
390241 gauges : MetricKindCollection :: new ( vec ! [ ] ) ,
391242 } ;
@@ -401,7 +252,7 @@ mod tests {
401252
402253 #[ test]
403254 #[ should_panic( expected = "Metric names must be unique across counters and gauges" ) ]
404- fn test_duplicate_names_across_types ( ) {
255+ fn it_should_not_allow_duplicate_names_across_types ( ) {
405256 let counter = MetricKindCollection :: new ( vec ! [ Metric {
406257 name: MetricName :: new( "test_metric" ) ,
407258 samples: SampleCollection :: new( vec![ ] ) ,
@@ -428,11 +279,7 @@ mod tests {
428279 let metric_collection = MetricCollection :: new (
429280 MetricKindCollection :: new ( vec ! [ Metric {
430281 name: MetricName :: new( "announce_requests_received_total" ) ,
431- samples: SampleCollection :: new( vec![ Sample {
432- value: Counter :: new( 1 ) , // Initialize with 1 to match the test expectation
433- update_at: time,
434- labels: label_set. clone( ) ,
435- } ] ) ,
282+ samples: SampleCollection :: new( vec![ Sample :: new( Counter :: new( 1 ) , time, label_set. clone( ) ) ] ) ,
436283 } ] ) ,
437284 MetricKindCollection :: new ( vec ! [ ] ) ,
438285 ) ;
@@ -487,11 +334,7 @@ mod tests {
487334 let metric_collection = MetricCollection :: new (
488335 MetricKindCollection :: new ( vec ! [ Metric {
489336 name: MetricName :: new( "announce_requests_received_total" ) ,
490- samples: SampleCollection :: new( vec![ Sample {
491- value: Counter :: new( 1 ) ,
492- update_at: time,
493- labels: label_set. clone( ) ,
494- } ] ) ,
337+ samples: SampleCollection :: new( vec![ Sample :: new( Counter :: new( 1 ) , time, label_set. clone( ) ) ] ) ,
495338 } ] ) ,
496339 MetricKindCollection :: new ( vec ! [ ] ) ,
497340 ) ;
@@ -502,17 +345,4 @@ mod tests {
502345
503346 assert_eq ! ( prometheus_output, expected) ;
504347 }
505-
506- #[ test]
507- fn test_counter ( ) {
508- let counter = Counter :: new ( 42 ) ;
509- assert_eq ! ( counter. value( ) , 42 ) ;
510- }
511-
512- #[ test]
513- #[ allow( clippy:: float_cmp) ]
514- fn test_gauge ( ) {
515- let gauge = Gauge :: new ( 3.35 ) ;
516- assert_eq ! ( gauge. value( ) , 3.35 ) ;
517- }
518348}
0 commit comments