@@ -58,6 +58,7 @@ struct FnAttrs {
5858 doc : String ,
5959 ctor : Option < ExprStruct > ,
6060 optional : bool ,
61+ with_removal : bool ,
6162}
6263
6364struct FnArg {
@@ -300,6 +301,7 @@ fn metric_init(foundations: &Path, fn_: &ItemFn) -> proc_macro2::TokenStream {
300301 doc,
301302 optional,
302303 ctor,
304+ ..
303305 } ,
304306 ident : field_name,
305307 args,
@@ -357,7 +359,13 @@ fn metric_init(foundations: &Path, fn_: &ItemFn) -> proc_macro2::TokenStream {
357359
358360fn metric_fn ( foundations : & Path , metrics_struct : & Ident , fn_ : & ItemFn ) -> proc_macro2:: TokenStream {
359361 let ItemFn {
360- attrs : FnAttrs { cfg, doc, .. } ,
362+ attrs :
363+ FnAttrs {
364+ cfg,
365+ doc,
366+ with_removal,
367+ ..
368+ } ,
361369 fn_token,
362370 vis : fn_vis,
363371 ident : metric_name,
@@ -366,35 +374,77 @@ fn metric_fn(foundations: &Path, metrics_struct: &Ident, fn_: &ItemFn) -> proc_m
366374 ty : metric_type,
367375 } = fn_;
368376
369- let fn_args = args. iter ( ) . map ( |arg| arg. to_arg ( ) ) ;
377+ let fn_args: Vec < _ > = args. iter ( ) . map ( |arg| arg. to_arg ( ) ) . collect ( ) ;
370378
371- let fn_body = if args. is_empty ( ) {
372- quote ! {
379+ let ( convert_args , access_metric ) = if args. is_empty ( ) {
380+ let accessor = quote ! {
373381 :: std:: clone:: Clone :: clone( & #metrics_struct. #metric_name)
374- }
382+ } ;
383+ ( quote ! { } , accessor)
375384 } else {
376385 let label_inits = args. iter ( ) . map ( |arg| arg. to_initializer ( ) ) ;
386+ let convert = quote ! {
387+ let __args = #metric_name {
388+ #( #label_inits, ) *
389+ } ;
390+ } ;
377391
378-
379- quote ! {
392+ let accessor = quote ! {
380393 :: std:: clone:: Clone :: clone(
381394 & #foundations:: reexports_for_macros:: prometools:: serde:: Family :: get_or_create(
382395 & #metrics_struct. #metric_name,
383- & #metric_name {
384- #( #label_inits, ) *
385- } ,
396+ & __args,
386397 )
387398 )
399+ } ;
400+ ( convert, accessor)
401+ } ;
402+
403+ let removal_fns = if cfg ! ( foundations_unstable) && * with_removal {
404+ let remove_ident = format_ident ! ( "{metric_name}_remove" ) ;
405+ let remove_doc = LitStr :: new (
406+ & format ! ( "Removes one label set from the `{metric_name}` family." ) ,
407+ Span :: call_site ( ) ,
408+ ) ;
409+
410+ let clear_ident = format_ident ! ( "{metric_name}_clear" ) ;
411+ let clear_doc = LitStr :: new (
412+ & format ! ( "Removes all label sets from the `{metric_name}` family." ) ,
413+ Span :: call_site ( ) ,
414+ ) ;
415+
416+ quote ! {
417+ #[ doc = #remove_doc]
418+ #( #cfg) *
419+ #fn_vis #fn_token #remove_ident( #( #fn_args, ) * ) #arrow_token bool {
420+ #convert_args
421+ #foundations:: reexports_for_macros:: prometools:: serde:: Family :: remove(
422+ & #metrics_struct. #metric_name,
423+ & __args,
424+ )
425+ }
426+
427+ #[ doc = #clear_doc]
428+ #( #cfg) *
429+ #fn_vis #fn_token #clear_ident( ) {
430+ #foundations:: reexports_for_macros:: prometools:: serde:: Family :: clear(
431+ & #metrics_struct. #metric_name,
432+ )
433+ }
388434 }
435+ } else {
436+ quote ! { }
389437 } ;
390438
391439 quote ! {
392440 #[ doc = #doc]
393441 #( #cfg) *
394442 #[ must_use]
395443 #fn_vis #fn_token #metric_name( #( #fn_args, ) * ) #arrow_token #metric_type {
396- #fn_body
444+ #convert_args
445+ #access_metric
397446 }
447+ #removal_fns
398448 }
399449}
400450
@@ -713,15 +763,16 @@ mod tests {
713763 message: & ' static str ,
714764 error: impl Into <String >,
715765 ) -> Counter {
766+ let __args = connections_errors_total {
767+ endpoint: :: std:: clone:: Clone :: clone( endpoint) ,
768+ kind,
769+ message,
770+ error: :: std:: convert:: Into :: into( error) ,
771+ } ;
716772 :: std:: clone:: Clone :: clone(
717773 & :: foundations:: reexports_for_macros:: prometools:: serde:: Family :: get_or_create(
718774 & __oxy_Metrics. connections_errors_total,
719- & connections_errors_total {
720- endpoint: :: std:: clone:: Clone :: clone( endpoint) ,
721- kind,
722- message,
723- error: :: std:: convert:: Into :: into( error) ,
724- } ,
775+ & __args,
725776 )
726777 )
727778 }
@@ -827,15 +878,111 @@ mod tests {
827878 pub fn requests_per_connection(
828879 endpoint: String ,
829880 ) -> Histogram {
881+ let __args = requests_per_connection { endpoint, } ;
830882 :: std:: clone:: Clone :: clone(
831883 & :: foundations:: reexports_for_macros:: prometools:: serde:: Family :: get_or_create(
832884 & __oxy_Metrics. requests_per_connection,
833- & requests_per_connection {
834- endpoint,
885+ & __args,
886+ )
887+ )
888+ }
889+ }
890+ } ;
891+
892+ assert_eq ! ( actual, expected) ;
893+ }
894+
895+ #[ cfg( foundations_unstable) ]
896+ #[ test]
897+ fn expand_with_removal ( ) {
898+ let attr = parse_attr ! {
899+ #[ metrics]
900+ } ;
901+
902+ let src = parse_quote ! {
903+ pub ( crate ) mod oxy {
904+ /// Total number of requests
905+ #[ with_removal]
906+ pub ( crate ) fn requests_total( status: u16 ) -> Counter ;
907+ }
908+ } ;
909+
910+ let actual = expand_from_parsed ( attr, src) . to_string ( ) ;
911+
912+ let expected = code_str ! {
913+ pub ( crate ) mod oxy {
914+ use super :: * ;
915+
916+ #[ allow( non_camel_case_types) ]
917+ struct __oxy_Metrics {
918+ requests_total:
919+ :: foundations:: reexports_for_macros:: prometools:: serde:: Family <
920+ requests_total,
921+ Counter ,
922+ >,
923+ }
924+
925+ #[ allow( non_camel_case_types) ]
926+ #[ derive(
927+ :: std:: clone:: Clone ,
928+ :: std:: cmp:: Eq ,
929+ :: std:: hash:: Hash ,
930+ :: std:: cmp:: PartialEq ,
931+ :: foundations:: reexports_for_macros:: serde:: Serialize ,
932+ ) ]
933+ #[ serde( crate = ":: foundations :: reexports_for_macros :: serde" ) ]
934+ struct requests_total {
935+ status: u16 ,
936+ }
937+
938+ #[ allow( non_upper_case_globals) ]
939+ static __oxy_Metrics: :: foundations:: reexports_for_macros:: once_cell:: sync:: Lazy <__oxy_Metrics> =
940+ :: foundations:: reexports_for_macros:: once_cell:: sync:: Lazy :: new( || {
941+ let registry = & mut * :: foundations:: telemetry:: metrics:: internal:: Registries :: get_subsystem( stringify!( oxy) , false , true ) ;
942+
943+ __oxy_Metrics {
944+ requests_total: {
945+ let metric = :: std:: default :: Default :: default ( ) ;
946+
947+ :: foundations:: reexports_for_macros:: prometheus_client:: registry:: Registry :: register(
948+ registry,
949+ :: std:: stringify!( requests_total) ,
950+ str :: trim( " Total number of requests" ) ,
951+ :: std:: boxed:: Box :: new( :: std:: clone:: Clone :: clone( & metric) )
952+ ) ;
953+
954+ metric
835955 } ,
956+ }
957+ } ) ;
958+
959+ #[ doc = " Total number of requests" ]
960+ #[ must_use]
961+ pub ( crate ) fn requests_total( status: u16 , ) -> Counter {
962+ let __args = requests_total { status, } ;
963+ :: std:: clone:: Clone :: clone(
964+ & :: foundations:: reexports_for_macros:: prometools:: serde:: Family :: get_or_create(
965+ & __oxy_Metrics. requests_total,
966+ & __args,
836967 )
837968 )
838969 }
970+
971+ #[ doc = "Removes one label set from the `requests_total` family." ]
972+ pub ( crate ) fn requests_total_remove( status: u16 , ) -> bool {
973+ let __args = requests_total { status, } ;
974+ :: foundations:: reexports_for_macros:: prometools:: serde:: Family :: remove(
975+ & __oxy_Metrics. requests_total,
976+ & __args,
977+ )
978+ }
979+
980+ #[ doc = "Removes all label sets from the `requests_total` family." ]
981+ pub ( crate ) fn requests_total_clear( ) {
982+ :: foundations:: reexports_for_macros:: prometools:: serde:: Family :: clear(
983+ & __oxy_Metrics. requests_total,
984+ )
985+ }
839986 }
840987 } ;
841988
0 commit comments