diff options
Diffstat (limited to 'src/proxy_config.rs')
-rw-r--r-- | src/proxy_config.rs | 70 |
1 files changed, 62 insertions, 8 deletions
diff --git a/src/proxy_config.rs b/src/proxy_config.rs index e45cc7b..24ade8b 100644 --- a/src/proxy_config.rs +++ b/src/proxy_config.rs @@ -4,6 +4,7 @@ use std::sync::{atomic, Arc}; use std::{cmp, time::Duration}; use anyhow::Result; +use opentelemetry::{metrics, KeyValue}; use futures::future::BoxFuture; use futures::stream::{FuturesUnordered, StreamExt}; @@ -38,6 +39,15 @@ impl HostDescription { } } +impl std::fmt::Display for HostDescription { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + HostDescription::Hostname(h) => write!(f, "{}", h), + HostDescription::Pattern(p) => write!(f, "Pattern('{}')", p.as_str()), + } + } +} + #[derive(Debug)] pub struct ProxyEntry { /// Publicly exposed TLS hostnames for matching this rule @@ -47,6 +57,8 @@ pub struct ProxyEntry { /// Priority with which this rule is considered (highest first) pub priority: u32, + /// Consul service name + pub service_name: String, /// Node address (ip+port) to handle requests that match this entry pub target_addr: SocketAddr, /// Is the target serving HTTPS instead of HTTP? @@ -75,14 +87,11 @@ impl std::fmt::Display for ProxyEntry { write!(f, "https://")?; } write!(f, "{} ", self.target_addr)?; - match &self.host { - HostDescription::Hostname(h) => write!(f, "{}", h)?, - HostDescription::Pattern(p) => write!(f, "Pattern('{}')", p.as_str())?, - } write!( f, - "{} {}", - self.path_prefix.as_ref().unwrap_or(&String::new()), + "{}{} {}", + self.host, + self.path_prefix.as_deref().unwrap_or_default(), self.priority )?; if self.same_node { @@ -113,6 +122,7 @@ fn retry_to_time(retries: u32, max_time: Duration) -> Duration { } fn parse_tricot_tag( + service_name: String, tag: &str, target_addr: SocketAddr, add_headers: &[(String, String)], @@ -148,6 +158,7 @@ fn parse_tricot_tag( }; Some(ProxyEntry { + service_name, target_addr, https_target: (splits[0] == "tricot-https"), host, @@ -178,7 +189,7 @@ fn parse_consul_catalog( let mut entries = vec![]; - for (_, svc) in catalog.services.iter() { + for (service_name, svc) in catalog.services.iter() { let ip_addr = match svc.address.parse() { Ok(ip) => ip, _ => match catalog.node.address.parse() { @@ -210,7 +221,14 @@ fn parse_consul_catalog( } for tag in svc.tags.iter() { - if let Some(ent) = parse_tricot_tag(tag, addr, &add_headers[..], same_node, same_site) { + if let Some(ent) = parse_tricot_tag( + service_name.clone(), + tag, + addr, + &add_headers[..], + same_node, + same_site, + ) { entries.push(ent); } } @@ -239,6 +257,7 @@ pub fn spawn_proxy_config_task( entries: Vec::new(), })); + let metrics = ProxyConfigMetrics::new(rx.clone()); let consul = Arc::new(consul); tokio::spawn(async move { @@ -348,11 +367,46 @@ pub fn spawn_proxy_config_task( tx.send(Arc::new(config)).expect("Internal error"); } + + drop(metrics); // ensure Metrics lives up to here }); rx } +// ---- + +struct ProxyConfigMetrics { + _proxy_config_entries: metrics::ValueObserver<u64>, +} + +impl ProxyConfigMetrics { + fn new(rx: watch::Receiver<Arc<ProxyConfig>>) -> Self { + let meter = opentelemetry::global::meter("tricot"); + Self { + _proxy_config_entries: meter + .u64_value_observer("proxy_config_entries", move |observer| { + let mut patterns = HashMap::new(); + for ent in rx.borrow().entries.iter() { + let pat = format!( + "{}{}", + ent.host, + ent.path_prefix.as_deref().unwrap_or_default() + ); + *patterns.entry(pat).or_default() += 1; + } + for (pat, num) in patterns { + observer.observe(num, &[KeyValue::new("host", pat)]); + } + }) + .with_description("Number of proxy entries (back-ends) configured in Tricot") + .init(), + } + } +} + +// ---- + #[cfg(test)] mod tests { use super::*; |