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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
//! This crate allow to put a `time` attribut macro on any function
//! or `impl` block.
//! It will time the execution of functions and emit a histogram
//! metric using [metrics](https://crates.io/crates/metrics) crate.
//!
//! In case the annotation is on an `impl` block :
//! * all method will be timed
//! * there will be a tag `struct` with the struct name.
//! * all `time` annotations on any method will override the one on `impl` block.
//! * it's possible to disable specific methods using `#[time(disable)]`.
//!
//! Note that `#[time(disable)]` can't be on an `impl` block.
//!
//! # Example
//!
//! * On functions and methods :
//!
//! ```rust
//! use std::error::Error;
//! use metrics_exporter_prometheus::PrometheusBuilder;
//! use function_timer::time;
//!
//! struct Test {}
//!
//! impl Test {
//! #[time("my_metric")]
//! pub fn impl_function(&self) {
//! println!("This another test");
//! }
//!
//! #[time("another_metric")]
//! pub fn impl_fail_function(&self, text:&str) -> Result<(), Box<dyn Error>>{
//! let number:usize = text.parse()?;
//! println!("{number}");
//!
//! Ok(())
//! }
//!
//! #[time("my_metric")]
//! pub fn static_function() {
//! println!("This another test");
//! }
//! }
//!
//! #[time("my_metric")]
//! pub fn free_function() {
//! println!("This a test");
//! }
//!
//! fn main() -> Result<(), Box<dyn Error>> {
//! let builder = PrometheusBuilder::new();
//! let handle = builder.install_recorder()?;
//!
//! free_function();
//!
//! Test::static_function();
//!
//! let t = Test {};
//! t.impl_function();
//!
//! let result = t.impl_fail_function("azerty");
//! assert!(result.is_err());
//! let result = t.impl_fail_function("1");
//! assert!(result.is_ok());
//!
//!
//! println!("{}", handle.render());
//!
//! Ok(())
//! }
//! ```
//!
//! * on `impl` block :
//!
//! ```rust
//! use std::error::Error;
//! use metrics_exporter_prometheus::PrometheusBuilder;
//! use function_timer::time;
//!
//! struct Test {}
//!
//! #[time("my_metric")]
//! impl Test {
//! #[time("override_my_metric")]
//! pub fn impl_function(&self) {
//! println!("This another test");
//! }
//!
//! pub fn impl_fail_function(&self, text:&str) -> Result<(), Box<dyn Error>>{
//! let number:usize = text.parse()?;
//! println!("{number}");
//!
//! Ok(())
//! }
//!
//! pub fn static_function() {
//! println!("This another test");
//! }
//! }
//!
//! fn main() -> Result<(), Box<dyn Error>> {
//! let builder = PrometheusBuilder::new();
//! let handle = builder.install_recorder()?;
//!
//! Test::static_function();
//!
//! let t = Test {};
//! t.impl_function();
//!
//! let result = t.impl_fail_function("azerty");
//! assert!(result.is_err());
//! let result = t.impl_fail_function("1");
//! assert!(result.is_ok());
//!
//!
//! println!("{}", handle.render());
//!
//! Ok(())
//! }
//! ```
pub use function_timer_macro::time;
use metrics::histogram;
use std::time::Instant;
/// Timer.
pub struct FunctionTimer {
metric_name: &'static str,
struct_name: Option<&'static str>,
function: &'static str,
chrono: Instant,
}
impl FunctionTimer {
/// Create a new [FunctionTimer].
///
/// # Parameters
///
/// * `metric_name` : name of the metric.
/// * `struct_name` : name of the struct.
/// * `function` : name of the function that have the annotation. It is used to generate
/// the tag `function`.
pub fn new(
metric_name: &'static str,
struct_name: Option<&'static str>,
function: &'static str,
) -> Self {
Self {
metric_name,
struct_name,
function,
chrono: Instant::now(),
}
}
}
impl Drop for FunctionTimer {
/// Get execution time and call [`histogram!`](histogram).
fn drop(&mut self) {
let d = self.chrono.elapsed();
let histogram = if let Some(struct_name) = self.struct_name {
histogram!(self.metric_name, "struct" => struct_name, "function" => self.function)
} else {
histogram!(self.metric_name, "function" => self.function)
};
histogram.record(d);
}
}