add configuration option to enable/disable monitoring bucket in web metrics
All checks were successful
ci/woodpecker/pr/debug Pipeline was successful
All checks were successful
ci/woodpecker/pr/debug Pipeline was successful
This commit is contained in:
parent
8b9cc5ca3f
commit
2f55889835
4 changed files with 35 additions and 30 deletions
|
@ -75,6 +75,7 @@ root_domain = ".s3.garage"
|
||||||
[s3_web]
|
[s3_web]
|
||||||
bind_addr = "[::]:3902"
|
bind_addr = "[::]:3902"
|
||||||
root_domain = ".web.garage"
|
root_domain = ".web.garage"
|
||||||
|
add_host_to_metrics = true
|
||||||
|
|
||||||
[admin]
|
[admin]
|
||||||
api_bind_addr = "0.0.0.0:3903"
|
api_bind_addr = "0.0.0.0:3903"
|
||||||
|
@ -138,6 +139,7 @@ The `[s3_api]` section:
|
||||||
[`s3_region`](#s3_region).
|
[`s3_region`](#s3_region).
|
||||||
|
|
||||||
The `[s3_web]` section:
|
The `[s3_web]` section:
|
||||||
|
[`add_host_to_metrics`](#web_add_host_to_metrics),
|
||||||
[`bind_addr`](#web_bind_addr),
|
[`bind_addr`](#web_bind_addr),
|
||||||
[`root_domain`](#web_root_domain).
|
[`root_domain`](#web_root_domain).
|
||||||
|
|
||||||
|
@ -744,6 +746,13 @@ For instance, if `root_domain` is `web.garage.eu`, a bucket called `deuxfleurs.f
|
||||||
will be accessible either with hostname `deuxfleurs.fr.web.garage.eu`
|
will be accessible either with hostname `deuxfleurs.fr.web.garage.eu`
|
||||||
or with hostname `deuxfleurs.fr`.
|
or with hostname `deuxfleurs.fr`.
|
||||||
|
|
||||||
|
#### `add_host_to_metrics` {#web_add_host_to_metrics}
|
||||||
|
|
||||||
|
Whether to include the requested domain name (HTTP `Host` header) in the
|
||||||
|
Prometheus metrics of the web endpoint. This is disabled by default as the
|
||||||
|
number of possible values is not bounded and can be a source of cardinality
|
||||||
|
explosion in the exported metrics.
|
||||||
|
|
||||||
|
|
||||||
### The `[admin]` section
|
### The `[admin]` section
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ pub async fn run_server(config_file: PathBuf, secrets: Secrets) -> Result<(), Er
|
||||||
|
|
||||||
if let Some(web_config) = &config.s3_web {
|
if let Some(web_config) = &config.s3_web {
|
||||||
info!("Initializing web server...");
|
info!("Initializing web server...");
|
||||||
let web_server = WebServer::new(garage.clone(), web_config.root_domain.clone());
|
let web_server = WebServer::new(garage.clone(), &web_config);
|
||||||
servers.push((
|
servers.push((
|
||||||
"Web",
|
"Web",
|
||||||
tokio::spawn(web_server.run(web_config.bind_addr.clone(), watch_cancel.clone())),
|
tokio::spawn(web_server.run(web_config.bind_addr.clone(), watch_cancel.clone())),
|
||||||
|
|
|
@ -183,6 +183,9 @@ pub struct WebConfig {
|
||||||
pub bind_addr: UnixOrTCPSocketAddress,
|
pub bind_addr: UnixOrTCPSocketAddress,
|
||||||
/// Suffix to remove from domain name to find bucket
|
/// Suffix to remove from domain name to find bucket
|
||||||
pub root_domain: String,
|
pub root_domain: String,
|
||||||
|
/// Whether to add the requested domain to exported Prometheus metrics
|
||||||
|
#[serde(default)]
|
||||||
|
pub add_host_to_metrics: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration for the admin and monitoring HTTP API
|
/// Configuration for the admin and monitoring HTTP API
|
||||||
|
|
|
@ -33,6 +33,7 @@ use garage_api_s3::get::{handle_get_without_ctx, handle_head_without_ctx};
|
||||||
use garage_model::garage::Garage;
|
use garage_model::garage::Garage;
|
||||||
|
|
||||||
use garage_table::*;
|
use garage_table::*;
|
||||||
|
use garage_util::config::WebConfig;
|
||||||
use garage_util::data::Uuid;
|
use garage_util::data::Uuid;
|
||||||
use garage_util::error::Error as GarageError;
|
use garage_util::error::Error as GarageError;
|
||||||
use garage_util::forwarded_headers;
|
use garage_util::forwarded_headers;
|
||||||
|
@ -69,16 +70,18 @@ pub struct WebServer {
|
||||||
garage: Arc<Garage>,
|
garage: Arc<Garage>,
|
||||||
metrics: Arc<WebMetrics>,
|
metrics: Arc<WebMetrics>,
|
||||||
root_domain: String,
|
root_domain: String,
|
||||||
|
add_host_to_metrics: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebServer {
|
impl WebServer {
|
||||||
/// Run a web server
|
/// Run a web server
|
||||||
pub fn new(garage: Arc<Garage>, root_domain: String) -> Arc<Self> {
|
pub fn new(garage: Arc<Garage>, config: &WebConfig) -> Arc<Self> {
|
||||||
let metrics = Arc::new(WebMetrics::new());
|
let metrics = Arc::new(WebMetrics::new());
|
||||||
Arc::new(WebServer {
|
Arc::new(WebServer {
|
||||||
garage,
|
garage,
|
||||||
metrics,
|
metrics,
|
||||||
root_domain,
|
root_domain: config.root_domain.clone(),
|
||||||
|
add_host_to_metrics: config.add_host_to_metrics,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,12 +123,11 @@ impl WebServer {
|
||||||
req: Request<IncomingBody>,
|
req: Request<IncomingBody>,
|
||||||
addr: String,
|
addr: String,
|
||||||
) -> Result<Response<BoxBody<Error>>, http::Error> {
|
) -> Result<Response<BoxBody<Error>>, http::Error> {
|
||||||
let request_host_bucket = req
|
let host_header = req
|
||||||
.headers()
|
.headers()
|
||||||
.get(HOST)
|
.get(HOST)
|
||||||
.expect("No host header found")
|
.and_then(|x| x.to_str().ok())
|
||||||
.to_str()
|
.unwrap_or("<unknown>")
|
||||||
.expect("Error converting host header to string")
|
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
if let Ok(forwarded_for_ip_addr) =
|
if let Ok(forwarded_for_ip_addr) =
|
||||||
|
@ -137,17 +139,11 @@ impl WebServer {
|
||||||
forwarded_for_ip_addr,
|
forwarded_for_ip_addr,
|
||||||
addr,
|
addr,
|
||||||
req.method(),
|
req.method(),
|
||||||
request_host_bucket,
|
host_header,
|
||||||
req.uri()
|
req.uri()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
info!(
|
info!("{} {} {}{}", addr, req.method(), host_header, req.uri());
|
||||||
"{} {} {}{}",
|
|
||||||
addr,
|
|
||||||
req.method(),
|
|
||||||
request_host_bucket,
|
|
||||||
req.uri()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lots of instrumentation
|
// Lots of instrumentation
|
||||||
|
@ -156,16 +152,16 @@ impl WebServer {
|
||||||
.span_builder(format!("Web {} request", req.method()))
|
.span_builder(format!("Web {} request", req.method()))
|
||||||
.with_trace_id(gen_trace_id())
|
.with_trace_id(gen_trace_id())
|
||||||
.with_attributes(vec![
|
.with_attributes(vec![
|
||||||
KeyValue::new("domain", format!("{}", request_host_bucket.to_string())),
|
KeyValue::new("host", format!("{}", host_header.clone())),
|
||||||
KeyValue::new("method", format!("{}", req.method())),
|
KeyValue::new("method", format!("{}", req.method())),
|
||||||
KeyValue::new("uri", req.uri().to_string()),
|
KeyValue::new("uri", req.uri().to_string()),
|
||||||
])
|
])
|
||||||
.start(&tracer);
|
.start(&tracer);
|
||||||
|
|
||||||
let metrics_tags = &[
|
let mut metrics_tags = vec![KeyValue::new("method", req.method().to_string())];
|
||||||
KeyValue::new("domain", request_host_bucket.to_string()),
|
if self.add_host_to_metrics {
|
||||||
KeyValue::new("method", req.method().to_string()),
|
metrics_tags.push(KeyValue::new("host", host_header.clone()));
|
||||||
];
|
}
|
||||||
|
|
||||||
// The actual handler
|
// The actual handler
|
||||||
let res = self
|
let res = self
|
||||||
|
@ -184,7 +180,7 @@ impl WebServer {
|
||||||
"{} {} {}{}",
|
"{} {} {}{}",
|
||||||
req.method(),
|
req.method(),
|
||||||
res.status(),
|
res.status(),
|
||||||
request_host_bucket,
|
host_header,
|
||||||
req.uri()
|
req.uri()
|
||||||
);
|
);
|
||||||
Ok(res
|
Ok(res
|
||||||
|
@ -195,18 +191,15 @@ impl WebServer {
|
||||||
"{} {} {}{} {}",
|
"{} {} {}{} {}",
|
||||||
req.method(),
|
req.method(),
|
||||||
error.http_status_code(),
|
error.http_status_code(),
|
||||||
request_host_bucket,
|
host_header,
|
||||||
req.uri(),
|
req.uri(),
|
||||||
error
|
error
|
||||||
);
|
);
|
||||||
self.metrics.error_counter.add(
|
metrics_tags.push(KeyValue::new(
|
||||||
1,
|
"status_code",
|
||||||
&[
|
error.http_status_code().to_string(),
|
||||||
KeyValue::new("domain", request_host_bucket.to_string()),
|
));
|
||||||
KeyValue::new("method", req.method().to_string()),
|
self.metrics.error_counter.add(1, &metrics_tags);
|
||||||
KeyValue::new("status_code", error.http_status_code().to_string()),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
Ok(error_to_res(error))
|
Ok(error_to_res(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue