rs_consul/
metrics.rs

1#[cfg(feature = "metrics")]
2use http::StatusCode;
3
4#[cfg(feature = "metrics")]
5use std::time::Duration;
6
7/// A struct to hold information about a calls to consul for metrics.
8#[cfg(feature = "metrics")]
9#[derive(Debug, Clone, Copy)]
10pub struct MetricInfo {
11    /// The HTTP method used in the call.
12    pub method: HttpMethod,
13    /// The function called in the consul client.
14    pub function: Function,
15    /// The status code returned by the call if any.
16    pub status: Option<StatusCode>,
17    /// The duration of the call.
18    pub duration: Option<Duration>,
19}
20
21#[cfg(feature = "metrics")]
22impl MetricInfo {
23    fn new(method: HttpMethod, function: Function, status: Option<StatusCode>) -> Self {
24        Self {
25            method,
26            function,
27            status,
28            duration: None,
29        }
30    }
31
32    /// Get the labels for the metric as an array of `&str`.
33    pub fn labels(&self) -> [&str; 3] {
34        if let Some(status) = self.status.and_then(|o| o.canonical_reason()) {
35            [self.method.as_str(), self.function.as_str(), status]
36        } else {
37            [self.method.as_str(), self.function.as_str(), "unknown"]
38        }
39    }
40}
41
42#[cfg(feature = "metrics")]
43#[derive(Debug, Clone)]
44pub(crate) struct MetricInfoWrapper {
45    metrics: MetricInfo,
46    sender: Option<tokio::sync::mpsc::UnboundedSender<MetricInfo>>,
47    start: std::time::Instant,
48}
49
50#[cfg(feature = "metrics")]
51impl MetricInfoWrapper {
52    pub fn new(
53        method: HttpMethod,
54        function: Function,
55        status: Option<StatusCode>,
56        sender: tokio::sync::mpsc::UnboundedSender<MetricInfo>,
57    ) -> Self {
58        Self {
59            metrics: MetricInfo::new(method, function, status),
60            sender: Some(sender),
61            start: std::time::Instant::now(),
62        }
63    }
64
65    pub fn set_status(&mut self, status: StatusCode) {
66        self.metrics.status = Some(status);
67    }
68
69    pub fn emit_metrics(&mut self) {
70        if let Some(sender) = self.sender.take() {
71            let mut metrics = self.metrics;
72            metrics.duration = Some(self.start.elapsed());
73            let _ = sender.send(metrics);
74        }
75    }
76}
77
78#[cfg(feature = "metrics")]
79impl Drop for MetricInfoWrapper {
80    fn drop(&mut self) {
81        self.emit_metrics();
82    }
83}
84
85/// The HTTP methods supported by the consul API.
86#[derive(Debug, Clone, Copy)]
87pub enum HttpMethod {
88    /// The OPTIONS method.
89    Options,
90    /// The GET method.
91    Get,
92    /// The POST method.
93    Post,
94    /// The PUT method.
95    Put,
96    /// The DELETE method.
97    Delete,
98    /// The HEAD method.
99    Head,
100    /// The TRACE method.
101    Trace,
102    /// The CONNECT method.
103    Connect,
104    /// The PATCH method.
105    Patch,
106    /// Extensions to the HTTP methods.
107    Extensions,
108}
109
110impl HttpMethod {
111    #[cfg(feature = "metrics")]
112    fn as_str(&self) -> &'static str {
113        match self {
114            HttpMethod::Options => "options",
115            HttpMethod::Get => "get",
116            HttpMethod::Post => "post",
117            HttpMethod::Put => "put",
118            HttpMethod::Delete => "delete",
119            HttpMethod::Head => "head",
120            HttpMethod::Trace => "trace",
121            HttpMethod::Connect => "connect",
122            HttpMethod::Patch => "patch",
123            HttpMethod::Extensions => "extensions",
124        }
125    }
126}
127
128#[cfg(feature = "metrics")]
129impl From<http::Method> for HttpMethod {
130    fn from(method: http::Method) -> Self {
131        match method {
132            http::Method::OPTIONS => HttpMethod::Options,
133            http::Method::GET => HttpMethod::Get,
134            http::Method::POST => HttpMethod::Post,
135            http::Method::PUT => HttpMethod::Put,
136            http::Method::DELETE => HttpMethod::Delete,
137            http::Method::HEAD => HttpMethod::Head,
138            http::Method::TRACE => HttpMethod::Trace,
139            http::Method::CONNECT => HttpMethod::Connect,
140            http::Method::PATCH => HttpMethod::Patch,
141            _ => HttpMethod::Extensions,
142        }
143    }
144}
145
146/// The functions supported by the consul client.
147#[derive(Debug, Clone, Copy)]
148pub enum Function {
149    /// The read_key function.
150    ReadKey,
151    /// The create_or_update_key function.
152    CreateOrUpdateKey,
153    /// The delete_key function.
154    DeleteKey,
155    /// The register_entity function.
156    RegisterEntity,
157    /// The deregister_entity function.
158    DeregisterEntity,
159    /// The get_service_nodes function.
160    GetServiceNodes,
161    /// The get_nodes function.
162    GetNodes,
163    /// The get_all_registered_services function.
164    GetAllRegisteredServices,
165    /// The get_session function.
166    GetSession,
167    /// The list_acl_tokens function
168    GetAclTokens,
169    /// The create_acl_policy function
170    CreateACLPolicy,
171    /// The list_acl_policies function
172    GetACLPolicies,
173    /// The read_acl_token function
174    ReadACLPolicies,
175    /// The delete_acl_token function
176    DeleteACLToken,
177    /// The read_acl_token function
178    ReadACLToken,
179    /// The delete_acl_policy function
180    DeleteACLPolicy,
181}
182
183impl Function {
184    /// Get the function as a string.
185    #[cfg(feature = "metrics")]
186    pub fn as_str(&self) -> &'static str {
187        match self {
188            Function::ReadKey => "read_key",
189            Function::CreateOrUpdateKey => "create_or_update_key",
190            Function::DeleteKey => "delete_key",
191            Function::RegisterEntity => "register_entity",
192            Function::DeregisterEntity => "deregister_entity",
193            Function::GetServiceNodes => "get_service_nodes",
194            Function::GetNodes => "get_nodes",
195            Function::GetAllRegisteredServices => "get_all_registered_services",
196            Function::GetSession => "get_session",
197            Function::GetAclTokens => "list_acl_tokens",
198            Function::CreateACLPolicy => "create_acl_policy",
199            Function::GetACLPolicies => "get_acl_policies",
200            Function::ReadACLPolicies => "read_acl_policies",
201            Function::DeleteACLToken => "delete_acl_token",
202            Function::ReadACLToken => "read_acl_token",
203            Function::DeleteACLPolicy => "delete_acl_policy",
204        }
205    }
206}