diff --git a/src/metrics.rs b/src/metrics.rs index 81969327..fbab8f01 100644 --- a/src/metrics.rs +++ b/src/metrics.rs @@ -61,8 +61,9 @@ impl Drop for Metrics { impl From<&HttpRequest> for Metrics { fn from(req: &HttpRequest) -> Self { + let state = req.app_data::>().expect("No State!"); let exts = req.extensions(); - let def_tags = Tags::from(req.head()); + let def_tags = Tags::from_head(req.head(), &state.settings); let tags = exts.get::().unwrap_or(&def_tags); Metrics { client: match req.app_data::>() { @@ -236,6 +237,7 @@ mod tests { use std::collections::HashMap; let mut rh = RequestHead::default(); + let settings = Settings::default(); let path = "/1.5/42/storage/meta/global"; rh.uri = Uri::from_static(path); rh.headers.insert( @@ -245,7 +247,7 @@ mod tests { ), ); - let tags = Tags::from(&rh); + let tags = Tags::from_head(&rh, &settings); let mut result = HashMap::::new(); result.insert("ua.os.ver".to_owned(), "NT 10.0".to_owned()); @@ -262,6 +264,7 @@ mod tests { use actix_web::http::{header, uri::Uri}; let mut rh = RequestHead::default(); + let settings = Settings::default(); let path = "/1.5/42/storage/meta/global"; rh.uri = Uri::from_static(path); rh.headers.insert( @@ -269,7 +272,7 @@ mod tests { header::HeaderValue::from_static("Mozilla/5.0 (curl) Gecko/20100101 curl"), ); - let tags = Tags::from(&rh); + let tags = Tags::from_head(&rh, &settings); assert!(!tags.tags.contains_key("ua.os.ver")); println!("{:?}", tags); } diff --git a/src/settings.rs b/src/settings.rs index 3ae3a3b6..90dfb21c 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -2,11 +2,12 @@ use std::collections::HashMap; +use actix_web::{dev::ServiceRequest, web::Data, HttpRequest}; use config::{Config, ConfigError, Environment, File}; use serde::Deserialize; use crate::adm::AdmSettings; -use crate::server::{img_storage::StorageSettings, location::Location}; +use crate::server::{img_storage::StorageSettings, location::Location, ServerState}; static PREFIX: &str = "contile"; @@ -66,6 +67,8 @@ pub struct Settings { pub fallback_location: String, /// URL to the official documentation pub documentation_url: String, + /// Operational trace header + pub trace_header: Option, // TODO: break these out into a PartnerSettings? /// Adm partner ID (default: "demofeed") @@ -116,6 +119,7 @@ impl Default for Settings { location_test_header: None, fallback_location: "USOK".to_owned(), documentation_url: "https://developer.mozilla.org/".to_owned(), + trace_header: Some("X-Cloud-Trace-Context".to_owned()), // ADM specific settings adm_endpoint_url: "".to_owned(), adm_partner_id: None, @@ -217,6 +221,20 @@ impl Settings { } } +impl<'a> From<&'a HttpRequest> for &'a Settings { + fn from(req: &'a HttpRequest) -> Self { + let state = req.app_data::>().expect("No State!"); + &state.settings + } +} + +impl<'a> From<&'a ServiceRequest> for &'a Settings { + fn from(req: &'a ServiceRequest) -> Self { + let state = req.app_data::>().expect("No State!"); + &state.settings + } +} + #[cfg(test)] pub fn test_settings() -> Settings { Settings::with_env_and_config_file(&None, true) diff --git a/src/tags.rs b/src/tags.rs index 70fb8f15..5c734f97 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -20,6 +20,8 @@ use serde_json::value::Value; use slog::{Key, Record, KV}; use woothee::parser::{Parser, WootheeResult}; +use crate::settings::Settings; + /* /// List of valid user-agent attributes to keep, anything not in this /// list is considered 'Other'. We log the user-agent on connect always @@ -111,8 +113,8 @@ fn insert_if_not_empty(label: &str, val: &str, tags: &mut HashMap for Tags { - fn from(req_head: &RequestHead) -> Self { +impl Tags { + pub fn from_head(req_head: &RequestHead, settings: &Settings) -> Self { // Return an Option<> type because the later consumers (HandlerErrors) presume that // tags are optional and wrapped by an Option<> type. let mut tags = HashMap::new(); @@ -127,6 +129,15 @@ impl From<&RequestHead> for Tags { extra.insert("ua".to_owned(), uas.to_string()); } } + if let Some(tracer) = settings.trace_header.clone() { + if let Some(header) = req_head.headers().get(tracer) { + if let Ok(val) = header.to_str() { + if !val.is_empty() { + extra.insert("header.trace".to_owned(), val.to_owned()); + } + } + } + } tags.insert("uri.method".to_owned(), req_head.method.to_string()); // `uri.path` causes too much cardinality for influx but keep it in // extra for sentry @@ -137,9 +148,10 @@ impl From<&RequestHead> for Tags { impl From for Tags { fn from(request: HttpRequest) -> Self { + let settings = (&request).into(); match request.extensions().get::() { Some(v) => v.clone(), - None => Tags::from(request.head()), + None => Tags::from_head(request.head(), settings), } } } @@ -254,11 +266,12 @@ impl FromRequest for Tags { type Future = Ready>; fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { + let settings = req.into(); let tags = { let exts = req.extensions(); match exts.get::() { Some(t) => t.clone(), - None => Tags::from(req.head()), + None => Tags::from_head(req.head(), settings), } }; diff --git a/src/web/handlers.rs b/src/web/handlers.rs index 9cca4182..c1edecd0 100644 --- a/src/web/handlers.rs +++ b/src/web/handlers.rs @@ -133,7 +133,7 @@ pub async fn get_tiles( metrics.incr_with_tags("tiles.invalid", Some(&tags)); // Report directly to sentry // (This is starting to become a pattern. 🤔) - let mut tags = Tags::from(request.head()); + let mut tags = Tags::from_head(request.head(), &settings); tags.add_extra("err", &es); tags.add_tag("level", "warning"); l_sentry::report(&tags, sentry::event_from_error(&e)); diff --git a/src/web/middleware/sentry.rs b/src/web/middleware/sentry.rs index 1fe7fcdc..c37c1649 100644 --- a/src/web/middleware/sentry.rs +++ b/src/web/middleware/sentry.rs @@ -18,6 +18,7 @@ use sentry::protocol::Event; use std::task::Poll; use crate::error::HandlerError; +use crate::settings::Settings; use crate::tags::Tags; pub struct SentryWrapper; @@ -106,7 +107,8 @@ where } fn call(&mut self, sreq: ServiceRequest) -> Self::Future { - let mut tags = Tags::from(sreq.head()); + let settings: &Settings = (&sreq).into(); + let mut tags = Tags::from_head(sreq.head(), settings); sreq.extensions_mut().insert(tags.clone()); Box::pin(self.service.call(sreq).and_then(move |mut sresp| {