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
//! This crate allow to put a `time` attribut macro on any function.
//! It will time the execution of the function and emit a histogram
//! metric using [metrics](https://crates.io/crates/metrics) crate.
//!
//! # Example
//!
//! ```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(())
//! }
//! ```
//!
//! # Note
//!
//! If time is put on functions that have the same names, the only way to distinguish between them
//! is to not use the same metric name. Plan is to allow custom tag on annotation and/or allow to
//! put `time` on an `impl` block.
pub use function_timer_macro::time;
use metrics::histogram;
use std::time::Instant;

/// Timer.
pub struct FunctionTimer {
    metric_name: String,
    function: String,
    chrono: Instant,
}

impl FunctionTimer {
    /// Create a new [FunctionTimer].
    ///
    /// # Parameters
    ///
    /// * `metric_name` : name of the metric.
    /// * `function` : name of the function that have the annotation. It is used to generate
    /// the tag `function`.
    pub fn new(metric_name: String, function: String) -> Self {
        Self {
            metric_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();
        histogram!(self.metric_name.clone(), d, "function" => self.function.clone());
    }
}