1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
//! Procedural macros for Metered, a metric library for Rust. //! //! Please check the Metered crate for more documentation. #![deny(warnings)] // The `quote!` macro requires deep recursion. #![recursion_limit = "512"] #[macro_use] extern crate syn; #[macro_use] extern crate quote; mod error_count; mod error_count_opts; mod measure_opts; mod metered; mod metered_opts; use proc_macro::TokenStream; /// A procedural macro that generates a metric registry for an `impl` block. /// /// ``` /// use metered::{metered, Throughput, HitCount}; /// /// #[derive(Default, Debug)] /// pub struct Biz { /// metrics: BizMetrics, /// } /// /// #[metered::metered(registry = BizMetrics)] /// impl Biz { /// #[measure([HitCount, Throughput])] /// pub fn biz(&self) { /// let delay = std::time::Duration::from_millis(rand::random::<u64>() % 200); /// std::thread::sleep(delay); /// } /// } /// # /// # let biz = Biz::default(); /// # biz.biz(); /// # assert_eq!(biz.metrics.biz.hit_count.0.get(), 1); /// ``` /// /// ### The `metered` attribute /// /// `#[metered(registry = YourRegistryName, registry_expr = /// self.wrapper.my_registry)]` /// /// `registry` is mandatory and must be a valid Rust ident. /// /// `registry_expr` defaults to `self.metrics`, alternate values must be a valid /// Rust expression. /// /// ### The `measure` attribute /// /// Single metric: /// /// `#[measure(path::to::MyMetric<u64>)]` /// /// or: /// /// `#[measure(type = path::to::MyMetric<u64>)]` /// /// Multiple metrics: /// /// `#[measure([path::to::MyMetric<u64>, path::AnotherMetric])]` /// /// or /// /// `#[measure(type = [path::to::MyMetric<u64>, path::AnotherMetric])]` /// /// The `type` keyword is allowed because other keywords are planned for future /// extra attributes (e.g, instantation options). /// /// When `measure` attribute is applied to an `impl` block, it applies for every /// method that has a `measure` attribute. If a method does not need extra /// measure infos, it is possible to annotate it with simply `#[measure]` and /// the `impl` block's `measure` configuration will be applied. /// /// The `measure` keyword can be added several times on an `impl` block or /// method, which will add to the list of metrics applied. Adding the same /// metric several time will lead in a name clash. #[proc_macro_attribute] pub fn metered(attrs: TokenStream, item: TokenStream) -> TokenStream { metered::metered(attrs, item).unwrap_or_else(|e| TokenStream::from(e.to_compile_error())) } /// A procedural macro that generates a new metric that measures the amount /// of times each variant of an error has been thrown, to be used as crate-specific /// replacement for `metered::ErrorCount`. /// /// ``` /// # use metered_macro::{metered, error_count}; /// # use thiserror::Error; /// # /// #[error_count(name = LibErrorCount, visibility = pub)] /// #[derive(Debug, Error)] /// pub enum LibError { /// # #[error("read error")] /// ReadError, /// # #[error("init error")] /// InitError, /// } /// /// #[error_count(name = ErrorCount, visibility = pub)] /// #[derive(Debug, Error)] /// pub enum Error { /// # #[error("error from lib: {0}")] /// MyLibrary(#[from] #[nested] LibError), /// } /// /// #[derive(Default, Debug)] /// pub struct Baz { /// metrics: BazMetrics, /// } /// /// #[metered(registry = BazMetrics)] /// impl Baz { /// #[measure(ErrorCount)] /// pub fn biz(&self) -> Result<(), Error> { /// Err(LibError::InitError.into()) /// } /// } /// /// let baz = Baz::default(); /// baz.biz(); /// assert_eq!(baz.metrics.biz.error_count.my_library.read_error.get(), 0); /// assert_eq!(baz.metrics.biz.error_count.my_library.init_error.get(), 1); /// ``` /// /// - `name` is required and must be a valid Rust ident, this is the name /// of the generated struct containing a counter for each enum variant. /// - `visibility` specifies to visibility of the generated struct, it /// defaults to `pub(crate)`. /// /// The `error_count` macro may only be applied to any enums that have a /// `std::error::Error` impl. The generated struct may then be included /// in `measure` attributes to measure the amount of errors returned of /// each variant defined in your error enum. #[proc_macro_attribute] pub fn error_count(attrs: TokenStream, item: TokenStream) -> TokenStream { error_count::error_count(attrs, item) .unwrap_or_else(|e| TokenStream::from(e.to_compile_error())) }