@@ -226,9 +226,7 @@ impl<S: Clone + std::hash::Hash + Eq, M, C: MetricConstructor<M>> Family<S, M, C
226226 /// family.get_or_create(&vec![("method".to_owned(), "GET".to_owned())]).inc();
227227 /// ```
228228 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) {
232230 return metric;
233231 }
234232
@@ -247,6 +245,23 @@ impl<S: Clone + std::hash::Hash + Eq, M, C: MetricConstructor<M>> Family<S, M, C
247245 } )
248246 }
249247
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+
250265 /// Remove a label set from the metric family.
251266 ///
252267 /// Returns a bool indicating if a label set was removed or not.
@@ -452,4 +467,47 @@ mod tests {
452467 . get( )
453468 ) ;
454469 }
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+ }
455513}
0 commit comments