aboutsummaryrefslogtreecommitdiff
path: root/src/proxy_config.rs
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2022-12-05 18:43:48 +0100
committerAlex Auvolat <alex@adnab.me>2022-12-05 18:43:48 +0100
commit5d38f2cf7f312de69a3106556fc43219ca1473c3 (patch)
tree2ecc767ffeae5dd9b4a528f8294a61385a1fb5b1 /src/proxy_config.rs
parent43a0fe14b2ae6a3e97f39169cda7ca5579a3259c (diff)
downloadtricot-5d38f2cf7f312de69a3106556fc43219ca1473c3.tar.gz
tricot-5d38f2cf7f312de69a3106556fc43219ca1473c3.zip
Add basic support for metrics
Diffstat (limited to 'src/proxy_config.rs')
-rw-r--r--src/proxy_config.rs70
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::*;