@@ -226,9 +226,7 @@ impl<S: Clone + std::hash::Hash + Eq, M, C: MetricConstructor<M>> Family<S, M, C
226
226
/// family.get_or_create(&vec![("method".to_owned(), "GET".to_owned())]).inc();
227
227
/// ```
228
228
pub fn get_or_create ( & self , label_set : & S ) -> MappedRwLockReadGuard < M > {
229
- if let Ok ( metric) =
230
- RwLockReadGuard :: try_map ( self . metrics . read ( ) , |metrics| metrics. get ( label_set) )
231
- {
229
+ if let Some ( metric) = self . get ( label_set) {
232
230
return metric;
233
231
}
234
232
@@ -247,6 +245,23 @@ impl<S: Clone + std::hash::Hash + Eq, M, C: MetricConstructor<M>> Family<S, M, C
247
245
} )
248
246
}
249
247
248
+ /// Access a metric with the given label set, returning None if one
249
+ /// does not yet exist.
250
+ ///
251
+ /// ```
252
+ /// # use prometheus_client::metrics::counter::{Atomic, Counter};
253
+ /// # use prometheus_client::metrics::family::Family;
254
+ /// #
255
+ /// let family = Family::<Vec<(String, String)>, Counter>::default();
256
+ ///
257
+ /// if let Some(metric) = family.get(&vec![("method".to_owned(), "GET".to_owned())]) {
258
+ /// metric.inc();
259
+ /// };
260
+ /// ```
261
+ pub fn get ( & self , label_set : & S ) -> Option < MappedRwLockReadGuard < M > > {
262
+ RwLockReadGuard :: try_map ( self . metrics . read ( ) , |metrics| metrics. get ( label_set) ) . ok ( )
263
+ }
264
+
250
265
/// Remove a label set from the metric family.
251
266
///
252
267
/// Returns a bool indicating if a label set was removed or not.
@@ -452,4 +467,47 @@ mod tests {
452
467
. get( )
453
468
) ;
454
469
}
470
+
471
+ #[ test]
472
+ fn test_get ( ) {
473
+ let family = Family :: < Vec < ( String , String ) > , Counter > :: default ( ) ;
474
+
475
+ // Test getting a non-existent metric.
476
+ let non_existent = family. get ( & vec ! [ ( "method" . to_string( ) , "GET" . to_string( ) ) ] ) ;
477
+ assert ! ( non_existent. is_none( ) ) ;
478
+
479
+ // Create a metric.
480
+ family
481
+ . get_or_create ( & vec ! [ ( "method" . to_string( ) , "GET" . to_string( ) ) ] )
482
+ . inc ( ) ;
483
+
484
+ // Test getting an existing metric.
485
+ let existing = family. get ( & vec ! [ ( "method" . to_string( ) , "GET" . to_string( ) ) ] ) ;
486
+ assert ! ( existing. is_some( ) ) ;
487
+ assert_eq ! ( existing. unwrap( ) . get( ) , 1 ) ;
488
+
489
+ // Test getting a different non-existent metric.
490
+ let another_non_existent = family. get ( & vec ! [ ( "method" . to_string( ) , "POST" . to_string( ) ) ] ) ;
491
+ assert ! ( another_non_existent. is_none( ) ) ;
492
+
493
+ // Test modifying the metric through the returned reference.
494
+ if let Some ( metric) = family. get ( & vec ! [ ( "method" . to_string( ) , "GET" . to_string( ) ) ] ) {
495
+ metric. inc ( ) ;
496
+ }
497
+
498
+ // Verify the modification.
499
+ let modified = family. get ( & vec ! [ ( "method" . to_string( ) , "GET" . to_string( ) ) ] ) ;
500
+ assert_eq ! ( modified. unwrap( ) . get( ) , 2 ) ;
501
+
502
+ // Test with a different label set type.
503
+ let string_family = Family :: < String , Counter > :: default ( ) ;
504
+ string_family. get_or_create ( & "test" . to_string ( ) ) . inc ( ) ;
505
+
506
+ let string_metric = string_family. get ( & "test" . to_string ( ) ) ;
507
+ assert ! ( string_metric. is_some( ) ) ;
508
+ assert_eq ! ( string_metric. unwrap( ) . get( ) , 1 ) ;
509
+
510
+ let non_existent_string = string_family. get ( & "non_existent" . to_string ( ) ) ;
511
+ assert ! ( non_existent_string. is_none( ) ) ;
512
+ }
455
513
}
0 commit comments