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