@@ -58,6 +58,7 @@ struct FnAttrs {
5858 doc : String ,
5959 ctor : Option < ExprStruct > ,
6060 optional : bool ,
61+ with_removal : bool ,
6162}
6263
6364struct FnArg {
@@ -298,6 +299,7 @@ fn metric_init(foundations: &Path, fn_: &ItemFn) -> proc_macro2::TokenStream {
298299 doc,
299300 optional,
300301 ctor,
302+ ..
301303 } ,
302304 ident : field_name,
303305 args,
@@ -355,7 +357,13 @@ fn metric_init(foundations: &Path, fn_: &ItemFn) -> proc_macro2::TokenStream {
355357
356358fn metric_fn ( foundations : & Path , metrics_struct : & Ident , fn_ : & ItemFn ) -> proc_macro2:: TokenStream {
357359 let ItemFn {
358- attrs : FnAttrs { cfg, doc, .. } ,
360+ attrs :
361+ FnAttrs {
362+ cfg,
363+ doc,
364+ with_removal,
365+ ..
366+ } ,
359367 fn_token,
360368 vis : fn_vis,
361369 ident : metric_name,
@@ -364,35 +372,77 @@ fn metric_fn(foundations: &Path, metrics_struct: &Ident, fn_: &ItemFn) -> proc_m
364372 ty : metric_type,
365373 } = fn_;
366374
367- let fn_args = args. iter ( ) . map ( |arg| arg. to_arg ( ) ) ;
375+ let fn_args: Vec < _ > = args. iter ( ) . map ( |arg| arg. to_arg ( ) ) . collect ( ) ;
368376
369- let fn_body = if args. is_empty ( ) {
370- quote ! {
377+ let ( convert_args , access_metric ) = if args. is_empty ( ) {
378+ let accessor = quote ! {
371379 :: std:: clone:: Clone :: clone( & #metrics_struct. #metric_name)
372- }
380+ } ;
381+ ( quote ! { } , accessor)
373382 } else {
374383 let label_inits = args. iter ( ) . map ( |arg| arg. to_initializer ( ) ) ;
384+ let convert = quote ! {
385+ let __args = #metric_name {
386+ #( #label_inits, ) *
387+ } ;
388+ } ;
375389
376-
377- quote ! {
390+ let accessor = quote ! {
378391 :: std:: clone:: Clone :: clone(
379392 & #foundations:: reexports_for_macros:: prometools:: serde:: Family :: get_or_create(
380393 & #metrics_struct. #metric_name,
381- & #metric_name {
382- #( #label_inits, ) *
383- } ,
394+ & __args,
384395 )
385396 )
397+ } ;
398+ ( convert, accessor)
399+ } ;
400+
401+ let removal_fns = if cfg ! ( foundations_unstable) && * with_removal {
402+ let remove_ident = format_ident ! ( "{metric_name}_remove" ) ;
403+ let remove_doc = LitStr :: new (
404+ & format ! ( "Removes one label set from the `{metric_name}` family." ) ,
405+ Span :: call_site ( ) ,
406+ ) ;
407+
408+ let clear_ident = format_ident ! ( "{metric_name}_clear" ) ;
409+ let clear_doc = LitStr :: new (
410+ & format ! ( "Removes all label sets from the `{metric_name}` family." ) ,
411+ Span :: call_site ( ) ,
412+ ) ;
413+
414+ quote ! {
415+ #[ doc = #remove_doc]
416+ #( #cfg) *
417+ #fn_vis #fn_token #remove_ident( #( #fn_args, ) * ) #arrow_token bool {
418+ #convert_args
419+ #foundations:: reexports_for_macros:: prometools:: serde:: Family :: remove(
420+ & #metrics_struct. #metric_name,
421+ & __args,
422+ )
423+ }
424+
425+ #[ doc = #clear_doc]
426+ #( #cfg) *
427+ #fn_vis #fn_token #clear_ident( ) {
428+ #foundations:: reexports_for_macros:: prometools:: serde:: Family :: clear(
429+ & #metrics_struct. #metric_name,
430+ )
431+ }
386432 }
433+ } else {
434+ quote ! { }
387435 } ;
388436
389437 quote ! {
390438 #[ doc = #doc]
391439 #( #cfg) *
392440 #[ must_use]
393441 #fn_vis #fn_token #metric_name( #( #fn_args, ) * ) #arrow_token #metric_type {
394- #fn_body
442+ #convert_args
443+ #access_metric
395444 }
445+ #removal_fns
396446 }
397447}
398448
@@ -711,15 +761,16 @@ mod tests {
711761 message: & ' static str ,
712762 error: impl Into <String >,
713763 ) -> Counter {
764+ let __args = connections_errors_total {
765+ endpoint: :: std:: clone:: Clone :: clone( endpoint) ,
766+ kind,
767+ message,
768+ error: :: std:: convert:: Into :: into( error) ,
769+ } ;
714770 :: std:: clone:: Clone :: clone(
715771 & :: foundations:: reexports_for_macros:: prometools:: serde:: Family :: get_or_create(
716772 & __oxy_Metrics. connections_errors_total,
717- & connections_errors_total {
718- endpoint: :: std:: clone:: Clone :: clone( endpoint) ,
719- kind,
720- message,
721- error: :: std:: convert:: Into :: into( error) ,
722- } ,
773+ & __args,
723774 )
724775 )
725776 }
@@ -825,15 +876,111 @@ mod tests {
825876 pub fn requests_per_connection(
826877 endpoint: String ,
827878 ) -> Histogram {
879+ let __args = requests_per_connection { endpoint, } ;
828880 :: std:: clone:: Clone :: clone(
829881 & :: foundations:: reexports_for_macros:: prometools:: serde:: Family :: get_or_create(
830882 & __oxy_Metrics. requests_per_connection,
831- & requests_per_connection {
832- endpoint,
883+ & __args,
884+ )
885+ )
886+ }
887+ }
888+ } ;
889+
890+ assert_eq ! ( actual, expected) ;
891+ }
892+
893+ #[ cfg( foundations_unstable) ]
894+ #[ test]
895+ fn expand_with_removal ( ) {
896+ let attr = parse_attr ! {
897+ #[ metrics]
898+ } ;
899+
900+ let src = parse_quote ! {
901+ pub ( crate ) mod oxy {
902+ /// Total number of requests
903+ #[ with_removal]
904+ pub ( crate ) fn requests_total( status: u16 ) -> Counter ;
905+ }
906+ } ;
907+
908+ let actual = expand_from_parsed ( attr, src) . to_string ( ) ;
909+
910+ let expected = code_str ! {
911+ pub ( crate ) mod oxy {
912+ use super :: * ;
913+
914+ #[ allow( non_camel_case_types) ]
915+ struct __oxy_Metrics {
916+ requests_total:
917+ :: foundations:: reexports_for_macros:: prometools:: serde:: Family <
918+ requests_total,
919+ Counter ,
920+ >,
921+ }
922+
923+ #[ allow( non_camel_case_types) ]
924+ #[ derive(
925+ :: std:: clone:: Clone ,
926+ :: std:: cmp:: Eq ,
927+ :: std:: hash:: Hash ,
928+ :: std:: cmp:: PartialEq ,
929+ :: foundations:: reexports_for_macros:: serde:: Serialize ,
930+ ) ]
931+ #[ serde( crate = ":: foundations :: reexports_for_macros :: serde" ) ]
932+ struct requests_total {
933+ status: u16 ,
934+ }
935+
936+ #[ allow( non_upper_case_globals) ]
937+ static __oxy_Metrics: :: std:: sync:: LazyLock <__oxy_Metrics> =
938+ :: std:: sync:: LazyLock :: new( || {
939+ let registry = & mut * :: foundations:: telemetry:: metrics:: internal:: Registries :: get_subsystem( stringify!( oxy) , false , true ) ;
940+
941+ __oxy_Metrics {
942+ requests_total: {
943+ let metric = :: std:: default :: Default :: default ( ) ;
944+
945+ :: foundations:: reexports_for_macros:: prometheus_client:: registry:: Registry :: register(
946+ registry,
947+ :: std:: stringify!( requests_total) ,
948+ str :: trim( " Total number of requests" ) ,
949+ :: std:: boxed:: Box :: new( :: std:: clone:: Clone :: clone( & metric) )
950+ ) ;
951+
952+ metric
833953 } ,
954+ }
955+ } ) ;
956+
957+ #[ doc = " Total number of requests" ]
958+ #[ must_use]
959+ pub ( crate ) fn requests_total( status: u16 , ) -> Counter {
960+ let __args = requests_total { status, } ;
961+ :: std:: clone:: Clone :: clone(
962+ & :: foundations:: reexports_for_macros:: prometools:: serde:: Family :: get_or_create(
963+ & __oxy_Metrics. requests_total,
964+ & __args,
834965 )
835966 )
836967 }
968+
969+ #[ doc = "Removes one label set from the `requests_total` family." ]
970+ pub ( crate ) fn requests_total_remove( status: u16 , ) -> bool {
971+ let __args = requests_total { status, } ;
972+ :: foundations:: reexports_for_macros:: prometools:: serde:: Family :: remove(
973+ & __oxy_Metrics. requests_total,
974+ & __args,
975+ )
976+ }
977+
978+ #[ doc = "Removes all label sets from the `requests_total` family." ]
979+ pub ( crate ) fn requests_total_clear( ) {
980+ :: foundations:: reexports_for_macros:: prometools:: serde:: Family :: clear(
981+ & __oxy_Metrics. requests_total,
982+ )
983+ }
837984 }
838985 } ;
839986
0 commit comments