#[cfg(feature = "metrics")]
use http::StatusCode;
#[cfg(feature = "metrics")]
use std::time::Duration;
#[cfg(feature = "metrics")]
#[derive(Debug, Clone, Copy)]
pub struct MetricInfo {
pub method: HttpMethod,
pub function: Function,
pub status: Option<StatusCode>,
pub duration: Option<Duration>,
}
#[cfg(feature = "metrics")]
impl MetricInfo {
fn new(method: HttpMethod, function: Function, status: Option<StatusCode>) -> Self {
Self {
method,
function,
status,
duration: None,
}
}
pub fn labels(&self) -> [&str; 3] {
if let Some(status) = self.status.and_then(|o| o.canonical_reason()) {
[self.method.as_str(), self.function.as_str(), status]
} else {
[self.method.as_str(), self.function.as_str(), "unknown"]
}
}
}
#[cfg(feature = "metrics")]
#[derive(Debug, Clone)]
pub(crate) struct MetricInfoWrapper {
metrics: MetricInfo,
sender: Option<tokio::sync::mpsc::UnboundedSender<MetricInfo>>,
start: std::time::Instant,
}
#[cfg(feature = "metrics")]
impl MetricInfoWrapper {
pub fn new(
method: HttpMethod,
function: Function,
status: Option<StatusCode>,
sender: tokio::sync::mpsc::UnboundedSender<MetricInfo>,
) -> Self {
Self {
metrics: MetricInfo::new(method, function, status),
sender: Some(sender),
start: std::time::Instant::now(),
}
}
pub fn set_status(&mut self, status: StatusCode) {
self.metrics.status = Some(status);
}
pub fn emit_metrics(&mut self) {
if let Some(sender) = self.sender.take() {
let mut metrics = self.metrics;
metrics.duration = Some(self.start.elapsed());
let _ = sender.send(metrics);
}
}
}
#[cfg(feature = "metrics")]
impl Drop for MetricInfoWrapper {
fn drop(&mut self) {
self.emit_metrics();
}
}
#[derive(Debug, Clone, Copy)]
pub enum HttpMethod {
Options,
Get,
Post,
Put,
Delete,
Head,
Trace,
Connect,
Patch,
Extensions,
}
impl HttpMethod {
#[cfg(feature = "metrics")]
fn as_str(&self) -> &'static str {
match self {
HttpMethod::Options => "options",
HttpMethod::Get => "get",
HttpMethod::Post => "post",
HttpMethod::Put => "put",
HttpMethod::Delete => "delete",
HttpMethod::Head => "head",
HttpMethod::Trace => "trace",
HttpMethod::Connect => "connect",
HttpMethod::Patch => "patch",
HttpMethod::Extensions => "extensions",
}
}
}
#[cfg(feature = "metrics")]
impl From<http::Method> for HttpMethod {
fn from(method: http::Method) -> Self {
match method {
http::Method::OPTIONS => HttpMethod::Options,
http::Method::GET => HttpMethod::Get,
http::Method::POST => HttpMethod::Post,
http::Method::PUT => HttpMethod::Put,
http::Method::DELETE => HttpMethod::Delete,
http::Method::HEAD => HttpMethod::Head,
http::Method::TRACE => HttpMethod::Trace,
http::Method::CONNECT => HttpMethod::Connect,
http::Method::PATCH => HttpMethod::Patch,
_ => HttpMethod::Extensions,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum Function {
ReadKey,
CreateOrUpdateKey,
DeleteKey,
RegisterEntity,
DeregisterEntity,
GetServiceNodes,
GetNodes,
GetAllRegisteredServices,
GetSession,
GetAclTokens,
CreateACLPolicy,
GetACLPolicies,
ReadACLPolicies,
DeleteACLToken,
ReadACLToken,
DeleteACLPolicy,
}
impl Function {
#[cfg(feature = "metrics")]
pub fn as_str(&self) -> &'static str {
match self {
Function::ReadKey => "read_key",
Function::CreateOrUpdateKey => "create_or_update_key",
Function::DeleteKey => "delete_key",
Function::RegisterEntity => "register_entity",
Function::DeregisterEntity => "deregister_entity",
Function::GetServiceNodes => "get_service_nodes",
Function::GetNodes => "get_nodes",
Function::GetAllRegisteredServices => "get_all_registered_services",
Function::GetSession => "get_session",
Function::GetAclTokens => "list_acl_tokens",
Function::CreateACLPolicy => "create_acl_policy",
Function::GetACLPolicies => "get_acl_policies",
Function::ReadACLPolicies => "read_acl_policies",
Function::DeleteACLToken => "delete_acl_token",
Function::ReadACLToken => "read_acl_token",
Function::DeleteACLPolicy => "delete_acl_policy",
}
}
}