diff --git a/Cargo.lock b/Cargo.lock index 76358398..afe6793a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6421,7 +6421,6 @@ dependencies = [ "store", "tokio", "tokio-rustls 0.26.0", - "tracing", "tracing-subscriber", "trc", "utils", @@ -6883,6 +6882,7 @@ dependencies = [ "arc-swap", "base64 0.22.1", "bincode", + "mail-auth", "parking_lot", "reqwest 0.12.5", "rtrb", @@ -7146,7 +7146,6 @@ dependencies = [ "smtp-proto", "tokio", "tokio-rustls 0.26.0", - "tracing", "tracing-journald", "trc", "webpki-roots 0.26.3", diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index e40e06fe..de9c806b 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -20,7 +20,6 @@ dns-update = { version = "0.1" } ahash = { version = "0.8.2", features = ["serde"] } parking_lot = "0.12.1" regex = "1.7.0" -tracing = "0.1" proxy-header = { version = "0.1.0", features = ["tokio"] } arc-swap = "1.6.0" rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] } @@ -60,6 +59,7 @@ hostname = "0.4.0" zip = "2.1" pwhash = "1.0.0" xxhash-rust = { version = "0.8.5", features = ["xxh3"] } +tracing = "0.1" [target.'cfg(unix)'.dependencies] privdrop = "0.5.3" diff --git a/crates/common/src/addresses.rs b/crates/common/src/addresses.rs index 3e8ed7be..6c9430c8 100644 --- a/crates/common/src/addresses.rs +++ b/crates/common/src/addresses.rs @@ -153,6 +153,8 @@ impl AddressMapping { core: &Core, address: &'y str, ) -> Cow<'x, str> { + let todo = "pass session_id"; + let session_id = 0; match self { AddressMapping::Enable => { if let Some((local_part, domain_part)) = address.rsplit_once('@') { @@ -162,11 +164,10 @@ impl AddressMapping { } } AddressMapping::Custom(if_block) => { - if let Ok(result) = String::try_from( - if_block - .eval(&Address(address), core, "session.rcpt.sub-addressing") - .await, - ) { + if let Some(result) = core + .eval_if::(if_block, &Address(address), session_id) + .await + { return result.into(); } } @@ -181,23 +182,18 @@ impl AddressMapping { core: &Core, address: &'y str, ) -> Option> { + let todo = "pass session_id"; + let session_id = 0; + match self { AddressMapping::Enable => address .rsplit_once('@') .map(|(_, domain_part)| format!("@{}", domain_part)) .map(Cow::Owned), - - AddressMapping::Custom(if_block) => { - if let Ok(result) = String::try_from( - if_block - .eval(&Address(address), core, "session.rcpt.catch-all") - .await, - ) { - Some(result.into()) - } else { - None - } - } + AddressMapping::Custom(if_block) => core + .eval_if::(if_block, &Address(address), session_id) + .await + .map(Cow::Owned), AddressMapping::Disable => None, } } diff --git a/crates/common/src/config/tracers.rs b/crates/common/src/config/tracers.rs index 76ed7fc8..3fca1457 100644 --- a/crates/common/src/config/tracers.rs +++ b/crates/common/src/config/tracers.rs @@ -7,8 +7,8 @@ use std::{collections::HashMap, str::FromStr}; use opentelemetry_otlp::{HttpExporterBuilder, TonicExporterBuilder, WithExportConfig}; -use tracing::Level; use tracing_appender::rolling::RollingFileAppender; +use trc::Level; use utils::config::Config; #[derive(Debug)] @@ -69,7 +69,7 @@ impl Tracers { format!("Invalid log level: {err}"), ) }) - .unwrap_or(Level::INFO); + .unwrap_or(Level::Info); match config .value(("tracer", id, "type")) .unwrap_or_default() diff --git a/crates/common/src/enterprise/mod.rs b/crates/common/src/enterprise/mod.rs index 08c32041..a38deba7 100644 --- a/crates/common/src/enterprise/mod.rs +++ b/crates/common/src/enterprise/mod.rs @@ -15,6 +15,7 @@ pub mod undelete; use std::time::Duration; use license::LicenseKey; +use mail_parser::DateTime; use crate::Core; @@ -46,12 +47,14 @@ impl Core { pub fn log_license_details(&self) { if let Some(enterprise) = &self.enterprise { - tracing::info!( - licensed_to = enterprise.license.hostname, - valid_from = enterprise.license.valid_from, - valid_to = enterprise.license.valid_to, - accounts = enterprise.license.accounts, - "Stalwart Enterprise Edition license key is valid", + trc::event!( + Server(trc::ServerEvent::Licensing), + Details = "Stalwart Enterprise Edition license key is valid", + Hostname = enterprise.license.hostname.clone(), + Total = enterprise.license.accounts, + ValidFrom = + DateTime::from_timestamp(enterprise.license.valid_from as i64).to_rfc3339(), + ValidTo = DateTime::from_timestamp(enterprise.license.valid_to as i64).to_rfc3339(), ); } } diff --git a/crates/common/src/expr/eval.rs b/crates/common/src/expr/eval.rs index 937222e0..505320cd 100644 --- a/crates/common/src/expr/eval.rs +++ b/crates/common/src/expr/eval.rs @@ -6,6 +6,8 @@ use std::{borrow::Cow, cmp::Ordering, fmt::Display}; +use trc::EvalEvent; + use crate::Core; use super::{ @@ -19,23 +21,52 @@ impl Core { &self, if_block: &'x IfBlock, resolver: &'x V, + session_id: u64, ) -> Option { if if_block.is_empty() { - tracing::trace!(context = "eval_if", property = if_block.key, result = ""); + trc::event!( + Eval(EvalEvent::Result), + SessionId = session_id, + Property = if_block.key.clone(), + Result = "" + ); return None; } - let result = if_block.eval(resolver, self, &if_block.key).await; + match if_block.eval(resolver, self).await { + Ok(result) => { + trc::event!( + Eval(EvalEvent::Result), + SessionId = session_id, + Property = if_block.key.clone(), + Result = format!("{result:?}"), + ); - tracing::trace!(context = "eval_if", - property = if_block.key, - result = ?result, - ); + match result.try_into() { + Ok(value) => Some(value), + Err(_) => { + trc::event!( + Eval(EvalEvent::Error), + SessionId = session_id, + Property = if_block.key.clone(), + Details = "Failed to convert result", + ); - match result.try_into() { - Ok(value) => Some(value), - Err(_) => None, + None + } + } + } + Err(err) => { + trc::event!( + Eval(EvalEvent::Error), + SessionId = session_id, + Property = if_block.key.clone(), + CausedBy = err, + ); + + None + } } } @@ -44,21 +75,45 @@ impl Core { expr: &'x Expression, resolver: &'x V, expr_id: &str, + session_id: u64, ) -> Option { if expr.is_empty() { return None; } - let result = expr.eval(resolver, self, expr_id, &mut Vec::new()).await; + match expr.eval(resolver, self, &mut Vec::new()).await { + Ok(result) => { + trc::event!( + Eval(EvalEvent::Result), + SessionId = session_id, + Property = expr_id.to_string(), + Result = format!("{result:?}"), + ); - tracing::trace!(context = "eval_expr", - property = expr_id, - result = ?result, - ); + match result.try_into() { + Ok(value) => Some(value), + Err(_) => { + trc::event!( + Eval(EvalEvent::Error), + SessionId = session_id, + Property = expr_id.to_string(), + Details = "Failed to convert result", + ); - match result.try_into() { - Ok(value) => Some(value), - Err(_) => None, + None + } + } + } + Err(err) => { + trc::event!( + Eval(EvalEvent::Error), + SessionId = session_id, + Property = expr_id.to_string(), + CausedBy = err, + ); + + None + } } } } @@ -68,27 +123,21 @@ impl IfBlock { &'x self, resolver: &'x V, core: &Core, - property: &str, - ) -> Variable<'x> { + ) -> trc::Result> { let mut captures = Vec::new(); for if_then in &self.if_then { if if_then .expr - .eval(resolver, core, property, &mut captures) - .await + .eval(resolver, core, &mut captures) + .await? .to_bool() { - return if_then - .then - .eval(resolver, core, property, &mut captures) - .await; + return if_then.then.eval(resolver, core, &mut captures).await; } } - self.default - .eval(resolver, core, property, &mut captures) - .await + self.default.eval(resolver, core, &mut captures).await } } @@ -97,9 +146,8 @@ impl Expression { &'x self, resolver: &'x V, core: &Core, - property: &str, captures: &'y mut Vec, - ) -> Variable<'x> { + ) -> trc::Result> { let mut stack = Vec::new(); let mut exprs = self.items.iter(); @@ -157,8 +205,8 @@ impl Expression { let result = if let Some((_, fnc, _)) = FUNCTIONS.get(*id as usize) { (fnc)(arguments) } else { - core.eval_fnc(*id - FUNCTIONS.len() as u32, arguments, property) - .await + core.eval_fnc(*id - FUNCTIONS.len() as u32, arguments) + .await? }; stack.push(result); @@ -202,7 +250,7 @@ impl Expression { } } - stack.pop().unwrap_or_default() + Ok(stack.pop().unwrap_or_default()) } pub fn is_empty(&self) -> bool { diff --git a/crates/common/src/expr/functions/asynch.rs b/crates/common/src/expr/functions/asynch.rs index 182e5584..4ac48514 100644 --- a/crates/common/src/expr/functions/asynch.rs +++ b/crates/common/src/expr/functions/asynch.rs @@ -2,6 +2,7 @@ use std::{cmp::Ordering, net::IpAddr, vec::IntoIter}; use mail_auth::IpLookupStrategy; use store::{Deserialize, Rows, Value}; +use trc::AddContext; use crate::Core; @@ -12,8 +13,7 @@ impl Core { &self, fnc_id: u32, params: Vec>, - property: &str, - ) -> Variable<'x> { + ) -> trc::Result> { let mut params = FncParams::new(params); match fnc_id { @@ -24,18 +24,8 @@ impl Core { self.get_directory_or_default(directory.as_ref()) .is_local_domain(domain.as_ref()) .await - .unwrap_or_else(|err| { - tracing::warn!( - context = "eval_if", - event = "error", - property = property, - error = ?err, - "Failed to check if domain is local." - ); - - false - }) - .into() + .caused_by(trc::location!()) + .map(|v| v.into()) } F_IS_LOCAL_ADDRESS => { let directory = params.next_as_string(); @@ -44,18 +34,8 @@ impl Core { self.get_directory_or_default(directory.as_ref()) .rcpt(address.as_ref()) .await - .unwrap_or_else(|err| { - tracing::warn!( - context = "eval_if", - event = "error", - property = property, - error = ?err, - "Failed to check if address is local." - ); - - false - }) - .into() + .caused_by(trc::location!()) + .map(|v| v.into()) } F_KEY_GET => { let store = params.next_as_string(); @@ -65,17 +45,8 @@ impl Core { .key_get::(key.into_owned().into_bytes()) .await .map(|value| value.map(|v| v.into_inner()).unwrap_or_default()) - .unwrap_or_else(|err| { - tracing::warn!( - context = "eval_if", - event = "error", - property = property, - error = ?err, - "Failed to get key." - ); - - Variable::default() - }) + .caused_by(trc::location!()) + .map(|v| v.into()) } F_KEY_EXISTS => { let store = params.next_as_string(); @@ -84,18 +55,8 @@ impl Core { self.get_lookup_store(store.as_ref()) .key_exists(key.into_owned().into_bytes()) .await - .unwrap_or_else(|err| { - tracing::warn!( - context = "eval_if", - event = "error", - property = property, - error = ?err, - "Failed to get key." - ); - - false - }) - .into() + .caused_by(trc::location!()) + .map(|v| v.into()) } F_KEY_SET => { let store = params.next_as_string(); @@ -110,18 +71,8 @@ impl Core { ) .await .map(|_| true) - .unwrap_or_else(|err| { - tracing::warn!( - context = "eval_if", - event = "error", - property = property, - error = ?err, - "Failed to set key." - ); - - false - }) - .into() + .caused_by(trc::location!()) + .map(|v| v.into()) } F_COUNTER_INCR => { let store = params.next_as_string(); @@ -132,17 +83,8 @@ impl Core { .counter_incr(key.into_owned().into_bytes(), value, None, true) .await .map(Variable::Integer) - .unwrap_or_else(|err| { - tracing::warn!( - context = "eval_if", - event = "error", - property = property, - error = ?err, - "Failed to increment counter." - ); - - Variable::default() - }) + .caused_by(trc::location!()) + .map(|v| v.into()) } F_COUNTER_GET => { let store = params.next_as_string(); @@ -152,35 +94,23 @@ impl Core { .counter_get(key.into_owned().into_bytes()) .await .map(Variable::Integer) - .unwrap_or_else(|err| { - tracing::warn!( - context = "eval_if", - event = "error", - property = property, - error = ?err, - "Failed to increment counter." - ); - - Variable::default() - }) + .caused_by(trc::location!()) + .map(|v| v.into()) } F_DNS_QUERY => self.dns_query(params).await, F_SQL_QUERY => self.sql_query(params).await, - _ => Variable::default(), + _ => Ok(Variable::default()), } } - async fn sql_query<'x>(&self, mut arguments: FncParams<'x>) -> Variable<'x> { + async fn sql_query<'x>(&self, mut arguments: FncParams<'x>) -> trc::Result> { let store = self.get_lookup_store(arguments.next_as_string().as_ref()); let query = arguments.next_as_string(); if query.is_empty() { - tracing::warn!( - context = "eval:sql_query", - event = "invalid", - reason = "Empty query string", - ); - return Variable::default(); + return Err(trc::EventType::Eval(trc::EvalEvent::Error) + .into_err() + .details("Empty query string")); } // Obtain arguments @@ -195,115 +125,140 @@ impl Core { .get(..6) .map_or(false, |q| q.eq_ignore_ascii_case(b"SELECT")) { - if let Ok(mut rows) = store.query::(&query, arguments).await { - match rows.rows.len().cmp(&1) { - Ordering::Equal => { - let mut row = rows.rows.pop().unwrap().values; - match row.len().cmp(&1) { - Ordering::Equal if !matches!(row.first(), Some(Value::Null)) => { - row.pop().map(into_variable).unwrap() - } - Ordering::Less => Variable::default(), - _ => Variable::Array( - row.into_iter().map(into_variable).collect::>(), - ), + let mut rows = store + .query::(&query, arguments) + .await + .caused_by(trc::location!())?; + Ok(match rows.rows.len().cmp(&1) { + Ordering::Equal => { + let mut row = rows.rows.pop().unwrap().values; + match row.len().cmp(&1) { + Ordering::Equal if !matches!(row.first(), Some(Value::Null)) => { + row.pop().map(into_variable).unwrap() + } + Ordering::Less => Variable::default(), + _ => { + Variable::Array(row.into_iter().map(into_variable).collect::>()) } } - Ordering::Less => Variable::default(), - Ordering::Greater => rows - .rows - .into_iter() - .map(|r| { - Variable::Array( - r.values.into_iter().map(into_variable).collect::>(), - ) - }) - .collect::>() - .into(), } - } else { - false.into() - } + Ordering::Less => Variable::default(), + Ordering::Greater => rows + .rows + .into_iter() + .map(|r| { + Variable::Array(r.values.into_iter().map(into_variable).collect::>()) + }) + .collect::>() + .into(), + }) } else { - store.query::(&query, arguments).await.is_ok().into() + store + .query::(&query, arguments) + .await + .caused_by(trc::location!()) + .map(|v| v.into()) } } - async fn dns_query<'x>(&self, mut arguments: FncParams<'x>) -> Variable<'x> { + async fn dns_query<'x>(&self, mut arguments: FncParams<'x>) -> trc::Result> { let entry = arguments.next_as_string(); let record_type = arguments.next_as_string(); if record_type.eq_ignore_ascii_case("ip") { - match self - .smtp + self.smtp .resolvers .dns .ip_lookup(entry.as_ref(), IpLookupStrategy::Ipv4thenIpv6, 10) .await - { - Ok(result) => result - .iter() - .map(|ip| Variable::from(ip.to_string())) - .collect::>() - .into(), - Err(_) => Variable::default(), - } + .map_err(|err| trc::Error::from(err).caused_by(trc::location!())) + .map(|result| { + result + .iter() + .map(|ip| Variable::from(ip.to_string())) + .collect::>() + .into() + }) } else if record_type.eq_ignore_ascii_case("mx") { - match self.smtp.resolvers.dns.mx_lookup(entry.as_ref()).await { - Ok(result) => result - .iter() - .flat_map(|mx| { - mx.exchanges.iter().map(|host| { - Variable::String( - host.strip_suffix('.') - .unwrap_or(host.as_str()) - .to_string() - .into(), - ) + self.smtp + .resolvers + .dns + .mx_lookup(entry.as_ref()) + .await + .map_err(|err| trc::Error::from(err).caused_by(trc::location!())) + .map(|result| { + result + .iter() + .flat_map(|mx| { + mx.exchanges.iter().map(|host| { + Variable::String( + host.strip_suffix('.') + .unwrap_or(host.as_str()) + .to_string() + .into(), + ) + }) }) - }) - .collect::>() - .into(), - Err(_) => Variable::default(), - } + .collect::>() + .into() + }) } else if record_type.eq_ignore_ascii_case("txt") { - match self.smtp.resolvers.dns.txt_raw_lookup(entry.as_ref()).await { - Ok(result) => Variable::from(String::from_utf8(result).unwrap_or_default()), - Err(_) => Variable::default(), - } + self.smtp + .resolvers + .dns + .txt_raw_lookup(entry.as_ref()) + .await + .map_err(|err| trc::Error::from(err).caused_by(trc::location!())) + .map(|result| Variable::from(String::from_utf8(result).unwrap_or_default())) } else if record_type.eq_ignore_ascii_case("ptr") { - if let Ok(addr) = entry.parse::() { - match self.smtp.resolvers.dns.ptr_lookup(addr).await { - Ok(result) => result + self.smtp + .resolvers + .dns + .ptr_lookup(entry.parse::().map_err(|err| { + trc::EventType::Eval(trc::EvalEvent::Error) + .into_err() + .details("Failed to parse IP address") + .reason(err) + })?) + .await + .map_err(|err| trc::Error::from(err).caused_by(trc::location!())) + .map(|result| { + result .iter() .map(|host| Variable::from(host.to_string())) .collect::>() - .into(), - Err(_) => Variable::default(), - } - } else { - Variable::default() - } + .into() + }) } else if record_type.eq_ignore_ascii_case("ipv4") { - match self.smtp.resolvers.dns.ipv4_lookup(entry.as_ref()).await { - Ok(result) => result - .iter() - .map(|ip| Variable::from(ip.to_string())) - .collect::>() - .into(), - Err(_) => Variable::default(), - } + self.smtp + .resolvers + .dns + .ipv4_lookup(entry.as_ref()) + .await + .map_err(|err| trc::Error::from(err).caused_by(trc::location!())) + .map(|result| { + result + .iter() + .map(|ip| Variable::from(ip.to_string())) + .collect::>() + .into() + }) } else if record_type.eq_ignore_ascii_case("ipv6") { - match self.smtp.resolvers.dns.ipv6_lookup(entry.as_ref()).await { - Ok(result) => result - .iter() - .map(|ip| Variable::from(ip.to_string())) - .collect::>() - .into(), - Err(_) => Variable::default(), - } + self.smtp + .resolvers + .dns + .ipv6_lookup(entry.as_ref()) + .await + .map_err(|err| trc::Error::from(err).caused_by(trc::location!())) + .map(|result| { + result + .iter() + .map(|ip| Variable::from(ip.to_string())) + .collect::>() + .into() + }) } else { - Variable::default() + Ok(Variable::default()) } } } diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index 626f6aa3..08c8435d 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -253,7 +253,7 @@ impl Core { } Ok(None) => Ok(()), Err(err) => { - if err.matches(trc::Cause::Auth(trc::AuthCause::MissingTotp)) { + if err.matches(trc::EventType::Auth(trc::AuthEvent::MissingTotp)) { return Err(err); } else { Err(err) @@ -329,7 +329,7 @@ impl Core { .await; } - Err(trc::AuthCause::Failed.into()) + Err(trc::AuthEvent::Failed.into()) }; } } @@ -375,7 +375,7 @@ impl Core { .await; } - Err(trc::AuthCause::Banned.into()) + Err(trc::AuthEvent::Banned.into()) } else { // Send webhook event if self.has_webhook_subscribers(WebhookType::AuthFailure) { @@ -392,7 +392,7 @@ impl Core { .await; } - Err(trc::AuthCause::Failed.into()) + Err(trc::AuthEvent::Failed.into()) } } else { // Send webhook event @@ -409,7 +409,7 @@ impl Core { ) .await; } - Err(trc::AuthCause::Failed.into()) + Err(trc::AuthEvent::Failed.into()) } } } diff --git a/crates/common/src/listener/acme/cache.rs b/crates/common/src/listener/acme/cache.rs index 99421d43..5c30ee43 100644 --- a/crates/common/src/listener/acme/cache.rs +++ b/crates/common/src/listener/acme/cache.rs @@ -76,7 +76,7 @@ impl Core { URL_SAFE_NO_PAD .decode(content.as_bytes()) .map_err(|err| { - trc::Cause::Acme + trc::EventType::Acme(trc::AcmeEvent::Error) .caused_by(trc::location!()) .reason(err) .details("failed to decode certificate") diff --git a/crates/common/src/listener/acme/directory.rs b/crates/common/src/listener/acme/directory.rs index 2c1e5ece..511404ed 100644 --- a/crates/common/src/listener/acme/directory.rs +++ b/crates/common/src/listener/acme/directory.rs @@ -59,8 +59,12 @@ impl Account { S: AsRef + 'a, I: IntoIterator, { - let key_pair = EcdsaKeyPair::from_pkcs8(ALG, key_pair, &SystemRandom::new()) - .map_err(|err| trc::Cause::Acme.reason(err).caused_by(trc::location!()))?; + let key_pair = + EcdsaKeyPair::from_pkcs8(ALG, key_pair, &SystemRandom::new()).map_err(|err| { + trc::EventType::Acme(trc::AcmeEvent::Error) + .reason(err) + .caused_by(trc::location!()) + })?; let contact: Vec<&'a str> = contact.into_iter().map(AsRef::::as_ref).collect(); let payload = json!({ "termsOfServiceAgreed": true, @@ -100,7 +104,7 @@ impl Account { let body = response .text() .await - .map_err(|err| trc::Cause::Acme.from_http_error(err))?; + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_http_error(err))?; Ok((location, body)) } @@ -108,23 +112,25 @@ impl Account { let domains: Vec = domains.into_iter().map(Identifier::Dns).collect(); let payload = format!( "{{\"identifiers\":{}}}", - serde_json::to_string(&domains).map_err(|err| trc::Cause::Acme.from_json_error(err))? + serde_json::to_string(&domains) + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err))? ); let response = self.request(&self.directory.new_order, &payload).await?; let url = response.0.ok_or( - trc::Cause::Acme + trc::EventType::Acme(trc::AcmeEvent::Error) .caused_by(trc::location!()) .details("Missing header") .ctx(trc::Key::Id, "Location"), )?; let order = serde_json::from_str(&response.1) - .map_err(|err| trc::Cause::Acme.from_json_error(err))?; + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err))?; Ok((url, order)) } pub async fn auth(&self, url: impl AsRef) -> trc::Result { let response = self.request(url, "").await?; - serde_json::from_str(&response.1).map_err(|err| trc::Cause::Acme.from_json_error(err)) + serde_json::from_str(&response.1) + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err)) } pub async fn challenge(&self, url: impl AsRef) -> trc::Result<()> { @@ -133,13 +139,15 @@ impl Account { pub async fn order(&self, url: impl AsRef) -> trc::Result { let response = self.request(&url, "").await?; - serde_json::from_str(&response.1).map_err(|err| trc::Cause::Acme.from_json_error(err)) + serde_json::from_str(&response.1) + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err)) } pub async fn finalize(&self, url: impl AsRef, csr: Vec) -> trc::Result { let payload = format!("{{\"csr\":\"{}\"}}", URL_SAFE_NO_PAD.encode(csr)); let response = self.request(&url, &payload).await?; - serde_json::from_str(&response.1).map_err(|err| trc::Cause::Acme.from_json_error(err)) + serde_json::from_str(&response.1) + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err)) } pub async fn certificate(&self, url: impl AsRef) -> trc::Result { @@ -161,13 +169,18 @@ impl Account { let key_auth = key_authorization_sha256(&self.key_pair, &challenge.token)?; params.alg = &PKCS_ECDSA_P256_SHA256; params.custom_extensions = vec![CustomExtension::new_acme_identifier(key_auth.as_ref())]; - let cert = Certificate::from_params(params) - .map_err(|err| trc::Cause::Acme.caused_by(trc::location!()).reason(err))?; + let cert = Certificate::from_params(params).map_err(|err| { + trc::EventType::Acme(trc::AcmeEvent::Error) + .caused_by(trc::location!()) + .reason(err) + })?; Ok(Bincode::new(SerializedCert { - certificate: cert - .serialize_der() - .map_err(|err| trc::Cause::Acme.caused_by(trc::location!()).reason(err))?, + certificate: cert.serialize_der().map_err(|err| { + trc::EventType::Acme(trc::AcmeEvent::Error) + .caused_by(trc::location!()) + .reason(err) + })?, private_key: cert.serialize_private_key_der(), }) .serialize()) @@ -195,9 +208,9 @@ impl Directory { .await? .text() .await - .map_err(|err| trc::Cause::Acme.from_http_error(err))?, + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_http_error(err))?, ) - .map_err(|err| trc::Cause::Acme.from_json_error(err)) + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err)) } pub async fn nonce(&self) -> trc::Result { get_header( @@ -300,7 +313,7 @@ async fn https( let mut request = builder .build() - .map_err(|err| trc::Cause::Acme.from_http_error(err))? + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_http_error(err))? .request(method, url); if let Some(body) = body { @@ -312,8 +325,8 @@ async fn https( request .send() .await - .map_err(|err| trc::Cause::Acme.from_http_error(err))? - .assert_success(trc::Cause::Acme) + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_http_error(err))? + .assert_success(trc::EventType::Acme(trc::AcmeEvent::Error)) .await } @@ -321,9 +334,9 @@ fn get_header(response: &Response, header: &'static str) -> trc::Result match response.headers().get_all(header).iter().last() { Some(value) => Ok(value .to_str() - .map_err(|err| trc::Cause::Acme.from_http_str_error(err))? + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_http_str_error(err))? .to_string()), - None => Err(trc::Cause::Acme + None => Err(trc::EventType::Acme(trc::AcmeEvent::Error) .caused_by(trc::location!()) .details("Missing header") .ctx(trc::Key::Id, header)), diff --git a/crates/common/src/listener/acme/jose.rs b/crates/common/src/listener/acme/jose.rs index 612a37a5..40626dd5 100644 --- a/crates/common/src/listener/acme/jose.rs +++ b/crates/common/src/listener/acme/jose.rs @@ -23,7 +23,7 @@ pub(crate) fn sign( let combined = format!("{}.{}", &protected, &payload); let signature = key .sign(&SystemRandom::new(), combined.as_bytes()) - .map_err(|err| trc::Cause::Acme.caused_by(trc::location!()).reason(err))?; + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).caused_by(trc::location!()).reason(err))?; let signature = URL_SAFE_NO_PAD.encode(signature.as_ref()); let body = Body { protected, @@ -31,7 +31,7 @@ pub(crate) fn sign( signature, }; - serde_json::to_string(&body).map_err(|err| trc::Cause::Acme.from_json_error(err)) + serde_json::to_string(&body).map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err)) } pub(crate) fn key_authorization(key: &EcdsaKeyPair, token: &str) -> trc::Result { @@ -85,8 +85,8 @@ impl<'a> Protected<'a> { nonce, url, }; - let protected = - serde_json::to_vec(&protected).map_err(|err| trc::Cause::Acme.from_json_error(err))?; + let protected = serde_json::to_vec(&protected) + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err))?; Ok(URL_SAFE_NO_PAD.encode(protected)) } } @@ -121,8 +121,8 @@ impl Jwk { x: &self.x, y: &self.y, }; - let json = - serde_json::to_vec(&jwk_thumb).map_err(|err| trc::Cause::Acme.from_json_error(err))?; + let json = serde_json::to_vec(&jwk_thumb) + .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err))?; let hash = digest(&SHA256, &json); Ok(URL_SAFE_NO_PAD.encode(hash)) } diff --git a/crates/common/src/listener/acme/order.rs b/crates/common/src/listener/acme/order.rs index 12a92bb5..edaee105 100644 --- a/crates/common/src/listener/acme/order.rs +++ b/crates/common/src/listener/acme/order.rs @@ -36,14 +36,14 @@ impl Core { .unwrap_or_default(); let renewal_date = validity[1] - provider.renew_before; - tracing::info!( - context = "acme", - event = "process-cert", - valid_not_before = %validity[0], - valid_not_after = %validity[1], - renewal_date = ?renewal_date, - domains = ?provider.domains, - "Loaded certificate for domains {:?}", provider.domains); + trc::event!( + Acme(trc::AcmeEvent::ProcessCert), + Id = provider.id.to_string(), + Name = provider.domains.as_slice(), + ValidFrom = trc::Value::Timestamp(validity[0].timestamp() as u64), + ValidTo = trc::Value::Timestamp(validity[1].timestamp() as u64), + Renewal = trc::Value::Timestamp(renewal_date.timestamp() as u64), + ); if !cached { self.store_cert(provider, &pem).await?; @@ -58,18 +58,23 @@ impl Core { match self.order(provider).await { Ok(pem) => return self.process_cert(provider, pem, false).await, Err(err) if backoff < 16 => { - tracing::debug!( - context = "acme", - event = "renew-backoff", - domains = ?provider.domains, - attempt = backoff, - reason = ?err, - "Failed to renew certificate, backing off for {} seconds", - 1 << backoff); + trc::event!( + Acme(trc::AcmeEvent::RenewBackoff), + Id = provider.id.to_string(), + Name = provider.domains.as_slice(), + Attempt = backoff, + NextRetry = 1 << backoff, + CausedBy = err, + ); backoff = (backoff + 1).min(16); tokio::time::sleep(Duration::from_secs(1 << backoff)).await; } - Err(err) => return Err(err.details("Failed to renew certificate")), + Err(err) => { + return Err(err + .details("Failed to renew certificate") + .ctx_unique(trc::Key::Id, provider.id.to_string()) + .ctx_unique(trc::Key::Name, provider.domains.as_slice())) + } } } } @@ -86,8 +91,11 @@ impl Core { let mut params = CertificateParams::new(provider.domains.clone()); params.distinguished_name = DistinguishedName::new(); params.alg = &PKCS_ECDSA_P256_SHA256; - let cert = rcgen::Certificate::from_params(params) - .map_err(|err| trc::Cause::Acme.caused_by(trc::location!()).reason(err))?; + let cert = rcgen::Certificate::from_params(params).map_err(|err| { + trc::EventType::Acme(trc::AcmeEvent::Error) + .caused_by(trc::location!()) + .reason(err) + })?; let (order_url, mut order) = account.new_order(provider.domains.clone()).await?; loop { @@ -98,23 +106,22 @@ impl Core { .iter() .map(|url| self.authorize(provider, &account, url)); try_join_all(auth_futures).await?; - tracing::info!( - context = "acme", - event = "auth-complete", - domains = ?provider.domains.as_slice(), - "Completed all authorizations" + trc::event!( + Acme(trc::AcmeEvent::AuthCompleted), + Id = provider.id.to_string(), + Name = provider.domains.as_slice(), ); order = account.order(&order_url).await?; } OrderStatus::Processing => { for i in 0u64..10 { - tracing::info!( - context = "acme", - event = "processing", - domains = ?provider.domains.as_slice(), - attempt = i, - "Processing order" + trc::event!( + Acme(trc::AcmeEvent::OrderProcessing), + Id = provider.id.to_string(), + Name = provider.domains.as_slice(), + Attempt = i, ); + tokio::time::sleep(Duration::from_secs(1u64 << i)).await; order = account.order(&order_url).await?; if order.status != OrderStatus::Processing { @@ -122,30 +129,30 @@ impl Core { } } if order.status == OrderStatus::Processing { - return Err(trc::Cause::Acme + return Err(trc::EventType::Acme(trc::AcmeEvent::Error) .caused_by(trc::location!()) .details("Order processing timed out")); } } OrderStatus::Ready => { - tracing::info!( - context = "acme", - event = "csr-send", - domains = ?provider.domains.as_slice(), - "Sending CSR" + trc::event!( + Acme(trc::AcmeEvent::OrderReady), + Id = provider.id.to_string(), + Name = provider.domains.as_slice(), ); - let csr = cert - .serialize_request_der() - .map_err(|err| trc::Cause::Acme.caused_by(trc::location!()).reason(err))?; + let csr = cert.serialize_request_der().map_err(|err| { + trc::EventType::Acme(trc::AcmeEvent::Error) + .caused_by(trc::location!()) + .reason(err) + })?; order = account.finalize(order.finalize, csr).await? } OrderStatus::Valid { certificate } => { - tracing::info!( - context = "acme", - event = "download", - domains = ?provider.domains.as_slice(), - "Downloading certificate" + trc::event!( + Acme(trc::AcmeEvent::OrderValid), + Id = provider.id.to_string(), + Name = provider.domains.as_slice(), ); let pem = [ @@ -157,15 +164,15 @@ impl Core { return Ok(pem.into_bytes()); } OrderStatus::Invalid => { - tracing::warn!( - context = "acme", - event = "error", - reason = "invalid-order", - domains = ?provider.domains.as_slice(), - "Invalid order" + trc::event!( + Acme(trc::AcmeEvent::OrderInvalid), + Id = provider.id.to_string(), + Name = provider.domains.as_slice(), ); - return Err(trc::Cause::Acme.into_err().details("Invalid ACME order")); + return Err(trc::EventType::Acme(trc::AcmeEvent::Error) + .into_err() + .details("Invalid ACME order")); } } } @@ -182,22 +189,24 @@ impl Core { AuthStatus::Pending => { let Identifier::Dns(domain) = auth.identifier; let challenge_type = provider.challenge.challenge_type(); - tracing::info!( - context = "acme", - event = "challenge", - domain = domain, - challenge = ?challenge_type, - "Requesting challenge for domain {domain}" + + trc::event!( + Acme(trc::AcmeEvent::AuthStart), + Name = domain.to_string(), + Type = challenge_type.as_str(), + Id = provider.id.to_string(), ); + let challenge = auth .challenges .iter() .find(|c| c.typ == challenge_type) .ok_or( - trc::Cause::Acme + trc::EventType::Acme(trc::AcmeEvent::Error) .into_err() .details("Missing Parameter") - .ctx(trc::Key::Id, challenge_type.as_str()), + .ctx(trc::Key::Id, provider.id.to_string()) + .ctx(trc::Key::Type, challenge_type.as_str()), )?; match &provider.challenge { @@ -241,12 +250,12 @@ impl Core { // First try deleting the record if let Err(err) = updater.delete(&name, &origin).await { // Errors are expected if the record does not exist - tracing::trace!( - context = "acme", - event = "dns-delete", - name = name, - origin = origin, - error = ?err, + trc::event!( + Acme(trc::AcmeEvent::DnsRecordDeletionFailed), + Name = name.to_string(), + Reason = err.to_string(), + Origin = origin.to_string(), + Id = provider.id.to_string(), ); } @@ -262,23 +271,20 @@ impl Core { ) .await { - tracing::warn!( - context = "acme", - event = "dns-create", - name = name, - origin = origin, - error = ?err, - "Failed to create DNS record.", - ); - return Err(trc::Cause::Dns.caused_by(trc::location!()).reason(err)); + return Err(trc::EventType::Acme( + trc::AcmeEvent::DnsRecordCreationFailed, + ) + .ctx(trc::Key::Id, provider.id.to_string()) + .ctx(trc::Key::Name, name) + .ctx(trc::Key::Origin, origin) + .reason(err)); } - tracing::info!( - context = "acme", - event = "dns-create", - name = name, - origin = origin, - "Successfully created DNS record.", + trc::event!( + Acme(trc::AcmeEvent::DnsRecordCreated), + Name = name.to_string(), + Origin = origin.to_string(), + Id = provider.id.to_string(), ); // Wait for changes to propagate @@ -292,25 +298,23 @@ impl Core { did_propagate = true; break; } else { - tracing::debug!( - context = "acme", - event = "dns-lookup", - name = name, - origin = origin, - contents = ?result, - expected_proof = ?dns_proof, - "DNS record has not propagated yet.", + trc::event!( + Acme(trc::AcmeEvent::DnsRecordNotPropagated), + Id = provider.id.to_string(), + Name = name.to_string(), + Origin = origin.to_string(), + Result = result.to_string(), + Expected = dns_proof.to_string(), ); } } Err(err) => { - tracing::trace!( - context = "acme", - event = "dns-lookup", - name = name, - origin = origin, - error = ?err, - "Failed to lookup DNS record.", + trc::event!( + Acme(trc::AcmeEvent::DnsRecordLookupFailed), + Id = provider.id.to_string(), + Name = name.to_string(), + Origin = origin.to_string(), + Reason = err.to_string(), ); } } @@ -319,20 +323,18 @@ impl Core { } if did_propagate { - tracing::info!( - context = "acme", - event = "dns-lookup", - name = name, - origin = origin, - "DNS changes have been propagated.", + trc::event!( + Acme(trc::AcmeEvent::DnsRecordPropagated), + Id = provider.id.to_string(), + Name = name.to_string(), + Origin = origin.to_string(), ); } else { - tracing::warn!( - context = "acme", - event = "dns-lookup", - name = name, - origin = origin, - "DNS changes have not been propagated within the timeout.", + trc::event!( + Acme(trc::AcmeEvent::DnsRecordPropagationTimeout), + Id = provider.id.to_string(), + Name = name.to_string(), + Origin = origin.to_string(), ); } } @@ -343,9 +345,9 @@ impl Core { } AuthStatus::Valid => return Ok(()), _ => { - return Err(trc::Cause::Acme + return Err(trc::EventType::Acme(trc::AcmeEvent::AuthError) .into_err() - .details("Authentication error") + .ctx(trc::Key::Id, provider.id.to_string()) .ctx(trc::Key::Status, auth.status.as_str())) } }; @@ -355,45 +357,47 @@ impl Core { let auth = account.auth(url).await?; match auth.status { AuthStatus::Pending => { - tracing::info!( - context = "acme", - event = "auth-pending", - domain = domain, - attempt = i, - "Authorization for domain {domain} is still pending", + trc::event!( + Acme(trc::AcmeEvent::AuthPending), + Name = domain.to_string(), + Id = provider.id.to_string(), + Attempt = i, ); + account.challenge(&challenge_url).await? } AuthStatus::Valid => { - tracing::debug!( - context = "acme", - event = "auth-valid", - domain = domain, - "Authorization for domain {domain} is valid", + trc::event!( + Acme(trc::AcmeEvent::AuthValid), + Name = domain.to_string(), + Id = provider.id.to_string(), ); return Ok(()); } _ => { - return Err(trc::Cause::Acme + return Err(trc::EventType::Acme(trc::AcmeEvent::AuthError) .into_err() - .details("Authentication error") + .ctx(trc::Key::Id, provider.id.to_string()) .ctx(trc::Key::Status, auth.status.as_str())) } } } - Err(trc::Cause::Acme + Err(trc::EventType::Acme(trc::AcmeEvent::AuthTooManyAttempts) .into_err() - .details("Too many authentication attempts") - .ctx(trc::Key::Id, domain)) + .ctx(trc::Key::Id, provider.id.to_string()) + .ctx(trc::Key::Name, domain)) } } fn parse_cert(pem: &[u8]) -> trc::Result<(CertifiedKey, [DateTime; 2])> { - let mut pems = pem::parse_many(pem) - .map_err(|err| trc::Cause::Acme.reason(err).caused_by(trc::location!()))?; + let mut pems = pem::parse_many(pem).map_err(|err| { + trc::EventType::Acme(trc::AcmeEvent::Error) + .reason(err) + .caused_by(trc::location!()) + })?; if pems.len() < 2 { - return Err(trc::Cause::Acme + return Err(trc::EventType::Acme(trc::AcmeEvent::Error) .caused_by(trc::location!()) .ctx(trc::Key::Size, pems.len()) .details("Too few PEMs")); @@ -402,7 +406,11 @@ fn parse_cert(pem: &[u8]) -> trc::Result<(CertifiedKey, [DateTime; 2])> { pems.remove(0).contents(), ))) { Ok(pk) => pk, - Err(err) => return Err(trc::Cause::Acme.reason(err).caused_by(trc::location!())), + Err(err) => { + return Err(trc::EventType::Acme(trc::AcmeEvent::Error) + .reason(err) + .caused_by(trc::location!())) + } }; let cert_chain: Vec = pems .into_iter() @@ -417,7 +425,11 @@ fn parse_cert(pem: &[u8]) -> trc::Result<(CertifiedKey, [DateTime; 2])> { .unwrap_or_default() }) } - Err(err) => return Err(trc::Cause::Acme.reason(err).caused_by(trc::location!())), + Err(err) => { + return Err(trc::EventType::Acme(trc::AcmeEvent::Error) + .reason(err) + .caused_by(trc::location!())) + } }; let cert = CertifiedKey::new(cert_chain, pk); Ok((cert, validity)) diff --git a/crates/common/src/listener/listen.rs b/crates/common/src/listener/listen.rs index db4c92f8..c858f99a 100644 --- a/crates/common/src/listener/listen.rs +++ b/crates/common/src/listener/listen.rs @@ -18,7 +18,6 @@ use tokio::{ sync::watch, }; use tokio_rustls::server::TlsStream; -use tracing::Span; use utils::{config::Config, UnwrapFailure}; use crate::{ @@ -203,19 +202,21 @@ impl BuildSession for Arc { ); None } else if let Some(in_flight) = self.limiter.is_allowed() { + let todo = "build session id"; + let span = tracing::info_span!( + "session", + instance = self.id, + protocol = ?self.protocol, + remote.ip = remote_ip.to_string(), + remote.port = remote_port, + ); // Enforce concurrency SessionData { stream, in_flight, - span: tracing::info_span!( - "session", - instance = self.id, - protocol = ?self.protocol, - remote.ip = remote_ip.to_string(), - remote.port = remote_port, - ), local_ip: local_addr.ip(), local_port: local_addr.port(), + session_id: 0, remote_ip, remote_port, protocol: self.protocol, @@ -335,13 +336,12 @@ impl ServerInstance { pub async fn tls_accept( &self, stream: T, - span: &Span, + session_id: u64, ) -> Result, ()> { match &self.acceptor { TcpAcceptor::Tls { acceptor, .. } => match acceptor.accept(stream).await { Ok(stream) => { tracing::info!( - parent: span, context = "tls", event = "handshake", version = ?stream.get_ref().1.protocol_version().unwrap_or(rustls::ProtocolVersion::TLSv1_3), @@ -351,7 +351,6 @@ impl ServerInstance { } Err(err) => { tracing::debug!( - parent: span, context = "tls", event = "error", "Failed to accept TLS connection: {}", @@ -362,7 +361,6 @@ impl ServerInstance { }, TcpAcceptor::Plain => { tracing::debug!( - parent: span, context = "tls", event = "error", "Failed to accept TLS connection: {}", diff --git a/crates/common/src/listener/mod.rs b/crates/common/src/listener/mod.rs index 2d051346..ee6de5e5 100644 --- a/crates/common/src/listener/mod.rs +++ b/crates/common/src/listener/mod.rs @@ -67,7 +67,7 @@ pub struct SessionData { pub remote_ip: IpAddr, pub remote_port: u16, pub protocol: ServerProtocol, - pub span: tracing::Span, + pub session_id: u64, pub in_flight: InFlight, pub instance: Arc, } @@ -110,7 +110,7 @@ pub trait SessionManager: Sync + Send + 'static + Clone { remote_ip: session.remote_ip, remote_port: session.remote_port, protocol: session.protocol, - span: session.span, + session_id: session.session_id, in_flight: session.in_flight, instance: session.instance, }; diff --git a/crates/common/src/manager/backup.rs b/crates/common/src/manager/backup.rs index 4838c3b7..378474d8 100644 --- a/crates/common/src/manager/backup.rs +++ b/crates/common/src/manager/backup.rs @@ -1117,19 +1117,19 @@ pub(super) trait DeserializeBytes { impl DeserializeBytes for &[u8] { fn range(&self, range: Range) -> trc::Result<&[u8]> { self.get(range.start..std::cmp::min(range.end, self.len())) - .ok_or_else(|| trc::StoreCause::DataCorruption.caused_by(trc::location!())) + .ok_or_else(|| trc::StoreEvent::DataCorruption.caused_by(trc::location!())) } fn deserialize_u8(&self, offset: usize) -> trc::Result { self.get(offset) .copied() - .ok_or_else(|| trc::StoreCause::DataCorruption.caused_by(trc::location!())) + .ok_or_else(|| trc::StoreEvent::DataCorruption.caused_by(trc::location!())) } fn deserialize_leb128(&self) -> trc::Result { self.read_leb128::() .map(|(v, _)| v) - .ok_or_else(|| trc::StoreCause::DataCorruption.caused_by(trc::location!())) + .ok_or_else(|| trc::StoreEvent::DataCorruption.caused_by(trc::location!())) } } diff --git a/crates/common/src/manager/config.rs b/crates/common/src/manager/config.rs index 4dc0c05c..e9ab7024 100644 --- a/crates/common/src/manager/config.rs +++ b/crates/common/src/manager/config.rs @@ -315,7 +315,7 @@ impl ConfigManager { tokio::fs::write(&self.cfg_local_path, cfg_text) .await .map_err(|err| { - trc::Cause::Configuration + trc::EventType::Config(trc::ConfigEvent::WriteError) .reason(err) .details("Failed to write local configuration") .ctx(trc::Key::Path, self.cfg_local_path.display().to_string()) @@ -327,8 +327,9 @@ impl ConfigManager { .fetch_config_resource(resource_id) .await .map_err(|reason| { - trc::Cause::Configuration + trc::EventType::Config(trc::ConfigEvent::FetchError) .caused_by(trc::location!()) + .details("Failed to fetch external configuration") .ctx(trc::Key::Reason, reason) })?; diff --git a/crates/common/src/manager/webadmin.rs b/crates/common/src/manager/webadmin.rs index 2e59e68c..2ebd4081 100644 --- a/crates/common/src/manager/webadmin.rs +++ b/crates/common/src/manager/webadmin.rs @@ -46,7 +46,7 @@ impl WebAdminManager { contents, }) .map_err(|err| { - trc::ResourceCause::Error + trc::ResourceEvent::Error .reason(err) .ctx(trc::Key::Path, path.to_string()) .caused_by(trc::location!()) @@ -65,14 +65,14 @@ impl WebAdminManager { .get_blob(WEBADMIN_KEY, 0..usize::MAX) .await? .ok_or_else(|| { - trc::ResourceCause::NotFound + trc::ResourceEvent::NotFound .caused_by(trc::location!()) .details("Webadmin bundle not found") })?; // Uncompress let mut bundle = zip::ZipArchive::new(Cursor::new(bundle)).map_err(|err| { - trc::ResourceCause::Error + trc::ResourceEvent::Error .caused_by(trc::location!()) .reason(err) .details("Failed to decompress webadmin bundle") @@ -81,7 +81,7 @@ impl WebAdminManager { for i in 0..bundle.len() { let (file_name, contents) = { let mut file = bundle.by_index(i).map_err(|err| { - trc::ResourceCause::Error + trc::ResourceEvent::Error .caused_by(trc::location!()) .reason(err) .details("Failed to read file from webadmin bundle") @@ -139,7 +139,7 @@ impl WebAdminManager { .fetch_resource("webadmin") .await .map_err(|err| { - trc::ResourceCause::Error + trc::ResourceEvent::Error .caused_by(trc::location!()) .reason(err) .details("Failed to download webadmin") @@ -175,7 +175,7 @@ impl TempDir { } fn unpack_error(err: std::io::Error) -> trc::Error { - trc::ResourceCause::Error + trc::ResourceEvent::Error .reason(err) .details("Failed to unpack webadmin bundle") } diff --git a/crates/common/src/scripts/plugins/bayes.rs b/crates/common/src/scripts/plugins/bayes.rs index 76538453..ded2bb17 100644 --- a/crates/common/src/scripts/plugins/bayes.rs +++ b/crates/common/src/scripts/plugins/bayes.rs @@ -41,7 +41,6 @@ pub async fn exec_untrain(ctx: PluginContext<'_>) -> Variable { } async fn train(ctx: PluginContext<'_>, is_train: bool) -> Variable { - let span: &tracing::Span = ctx.span; let store = match &ctx.arguments[0] { Variable::String(v) if !v.is_empty() => ctx.core.storage.lookups.get(v.as_ref()), _ => Some(&ctx.core.storage.lookup), @@ -51,7 +50,7 @@ async fn train(ctx: PluginContext<'_>, is_train: bool) -> Variable { store } else { tracing::warn!( - parent: span, + context = "sieve:bayes_train", event = "failed", reason = "Unknown store id", @@ -63,7 +62,7 @@ async fn train(ctx: PluginContext<'_>, is_train: bool) -> Variable { let is_spam = ctx.arguments[2].to_bool(); if text.is_empty() { tracing::debug!( - parent: span, + context = "sieve:bayes_train", event = "failed", reason = "Empty message", @@ -82,7 +81,7 @@ async fn train(ctx: PluginContext<'_>, is_train: bool) -> Variable { ); if model.weights.is_empty() { tracing::debug!( - parent: span, + context = "sieve:bayes_train", event = "failed", reason = "No weights found", @@ -91,7 +90,7 @@ async fn train(ctx: PluginContext<'_>, is_train: bool) -> Variable { } tracing::debug!( - parent: span, + context = "sieve:bayes_train", event = "train", is_spam = is_spam, @@ -152,7 +151,7 @@ async fn train(ctx: PluginContext<'_>, is_train: bool) -> Variable { } pub async fn exec_classify(ctx: PluginContext<'_>) -> Variable { - let span = ctx.span; + let store = match &ctx.arguments[0] { Variable::String(v) if !v.is_empty() => ctx.core.storage.lookups.get(v.as_ref()), _ => Some(&ctx.core.storage.lookup), @@ -161,7 +160,7 @@ pub async fn exec_classify(ctx: PluginContext<'_>) -> Variable { store } else { tracing::warn!( - parent: span, + context = "sieve:bayes_classify", event = "failed", reason = "Unknown store id", @@ -198,7 +197,7 @@ pub async fn exec_classify(ctx: PluginContext<'_>) -> Variable { (weights.spam, weights.ham) } else { tracing::warn!( - parent: span, + context = "sieve:classify", event = "failed", reason = "Failed to obtain training counts", @@ -209,7 +208,7 @@ pub async fn exec_classify(ctx: PluginContext<'_>) -> Variable { // Make sure we have enough training data if spam_learns < classifier.min_learns || ham_learns < classifier.min_learns { tracing::debug!( - parent: span, + context = "sieve:bayes_classify", event = "skip-classify", reason = "Not enough training data", @@ -249,7 +248,7 @@ pub async fn exec_is_balanced(ctx: PluginContext<'_>) -> Variable { return true.into(); } - let span = ctx.span; + let store = match &ctx.arguments[0] { Variable::String(v) if !v.is_empty() => ctx.core.storage.lookups.get(v.as_ref()), _ => Some(&ctx.core.storage.lookup), @@ -258,7 +257,7 @@ pub async fn exec_is_balanced(ctx: PluginContext<'_>) -> Variable { store } else { tracing::warn!( - parent: span, + context = "sieve:bayes_is_balanced", event = "failed", reason = "Unknown store id", @@ -275,7 +274,7 @@ pub async fn exec_is_balanced(ctx: PluginContext<'_>) -> Variable { (weights.spam as f64, weights.ham as f64) } else { tracing::warn!( - parent: span, + context = "sieve:bayes_is_balanced", event = "failed", reason = "Failed to obtain training counts", @@ -294,7 +293,7 @@ pub async fn exec_is_balanced(ctx: PluginContext<'_>) -> Variable { }; tracing::debug!( - parent: span, + context = "sieve:bayes_is_balanced", event = "result", is_balanced = %result, diff --git a/crates/common/src/scripts/plugins/exec.rs b/crates/common/src/scripts/plugins/exec.rs index b4aabebb..8ea87b82 100644 --- a/crates/common/src/scripts/plugins/exec.rs +++ b/crates/common/src/scripts/plugins/exec.rs @@ -15,7 +15,6 @@ pub fn register(plugin_id: u32, fnc_map: &mut FunctionMap) { } pub async fn exec(ctx: PluginContext<'_>) -> Variable { - let span = ctx.span.clone(); let mut arguments = ctx.arguments.into_iter(); tokio::task::spawn_blocking(move || { @@ -36,7 +35,6 @@ pub async fn exec(ctx: PluginContext<'_>) -> Variable { Ok(result) => result.status.success(), Err(err) => { tracing::warn!( - parent: span, context = "sieve", event = "execute-failed", reason = %err, diff --git a/crates/common/src/scripts/plugins/lookup.rs b/crates/common/src/scripts/plugins/lookup.rs index bb9957d8..4b0a64a7 100644 --- a/crates/common/src/scripts/plugins/lookup.rs +++ b/crates/common/src/scripts/plugins/lookup.rs @@ -67,7 +67,6 @@ pub async fn exec(ctx: PluginContext<'_>) -> Variable { } } else { tracing::debug!( - parent: ctx.span, context = "sieve:lookup", event = "failed", reason = "Unknown lookup id", @@ -93,7 +92,6 @@ pub async fn exec_get(ctx: PluginContext<'_>) -> Variable { .unwrap_or_default() } else { tracing::debug!( - parent: ctx.span, context = "sieve:key_get", event = "failed", reason = "Unknown store or lookup id", @@ -131,7 +129,6 @@ pub async fn exec_set(ctx: PluginContext<'_>) -> Variable { .into() } else { tracing::warn!( - parent: ctx.span, context = "sieve:key_set", event = "failed", reason = "Unknown store id", @@ -293,7 +290,7 @@ pub async fn exec_remote(ctx: PluginContext<'_>) -> Variable { } Err(err) => { tracing::warn!( - parent: ctx.span, + context = "sieve:key_exists_http", event = "failed", resource = resource.as_ref(), @@ -309,7 +306,6 @@ pub async fn exec_remote(ctx: PluginContext<'_>) -> Variable { } tracing::debug!( - parent: ctx.span, context = "sieve:key_exists_http", event = "fetch", resource = resource.as_ref(), @@ -322,7 +318,7 @@ pub async fn exec_remote(ctx: PluginContext<'_>) -> Variable { } Err(err) => { tracing::warn!( - parent: ctx.span, + context = "sieve:key_exists_http", event = "failed", resource = resource.as_ref(), @@ -333,7 +329,7 @@ pub async fn exec_remote(ctx: PluginContext<'_>) -> Variable { } Ok(response) => { tracing::warn!( - parent: ctx.span, + context = "sieve:key_exists_http", event = "failed", resource = resource.as_ref(), @@ -342,7 +338,7 @@ pub async fn exec_remote(ctx: PluginContext<'_>) -> Variable { } Err(err) => { tracing::warn!( - parent: ctx.span, + context = "sieve:key_exists_http", event = "failed", resource = resource.as_ref(), @@ -384,7 +380,6 @@ pub async fn exec_local_domain(ctx: PluginContext<'_>) -> Variable { .into(); } else { tracing::warn!( - parent: ctx.span, context = "sieve:is_local_domain", event = "failed", reason = "Unknown directory", diff --git a/crates/common/src/scripts/plugins/mod.rs b/crates/common/src/scripts/plugins/mod.rs index c679bec5..d95c2c08 100644 --- a/crates/common/src/scripts/plugins/mod.rs +++ b/crates/common/src/scripts/plugins/mod.rs @@ -24,7 +24,7 @@ use super::ScriptModification; type RegisterPluginFnc = fn(u32, &mut FunctionMap) -> (); pub struct PluginContext<'x> { - pub span: &'x tracing::Span, + pub session_id: u64, pub core: &'x Core, pub cache: &'x ScriptCache, pub message: &'x Message<'x>, diff --git a/crates/common/src/scripts/plugins/pyzor.rs b/crates/common/src/scripts/plugins/pyzor.rs index cfe835e4..12800481 100644 --- a/crates/common/src/scripts/plugins/pyzor.rs +++ b/crates/common/src/scripts/plugins/pyzor.rs @@ -77,7 +77,6 @@ pub async fn exec(ctx: PluginContext<'_>) -> Variable { } } - let span = ctx.span; let address = ctx.arguments[0].to_string(); let timeout = Duration::from_secs((ctx.arguments[1].to_integer() as u64).clamp(5, 60)); // Send message to address @@ -85,7 +84,6 @@ pub async fn exec(ctx: PluginContext<'_>) -> Variable { Ok(response) => response.into(), Err(err) => { tracing::debug!( - parent: span, context = "sieve:pyzor_check", event = "failed", reason = %err, diff --git a/crates/common/src/scripts/plugins/query.rs b/crates/common/src/scripts/plugins/query.rs index 221629b7..9e31327d 100644 --- a/crates/common/src/scripts/plugins/query.rs +++ b/crates/common/src/scripts/plugins/query.rs @@ -17,8 +17,6 @@ pub fn register(plugin_id: u32, fnc_map: &mut FunctionMap) { } pub async fn exec(ctx: PluginContext<'_>) -> Variable { - let span = ctx.span; - // Obtain store name let store = match &ctx.arguments[0] { Variable::String(v) if !v.is_empty() => ctx.core.storage.lookups.get(v.as_ref()), @@ -29,7 +27,6 @@ pub async fn exec(ctx: PluginContext<'_>) -> Variable { store } else { tracing::warn!( - parent: span, context = "sieve:query", event = "failed", reason = "Unknown store", @@ -42,7 +39,6 @@ pub async fn exec(ctx: PluginContext<'_>) -> Variable { let query = ctx.arguments[1].to_string(); if query.is_empty() { tracing::warn!( - parent: span, context = "sieve:query", event = "invalid", reason = "Empty query string", diff --git a/crates/directory/src/backend/imap/lookup.rs b/crates/directory/src/backend/imap/lookup.rs index 02613054..6640b13e 100644 --- a/crates/directory/src/backend/imap/lookup.rs +++ b/crates/directory/src/backend/imap/lookup.rs @@ -38,7 +38,7 @@ impl ImapDirectory { AUTH_XOAUTH2 } _ => { - trc::bail!(trc::StoreCause::NotSupported + trc::bail!(trc::StoreEvent::NotSupported .ctx( trc::Key::Reason, "IMAP server does not offer any supported auth mechanisms." @@ -58,32 +58,32 @@ impl ImapDirectory { }, } } else { - Err(trc::StoreCause::NotSupported + Err(trc::StoreEvent::NotSupported .caused_by(trc::location!()) .protocol(trc::Protocol::Imap)) } } pub async fn email_to_ids(&self, _address: &str) -> trc::Result> { - Err(trc::StoreCause::NotSupported + Err(trc::StoreEvent::NotSupported .caused_by(trc::location!()) .protocol(trc::Protocol::Imap)) } pub async fn rcpt(&self, _address: &str) -> trc::Result { - Err(trc::StoreCause::NotSupported + Err(trc::StoreEvent::NotSupported .caused_by(trc::location!()) .protocol(trc::Protocol::Imap)) } pub async fn vrfy(&self, _address: &str) -> trc::Result> { - Err(trc::StoreCause::NotSupported + Err(trc::StoreEvent::NotSupported .caused_by(trc::location!()) .protocol(trc::Protocol::Imap)) } pub async fn expn(&self, _address: &str) -> trc::Result> { - Err(trc::StoreCause::NotSupported + Err(trc::StoreEvent::NotSupported .caused_by(trc::location!()) .protocol(trc::Protocol::Imap)) } diff --git a/crates/directory/src/backend/internal/manage.rs b/crates/directory/src/backend/internal/manage.rs index 6edc3497..7adb50b7 100644 --- a/crates/directory/src/backend/internal/manage.rs +++ b/crates/directory/src/backend/internal/manage.rs @@ -422,7 +422,7 @@ impl ManageDirectory for Store { continue; } } - return Err(trc::ManageCause::NotSupported.caused_by(trc::location!())); + return Err(trc::ManageEvent::NotSupported.caused_by(trc::location!())); } ( PrincipalAction::Set, @@ -762,7 +762,7 @@ impl ManageDirectory for Store { } _ => { - return Err(trc::StoreCause::NotSupported.caused_by(trc::location!())); + return Err(trc::StoreEvent::NotSupported.caused_by(trc::location!())); } } } @@ -1056,25 +1056,25 @@ impl From> for Principal { } pub fn err_missing(field: impl Into) -> trc::Error { - trc::ManageCause::MissingParameter.ctx(trc::Key::Key, field) + trc::ManageEvent::MissingParameter.ctx(trc::Key::Key, field) } pub fn err_exists(field: impl Into, value: impl Into) -> trc::Error { - trc::ManageCause::AlreadyExists + trc::ManageEvent::AlreadyExists .ctx(trc::Key::Key, field) .ctx(trc::Key::Value, value) } pub fn not_found(value: impl Into) -> trc::Error { - trc::ManageCause::NotFound.ctx(trc::Key::Key, value) + trc::ManageEvent::NotFound.ctx(trc::Key::Key, value) } pub fn unsupported(details: impl Into) -> trc::Error { - trc::ManageCause::NotSupported.ctx(trc::Key::Details, details) + trc::ManageEvent::NotSupported.ctx(trc::Key::Details, details) } pub fn error(details: impl Into, reason: Option>) -> trc::Error { - trc::ManageCause::Error + trc::ManageEvent::Error .ctx(trc::Key::Details, details) .ctx_opt(trc::Key::Reason, reason) } diff --git a/crates/directory/src/backend/internal/mod.rs b/crates/directory/src/backend/internal/mod.rs index 4aa0013f..f0421612 100644 --- a/crates/directory/src/backend/internal/mod.rs +++ b/crates/directory/src/backend/internal/mod.rs @@ -58,7 +58,7 @@ impl Serialize for &Principal { impl Deserialize for Principal { fn deserialize(bytes: &[u8]) -> trc::Result { deserialize(bytes).ok_or_else(|| { - trc::StoreCause::DataCorruption + trc::StoreEvent::DataCorruption .caused_by(trc::location!()) .ctx(trc::Key::Value, bytes) }) @@ -79,12 +79,12 @@ impl Deserialize for PrincipalIdType { let mut bytes = bytes_.iter(); Ok(PrincipalIdType { account_id: bytes.next_leb128().ok_or_else(|| { - trc::StoreCause::DataCorruption + trc::StoreEvent::DataCorruption .caused_by(trc::location!()) .ctx(trc::Key::Value, bytes_) })?, typ: Type::from_u8(*bytes.next().ok_or_else(|| { - trc::StoreCause::DataCorruption + trc::StoreEvent::DataCorruption .caused_by(trc::location!()) .ctx(trc::Key::Value, bytes_) })?), diff --git a/crates/directory/src/backend/ldap/lookup.rs b/crates/directory/src/backend/ldap/lookup.rs index 845cc357..82897501 100644 --- a/crates/directory/src/backend/ldap/lookup.rs +++ b/crates/directory/src/backend/ldap/lookup.rs @@ -79,7 +79,7 @@ impl LdapDirectory { { Ok(Some(principal)) => principal, Err(err) - if err.matches(trc::Cause::Store(trc::StoreCause::Ldap)) + if err.matches(trc::EventType::Store(trc::StoreEvent::LdapError)) && err .value(trc::Key::Code) .and_then(|v| v.to_uint()) @@ -332,7 +332,10 @@ impl LdapMappings { fn entry_to_principal(&self, entry: SearchEntry) -> Principal { let mut principal = Principal::default(); - trc::event!(LdapQuery, Value = format!("{entry:?}")); + trc::event!( + Store(trc::StoreEvent::LdapQuery), + Value = format!("{entry:?}") + ); for (attr, value) in entry.attrs { if self.attr_name.contains(&attr) { diff --git a/crates/directory/src/backend/smtp/lookup.rs b/crates/directory/src/backend/smtp/lookup.rs index f879b8ed..ec709507 100644 --- a/crates/directory/src/backend/smtp/lookup.rs +++ b/crates/directory/src/backend/smtp/lookup.rs @@ -21,14 +21,14 @@ impl SmtpDirectory { .authenticate(credentials) .await } else { - Err(trc::StoreCause::NotSupported + Err(trc::StoreEvent::NotSupported .caused_by(trc::location!()) .protocol(trc::Protocol::Smtp)) } } pub async fn email_to_ids(&self, _address: &str) -> trc::Result> { - Err(trc::StoreCause::NotSupported + Err(trc::StoreEvent::NotSupported .caused_by(trc::location!()) .protocol(trc::Protocol::Smtp)) } @@ -64,7 +64,7 @@ impl SmtpDirectory { Ok(true) } Severity::PermanentNegativeCompletion => Ok(false), - _ => Err(trc::StoreCause::Unexpected + _ => Err(trc::StoreEvent::UnexpectedError .ctx(trc::Key::Protocol, trc::Protocol::Smtp) .ctx(trc::Key::Code, reply.code()) .ctx(trc::Key::Details, reply.message)), @@ -127,10 +127,10 @@ impl SmtpClient { .split('\n') .map(|p| p.to_string()) .collect::>()), - code @ (550 | 551 | 553 | 500 | 502) => Err(trc::StoreCause::NotSupported + code @ (550 | 551 | 553 | 500 | 502) => Err(trc::StoreEvent::NotSupported .ctx(trc::Key::Protocol, trc::Protocol::Smtp) .ctx(trc::Key::Code, code)), - code => Err(trc::StoreCause::Unexpected + code => Err(trc::StoreEvent::UnexpectedError .ctx(trc::Key::Protocol, trc::Protocol::Smtp) .ctx(trc::Key::Code, code) .ctx(trc::Key::Details, reply.message)), diff --git a/crates/directory/src/core/secret.rs b/crates/directory/src/core/secret.rs index f6b18955..8a07c10a 100644 --- a/crates/directory/src/core/secret.rs +++ b/crates/directory/src/core/secret.rs @@ -59,7 +59,7 @@ impl Principal { // Token needs to validate with at least one of the TOTP secrets is_totp_verified = TOTP::from_url(secret) .map_err(|err| { - trc::AuthCause::Error + trc::AuthEvent::Error .reason(err) .details(secret.to_string()) })? @@ -86,7 +86,7 @@ impl Principal { // Only let the client know if the TOTP code is missing // if the password is correct - Err(trc::AuthCause::MissingTotp.into_err()) + Err(trc::AuthEvent::MissingTotp.into_err()) } else { // Return the TOTP verification status @@ -128,7 +128,7 @@ async fn verify_hash_prefix(hashed_secret: &str, secret: &str) -> trc::Result { - tx.send(Err(trc::AuthCause::Error + tx.send(Err(trc::AuthEvent::Error .reason(err) .details(hashed_secret))) .ok(); @@ -137,7 +137,9 @@ async fn verify_hash_prefix(hashed_secret: &str, secret: &str) -> trc::Result result, - Err(err) => Err(trc::Cause::Thread.reason(err)), + Err(err) => Err(trc::EventType::Server(trc::ServerEvent::ThreadError) + .caused_by(trc::location!()) + .reason(err)), } } else if hashed_secret.starts_with("$2") { // Blowfish crypt @@ -155,7 +157,7 @@ async fn verify_hash_prefix(hashed_secret: &str, secret: &str) -> trc::Result trc::Resul } } "PLAIN" | "plain" | "CLEAR" | "clear" => Ok(hashed_secret == secret), - _ => Err(trc::AuthCause::Error + _ => Err(trc::AuthEvent::Error .ctx(trc::Key::Reason, "Unsupported algorithm") .details(hashed_secret.to_string())), } } else { - Err(trc::AuthCause::Error + Err(trc::AuthEvent::Error .into_err() .details(hashed_secret.to_string())) } diff --git a/crates/directory/src/lib.rs b/crates/directory/src/lib.rs index 8de4aee1..887eeada 100644 --- a/crates/directory/src/lib.rs +++ b/crates/directory/src/lib.rs @@ -158,10 +158,10 @@ impl IntoError for PoolError { fn into_error(self) -> trc::Error { match self { PoolError::Backend(error) => error.into_error(), - PoolError::Timeout(_) => trc::StoreCause::Pool + PoolError::Timeout(_) => trc::StoreEvent::PoolError .ctx(trc::Key::Protocol, trc::Protocol::Ldap) .details("Connection timed out"), - err => trc::StoreCause::Pool + err => trc::StoreEvent::PoolError .ctx(trc::Key::Protocol, trc::Protocol::Ldap) .reason(err), } @@ -172,10 +172,10 @@ impl IntoError for PoolError { fn into_error(self) -> trc::Error { match self { PoolError::Backend(error) => error.into_error(), - PoolError::Timeout(_) => trc::StoreCause::Pool + PoolError::Timeout(_) => trc::StoreEvent::PoolError .ctx(trc::Key::Protocol, trc::Protocol::Imap) .details("Connection timed out"), - err => trc::StoreCause::Pool + err => trc::StoreEvent::PoolError .ctx(trc::Key::Protocol, trc::Protocol::Imap) .reason(err), } @@ -186,10 +186,10 @@ impl IntoError for PoolError { fn into_error(self) -> trc::Error { match self { PoolError::Backend(error) => error.into_error(), - PoolError::Timeout(_) => trc::StoreCause::Pool + PoolError::Timeout(_) => trc::StoreEvent::PoolError .ctx(trc::Key::Protocol, trc::Protocol::Smtp) .details("Connection timed out"), - err => trc::StoreCause::Pool + err => trc::StoreEvent::PoolError .ctx(trc::Key::Protocol, trc::Protocol::Smtp) .reason(err), } @@ -198,24 +198,24 @@ impl IntoError for PoolError { impl IntoError for ImapError { fn into_error(self) -> trc::Error { - trc::Cause::Imap.reason(self) + trc::ImapEvent::Error.into_err().reason(self) } } impl IntoError for mail_send::Error { fn into_error(self) -> trc::Error { - trc::Cause::Smtp.reason(self) + trc::SmtpEvent::Error.into_err().reason(self) } } impl IntoError for LdapError { fn into_error(self) -> trc::Error { if let LdapError::LdapResult { result } = &self { - trc::StoreCause::Ldap + trc::StoreEvent::LdapError .ctx(trc::Key::Code, result.rc) .reason(self) } else { - trc::StoreCause::Ldap.reason(self) + trc::StoreEvent::LdapError.reason(self) } } } diff --git a/crates/imap-proto/src/protocol/mod.rs b/crates/imap-proto/src/protocol/mod.rs index a3d60591..ec8caa5f 100644 --- a/crates/imap-proto/src/protocol/mod.rs +++ b/crates/imap-proto/src/protocol/mod.rs @@ -497,13 +497,13 @@ impl SerializeResponse for trc::Error { if let Some(code) = self .value_as_str(trc::Key::Code) .or_else(|| match self.as_ref() { - trc::Cause::Store(trc::StoreCause::NotFound) => { + trc::EventType::Store(trc::StoreEvent::NotFound) => { Some(ResponseCode::NonExistent.as_str()) } - trc::Cause::Store(_) => Some(ResponseCode::ContactAdmin.as_str()), - trc::Cause::Limit(trc::LimitCause::Quota) => Some(ResponseCode::OverQuota.as_str()), - trc::Cause::Limit(_) => Some(ResponseCode::Limit.as_str()), - trc::Cause::Auth(_) => Some(ResponseCode::AuthenticationFailed.as_str()), + trc::EventType::Store(_) => Some(ResponseCode::ContactAdmin.as_str()), + trc::EventType::Limit(trc::LimitEvent::Quota) => Some(ResponseCode::OverQuota.as_str()), + trc::EventType::Limit(_) => Some(ResponseCode::Limit.as_str()), + trc::EventType::Auth(_) => Some(ResponseCode::AuthenticationFailed.as_str()), _ => None, }) { diff --git a/crates/imap-proto/src/receiver.rs b/crates/imap-proto/src/receiver.rs index 3d4d58b1..dacc2a32 100644 --- a/crates/imap-proto/src/receiver.rs +++ b/crates/imap-proto/src/receiver.rs @@ -464,7 +464,7 @@ impl Display for Token { impl Error { pub fn err(tag: Option, message: impl Into) -> Self { Error::Error { - response: trc::Cause::Imap + response: trc::ImapEvent::Error .ctx(trc::Key::Details, message) .ctx_opt(trc::Key::Id, tag) .ctx(trc::Key::Type, ResponseType::Bad) @@ -488,13 +488,13 @@ impl Default for Receiver { impl Request { pub fn into_error(self, message: impl Into) -> trc::Error { - trc::Cause::Imap + trc::ImapEvent::Error .ctx(trc::Key::Details, message) .ctx(trc::Key::Id, self.tag) } pub fn into_parse_error(self, message: impl Into) -> trc::Error { - trc::Cause::Imap + trc::ImapEvent::Error .ctx(trc::Key::Details, message) .ctx(trc::Key::Id, self.tag) .ctx(trc::Key::Code, ResponseCode::Parse) @@ -503,7 +503,7 @@ impl Request { } pub(crate) fn bad(tag: impl Into, message: impl Into) -> trc::Error { - trc::Cause::Imap + trc::ImapEvent::Error .ctx(trc::Key::Details, message) .ctx(trc::Key::Id, tag) .ctx(trc::Key::Type, ResponseType::Bad) diff --git a/crates/imap/Cargo.toml b/crates/imap/Cargo.toml index 69d123f2..3f8644d1 100644 --- a/crates/imap/Cargo.toml +++ b/crates/imap/Cargo.toml @@ -21,11 +21,11 @@ rustls-pemfile = "2.0" tokio = { version = "1.23", features = ["full"] } tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] } parking_lot = "0.12" -tracing = "0.1" ahash = { version = "0.8" } md5 = "0.7.0" dashmap = "6.0" rand = "0.8.5" +tracing = "0.1" [features] test_mode = [] diff --git a/crates/imap/src/core/client.rs b/crates/imap/src/core/client.rs index 175dc986..6eabc51c 100644 --- a/crates/imap/src/core/client.rs +++ b/crates/imap/src/core/client.rs @@ -21,10 +21,11 @@ impl Session { let c = println!("{}", line); }*/ - tracing::trace!(parent: &self.span, + tracing::trace!( event = "read", - data = std::str::from_utf8(bytes).unwrap_or("[invalid UTF8]"), - size = bytes.len()); + data = std::str::from_utf8(bytes).unwrap_or("[invalid UTF8]"), + size = bytes.len() + ); let mut bytes = bytes.iter(); let mut requests = Vec::with_capacity(2); @@ -267,7 +268,7 @@ impl Session { .await? .is_some() { - return Err(trc::LimitCause::TooManyRequests.into_err()); + return Err(trc::LimitEvent::TooManyRequests.into_err()); } } } @@ -279,13 +280,13 @@ impl Session { if self.instance.acceptor.is_tls() { Ok(request) } else { - Err(trc::Cause::Imap + Err(trc::ImapEvent::Error .into_err() .details("TLS is not available.") .id(request.tag)) } } else { - Err(trc::Cause::Imap + Err(trc::ImapEvent::Error .into_err() .details("Already in TLS mode.") .id(request.tag)) @@ -295,7 +296,7 @@ impl Session { if let State::NotAuthenticated { .. } = state { Ok(request) } else { - Err(trc::Cause::Imap + Err(trc::ImapEvent::Error .into_err() .details("Already authenticated.") .id(request.tag)) @@ -306,13 +307,13 @@ impl Session { if self.is_tls || self.jmap.core.imap.allow_plain_auth { Ok(request) } else { - Err(trc::Cause::Imap + Err(trc::ImapEvent::Error .into_err() .details("LOGIN is disabled on the clear-text port.") .id(request.tag)) } } else { - Err(trc::Cause::Imap + Err(trc::ImapEvent::Error .into_err() .details("Already authenticated.") .id(request.tag)) @@ -341,7 +342,7 @@ impl Session { if let State::Authenticated { .. } | State::Selected { .. } = state { Ok(request) } else { - Err(trc::Cause::Imap + Err(trc::ImapEvent::Error .into_err() .details("Not authenticated.") .id(request.tag)) @@ -367,18 +368,18 @@ impl Session { { Ok(request) } else { - Err(trc::Cause::Imap + Err(trc::ImapEvent::Error .into_err() .details("Not permitted in EXAMINE state.") .id(request.tag)) } } - State::Authenticated { .. } => Err(trc::Cause::Imap + State::Authenticated { .. } => Err(trc::ImapEvent::Error .into_err() .details("No mailbox is selected.") .ctx(trc::Key::Type, ResponseType::Bad) .id(request.tag)), - State::NotAuthenticated { .. } => Err(trc::Cause::Imap + State::NotAuthenticated { .. } => Err(trc::ImapEvent::Error .into_err() .details("Not authenticated.") .id(request.tag)), diff --git a/crates/imap/src/core/mailbox.rs b/crates/imap/src/core/mailbox.rs index c6371a8b..7c6dae08 100644 --- a/crates/imap/src/core/mailbox.rs +++ b/crates/imap/src/core/mailbox.rs @@ -36,7 +36,7 @@ impl SessionData { jmap: session.jmap.clone(), imap: session.imap.clone(), account_id: access_token.primary_id(), - span: session.span.clone(), + session_id: session.session_id, mailboxes: Mutex::new(vec![]), state: access_token.state().into(), in_flight, @@ -356,7 +356,7 @@ impl SessionData { { new_accounts.push(account); } else { - tracing::debug!(parent: &self.span, "Removed unlinked shared account {}", account.account_id); + tracing::debug!("Removed unlinked shared account {}", account.account_id); // Add unshared mailboxes to deleted list if let Some(changes) = &mut changes { @@ -374,7 +374,7 @@ impl SessionData { .skip(1) .any(|m| m.account_id == account_id) { - tracing::debug!(parent: &self.span, "Adding shared account {}", account_id); + tracing::debug!("Adding shared account {}", account_id); added_account_ids.push(account_id); } } @@ -404,7 +404,7 @@ impl SessionData { added_accounts.push(account); } Err(_) => { - tracing::debug!(parent: &self.span, "Failed to fetch shared mailbox."); + tracing::debug!("Failed to fetch shared mailbox."); } } } @@ -520,7 +520,7 @@ impl SessionData { changed_accounts.push(account_mailboxes); } Err(_) => { - tracing::debug!(parent: &self.span, "Failed to fetch mailboxes:."); + tracing::debug!("Failed to fetch mailboxes:."); } } } @@ -638,7 +638,7 @@ impl SessionData { .await? .map(|mailbox| mailbox.effective_acl(&access_token).contains(item)) .ok_or_else(|| { - trc::Cause::Imap + trc::ImapEvent::Error .caused_by(trc::location!()) .details("Mailbox no longer exists.") })?) diff --git a/crates/imap/src/core/message.rs b/crates/imap/src/core/message.rs index b42592ba..6b480605 100644 --- a/crates/imap/src/core/message.rs +++ b/crates/imap/src/core/message.rs @@ -229,7 +229,7 @@ impl SessionData { .await? .and_then(|obj| obj.get(&Property::Cid).as_uint()) .ok_or_else(|| { - trc::Cause::Imap + trc::ImapEvent::Error .caused_by(trc::location!()) .details("Mailbox unavailable") .account_id(mailbox.account_id) @@ -270,7 +270,7 @@ impl SelectedMailbox { Ok(ids) } else { let saved_ids = self.get_saved_search().await.ok_or_else(|| { - trc::Cause::Imap + trc::ImapEvent::Error .into_err() .details("No saved search found.") })?; diff --git a/crates/imap/src/core/mod.rs b/crates/imap/src/core/mod.rs index a38a507f..92f812ae 100644 --- a/crates/imap/src/core/mod.rs +++ b/crates/imap/src/core/mod.rs @@ -77,14 +77,14 @@ pub struct Session { pub stream_tx: Arc>>, pub in_flight: InFlight, pub remote_addr: IpAddr, - pub span: tracing::Span, + pub session_id: u64, } pub struct SessionData { pub account_id: u32, pub jmap: JMAP, pub imap: Arc, - pub span: tracing::Span, + pub session_id: u64, pub mailboxes: parking_lot::Mutex>, pub stream_tx: Arc>>, pub state: AtomicU32, @@ -234,7 +234,7 @@ impl SessionData { account_id: self.account_id, jmap: self.jmap, imap: self.imap, - span: self.span, + session_id: self.session_id, mailboxes: self.mailboxes, stream_tx: new_stream, state: self.state, diff --git a/crates/imap/src/core/session.rs b/crates/imap/src/core/session.rs index d242a25e..65f81a51 100644 --- a/crates/imap/src/core/session.rs +++ b/crates/imap/src/core/session.rs @@ -67,24 +67,24 @@ impl Session { } } } else { - tracing::debug!(parent: &self.span, event = "close", "IMAP connection closed by client."); + tracing::debug!( event = "close", "IMAP connection closed by client."); break; } }, Ok(Err(err)) => { - tracing::debug!(parent: &self.span, event = "error", reason = %err, "IMAP connection error."); + tracing::debug!( event = "error", reason = %err, "IMAP connection error."); break; }, Err(_) => { self.write_bytes(&b"* BYE Connection timed out.\r\n"[..]).await.ok(); - tracing::debug!(parent: &self.span, "IMAP connection timed out."); + tracing::debug!( "IMAP connection timed out."); break; } } }, _ = shutdown_rx.changed() => { self.write_bytes(&b"* BYE Server shutting down.\r\n"[..]).await.ok(); - tracing::debug!(parent: &self.span, event = "shutdown", "IMAP server shutting down."); + tracing::debug!( event = "shutdown", "IMAP server shutting down."); break; } }; @@ -104,7 +104,7 @@ impl Session { (false, &manager.imap.imap_inner.greeting_plain) }; if let Err(err) = session.stream.write_all(greeting).await { - tracing::debug!(parent: &session.span, event = "error", reason = %err, "Failed to write greeting."); + tracing::debug!( event = "error", reason = %err, "Failed to write greeting."); return Err(()); } let _ = session.stream.flush().await; @@ -123,7 +123,7 @@ impl Session { jmap, imap: manager.imap.imap_inner, instance: session.instance, - span: session.span, + session_id: session.session_id, in_flight: session.in_flight, remote_addr: session.remote_ip, stream_rx, @@ -156,7 +156,7 @@ impl Session { // Upgrade to TLS let (stream_rx, stream_tx) = - tokio::io::split(self.instance.tls_accept(stream, &self.span).await?); + tokio::io::split(self.instance.tls_accept(stream, self.session_id).await?); let stream_tx = Arc::new(tokio::sync::Mutex::new(stream_tx)); Ok(Session { @@ -169,7 +169,7 @@ impl Session { is_tls: true, is_condstore: self.is_condstore, is_qresync: self.is_qresync, - span: self.span, + session_id: self.session_id, in_flight: self.in_flight, remote_addr: self.remote_addr, stream_rx, @@ -185,7 +185,6 @@ impl Session { let c = println!("{}", line); }*/ tracing::trace!( - parent: &self.span, event = "write", data = std::str::from_utf8(bytes).unwrap_or_default(), size = bytes.len() @@ -193,7 +192,8 @@ impl Session { let mut stream = self.stream_tx.lock().await; if let Err(err) = stream.write_all(bytes).await { - Err(trc::Cause::Network + Err(trc::NetworkEvent::WriteError + .into_err() .reason(err) .details("Failed to write to stream")) } else { @@ -203,13 +203,13 @@ impl Session { } pub async fn write_error(&self, err: trc::Error) -> bool { - tracing::warn!(parent: &self.span, event = "error", reason = %err, "IMAP error."); + tracing::warn!( event = "error", reason = %err, "IMAP error."); if err.should_write_err() { let disconnect = err.must_disconnect(); if let Err(err) = self.write_bytes(err.serialize()).await { - tracing::debug!(parent: &self.span, event = "error", reason = %err, "Failed to write error."); + tracing::debug!( event = "error", reason = %err, "Failed to write error."); false } else { !disconnect @@ -227,7 +227,6 @@ impl super::SessionData { let c = println!("{}", line); }*/ tracing::trace!( - parent: &self.span, event = "write", data = std::str::from_utf8(bytes).unwrap_or_default(), size = bytes.len() @@ -235,7 +234,8 @@ impl super::SessionData { let mut stream = self.stream_tx.lock().await; if let Err(err) = stream.write_all(bytes.as_ref()).await { - Err(trc::Cause::Network + Err(trc::NetworkEvent::WriteError + .into_err() .reason(err) .details("Failed to write to stream")) } else { @@ -245,7 +245,7 @@ impl super::SessionData { } pub async fn write_error(&self, err: trc::Error) -> trc::Result<()> { - tracing::warn!(parent: &self.span, event = "error", reason = %err, "IMAP error."); + tracing::warn!( event = "error", reason = %err, "IMAP error."); if err.should_write_err() { self.write_bytes(err.serialize()).await diff --git a/crates/imap/src/op/acl.rs b/crates/imap/src/op/acl.rs index 32cd9ef0..54f3394e 100644 --- a/crates/imap/src/op/acl.rs +++ b/crates/imap/src/op/acl.rs @@ -218,7 +218,7 @@ impl Session { .await .imap_ctx(&arguments.tag, trc::location!())? .ok_or_else(|| { - trc::Cause::Imap + trc::ImapEvent::Error .into_err() .details("Account does not exist") .id(arguments.tag.to_string()) @@ -250,7 +250,7 @@ impl Session { }) { acl } else { - return Err(trc::StoreCause::DataCorruption + return Err(trc::StoreEvent::DataCorruption .into_err() .id(arguments.tag) .ctx(trc::Key::Reason, "Invalid mailbox ACL") @@ -393,18 +393,18 @@ impl SessionData { { Ok((mailbox, values, access_token)) } else { - Err(trc::Cause::Imap + Err(trc::ImapEvent::Error .into_err() .details("You do not have enough permissions to perform this operation.") .code(ResponseCode::NoPerm)) } } else { - Err(trc::Cause::Imap + Err(trc::ImapEvent::Error .caused_by(trc::location!()) .details("Mailbox does not exist.")) } } else { - Err(trc::Cause::Imap + Err(trc::ImapEvent::Error .into_err() .details("Mailbox does not exist.")) } diff --git a/crates/imap/src/op/append.rs b/crates/imap/src/op/append.rs index b923e83c..6f93d9c5 100644 --- a/crates/imap/src/op/append.rs +++ b/crates/imap/src/op/append.rs @@ -37,7 +37,7 @@ impl Session { let mailbox = if let Some(mailbox) = data.get_mailbox_by_name(&arguments.mailbox_name) { mailbox } else { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("Mailbox does not exist.") .code(ResponseCode::TryCreate) @@ -72,7 +72,7 @@ impl SessionData { .await .imap_ctx(&arguments.tag, trc::location!())? { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details( "You do not have the required permissions to append messages to this mailbox.", @@ -116,7 +116,7 @@ impl SessionData { last_change_id = Some(email.change_id); } Err(err) => { - return Err(if err.matches(trc::Cause::Limit(trc::LimitCause::Quota)) { + return Err(if err.matches(trc::EventType::Limit(trc::LimitEvent::Quota)) { err.details("Disk quota exceeded.") .code(ResponseCode::OverQuota) } else { diff --git a/crates/imap/src/op/authenticate.rs b/crates/imap/src/op/authenticate.rs index 26a43468..387e1cc1 100644 --- a/crates/imap/src/op/authenticate.rs +++ b/crates/imap/src/op/authenticate.rs @@ -25,7 +25,7 @@ impl Session { if !args.params.is_empty() { let challenge = base64_decode(args.params.pop().unwrap().as_bytes()) .ok_or_else(|| { - trc::AuthCause::Error + trc::AuthEvent::Error .into_err() .details("Failed to decode challenge.") .id(args.tag.clone()) @@ -38,7 +38,7 @@ impl Session { decode_challenge_oauth(&challenge) } .map_err(|err| { - trc::AuthCause::Error + trc::AuthEvent::Error .into_err() .details(err) .id(args.tag.clone()) @@ -55,7 +55,7 @@ impl Session { self.write_bytes(b"+ \"\"\r\n".to_vec()).await } } - _ => Err(trc::AuthCause::Error + _ => Err(trc::AuthEvent::Error .into_err() .details("Authentication mechanism not supported.") .id(args.tag) @@ -93,14 +93,14 @@ impl Session { } } .map_err(|err| { - if err.matches(trc::Cause::Auth(trc::AuthCause::Failed)) { + if err.matches(trc::EventType::Auth(trc::AuthEvent::Failed)) { let auth_failures = self.state.auth_failures(); if auth_failures < self.jmap.core.imap.max_auth_failures { self.state = State::NotAuthenticated { auth_failures: auth_failures + 1, }; } else { - return trc::AuthCause::TooManyAttempts.into_err().caused_by(err); + return trc::AuthEvent::TooManyAttempts.into_err().caused_by(err); } } @@ -115,7 +115,7 @@ impl Session { Some(Some(limiter)) => Some(limiter), None => None, Some(None) => { - return Err(trc::LimitCause::ConcurrentRequest + return Err(trc::LimitEvent::ConcurrentRequest .into_err() .id(tag.clone())); } diff --git a/crates/imap/src/op/copy_move.rs b/crates/imap/src/op/copy_move.rs index 8f51159a..48928fd7 100644 --- a/crates/imap/src/op/copy_move.rs +++ b/crates/imap/src/op/copy_move.rs @@ -53,7 +53,7 @@ impl Session { if let Some(mailbox) = data.get_mailbox_by_name(&arguments.mailbox_name) { mailbox } else { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("Destination mailbox does not exist.") .code(ResponseCode::TryCreate) @@ -64,7 +64,7 @@ impl Session { if src_mailbox.id.account_id == dest_mailbox.account_id && src_mailbox.id.mailbox_id == dest_mailbox.mailbox_id { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("Source and destination mailboxes are the same.") .code(ResponseCode::Cannot) @@ -101,7 +101,7 @@ impl SessionData { .imap_ctx(&arguments.tag, trc::location!())?; if ids.is_empty() { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("No messages were found.") .id(arguments.tag)); @@ -118,7 +118,7 @@ impl SessionData { .await .imap_ctx(&arguments.tag, trc::location!())? { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details(concat!( "You do not have the required permissions to ", @@ -135,7 +135,7 @@ impl SessionData { .await .imap_ctx(&arguments.tag, trc::location!())? { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details(concat!( "You do not have the required permissions to ", @@ -325,12 +325,12 @@ impl SessionData { // Map copied JMAP Ids to IMAP UIDs in the destination folder. if copied_ids.is_empty() { return Err(if response.rtype != ResponseType::Ok { - trc::Cause::Imap + trc::ImapEvent::Error .into_err() .details(response.message) .ctx_opt(trc::Key::Code, response.code) } else { - trc::Cause::Imap.into_err().details(if is_move { + trc::ImapEvent::Error.into_err().details(if is_move { "No messages were moved." } else { "No messages were copied." diff --git a/crates/imap/src/op/create.rs b/crates/imap/src/op/create.rs index f026e567..05fa71dc 100644 --- a/crates/imap/src/op/create.rs +++ b/crates/imap/src/op/create.rs @@ -150,7 +150,7 @@ impl SessionData { { account } else { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("Account no longer available.") .caused_by(trc::location!())); @@ -236,7 +236,7 @@ impl SessionData { name = prefix.trim(); } if name.is_empty() { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details(format!("Invalid folder name '{mailbox_name}'.",))); } @@ -248,11 +248,11 @@ impl SessionData { for path_item in name.split('/') { let path_item = path_item.trim(); if path_item.is_empty() { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("Invalid empty path item.")); } else if path_item.len() > self.jmap.core.jmap.mailbox_name_max_len { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("Mailbox name is too long.")); } @@ -260,7 +260,7 @@ impl SessionData { } if path.len() > self.jmap.core.jmap.mailbox_max_depth { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("Mailbox path is too deep.")); } @@ -278,7 +278,7 @@ impl SessionData { let account = if first_path_item == &self.jmap.core.jmap.shared_folder { // Shared Folders// if path.len() < 3 { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("Mailboxes under root shared folders are not allowed.") .code(ResponseCode::Cannot)); @@ -294,7 +294,7 @@ impl SessionData { account } else { #[allow(clippy::unnecessary_literal_unwrap)] - return Err(trc::Cause::Imap.into_err().details(format!( + return Err(trc::ImapEvent::Error.into_err().details(format!( "Shared account '{}' not found.", prefix.unwrap_or_default() ))); @@ -302,7 +302,7 @@ impl SessionData { } else if let Some(account) = mailboxes.first() { account } else { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("Internal server error.") .caused_by(trc::location!()) @@ -311,7 +311,7 @@ impl SessionData { // Locate parent mailbox if account.mailbox_names.contains_key(&full_path) { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details(format!("Mailbox '{}' already exists.", full_path))); } @@ -344,7 +344,7 @@ impl SessionData { .check_mailbox_acl(account_id, parent_mailbox_id, Acl::CreateChild) .await? { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("You are not allowed to create sub mailboxes under this mailbox.") .code(ResponseCode::NoPerm)); @@ -356,7 +356,7 @@ impl SessionData { .caused_by(trc::location!())? .is_member(account_id) { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("You are not allowed to create root folders under shared folders.") .code(ResponseCode::Cannot)); @@ -382,7 +382,7 @@ impl SessionData { .results .is_empty() { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details(format!( "A mailbox with role '{mailbox_role}' already exists.", diff --git a/crates/imap/src/op/delete.rs b/crates/imap/src/op/delete.rs index 7d2f41e0..29400f2b 100644 --- a/crates/imap/src/op/delete.rs +++ b/crates/imap/src/op/delete.rs @@ -54,7 +54,7 @@ impl SessionData { if let Some(mailbox) = self.get_mailbox_by_name(&arguments.mailbox_name) { (mailbox.account_id, mailbox.mailbox_id) } else { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("Mailbox does not exist.") .code(ResponseCode::TryCreate) @@ -75,7 +75,7 @@ impl SessionData { { Ok(did_remove_emails) => did_remove_emails, Err(err) => { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details(err.description.unwrap_or("Delete failed".into())) .code(ResponseCode::from(err.type_)) diff --git a/crates/imap/src/op/expunge.rs b/crates/imap/src/op/expunge.rs index 093868ba..4441a930 100644 --- a/crates/imap/src/op/expunge.rs +++ b/crates/imap/src/op/expunge.rs @@ -46,7 +46,7 @@ impl Session { .await .imap_ctx(&request.tag, trc::location!())? { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details(concat!( "You do not have the required permissions ", @@ -60,7 +60,7 @@ impl Session { let sequence = match request.tokens.into_iter().next() { Some(Token::Argument(value)) if is_uid => { let sequence = parse_sequence_set(&value).map_err(|err| { - trc::Cause::Imap + trc::ImapEvent::Error .into_err() .details(err) .ctx(trc::Key::Type, ResponseType::Bad) diff --git a/crates/imap/src/op/fetch.rs b/crates/imap/src/op/fetch.rs index 70603f7a..43c4db54 100644 --- a/crates/imap/src/op/fetch.rs +++ b/crates/imap/src/op/fetch.rs @@ -88,13 +88,13 @@ impl SessionData { // Validate VANISHED parameter if arguments.include_vanished { if !is_qresync { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("Enable QRESYNC first to use the VANISHED parameter.") .ctx(trc::Key::Type, ResponseType::Bad) .id(arguments.tag)); } else if !is_uid { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("VANISHED parameter is only available for UID FETCH.") .ctx(trc::Key::Type, ResponseType::Bad) @@ -423,7 +423,7 @@ impl SessionData { } Err(_) => { self.write_error( - trc::Cause::Imap + trc::ImapEvent::Error .into_err() .details(format!( "Failed to decode part {} of message {}.", diff --git a/crates/imap/src/op/idle.rs b/crates/imap/src/op/idle.rs index b0802fba..fdcf7f30 100644 --- a/crates/imap/src/op/idle.rs +++ b/crates/imap/src/op/idle.rs @@ -56,7 +56,7 @@ impl Session { // Send continuation response self.write_bytes(b"+ Idling, send 'DONE' to stop.\r\n".to_vec()) .await?; - tracing::debug!(parent: &self.span, event = "start", context = "idle", "Starting IDLE."); + tracing::debug!(event = "start", context = "idle", "Starting IDLE."); let mut buf = vec![0; 1024]; loop { tokio::select! { @@ -65,22 +65,22 @@ impl Session { Ok(Ok(bytes_read)) => { if bytes_read > 0 { if (buf[..bytes_read]).windows(4).any(|w| w == b"DONE") { - tracing::debug!(parent: &self.span, event = "stop", context = "idle", "Stopping IDLE."); + tracing::debug!( event = "stop", context = "idle", "Stopping IDLE."); return self.write_bytes(StatusResponse::completed(Command::Idle) .with_tag(request.tag) .into_bytes()).await; } } else { - tracing::debug!(parent: &self.span, event = "close", ); - return Err(trc::Cause::Network.into_err().details("IMAP connection closed by client.").id(request.tag)); + tracing::debug!( event = "close", ); + return Err(trc::NetworkEvent::Closed.into_err().details("IMAP connection closed by client.").id(request.tag)); } }, Ok(Err(err)) => { - return Err(trc::Cause::Network.reason(err).details("IMAP connection error.").id(request.tag)); + return Err(trc::NetworkEvent::ReadError.into_err().reason(err).details("IMAP connection error.").id(request.tag)); }, Err(_) => { self.write_bytes(&b"* BYE IDLE timed out.\r\n"[..]).await.ok(); - return Err(trc::Cause::Network.into_err().details("IMAP IDLE timed out.").id(request.tag)); + return Err(trc::NetworkEvent::Timeout.into_err().details("IMAP IDLE timed out.").id(request.tag)); } } } @@ -106,7 +106,7 @@ impl Session { } } else { self.write_bytes(&b"* BYE Server shutting down.\r\n"[..]).await.ok(); - return Err(trc::Cause::Network.into_err().details("IDLE channel closed.").id(request.tag)); + return Err(trc::NetworkEvent::Closed.into_err().details("IDLE channel closed.").id(request.tag)); } } } diff --git a/crates/imap/src/op/list.rs b/crates/imap/src/op/list.rs index cf63c701..3db893ec 100644 --- a/crates/imap/src/op/list.rs +++ b/crates/imap/src/op/list.rs @@ -141,7 +141,7 @@ impl SessionData { } } if recursive_match && !filter_subscribed { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("RECURSIVEMATCH requires the SUBSCRIBED selection option.") .id(tag)); diff --git a/crates/imap/src/op/mod.rs b/crates/imap/src/op/mod.rs index 43706623..057faf6e 100644 --- a/crates/imap/src/op/mod.rs +++ b/crates/imap/src/op/mod.rs @@ -84,14 +84,16 @@ impl ImapContext for trc::Result { fn imap_ctx(self, tag: &str, location: &'static str) -> trc::Result { match self { Ok(value) => Ok(value), - Err(err) => Err(if !err.matches(trc::Cause::Imap) { - err.ctx(trc::Key::Id, tag.to_string()) - .ctx(trc::Key::Details, "Internal Server Error") - .ctx(trc::Key::Code, ResponseCode::ContactAdmin) - .ctx(trc::Key::CausedBy, location) - } else { - err.ctx(trc::Key::Id, tag.to_string()) - }), + Err(err) => Err( + if !err.matches(trc::EventType::Imap(trc::ImapEvent::Error)) { + err.ctx(trc::Key::Id, tag.to_string()) + .ctx(trc::Key::Details, "Internal Server Error") + .ctx(trc::Key::Code, ResponseCode::ContactAdmin) + .ctx(trc::Key::CausedBy, location) + } else { + err.ctx(trc::Key::Id, tag.to_string()) + }, + ), } } } diff --git a/crates/imap/src/op/rename.rs b/crates/imap/src/op/rename.rs index 463be2b8..e061c554 100644 --- a/crates/imap/src/op/rename.rs +++ b/crates/imap/src/op/rename.rs @@ -62,7 +62,7 @@ impl SessionData { mailbox_id = (*mailbox_id_).into(); break; } else { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("Cannot move mailboxes between accounts.") .code(ResponseCode::Cannot) @@ -73,7 +73,7 @@ impl SessionData { if let Some(mailbox_id) = mailbox_id { mailbox_id } else { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details(format!("Mailbox '{}' not found.", arguments.mailbox_name)) .code(ResponseCode::NonExistent) @@ -93,7 +93,7 @@ impl SessionData { .await .imap_ctx(&arguments.tag, trc::location!())? .ok_or_else(|| { - trc::Cause::Imap + trc::ImapEvent::Error .into_err() .details(format!("Mailbox '{}' not found.", arguments.mailbox_name)) .caused_by(trc::location!()) @@ -112,7 +112,7 @@ impl SessionData { .effective_acl(&access_token) .contains(Acl::Modify) { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("You are not allowed to rename this mailbox.") .code(ResponseCode::NoPerm) diff --git a/crates/imap/src/op/search.rs b/crates/imap/src/op/search.rs index 3018f7f0..12d18152 100644 --- a/crates/imap/src/op/search.rs +++ b/crates/imap/src/op/search.rs @@ -287,9 +287,11 @@ impl SessionData { search::Filter::Header(header, value) => { match HeaderName::parse(header) { Some(HeaderName::Other(header_name)) => { - return Err(trc::Cause::Imap.into_err().details(format!( - "Querying header '{header_name}' is not supported.", - ))); + return Err(trc::ImapEvent::Error.into_err().details( + format!( + "Querying header '{header_name}' is not supported.", + ), + )); } Some(header_name) => { if !value.is_empty() { @@ -410,7 +412,7 @@ impl SessionData { } } } else { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("No saved search found.")); } @@ -610,7 +612,7 @@ impl SessionData { RoaringBitmap::from_sorted_iter([id.document_id()]).unwrap(), )); } else { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details(format!("Failed to parse email id '{id}'.",))); } @@ -622,7 +624,7 @@ impl SessionData { id.document_id(), )); } else { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details(format!("Failed to parse thread id '{id}'.",))); } diff --git a/crates/imap/src/op/select.rs b/crates/imap/src/op/select.rs index 4e4e9e38..d76a1607 100644 --- a/crates/imap/src/op/select.rs +++ b/crates/imap/src/op/select.rs @@ -93,7 +93,7 @@ impl Session { // Validate QRESYNC arguments if let Some(qresync) = arguments.qresync { if !self.is_qresync { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("QRESYNC is not enabled.") .id(arguments.tag)); @@ -155,7 +155,7 @@ impl Session { ) .await } else { - Err(trc::Cause::Imap + Err(trc::ImapEvent::Error .into_err() .details("Mailbox does not exist.") .code(ResponseCode::NonExistent) diff --git a/crates/imap/src/op/status.rs b/crates/imap/src/op/status.rs index d4fa855e..e418b494 100644 --- a/crates/imap/src/op/status.rs +++ b/crates/imap/src/op/status.rs @@ -99,7 +99,7 @@ impl SessionData { .collect(), }) } else { - Err(trc::Cause::Imap + Err(trc::ImapEvent::Error .into_err() .details("Mailbox does not exist.") .code(ResponseCode::NonExistent)) @@ -239,7 +239,7 @@ impl SessionData { .await? .and_then(|obj| obj.get(&Property::Cid).as_uint()) .ok_or_else(|| { - trc::StoreCause::Unexpected + trc::StoreEvent::UnexpectedError .into_err() .details("Mailbox unavailable") .ctx(trc::Key::Reason, "Failed to obtain uid validity") diff --git a/crates/imap/src/op/store.rs b/crates/imap/src/op/store.rs index a07647fa..f7ec4781 100644 --- a/crates/imap/src/op/store.rs +++ b/crates/imap/src/op/store.rs @@ -87,7 +87,7 @@ impl SessionData { .await .imap_ctx(&arguments.tag, trc::location!())? { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details( "You do not have the required permissions to modify messages in this mailbox.", diff --git a/crates/imap/src/op/subscribe.rs b/crates/imap/src/op/subscribe.rs index 6640b504..b1cdebd3 100644 --- a/crates/imap/src/op/subscribe.rs +++ b/crates/imap/src/op/subscribe.rs @@ -57,7 +57,7 @@ impl SessionData { let (account_id, mailbox_id) = match self.get_mailbox_by_name(&mailbox_name) { Some(mailbox) => (mailbox.account_id, mailbox.mailbox_id), None => { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details("Mailbox does not exist.") .code(ResponseCode::NonExistent) @@ -71,7 +71,7 @@ impl SessionData { if account.account_id == account_id { if let Some(mailbox) = account.mailbox_state.get(&mailbox_id) { if mailbox.is_subscribed == subscribe { - return Err(trc::Cause::Imap + return Err(trc::ImapEvent::Error .into_err() .details(if subscribe { "Mailbox is already subscribed." @@ -97,7 +97,7 @@ impl SessionData { .await .imap_ctx(&tag, trc::location!())? .ok_or_else(|| { - trc::Cause::Imap + trc::ImapEvent::Error .into_err() .details("Mailbox does not exist.") .code(ResponseCode::NonExistent) diff --git a/crates/jmap-proto/src/error/method.rs b/crates/jmap-proto/src/error/method.rs index 18c1fd1e..af98433e 100644 --- a/crates/jmap-proto/src/error/method.rs +++ b/crates/jmap-proto/src/error/method.rs @@ -79,64 +79,64 @@ impl Serialize for MethodErrorWrapper { let description = self.0.value(trc::Key::Details).and_then(|v| v.as_str()); let (error_type, description) = match self.0.as_ref() { - trc::Cause::Jmap(cause) => match cause { - trc::JmapCause::InvalidArguments => { + trc::EventType::Jmap(cause) => match cause { + trc::JmapEvent::InvalidArguments => { ("invalidArguments", description.unwrap_or_default()) } - trc::JmapCause::RequestTooLarge => ( + trc::JmapEvent::RequestTooLarge => ( "requestTooLarge", concat!( "The number of ids requested by the client exceeds the maximum number ", "the server is willing to process in a single method call." ), ), - trc::JmapCause::StateMismatch => ( + trc::JmapEvent::StateMismatch => ( "stateMismatch", concat!( "An \"ifInState\" argument was supplied, but ", "it does not match the current state." ), ), - trc::JmapCause::AnchorNotFound => ( + trc::JmapEvent::AnchorNotFound => ( "anchorNotFound", concat!( "An anchor argument was supplied, but it ", "cannot be found in the results of the query." ), ), - trc::JmapCause::UnsupportedFilter => { + trc::JmapEvent::UnsupportedFilter => { ("unsupportedFilter", description.unwrap_or_default()) } - trc::JmapCause::UnsupportedSort => { + trc::JmapEvent::UnsupportedSort => { ("unsupportedSort", description.unwrap_or_default()) } - trc::JmapCause::NotFound => ("serverPartialFail", { + trc::JmapEvent::NotFound => ("serverPartialFail", { concat!( "One or more items are no longer available on the ", "server, please try again." ) }), - trc::JmapCause::UnknownMethod => ("unknownMethod", description.unwrap_or_default()), - trc::JmapCause::InvalidResultReference => { + trc::JmapEvent::UnknownMethod => ("unknownMethod", description.unwrap_or_default()), + trc::JmapEvent::InvalidResultReference => { ("invalidResultReference", description.unwrap_or_default()) } - trc::JmapCause::Forbidden => ("forbidden", description.unwrap_or_default()), - trc::JmapCause::AccountNotFound => ( + trc::JmapEvent::Forbidden => ("forbidden", description.unwrap_or_default()), + trc::JmapEvent::AccountNotFound => ( "accountNotFound", "The accountId does not correspond to a valid account", ), - trc::JmapCause::AccountNotSupportedByMethod => ( + trc::JmapEvent::AccountNotSupportedByMethod => ( "accountNotSupportedByMethod", concat!( "The accountId given corresponds to a valid account, ", "but the account does not support this method or data type." ), ), - trc::JmapCause::AccountReadOnly => ( + trc::JmapEvent::AccountReadOnly => ( "accountReadOnly", "This method modifies state, but the account is read-only.", ), - trc::JmapCause::UnknownDataType => ( + trc::JmapEvent::UnknownDataType => ( "unknownDataType", concat!( "The server does not recognise this data type, ", @@ -144,16 +144,16 @@ impl Serialize for MethodErrorWrapper { "in the current Request Object." ), ), - trc::JmapCause::CannotCalculateChanges => ( + trc::JmapEvent::CannotCalculateChanges => ( "cannotCalculateChanges", concat!( "The server cannot calculate the changes ", "between the old and new states." ), ), - trc::JmapCause::UnknownCapability - | trc::JmapCause::NotJSON - | trc::JmapCause::NotRequest => ( + trc::JmapEvent::UnknownCapability + | trc::JmapEvent::NotJSON + | trc::JmapEvent::NotRequest => ( "serverUnavailable", concat!( "This server is temporarily unavailable. ", diff --git a/crates/jmap-proto/src/method/changes.rs b/crates/jmap-proto/src/method/changes.rs index 1450b2c1..2c6e32a2 100644 --- a/crates/jmap-proto/src/method/changes.rs +++ b/crates/jmap-proto/src/method/changes.rs @@ -67,7 +67,7 @@ impl JsonObjectParser for ChangesRequest { MethodObject::EmailSubmission => RequestArguments::EmailSubmission, MethodObject::Quota => RequestArguments::Quota, _ => { - return Err(trc::JmapCause::UnknownMethod + return Err(trc::JmapEvent::UnknownMethod .into_err() .details(format!("{}/changes", parser.ctx))) } diff --git a/crates/jmap-proto/src/method/copy.rs b/crates/jmap-proto/src/method/copy.rs index 7e69bfa2..e95a2138 100644 --- a/crates/jmap-proto/src/method/copy.rs +++ b/crates/jmap-proto/src/method/copy.rs @@ -96,7 +96,7 @@ impl JsonObjectParser for CopyRequest { arguments: match &parser.ctx { MethodObject::Email => RequestArguments::Email, _ => { - return Err(trc::JmapCause::UnknownMethod + return Err(trc::JmapEvent::UnknownMethod .into_err() .details(format!("{}/copy", parser.ctx))) } diff --git a/crates/jmap-proto/src/method/get.rs b/crates/jmap-proto/src/method/get.rs index c05a83b9..e7fbb6eb 100644 --- a/crates/jmap-proto/src/method/get.rs +++ b/crates/jmap-proto/src/method/get.rs @@ -72,7 +72,7 @@ impl JsonObjectParser for GetRequest { MethodObject::Blob => RequestArguments::Blob(Default::default()), MethodObject::Quota => RequestArguments::Quota, _ => { - return Err(trc::JmapCause::UnknownMethod + return Err(trc::JmapEvent::UnknownMethod .into_err() .details(format!("{}/get", parser.ctx))) } @@ -175,7 +175,7 @@ impl GetRequest { .collect::>(), )) } else { - Err(trc::JmapCause::RequestTooLarge.into_err()) + Err(trc::JmapEvent::RequestTooLarge.into_err()) } } else { Ok(None) @@ -195,7 +195,7 @@ impl GetRequest { .collect::>(), )) } else { - Err(trc::JmapCause::RequestTooLarge.into_err()) + Err(trc::JmapEvent::RequestTooLarge.into_err()) } } else { Ok(None) diff --git a/crates/jmap-proto/src/method/query.rs b/crates/jmap-proto/src/method/query.rs index 515a3cbf..aaffeb77 100644 --- a/crates/jmap-proto/src/method/query.rs +++ b/crates/jmap-proto/src/method/query.rs @@ -163,7 +163,7 @@ impl JsonObjectParser for QueryRequest { MethodObject::Principal => RequestArguments::Principal, MethodObject::Quota => RequestArguments::Quota, _ => { - return Err(trc::JmapCause::UnknownMethod + return Err(trc::JmapEvent::UnknownMethod .into_err() .details(format!("{}/query", parser.ctx))) } @@ -451,7 +451,7 @@ pub fn parse_filter(parser: &mut Parser) -> trc::Result> { break; } } else { - return Err(trc::JmapCause::InvalidArguments + return Err(trc::JmapEvent::InvalidArguments .into_err() .details("Malformed filter")); } diff --git a/crates/jmap-proto/src/method/query_changes.rs b/crates/jmap-proto/src/method/query_changes.rs index f4181840..8df92b9e 100644 --- a/crates/jmap-proto/src/method/query_changes.rs +++ b/crates/jmap-proto/src/method/query_changes.rs @@ -70,7 +70,7 @@ impl JsonObjectParser for QueryChangesRequest { MethodObject::EmailSubmission => RequestArguments::EmailSubmission, MethodObject::Quota => RequestArguments::Quota, _ => { - return Err(trc::JmapCause::UnknownMethod + return Err(trc::JmapEvent::UnknownMethod .into_err() .details(format!("{}/queryChanges", parser.ctx))) } diff --git a/crates/jmap-proto/src/method/set.rs b/crates/jmap-proto/src/method/set.rs index 3fa4b803..35bc71a3 100644 --- a/crates/jmap-proto/src/method/set.rs +++ b/crates/jmap-proto/src/method/set.rs @@ -112,7 +112,7 @@ impl JsonObjectParser for SetRequest { MethodObject::VacationResponse => RequestArguments::VacationResponse, MethodObject::SieveScript => RequestArguments::SieveScript(Default::default()), _ => { - return Err(trc::JmapCause::UnknownMethod + return Err(trc::JmapEvent::UnknownMethod .into_err() .details(format!("{}/set", parser.ctx))) } @@ -404,7 +404,7 @@ impl SetRequest { }) > max_objects_in_set { - Err(trc::JmapCause::RequestTooLarge.into_err()) + Err(trc::JmapEvent::RequestTooLarge.into_err()) } else { Ok(()) } @@ -480,7 +480,7 @@ impl SetResponse { state_change: None, }) } else { - Err(trc::JmapCause::RequestTooLarge.into_err()) + Err(trc::JmapEvent::RequestTooLarge.into_err()) } } diff --git a/crates/jmap-proto/src/object/mod.rs b/crates/jmap-proto/src/object/mod.rs index 78157198..1787c558 100644 --- a/crates/jmap-proto/src/object/mod.rs +++ b/crates/jmap-proto/src/object/mod.rs @@ -124,7 +124,7 @@ impl Serialize for Value { impl Deserialize for Value { fn deserialize(bytes: &[u8]) -> trc::Result { Self::deserialize_from(&mut bytes.iter()).ok_or_else(|| { - trc::StoreCause::DataCorruption + trc::StoreEvent::DataCorruption .caused_by(trc::location!()) .ctx(trc::Key::Value, bytes) }) @@ -148,7 +148,7 @@ impl Serialize for &Object { impl Deserialize for Object { fn deserialize(bytes: &[u8]) -> trc::Result { Object::deserialize_from(&mut bytes.iter()).ok_or_else(|| { - trc::StoreCause::DataCorruption + trc::StoreEvent::DataCorruption .caused_by(trc::location!()) .ctx(trc::Key::Value, bytes) }) diff --git a/crates/jmap-proto/src/parser/json.rs b/crates/jmap-proto/src/parser/json.rs index 5d60aee8..00ac097a 100644 --- a/crates/jmap-proto/src/parser/json.rs +++ b/crates/jmap-proto/src/parser/json.rs @@ -41,20 +41,20 @@ impl<'x> Parser<'x> { } pub fn error(&self, message: &str) -> trc::Error { - trc::JmapCause::NotJSON + trc::JmapEvent::NotJSON .into_err() .details(format!("{message} at position {}.", self.pos)) } pub fn error_unterminated(&self) -> trc::Error { - trc::JmapCause::NotJSON.into_err().details(format!( + trc::JmapEvent::NotJSON.into_err().details(format!( "Unterminated string at position {pos}.", pos = self.pos )) } pub fn error_utf8(&self) -> trc::Error { - trc::JmapCause::NotJSON.into_err().details(format!( + trc::JmapEvent::NotJSON.into_err().details(format!( "Invalid UTF-8 sequence at position {pos}.", pos = self.pos )) @@ -62,7 +62,7 @@ impl<'x> Parser<'x> { pub fn error_value(&mut self) -> trc::Error { if self.is_eof || self.skip_string() { - trc::JmapCause::InvalidArguments.into_err().details(format!( + trc::JmapEvent::InvalidArguments.into_err().details(format!( "Invalid value {:?} at position {}.", String::from_utf8_lossy(self.bytes[self.pos_marker..self.pos - 1].as_ref()), self.pos diff --git a/crates/jmap-proto/src/parser/mod.rs b/crates/jmap-proto/src/parser/mod.rs index 56fca203..7dbcde2a 100644 --- a/crates/jmap-proto/src/parser/mod.rs +++ b/crates/jmap-proto/src/parser/mod.rs @@ -117,14 +117,14 @@ impl Token { if self == token { Ok(()) } else { - Err(trc::JmapCause::NotRequest.into_err().details(format!( + Err(trc::JmapEvent::NotRequest.into_err().details(format!( "Invalid JMAP request: expected '{token}', got '{self}'." ))) } } pub fn error(&self, property: &str, expected: &str) -> trc::Error { - trc::JmapCause::InvalidArguments.into_err().details(if !property.is_empty() { + trc::JmapEvent::InvalidArguments.into_err().details(if !property.is_empty() { format!("Invalid argument for '{property:?}': expected '{expected}', got '{self}'.",) } else { format!("Invalid argument: expected '{expected}', got '{self}'.") diff --git a/crates/jmap-proto/src/request/capability.rs b/crates/jmap-proto/src/request/capability.rs index 79d8e58e..51ab534d 100644 --- a/crates/jmap-proto/src/request/capability.rs +++ b/crates/jmap-proto/src/request/capability.rs @@ -351,7 +351,7 @@ impl JsonObjectParser for Capability { impl<'x> Parser<'x> { fn error_capability(&mut self) -> trc::Error { if self.is_eof || self.skip_string() { - trc::JmapCause::UnknownCapability.into_err().details( + trc::JmapEvent::UnknownCapability.into_err().details( String::from_utf8_lossy(self.bytes[self.pos_marker..self.pos - 1].as_ref()) .into_owned(), ) diff --git a/crates/jmap-proto/src/request/parser.rs b/crates/jmap-proto/src/request/parser.rs index b25327f5..13649df5 100644 --- a/crates/jmap-proto/src/request/parser.rs +++ b/crates/jmap-proto/src/request/parser.rs @@ -50,12 +50,12 @@ impl Request { if found_valid_keys { Ok(request) } else { - Err(trc::JmapCause::NotRequest + Err(trc::JmapEvent::NotRequest .into_err() .details("Invalid JMAP request")) } } else { - Err(trc::LimitCause::SizeRequest.into_err()) + Err(trc::LimitEvent::SizeRequest.into_err()) } } @@ -90,7 +90,7 @@ impl Request { Token::Comma => continue, Token::ArrayEnd => break, _ => { - return Err(trc::JmapCause::NotRequest + return Err(trc::JmapEvent::NotRequest .into_err() .details("Invalid JMAP request")); } @@ -99,13 +99,13 @@ impl Request { let method_name = match parser.next_token::() { Ok(Token::String(method)) => method, Ok(_) => { - return Err(trc::JmapCause::NotRequest + return Err(trc::JmapEvent::NotRequest .into_err() .details("Invalid JMAP request")); } Err(err) - if err.matches(trc::Cause::Jmap( - trc::JmapCause::InvalidArguments, + if err.matches(trc::EventType::Jmap( + trc::JmapEvent::InvalidArguments, )) => { MethodName::error() @@ -175,7 +175,7 @@ impl Request { (MethodFunction::Echo, MethodObject::Core) => { Echo::parse(parser).map(RequestMethod::Echo) } - _ => Err(trc::JmapCause::UnknownMethod + _ => Err(trc::JmapEvent::UnknownMethod .into_err() .details(method_name.to_string())), }; @@ -202,7 +202,7 @@ impl Request { name: method_name, }); } else { - return Err(trc::LimitCause::CallsIn.into_err()); + return Err(trc::LimitEvent::CallsIn.into_err()); } } Ok(true) diff --git a/crates/jmap-proto/src/request/reference.rs b/crates/jmap-proto/src/request/reference.rs index cd61b941..ddab1d3d 100644 --- a/crates/jmap-proto/src/request/reference.rs +++ b/crates/jmap-proto/src/request/reference.rs @@ -80,7 +80,7 @@ impl JsonObjectParser for ResultReference { path, }) } else { - Err(trc::JmapCause::InvalidResultReference + Err(trc::JmapEvent::InvalidResultReference .into_err() .details("Missing required fields")) } diff --git a/crates/jmap-proto/src/request/websocket.rs b/crates/jmap-proto/src/request/websocket.rs index 92c50a94..97028348 100644 --- a/crates/jmap-proto/src/request/websocket.rs +++ b/crates/jmap-proto/src/request/websocket.rs @@ -170,12 +170,12 @@ impl WebSocketMessage { MessageType::PushDisable if !found_request_keys && !found_push_keys => { Ok(WebSocketMessage::PushDisable) } - _ => Err(trc::JmapCause::NotRequest + _ => Err(trc::JmapEvent::NotRequest .into_err() .details("Invalid WebSocket JMAP request")), } } else { - Err(trc::LimitCause::SizeRequest.into_err()) + Err(trc::LimitEvent::SizeRequest.into_err()) } } } diff --git a/crates/jmap-proto/src/response/references.rs b/crates/jmap-proto/src/response/references.rs index 7769b019..eacae954 100644 --- a/crates/jmap-proto/src/response/references.rs +++ b/crates/jmap-proto/src/response/references.rs @@ -50,7 +50,7 @@ impl Response { if let Some(resolved_id) = self.created_ids.get(reference) { *id = MaybeReference::Value(resolved_id.clone()); } else { - return Err(trc::JmapCause::InvalidResultReference + return Err(trc::JmapEvent::InvalidResultReference .into_err() .details(format!( "Id reference {reference:?} does not exist." @@ -151,7 +151,7 @@ impl Response { *id = MaybeReference::Value(blob_id.clone()); } Some(_) => { - return Err(trc::JmapCause::InvalidResultReference + return Err(trc::JmapEvent::InvalidResultReference .into_err() .details(format!( "Id reference {parent_id:?} points to invalid type." @@ -254,7 +254,7 @@ impl Response { if let Some(AnyId::Id(id)) = self.created_ids.get(ir) { Ok(*id) } else { - Err(trc::JmapCause::InvalidResultReference + Err(trc::JmapEvent::InvalidResultReference .into_err() .details(format!("Id reference {ir:?} not found."))) } @@ -276,7 +276,7 @@ impl Response { .or_insert_with(Vec::new) .push(parent_id.to_string()); } else { - return Err(trc::JmapCause::InvalidResultReference + return Err(trc::JmapEvent::InvalidResultReference .into_err() .details(format!("Id reference {parent_id:?} not found."))); } @@ -292,7 +292,7 @@ impl Response { .or_insert_with(Vec::new) .push(parent_id.to_string()); } else { - return Err(trc::JmapCause::InvalidResultReference + return Err(trc::JmapEvent::InvalidResultReference .into_err() .details(format!("Id reference {parent_id:?} not found."))); } @@ -319,7 +319,7 @@ fn topological_sort( for (from_id, to_ids) in graph.iter() { for to_id in to_ids { if !create.contains_key(to_id) { - return Err(trc::JmapCause::InvalidResultReference + return Err(trc::JmapEvent::InvalidResultReference .into_err() .details(format!( "Invalid reference to non-existing object {to_id:?} from {from_id:?}" @@ -338,7 +338,7 @@ fn topological_sort( if let Some(to_ids) = graph.get(from_id) { it_stack.push((it, from_id)); if it_stack.len() > 1000 { - return Err(trc::JmapCause::InvalidArguments + return Err(trc::JmapEvent::InvalidArguments .into_err() .details("Cyclical references are not allowed.".to_string())); } @@ -454,7 +454,7 @@ impl EvalResult { match value { Value::Id(id) => ids.push(id), _ => { - return Err(trc::JmapCause::InvalidResultReference + return Err(trc::JmapEvent::InvalidResultReference .into_err() .details(format!( "Failed to evaluate {rr} result reference." @@ -464,7 +464,7 @@ impl EvalResult { } } _ => { - return Err(trc::JmapCause::InvalidResultReference + return Err(trc::JmapEvent::InvalidResultReference .into_err() .details(format!("Failed to evaluate {rr} result reference."))) } @@ -472,7 +472,7 @@ impl EvalResult { } Ok(ids) } else { - Err(trc::JmapCause::InvalidResultReference + Err(trc::JmapEvent::InvalidResultReference .into_err() .details(format!("Failed to evaluate {rr} result reference."))) } @@ -496,7 +496,7 @@ impl EvalResult { ids.push(MaybeReference::Value(blob_id.into())) } _ => { - return Err(trc::JmapCause::InvalidResultReference + return Err(trc::JmapEvent::InvalidResultReference .into_err() .details(format!( "Failed to evaluate {rr} result reference." @@ -506,7 +506,7 @@ impl EvalResult { } } _ => { - return Err(trc::JmapCause::InvalidResultReference + return Err(trc::JmapEvent::InvalidResultReference .into_err() .details(format!("Failed to evaluate {rr} result reference."))) } @@ -514,7 +514,7 @@ impl EvalResult { } Ok(ids) } else { - Err(trc::JmapCause::InvalidResultReference + Err(trc::JmapEvent::InvalidResultReference .into_err() .details(format!("Failed to evaluate {rr} result reference."))) } @@ -524,7 +524,7 @@ impl EvalResult { if let EvalResult::Properties(properties) = self { Ok(properties) } else { - Err(trc::JmapCause::InvalidResultReference + Err(trc::JmapEvent::InvalidResultReference .into_err() .details(format!("Failed to evaluate {rr} result reference."))) } diff --git a/crates/jmap/Cargo.toml b/crates/jmap/Cargo.toml index 0b8644e8..f5bdd9f8 100644 --- a/crates/jmap/Cargo.toml +++ b/crates/jmap/Cargo.toml @@ -25,7 +25,6 @@ hyper = { version = "1.0.1", features = ["server", "http1", "http2"] } hyper-util = { version = "0.1.1", features = ["tokio"] } http-body-util = "0.1.0" form_urlencoded = "1.1.0" -tracing = "0.1" tokio = { version = "1.23", features = ["rt"] } aes-gcm = "0.10.1" aes-gcm-siv = "0.11.1" @@ -58,6 +57,7 @@ lz4_flex = { version = "0.11", default-features = false } rev_lines = "0.3.0" x509-parser = "0.16.0" quick-xml = "0.35" +tracing = "0.1" [features] test_mode = [] diff --git a/crates/jmap/src/api/autoconfig.rs b/crates/jmap/src/api/autoconfig.rs index d18470d5..6622495e 100644 --- a/crates/jmap/src/api/autoconfig.rs +++ b/crates/jmap/src/api/autoconfig.rs @@ -81,7 +81,7 @@ impl JMAP { // Obtain parameters let emailaddress = parse_autodiscover_request(body.as_deref().unwrap_or_default()) .map_err(|err| { - trc::ResourceCause::BadParameters + trc::ResourceEvent::BadParameters .into_err() .details("Failed to parse autodiscover request") .ctx(trc::Key::Reason, err) @@ -159,7 +159,7 @@ impl JMAP { emailaddress: &'x str, ) -> trc::Result<(String, String, &'x str)> { let (_, domain) = emailaddress.rsplit_once('@').ok_or_else(|| { - trc::ResourceCause::BadParameters + trc::ResourceEvent::BadParameters .into_err() .details("Missing domain in email address") })?; @@ -172,8 +172,8 @@ impl JMAP { .get("lookup.default.hostname") .await? .ok_or_else(|| { - trc::Cause::Configuration - .into_err() + trc::EventType::Config(trc::ConfigEvent::BuildError) + .caused_by(trc::location!()) .details("Server name not configured") })?; diff --git a/crates/jmap/src/api/event_source.rs b/crates/jmap/src/api/event_source.rs index 66d1d5cb..7ed6bb09 100644 --- a/crates/jmap/src/api/event_source.rs +++ b/crates/jmap/src/api/event_source.rs @@ -49,7 +49,7 @@ impl JMAP { } else if let Ok(type_state) = DataType::try_from(type_state) { types.insert(type_state); } else { - return Err(trc::ResourceCause::BadParameters.into_err()); + return Err(trc::ResourceEvent::BadParameters.into_err()); } } } @@ -58,13 +58,13 @@ impl JMAP { close_after_state = true; } "no" => {} - _ => return Err(trc::ResourceCause::BadParameters.into_err()), + _ => return Err(trc::ResourceEvent::BadParameters.into_err()), }, "ping" => match value.parse::() { Ok(value) => { ping = value; } - Err(_) => return Err(trc::ResourceCause::BadParameters.into_err()), + Err(_) => return Err(trc::ResourceEvent::BadParameters.into_err()), }, _ => {} } diff --git a/crates/jmap/src/api/http.rs b/crates/jmap/src/api/http.rs index 45168480..fe2f9fe9 100644 --- a/crates/jmap/src/api/http.rs +++ b/crates/jmap/src/api/http.rs @@ -47,6 +47,7 @@ pub struct HttpSessionData { pub remote_ip: IpAddr, pub remote_port: u16, pub is_tls: bool, + pub session_id: u64, } impl JMAP { @@ -75,7 +76,7 @@ impl JMAP { }, ) .await - .ok_or_else(|| trc::LimitCause::SizeRequest.into_err()) + .ok_or_else(|| trc::LimitEvent::SizeRequest.into_err()) .and_then(|bytes| { //let c = println!("<- {}", String::from_utf8_lossy(&bytes)); @@ -116,7 +117,7 @@ impl JMAP { blob, } .into_http_response()), - None => Err(trc::ResourceCause::NotFound.into_err()), + None => Err(trc::ResourceEvent::NotFound.into_err()), }; } } @@ -150,7 +151,7 @@ impl JMAP { ) .await? .into_http_response()), - None => Err(trc::LimitCause::SizeUpload.into_err()), + None => Err(trc::LimitEvent::SizeUpload.into_err()), }; } } @@ -217,7 +218,7 @@ impl JMAP { contents: proof.into_bytes(), } .into_http_response()), - None => Err(trc::ResourceCause::NotFound.into_err()), + None => Err(trc::ResourceEvent::NotFound.into_err()), }; } } @@ -229,7 +230,7 @@ impl JMAP { } .into_http_response()); } else { - return Err(trc::ResourceCause::NotFound.into_err()); + return Err(trc::ResourceEvent::NotFound.into_err()); } } ("mail-v1.xml", &Method::GET) => { @@ -328,18 +329,17 @@ impl JMAP { return if !resource.is_empty() { Ok(resource.into_http_response()) } else { - Err(trc::ResourceCause::NotFound.into_err()) + Err(trc::ResourceEvent::NotFound.into_err()) }; } } - Err(trc::ResourceCause::NotFound.into_err()) + Err(trc::ResourceEvent::NotFound.into_err()) } } impl JmapInstance { async fn handle_session(self, session: SessionData) { - let span = session.span; let _in_flight = session.in_flight; let is_tls = session.stream.is_tls(); @@ -349,15 +349,10 @@ impl JmapInstance { TokioIo::new(session.stream), service_fn(|req: hyper::Request| { let jmap_instance = self.clone(); - let span = span.clone(); let instance = session.instance.clone(); async move { - tracing::debug!( - parent: &span, - event = "request", - uri = req.uri().to_string(), - ); + tracing::debug!(event = "request", uri = req.uri().to_string(),); let jmap = JMAP::from(jmap_instance); // Obtain remote IP @@ -389,6 +384,7 @@ impl JmapInstance { remote_ip, remote_port: session.remote_port, is_tls, + session_id: session.session_id, }, ) .await @@ -396,7 +392,7 @@ impl JmapInstance { Ok(response) => response, Err(err) => { tracing::error!( - parent: &span, + event = "error", context = "http", reason = %err, @@ -422,7 +418,7 @@ impl JmapInstance { .await { tracing::debug!( - parent: &span, + event = "error", context = "http", reason = %http_err, @@ -469,7 +465,7 @@ impl ResolveVariable for HttpSessionData { impl HttpSessionData { pub async fn resolve_url(&self, core: &Core) -> String { - core.eval_if(&core.network.url, self) + core.eval_if(&core.network.url, self, self.session_id) .await .unwrap_or_else(|| { format!( @@ -517,28 +513,28 @@ impl ToHttpResponse for JsonResponse { impl ToHttpResponse for trc::Error { fn into_http_response(self) -> HttpResponse { match self.as_ref() { - trc::Cause::Manage(cause) => { + trc::EventType::Manage(cause) => { let details_or_reason = self .value(trc::Key::Details) .or_else(|| self.value(trc::Key::Reason)) .and_then(|v| v.as_str()); match cause { - trc::ManageCause::MissingParameter => ManagementApiError::FieldMissing { + trc::ManageEvent::MissingParameter => ManagementApiError::FieldMissing { field: self.value_as_str(trc::Key::Key).unwrap_or_default(), }, - trc::ManageCause::AlreadyExists => ManagementApiError::FieldAlreadyExists { + trc::ManageEvent::AlreadyExists => ManagementApiError::FieldAlreadyExists { field: self.value_as_str(trc::Key::Key).unwrap_or_default(), value: self.value_as_str(trc::Key::Value).unwrap_or_default(), }, - trc::ManageCause::NotFound => ManagementApiError::NotFound { + trc::ManageEvent::NotFound => ManagementApiError::NotFound { item: self.value_as_str(trc::Key::Key).unwrap_or_default(), }, - trc::ManageCause::NotSupported => ManagementApiError::Unsupported { + trc::ManageEvent::NotSupported => ManagementApiError::Unsupported { details: details_or_reason.unwrap_or("Requested action is unsupported"), }, - trc::ManageCause::AssertFailed => ManagementApiError::AssertFailed, - trc::ManageCause::Error => ManagementApiError::Other { + trc::ManageEvent::AssertFailed => ManagementApiError::AssertFailed, + trc::ManageEvent::Error => ManagementApiError::Other { details: details_or_reason.unwrap_or("An error occurred."), }, } @@ -563,24 +559,24 @@ impl ToRequestError for trc::Error { let details = details_or_reason.unwrap_or_else(|| self.as_ref().message()); match self.as_ref() { - trc::Cause::Jmap(cause) => match cause { - trc::JmapCause::UnknownCapability => RequestError::unknown_capability(details), - trc::JmapCause::NotJSON => RequestError::not_json(details), - trc::JmapCause::NotRequest => RequestError::not_request(details), + trc::EventType::Jmap(cause) => match cause { + trc::JmapEvent::UnknownCapability => RequestError::unknown_capability(details), + trc::JmapEvent::NotJSON => RequestError::not_json(details), + trc::JmapEvent::NotRequest => RequestError::not_request(details), _ => RequestError::invalid_parameters(), }, - trc::Cause::Limit(cause) => match cause { - trc::LimitCause::SizeRequest => RequestError::limit(RequestLimitError::SizeRequest), - trc::LimitCause::SizeUpload => RequestError::limit(RequestLimitError::SizeUpload), - trc::LimitCause::CallsIn => RequestError::limit(RequestLimitError::CallsIn), - trc::LimitCause::ConcurrentRequest => { + trc::EventType::Limit(cause) => match cause { + trc::LimitEvent::SizeRequest => RequestError::limit(RequestLimitError::SizeRequest), + trc::LimitEvent::SizeUpload => RequestError::limit(RequestLimitError::SizeUpload), + trc::LimitEvent::CallsIn => RequestError::limit(RequestLimitError::CallsIn), + trc::LimitEvent::ConcurrentRequest => { RequestError::limit(RequestLimitError::ConcurrentRequest) } - trc::LimitCause::ConcurrentUpload => { + trc::LimitEvent::ConcurrentUpload => { RequestError::limit(RequestLimitError::ConcurrentUpload) } - trc::LimitCause::Quota => RequestError::over_quota(), - trc::LimitCause::BlobQuota => RequestError::over_blob_quota( + trc::LimitEvent::Quota => RequestError::over_quota(), + trc::LimitEvent::BlobQuota => RequestError::over_blob_quota( self.value(trc::Key::Total) .and_then(|v| v.to_uint()) .unwrap_or_default() as usize, @@ -588,26 +584,26 @@ impl ToRequestError for trc::Error { .and_then(|v| v.to_uint()) .unwrap_or_default() as usize, ), - trc::LimitCause::TooManyRequests => RequestError::too_many_requests(), + trc::LimitEvent::TooManyRequests => RequestError::too_many_requests(), }, - trc::Cause::Auth(cause) => match cause { - trc::AuthCause::Failed => RequestError::unauthorized(), - trc::AuthCause::MissingTotp => { + trc::EventType::Auth(cause) => match cause { + trc::AuthEvent::Failed => RequestError::unauthorized(), + trc::AuthEvent::MissingTotp => { RequestError::blank(403, "TOTP code required", cause.message()) } - trc::AuthCause::TooManyAttempts | trc::AuthCause::Banned => { + trc::AuthEvent::TooManyAttempts | trc::AuthEvent::Banned => { RequestError::too_many_auth_attempts() } - trc::AuthCause::Error => RequestError::unauthorized(), + trc::AuthEvent::Error => RequestError::unauthorized(), }, - trc::Cause::Resource(cause) => match cause { - trc::ResourceCause::NotFound => RequestError::not_found(), - trc::ResourceCause::BadParameters => RequestError::blank( + trc::EventType::Resource(cause) => match cause { + trc::ResourceEvent::NotFound => RequestError::not_found(), + trc::ResourceEvent::BadParameters => RequestError::blank( StatusCode::BAD_REQUEST.as_u16(), "Invalid parameters", details_or_reason.unwrap_or("One or multiple parameters could not be parsed."), ), - trc::ResourceCause::Error => RequestError::internal_server_error(), + trc::ResourceEvent::Error => RequestError::internal_server_error(), }, _ => RequestError::internal_server_error(), } diff --git a/crates/jmap/src/api/management/dkim.rs b/crates/jmap/src/api/management/dkim.rs index cba78295..09c37c13 100644 --- a/crates/jmap/src/api/management/dkim.rs +++ b/crates/jmap/src/api/management/dkim.rs @@ -52,7 +52,7 @@ impl JMAP { match *req.method() { Method::GET => self.handle_get_public_key(path).await, Method::POST => self.handle_create_signature(body).await, - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), } } @@ -60,7 +60,7 @@ impl JMAP { let signature_id = match path.get(1) { Some(signature_id) => decode_path_element(signature_id), None => { - return Err(trc::ResourceCause::NotFound.into_err()); + return Err(trc::ResourceEvent::NotFound.into_err()); } }; @@ -79,7 +79,7 @@ impl JMAP { ) { (Ok(Some(pk)), Ok(Some(algorithm))) => (pk, algorithm), (Err(err), _) | (_, Err(err)) => return Err(err.caused_by(trc::location!())), - _ => return Err(trc::ResourceCause::NotFound.into_err()), + _ => return Err(trc::ResourceEvent::NotFound.into_err()), }; match obtain_dkim_public_key(algo, &pk) { @@ -96,7 +96,9 @@ impl JMAP { match serde_json::from_slice::(body.as_deref().unwrap_or_default()) { Ok(request) => request, Err(err) => { - return Err(trc::Cause::Resource(trc::ResourceCause::BadParameters).reason(err)) + return Err( + trc::EventType::Resource(trc::ResourceEvent::BadParameters).reason(err) + ) } }; diff --git a/crates/jmap/src/api/management/domain.rs b/crates/jmap/src/api/management/domain.rs index e7a007c5..1ab46d69 100644 --- a/crates/jmap/src/api/management/domain.rs +++ b/crates/jmap/src/api/management/domain.rs @@ -118,7 +118,7 @@ impl JMAP { .into_http_response()) } - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), } } diff --git a/crates/jmap/src/api/management/enterprise.rs b/crates/jmap/src/api/management/enterprise.rs index 7ba9c2fb..b50870a5 100644 --- a/crates/jmap/src/api/management/enterprise.rs +++ b/crates/jmap/src/api/management/enterprise.rs @@ -57,7 +57,7 @@ impl JMAP { ) -> trc::Result { match path.get(1).copied().unwrap_or_default() { "undelete" => self.handle_undelete_api_request(req, path, body).await, - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), } } @@ -75,7 +75,7 @@ impl JMAP { .data .get_account_id(account_name) .await? - .ok_or_else(|| trc::ResourceCause::NotFound.into_err())?; + .ok_or_else(|| trc::ResourceEvent::NotFound.into_err())?; let mut deleted = self.core.list_deleted(account_id).await?; let params = UrlParams::new(req.uri().query()); @@ -125,7 +125,7 @@ impl JMAP { .data .get_account_id(account_name) .await? - .ok_or_else(|| trc::ResourceCause::NotFound.into_err())?; + .ok_or_else(|| trc::ResourceEvent::NotFound.into_err())?; let requests = serde_json::from_slice::>>( @@ -162,7 +162,7 @@ impl JMAP { }) .collect::>>() }) - .ok_or_else(|| trc::ResourceCause::BadParameters.into_err())?; + .ok_or_else(|| trc::ResourceEvent::BadParameters.into_err())?; let mut results = Vec::with_capacity(requests.len()); let mut batch = BatchBuilder::new(); @@ -195,7 +195,11 @@ impl JMAP { })); } } - Err(mut err) if err.matches(trc::Cause::Ingest) => { + Err(mut err) + if err.matches(trc::EventType::Store( + trc::StoreEvent::IngestError, + )) => + { results.push(UndeleteResponse::Error { reason: err .take_value(trc::Key::Reason) @@ -237,7 +241,7 @@ impl JMAP { })) .into_http_response()) } - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), } } } diff --git a/crates/jmap/src/api/management/log.rs b/crates/jmap/src/api/management/log.rs index 557b8cd8..271daeb7 100644 --- a/crates/jmap/src/api/management/log.rs +++ b/crates/jmap/src/api/management/log.rs @@ -49,9 +49,13 @@ impl JMAP { let (total, items) = rx .await - .map_err(|err| trc::Cause::Thread.reason(err).caused_by(trc::location!()))? .map_err(|err| { - trc::ManageCause::Error + trc::EventType::Server(trc::ServerEvent::ThreadError) + .reason(err) + .caused_by(trc::location!()) + })? + .map_err(|err| { + trc::ManageEvent::Error .reason(err) .details("Failed to read log files") .caused_by(trc::location!()) diff --git a/crates/jmap/src/api/management/mod.rs b/crates/jmap/src/api/management/mod.rs index 455f081b..da0782bb 100644 --- a/crates/jmap/src/api/management/mod.rs +++ b/crates/jmap/src/api/management/mod.rs @@ -73,7 +73,7 @@ impl JMAP { ("auth", &Method::POST) => { self.handle_account_auth_post(req, access_token, body).await } - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), }, // SPDX-SnippetBegin @@ -99,7 +99,7 @@ impl JMAP { } } // SPDX-SnippetEnd - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), } } } diff --git a/crates/jmap/src/api/management/principal.rs b/crates/jmap/src/api/management/principal.rs index a2a08520..ec4b7944 100644 --- a/crates/jmap/src/api/management/principal.rs +++ b/crates/jmap/src/api/management/principal.rs @@ -91,7 +91,7 @@ impl JMAP { body.as_deref().unwrap_or_default(), ) .map_err(|err| { - trc::Cause::Resource(trc::ResourceCause::BadParameters).from_json_error(err) + trc::EventType::Resource(trc::ResourceEvent::BadParameters).from_json_error(err) })?; Ok(JsonResponse::new(json!({ @@ -152,7 +152,7 @@ impl JMAP { .data .get_account_id(name.as_ref()) .await? - .ok_or_else(|| trc::ManageCause::NotFound.into_err())?; + .ok_or_else(|| trc::ManageEvent::NotFound.into_err())?; match *method { Method::GET => { @@ -162,7 +162,7 @@ impl JMAP { .data .query(QueryBy::Id(account_id), true) .await? - .ok_or_else(|| trc::ManageCause::NotFound.into_err())?; + .ok_or_else(|| trc::ManageEvent::NotFound.into_err())?; let principal = self.core.storage.data.map_group_ids(principal).await?; // Obtain quota usage @@ -210,7 +210,7 @@ impl JMAP { body.as_deref().unwrap_or_default(), ) .map_err(|err| { - trc::Cause::Resource(trc::ResourceCause::BadParameters) + trc::EventType::Resource(trc::ResourceEvent::BadParameters) .from_json_error(err) })?; @@ -243,11 +243,11 @@ impl JMAP { })) .into_http_response()) } - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), } } - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), } } @@ -268,7 +268,7 @@ impl JMAP { .directory .query(QueryBy::Id(access_token.primary_id()), false) .await? - .ok_or_else(|| trc::ManageCause::NotFound.into_err())?; + .ok_or_else(|| trc::ManageEvent::NotFound.into_err())?; for secret in principal.secrets { if secret.is_otp_auth() { @@ -297,11 +297,11 @@ impl JMAP { let requests = serde_json::from_slice::>(body.as_deref().unwrap_or_default()) .map_err(|err| { - trc::Cause::Resource(trc::ResourceCause::BadParameters).from_json_error(err) + trc::EventType::Resource(trc::ResourceEvent::BadParameters).from_json_error(err) })?; if requests.is_empty() { - return Err(trc::Cause::Resource(trc::ResourceCause::BadParameters) + return Err(trc::EventType::Resource(trc::ResourceEvent::BadParameters) .into_err() .details("Empty request")); } diff --git a/crates/jmap/src/api/management/queue.rs b/crates/jmap/src/api/management/queue.rs index 923a20e2..ce12dc5f 100644 --- a/crates/jmap/src/api/management/queue.rs +++ b/crates/jmap/src/api/management/queue.rs @@ -225,7 +225,7 @@ impl JMAP { })) .into_http_response()) } else { - Err(trc::ResourceCause::NotFound.into_err()) + Err(trc::ResourceEvent::NotFound.into_err()) } } ("messages", Some(queue_id), &Method::PATCH) => { @@ -272,7 +272,7 @@ impl JMAP { })) .into_http_response()) } else { - Err(trc::ResourceCause::NotFound.into_err()) + Err(trc::ResourceEvent::NotFound.into_err()) } } ("messages", Some(queue_id), &Method::DELETE) => { @@ -352,7 +352,7 @@ impl JMAP { })) .into_http_response()) } else { - Err(trc::ResourceCause::NotFound.into_err()) + Err(trc::ResourceEvent::NotFound.into_err()) } } ("reports", None, &Method::GET) => { @@ -441,7 +441,7 @@ impl JMAP { let mut rua = Vec::new(); if let Some(report) = self .smtp - .generate_dmarc_aggregate_report(&event, &mut rua, None) + .generate_dmarc_aggregate_report(&event, &mut rua, None, 0) .await? { result = Report::dmarc(event, report, rua).into(); @@ -451,7 +451,7 @@ impl JMAP { let mut rua = Vec::new(); if let Some(report) = self .smtp - .generate_tls_aggregate_report(&[event.clone()], &mut rua, None) + .generate_tls_aggregate_report(&[event.clone()], &mut rua, None, 0) .await? { result = Report::tls(event, report, rua).into(); @@ -467,7 +467,7 @@ impl JMAP { })) .into_http_response()) } else { - Err(trc::ResourceCause::NotFound.into_err()) + Err(trc::ResourceEvent::NotFound.into_err()) } } ("reports", Some(report_id), &Method::DELETE) => { @@ -487,10 +487,10 @@ impl JMAP { })) .into_http_response()) } else { - Err(trc::ResourceCause::NotFound.into_err()) + Err(trc::ResourceEvent::NotFound.into_err()) } } - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), } } } diff --git a/crates/jmap/src/api/management/reload.rs b/crates/jmap/src/api/management/reload.rs index 01be5e90..a51c451c 100644 --- a/crates/jmap/src/api/management/reload.rs +++ b/crates/jmap/src/api/management/reload.rs @@ -64,7 +64,7 @@ impl JMAP { .send(Event::AcmeReload) .await .map_err(|err| { - trc::Cause::Thread + trc::EventType::Server(trc::ServerEvent::ThreadError) .reason(err) .details("Failed to send ACME reload event to housekeeper") .caused_by(trc::location!()) @@ -76,7 +76,7 @@ impl JMAP { })) .into_http_response()) } - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), } } @@ -103,7 +103,7 @@ impl JMAP { })) .into_http_response()) } - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), } } } diff --git a/crates/jmap/src/api/management/report.rs b/crates/jmap/src/api/management/report.rs index a07f62eb..d8bd0318 100644 --- a/crates/jmap/src/api/management/report.rs +++ b/crates/jmap/src/api/management/report.rs @@ -169,7 +169,7 @@ impl JMAP { "data": report.inner, })) .into_http_response()), - None => Err(trc::ResourceCause::NotFound.into_err()), + None => Err(trc::ResourceEvent::NotFound.into_err()), }, ReportClass::Dmarc { .. } => match self .core @@ -184,7 +184,7 @@ impl JMAP { "data": report.inner, })) .into_http_response()), - None => Err(trc::ResourceCause::NotFound.into_err()), + None => Err(trc::ResourceEvent::NotFound.into_err()), }, ReportClass::Arf { .. } => match self .core @@ -199,11 +199,11 @@ impl JMAP { "data": report.inner, })) .into_http_response()), - None => Err(trc::ResourceCause::NotFound.into_err()), + None => Err(trc::ResourceEvent::NotFound.into_err()), }, } } else { - Err(trc::ResourceCause::NotFound.into_err()) + Err(trc::ResourceEvent::NotFound.into_err()) } } (class @ ("dmarc" | "tls" | "arf"), Some(report_id), &Method::DELETE) => { @@ -217,10 +217,10 @@ impl JMAP { })) .into_http_response()) } else { - Err(trc::ResourceCause::NotFound.into_err()) + Err(trc::ResourceEvent::NotFound.into_err()) } } - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), } } } diff --git a/crates/jmap/src/api/management/settings.rs b/crates/jmap/src/api/management/settings.rs index 86fd0f0c..7acd0dfb 100644 --- a/crates/jmap/src/api/management/settings.rs +++ b/crates/jmap/src/api/management/settings.rs @@ -246,7 +246,7 @@ impl JMAP { body.as_deref().unwrap_or_default(), ) .map_err(|err| { - trc::Cause::Resource(trc::ResourceCause::BadParameters).from_json_error(err) + trc::EventType::Resource(trc::ResourceEvent::BadParameters).from_json_error(err) })?; for change in changes { @@ -274,11 +274,11 @@ impl JMAP { .await? .is_empty() { - return Err(trc::ManageCause::AssertFailed.into_err()); + return Err(trc::ManageEvent::AssertFailed.into_err()); } } else if let Some((key, _)) = values.first() { if self.core.storage.config.get(key).await?.is_some() { - return Err(trc::ManageCause::AssertFailed.into_err()); + return Err(trc::ManageEvent::AssertFailed.into_err()); } } } @@ -304,7 +304,7 @@ impl JMAP { })) .into_http_response()) } - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), } } } diff --git a/crates/jmap/src/api/management/sieve.rs b/crates/jmap/src/api/management/sieve.rs index 33bb3f03..80fa9d5f 100644 --- a/crates/jmap/src/api/management/sieve.rs +++ b/crates/jmap/src/api/management/sieve.rs @@ -50,7 +50,7 @@ impl JMAP { ) { (Some(script), &Method::POST) => script, _ => { - return Err(trc::ResourceCause::NotFound.into_err()); + return Err(trc::ResourceEvent::NotFound.into_err()); } }; @@ -94,11 +94,7 @@ impl JMAP { } // Run script - let result = match self - .smtp - .run_script(script, params, tracing::debug_span!("sieve_manual_run")) - .await - { + let result = match self.smtp.run_script(script, params, 0).await { ScriptResult::Accept { modifications } => Response::Accept { modifications }, ScriptResult::Replace { message, diff --git a/crates/jmap/src/api/management/stores.rs b/crates/jmap/src/api/management/stores.rs index 3c82c127..7d30d5ec 100644 --- a/crates/jmap/src/api/management/stores.rs +++ b/crates/jmap/src/api/management/stores.rs @@ -35,7 +35,7 @@ impl JMAP { let blob_hash = URL_SAFE_NO_PAD .decode(decode_path_element(blob_hash).as_bytes()) .map_err(|err| { - trc::Cause::Resource(trc::ResourceCause::BadParameters) + trc::EventType::Resource(trc::ResourceEvent::BadParameters) .from_base64_error(err) })?; let contents = self @@ -44,7 +44,7 @@ impl JMAP { .blob .get_blob(&blob_hash, 0..usize::MAX) .await? - .ok_or_else(|| trc::ManageCause::NotFound.into_err())?; + .ok_or_else(|| trc::ManageEvent::NotFound.into_err())?; let params = UrlParams::new(req.uri().query()); let offset = params.parse("offset").unwrap_or(0); let limit = params.parse("limit").unwrap_or(usize::MAX); @@ -75,7 +75,7 @@ impl JMAP { if let Some(store) = self.core.storage.stores.get(id) { store.clone() } else { - return Err(trc::ResourceCause::NotFound.into_err()); + return Err(trc::ResourceEvent::NotFound.into_err()); } } else { self.core.storage.data.clone() @@ -89,7 +89,7 @@ impl JMAP { if let Some(store) = self.core.storage.lookups.get(id) { store.clone() } else { - return Err(trc::ResourceCause::NotFound.into_err()); + return Err(trc::ResourceEvent::NotFound.into_err()); } } else { self.core.storage.lookup.clone() @@ -105,7 +105,7 @@ impl JMAP { .data .get_account_id(decode_path_element(id).as_ref()) .await? - .ok_or_else(|| trc::ManageCause::NotFound.into_err())? + .ok_or_else(|| trc::ManageEvent::NotFound.into_err())? .into() } else { None @@ -114,13 +114,13 @@ impl JMAP { self.housekeeper_request(Event::Purge(PurgeType::Account(account_id))) .await } - _ => Err(trc::ResourceCause::NotFound.into_err()), + _ => Err(trc::ResourceEvent::NotFound.into_err()), } } async fn housekeeper_request(&self, event: Event) -> trc::Result { self.inner.housekeeper_tx.send(event).await.map_err(|err| { - trc::Cause::Thread + trc::EventType::Server(trc::ServerEvent::ThreadError) .reason(err) .details("Failed to send housekeeper event") })?; diff --git a/crates/jmap/src/api/request.rs b/crates/jmap/src/api/request.rs index 89d264b4..6ffa9911 100644 --- a/crates/jmap/src/api/request.rs +++ b/crates/jmap/src/api/request.rs @@ -163,7 +163,7 @@ impl JMAP { if self.core.jmap.principal_allow_lookups || access_token.is_super_user() { self.principal_get(req).await?.into() } else { - return Err(trc::JmapCause::Forbidden + return Err(trc::JmapEvent::Forbidden .into_err() .details("Principal lookups are disabled".to_string())); } @@ -210,7 +210,7 @@ impl JMAP { if self.core.jmap.principal_allow_lookups || access_token.is_super_user() { self.principal_query(req).await?.into() } else { - return Err(trc::JmapCause::Forbidden + return Err(trc::JmapEvent::Forbidden .into_err() .details("Principal lookups are disabled".to_string())); } diff --git a/crates/jmap/src/auth/acl.rs b/crates/jmap/src/auth/acl.rs index 676e77ef..490f675d 100644 --- a/crates/jmap/src/auth/acl.rs +++ b/crates/jmap/src/auth/acl.rs @@ -49,7 +49,7 @@ impl JMAP { let acl = Bitmap::::from(acl_item.permissions); let collection = Collection::from(acl_item.to_collection); if !collection.is_valid() { - return Err(trc::StoreCause::DataCorruption + return Err(trc::StoreEvent::DataCorruption .ctx(trc::Key::Reason, "Corrupted collection found in ACL key.") .details(format!("{acl_item:?}")) .account_id(grant_account_id) diff --git a/crates/jmap/src/auth/authenticate.rs b/crates/jmap/src/auth/authenticate.rs index 86883455..fe20d9d6 100644 --- a/crates/jmap/src/auth/authenticate.rs +++ b/crates/jmap/src/auth/authenticate.rs @@ -48,7 +48,7 @@ impl JMAP { self.authenticate_plain(&account, &secret, remote_ip, ServerProtocol::Http) .await? } else { - return Err(trc::AuthCause::Error + return Err(trc::AuthEvent::Error .into_err() .details("Failed to decode Basic auth request.") .id(token) @@ -65,7 +65,7 @@ impl JMAP { } else { // Enforce anonymous rate limit self.is_anonymous_allowed(&remote_ip).await?; - return Err(trc::AuthCause::Error + return Err(trc::AuthEvent::Error .into_err() .reason("Unsupported authentication mechanism.") .details(token) @@ -87,7 +87,7 @@ impl JMAP { // Enforce anonymous rate limit self.is_anonymous_allowed(&remote_ip).await?; - Err(trc::AuthCause::Error + Err(trc::AuthEvent::Error .into_err() .details("Missing Authorization header.") .caused_by(trc::location!())) @@ -147,7 +147,7 @@ impl JMAP { { Ok(principal) => Ok(AccessToken::new(principal)), Err(err) => { - if !err.matches(trc::Cause::Auth(trc::AuthCause::MissingTotp)) { + if !err.matches(trc::EventType::Auth(trc::AuthEvent::MissingTotp)) { let _ = self.is_auth_allowed_hard(&remote_ip).await; } Err(err) @@ -164,7 +164,7 @@ impl JMAP { .await { Ok(Some(principal)) => self.update_access_token(AccessToken::new(principal)).await, - Ok(None) => Err(trc::AuthCause::Error + Ok(None) => Err(trc::AuthEvent::Error .into_err() .details("Account not found.") .caused_by(trc::location!())), diff --git a/crates/jmap/src/auth/mod.rs b/crates/jmap/src/auth/mod.rs index 69b0cd98..6830f82a 100644 --- a/crates/jmap/src/auth/mod.rs +++ b/crates/jmap/src/auth/mod.rs @@ -115,7 +115,7 @@ impl AccessToken { if self.has_access(to_account_id.document_id(), to_collection) { Ok(self) } else { - Err(trc::JmapCause::Forbidden.into_err().details(format!( + Err(trc::JmapEvent::Forbidden.into_err().details(format!( "You do not have access to account {}", to_account_id ))) @@ -126,7 +126,7 @@ impl AccessToken { if self.is_member(account_id.document_id()) { Ok(self) } else { - Err(trc::JmapCause::Forbidden + Err(trc::JmapEvent::Forbidden .into_err() .details(format!("You are not an owner of account {}", account_id))) } diff --git a/crates/jmap/src/auth/oauth/auth.rs b/crates/jmap/src/auth/oauth/auth.rs index 22cc020b..a5e8edd9 100644 --- a/crates/jmap/src/auth/oauth/auth.rs +++ b/crates/jmap/src/auth/oauth/auth.rs @@ -34,7 +34,7 @@ impl JMAP { let request = serde_json::from_slice::(body.as_deref().unwrap_or_default()) .map_err(|err| { - trc::Cause::Resource(trc::ResourceCause::BadParameters).from_json_error(err) + trc::EventType::Resource(trc::ResourceEvent::BadParameters).from_json_error(err) })?; let response = match request { @@ -44,14 +44,14 @@ impl JMAP { } => { // Validate clientId if client_id.len() > CLIENT_ID_MAX_LEN { - return Err(trc::ManageCause::Error + return Err(trc::ManageEvent::Error .into_err() .details("Client ID is invalid.")); } else if redirect_uri .as_ref() .map_or(false, |uri| !uri.starts_with("https://")) { - return Err(trc::ManageCause::Error + return Err(trc::ManageEvent::Error .into_err() .details("Redirect URI must be HTTPS.")); } @@ -153,7 +153,7 @@ impl JMAP { .remove("client_id") .filter(|client_id| client_id.len() < CLIENT_ID_MAX_LEN) .ok_or_else(|| { - trc::ResourceCause::BadParameters + trc::ResourceEvent::BadParameters .into_err() .details("Client ID is missing.") })?; diff --git a/crates/jmap/src/auth/oauth/mod.rs b/crates/jmap/src/auth/oauth/mod.rs index 65c74e6f..c9a9c604 100644 --- a/crates/jmap/src/auth/oauth/mod.rs +++ b/crates/jmap/src/auth/oauth/mod.rs @@ -226,7 +226,7 @@ impl FormData { } Ok(FormData { fields }) } - _ => Err(trc::ResourceCause::BadParameters + _ => Err(trc::ResourceEvent::BadParameters .into_err() .details("Invalid post request")), } diff --git a/crates/jmap/src/auth/oauth/token.rs b/crates/jmap/src/auth/oauth/token.rs index 38569aaf..a3f38e19 100644 --- a/crates/jmap/src/auth/oauth/token.rs +++ b/crates/jmap/src/auth/oauth/token.rs @@ -68,7 +68,7 @@ impl JMAP { .await .map(TokenResponse::Granted) .map_err(|err| { - trc::AuthCause::Error + trc::AuthEvent::Error .into_err() .details(err) .caused_by(trc::location!()) @@ -114,7 +114,7 @@ impl JMAP { .await .map(TokenResponse::Granted) .map_err(|err| { - trc::AuthCause::Error + trc::AuthEvent::Error .into_err() .details(err) .caused_by(trc::location!()) @@ -145,7 +145,7 @@ impl JMAP { .await .map(TokenResponse::Granted) .map_err(|err| { - trc::AuthCause::Error + trc::AuthEvent::Error .into_err() .details(err) .caused_by(trc::location!()) @@ -282,7 +282,7 @@ impl JMAP { ) -> trc::Result<(u32, String, u64)> { // Base64 decode token let token = base64_decode(token_.as_bytes()).ok_or_else(|| { - trc::AuthCause::Error + trc::AuthEvent::Error .into_err() .ctx(trc::Key::Reason, "Failed to decode token") .caused_by(trc::location!()) @@ -300,7 +300,7 @@ impl JMAP { .into() }) .ok_or_else(|| { - trc::AuthCause::Error + trc::AuthEvent::Error .into_err() .ctx(trc::Key::Reason, "Failed to decode token") .caused_by(trc::location!()) @@ -314,7 +314,7 @@ impl JMAP { .unwrap_or(0) .saturating_sub(946684800); // Jan 1, 2000 if expiry <= now { - return Err(trc::AuthCause::Error + return Err(trc::AuthEvent::Error .into_err() .ctx(trc::Key::Reason, "Token expired")); } @@ -323,7 +323,7 @@ impl JMAP { let password_hash = self .password_hash(account_id) .await - .map_err(|err| trc::AuthCause::Error.into_err().ctx(trc::Key::Details, err))?; + .map_err(|err| trc::AuthEvent::Error.into_err().ctx(trc::Key::Details, err))?; // Build context let key = self.core.jmap.oauth_key.clone(); @@ -352,7 +352,7 @@ impl JMAP { &nonce, ) .map_err(|err| { - trc::AuthCause::Error + trc::AuthEvent::Error .into_err() .ctx(trc::Key::Details, "Failed to decode token") .caused_by(trc::location!()) diff --git a/crates/jmap/src/auth/rate_limit.rs b/crates/jmap/src/auth/rate_limit.rs index 3e0492f4..b5ac3491 100644 --- a/crates/jmap/src/auth/rate_limit.rs +++ b/crates/jmap/src/auth/rate_limit.rs @@ -64,12 +64,12 @@ impl JMAP { } else if access_token.is_super_user() { Ok(InFlight::default()) } else { - Err(trc::LimitCause::ConcurrentRequest.into_err()) + Err(trc::LimitEvent::ConcurrentRequest.into_err()) } } else if access_token.is_super_user() { Ok(InFlight::default()) } else { - Err(trc::LimitCause::TooManyRequests.into_err()) + Err(trc::LimitEvent::TooManyRequests.into_err()) } } @@ -84,7 +84,7 @@ impl JMAP { .caused_by(trc::location!())? .is_some() { - return Err(trc::LimitCause::TooManyRequests.into_err()); + return Err(trc::LimitEvent::TooManyRequests.into_err()); } } Ok(()) @@ -100,7 +100,7 @@ impl JMAP { } else if access_token.is_super_user() { Ok(InFlight::default()) } else { - Err(trc::LimitCause::ConcurrentUpload.into_err()) + Err(trc::LimitEvent::ConcurrentUpload.into_err()) } } @@ -115,7 +115,7 @@ impl JMAP { .caused_by(trc::location!())? .is_some() { - return Err(trc::AuthCause::TooManyAttempts.into_err()); + return Err(trc::AuthEvent::TooManyAttempts.into_err()); } } Ok(()) @@ -132,7 +132,7 @@ impl JMAP { .caused_by(trc::location!())? .is_some() { - return Err(trc::AuthCause::TooManyAttempts.into_err()); + return Err(trc::AuthEvent::TooManyAttempts.into_err()); } } Ok(()) diff --git a/crates/jmap/src/blob/get.rs b/crates/jmap/src/blob/get.rs index d7dee222..1ace52c0 100644 --- a/crates/jmap/src/blob/get.rs +++ b/crates/jmap/src/blob/get.rs @@ -172,7 +172,7 @@ impl JMAP { Ok(value) } - MaybeUnparsable::ParseError(_) => Err(trc::JmapCause::UnknownDataType.into_err()), + MaybeUnparsable::ParseError(_) => Err(trc::JmapEvent::UnknownDataType.into_err()), }) .collect::, _>>()?; let req_account_id = request.account_id.document_id(); diff --git a/crates/jmap/src/blob/upload.rs b/crates/jmap/src/blob/upload.rs index 54b0c881..7167f948 100644 --- a/crates/jmap/src/blob/upload.rs +++ b/crates/jmap/src/blob/upload.rs @@ -43,7 +43,7 @@ impl JMAP { let account_id = request.account_id.document_id(); if request.create.len() > self.core.jmap.set_max_objects { - return Err(trc::JmapCause::RequestTooLarge.into_err()); + return Err(trc::JmapEvent::RequestTooLarge.into_err()); } 'outer: for (create_id, upload_object) in request.create { @@ -211,7 +211,7 @@ impl JMAP { && used.count + 1 > self.core.jmap.upload_tmp_quota_amount)) && !access_token.is_super_user() { - let err = Err(trc::LimitCause::BlobQuota + let err = Err(trc::LimitEvent::BlobQuota .into_err() .ctx(trc::Key::Size, self.core.jmap.upload_tmp_quota_size) .ctx(trc::Key::Total, self.core.jmap.upload_tmp_quota_amount)); diff --git a/crates/jmap/src/changes/get.rs b/crates/jmap/src/changes/get.rs index a863180b..e1bc9fa2 100644 --- a/crates/jmap/src/changes/get.rs +++ b/crates/jmap/src/changes/get.rs @@ -48,7 +48,7 @@ impl JMAP { RequestArguments::Quota => { access_token.assert_is_member(request.account_id)?; - return Err(trc::JmapCause::CannotCalculateChanges.into_err()); + return Err(trc::JmapEvent::CannotCalculateChanges.into_err()); } }; diff --git a/crates/jmap/src/changes/query.rs b/crates/jmap/src/changes/query.rs index aa321618..bad2925d 100644 --- a/crates/jmap/src/changes/query.rs +++ b/crates/jmap/src/changes/query.rs @@ -33,7 +33,7 @@ impl JMAP { } query::RequestArguments::Quota => changes::RequestArguments::Quota, _ => { - return Err(trc::JmapCause::UnknownMethod + return Err(trc::JmapEvent::UnknownMethod .into_err() .details("Unknown method")) } diff --git a/crates/jmap/src/changes/state.rs b/crates/jmap/src/changes/state.rs index 955fa0dc..96f75c0d 100644 --- a/crates/jmap/src/changes/state.rs +++ b/crates/jmap/src/changes/state.rs @@ -34,7 +34,7 @@ impl JMAP { let old_state: State = self.get_state(account_id, collection).await?; if let Some(if_in_state) = if_in_state { if &old_state != if_in_state { - return Err(trc::JmapCause::StateMismatch.into_err()); + return Err(trc::JmapEvent::StateMismatch.into_err()); } } diff --git a/crates/jmap/src/changes/write.rs b/crates/jmap/src/changes/write.rs index 2047a300..a765a480 100644 --- a/crates/jmap/src/changes/write.rs +++ b/crates/jmap/src/changes/write.rs @@ -28,7 +28,7 @@ impl JMAP { pub fn generate_snowflake_id(&self) -> trc::Result { self.inner.snowflake_id.generate().ok_or_else(|| { - trc::StoreCause::Unexpected + trc::StoreEvent::UnexpectedError .into_err() .caused_by(trc::location!()) .ctx(trc::Key::Reason, "Failed to generate snowflake id.") @@ -58,7 +58,7 @@ impl JMAP { pub async fn delete_changes(&self, account_id: u32, before: Duration) -> trc::Result<()> { let reference_cid = self.inner.snowflake_id.past_id(before).ok_or_else(|| { - trc::StoreCause::Unexpected + trc::StoreEvent::UnexpectedError .caused_by(trc::location!()) .ctx(trc::Key::Reason, "Failed to generate reference change id.") })?; diff --git a/crates/jmap/src/email/copy.rs b/crates/jmap/src/email/copy.rs index d514ac0c..cb6eaa9d 100644 --- a/crates/jmap/src/email/copy.rs +++ b/crates/jmap/src/email/copy.rs @@ -60,7 +60,7 @@ impl JMAP { let from_account_id = request.from_account_id.document_id(); if account_id == from_account_id { - return Err(trc::JmapCause::InvalidArguments + return Err(trc::JmapEvent::InvalidArguments .into_err() .details("From accountId is equal to fromAccountId")); } diff --git a/crates/jmap/src/email/crypto.rs b/crates/jmap/src/email/crypto.rs index b3c779b4..bbff83aa 100644 --- a/crates/jmap/src/email/crypto.rs +++ b/crates/jmap/src/email/crypto.rs @@ -606,15 +606,15 @@ impl Deserialize for EncryptionParams { fn deserialize(bytes: &[u8]) -> trc::Result { let version = *bytes .first() - .ok_or_else(|| trc::StoreCause::DataCorruption.caused_by(trc::location!()))?; + .ok_or_else(|| trc::StoreEvent::DataCorruption.caused_by(trc::location!()))?; match version { 1 if bytes.len() > 1 => bincode::deserialize(&bytes[1..]).map_err(|err| { - trc::Cause::Store(trc::StoreCause::Deserialize) + trc::EventType::Store(trc::StoreEvent::DeserializeError) .from_bincode_error(err) .caused_by(trc::location!()) }), - _ => Err(trc::StoreCause::Deserialize + _ => Err(trc::StoreEvent::DeserializeError .into_err() .caused_by(trc::location!()) .ctx(trc::Key::Value, version as u64)), @@ -670,7 +670,7 @@ impl JMAP { body: Option>, ) -> trc::Result { let request = serde_json::from_slice::(body.as_deref().unwrap_or_default()) - .map_err(|err| trc::ResourceCause::BadParameters.into_err().reason(err))?; + .map_err(|err| trc::ResourceEvent::BadParameters.into_err().reason(err))?; let (method, algo, certs) = match request { EncryptionType::PGP { algo, certs } => (EncryptionMethod::PGP, algo, certs), diff --git a/crates/jmap/src/email/delete.rs b/crates/jmap/src/email/delete.rs index 87c1ebd0..a657ccca 100644 --- a/crates/jmap/src/email/delete.rs +++ b/crates/jmap/src/email/delete.rs @@ -337,7 +337,7 @@ impl JMAP { return Ok(()); } let reference_cid = self.inner.snowflake_id.past_id(period).ok_or_else(|| { - trc::StoreCause::Unexpected + trc::StoreEvent::UnexpectedError .into_err() .caused_by(trc::location!()) .ctx(trc::Key::Reason, "Failed to generate reference cid.") diff --git a/crates/jmap/src/email/get.rs b/crates/jmap/src/email/get.rs index 32b03894..30f0848f 100644 --- a/crates/jmap/src/email/get.rs +++ b/crates/jmap/src/email/get.rs @@ -399,7 +399,7 @@ impl JMAP { } _ => { - return Err(trc::JmapCause::InvalidArguments + return Err(trc::JmapEvent::InvalidArguments .into_err() .details(format!("Invalid property {property:?}"))); } diff --git a/crates/jmap/src/email/import.rs b/crates/jmap/src/email/import.rs index 07c7bbbc..a9186c07 100644 --- a/crates/jmap/src/email/import.rs +++ b/crates/jmap/src/email/import.rs @@ -129,14 +129,14 @@ impl JMAP { response.created.append(id, email.into()); } Err(mut err) => match err.as_ref() { - trc::Cause::Limit(trc::LimitCause::Quota) => { + trc::EventType::Limit(trc::LimitEvent::Quota) => { response.not_created.append( id, SetError::new(SetErrorType::OverQuota) .with_description("You have exceeded your disk quota."), ); } - trc::Cause::Ingest => { + trc::EventType::Store(trc::StoreEvent::IngestError) => { response.not_created.append( id, SetError::new(SetErrorType::InvalidEmail).with_description( diff --git a/crates/jmap/src/email/ingest.rs b/crates/jmap/src/email/ingest.rs index 2c9bada6..69526503 100644 --- a/crates/jmap/src/email/ingest.rs +++ b/crates/jmap/src/email/ingest.rs @@ -84,13 +84,13 @@ impl JMAP { .await .caused_by(trc::location!())? { - return Err(trc::LimitCause::Quota.into_err()); + return Err(trc::LimitEvent::Quota.into_err()); } // Parse message let mut raw_message = Cow::from(params.raw_message); let mut message = params.message.ok_or_else(|| { - trc::Cause::Ingest + trc::EventType::Store(trc::StoreEvent::IngestError) .ctx(trc::Key::Code, 550) .ctx(trc::Key::Reason, "Failed to parse e-mail message.") })?; @@ -201,10 +201,12 @@ impl JMAP { message = MessageParser::default() .parse(raw_message.as_ref()) .ok_or_else(|| { - trc::Cause::Ingest.ctx(trc::Key::Code, 550).ctx( - trc::Key::Reason, - "Failed to parse encrypted e-mail message.", - ) + trc::EventType::Store(trc::StoreEvent::IngestError) + .ctx(trc::Key::Code, 550) + .ctx( + trc::Key::Reason, + "Failed to parse encrypted e-mail message.", + ) })?; // Remove contents from parsed message @@ -224,7 +226,7 @@ impl JMAP { } } Err(EncryptMessageError::Error(err)) => { - trc::bail!(trc::StoreCause::Crypto + trc::bail!(trc::StoreEvent::CryptoError .into_err() .caused_by(trc::location!()) .reason(err)); diff --git a/crates/jmap/src/email/parse.rs b/crates/jmap/src/email/parse.rs index 55a01096..81578cec 100644 --- a/crates/jmap/src/email/parse.rs +++ b/crates/jmap/src/email/parse.rs @@ -29,7 +29,7 @@ impl JMAP { access_token: &AccessToken, ) -> trc::Result { if request.blob_ids.len() > self.core.jmap.mail_parse_max_items { - return Err(trc::JmapCause::RequestTooLarge.into_err()); + return Err(trc::JmapEvent::RequestTooLarge.into_err()); } let properties = request.properties.unwrap_or_else(|| { vec![ @@ -234,7 +234,7 @@ impl JMAP { } _ => { - return Err(trc::JmapCause::InvalidArguments + return Err(trc::JmapEvent::InvalidArguments .into_err() .details(format!("Invalid property {property:?}"))); } diff --git a/crates/jmap/src/email/query.rs b/crates/jmap/src/email/query.rs index ca44445d..7d59b5e3 100644 --- a/crates/jmap/src/email/query.rs +++ b/crates/jmap/src/email/query.rs @@ -108,14 +108,14 @@ impl JMAP { Filter::Header(header) => { let mut header = header.into_iter(); let header_name = header.next().ok_or_else(|| { - trc::JmapCause::InvalidArguments + trc::JmapEvent::InvalidArguments .into_err() .details("Header name is missing.".to_string()) })?; match HeaderName::parse(header_name) { Some(HeaderName::Other(header_name)) => { - return Err(trc::JmapCause::InvalidArguments + return Err(trc::JmapEvent::InvalidArguments .into_err() .details(format!( "Querying header '{header_name}' is not supported.", @@ -155,7 +155,7 @@ impl JMAP { fts_filters.push(cond.into()); } other => { - return Err(trc::JmapCause::UnsupportedFilter + return Err(trc::JmapEvent::UnsupportedFilter .into_err() .details(other.to_string())) } @@ -254,7 +254,7 @@ impl JMAP { } other => { - return Err(trc::JmapCause::UnsupportedFilter + return Err(trc::JmapEvent::UnsupportedFilter .into_err() .details(other.to_string())) } @@ -334,7 +334,7 @@ impl JMAP { } other => { - return Err(trc::JmapCause::UnsupportedSort + return Err(trc::JmapEvent::UnsupportedSort .into_err() .details(other.to_string())) } diff --git a/crates/jmap/src/email/set.rs b/crates/jmap/src/email/set.rs index e491a41a..84223ec4 100644 --- a/crates/jmap/src/email/set.rs +++ b/crates/jmap/src/email/set.rs @@ -726,7 +726,7 @@ impl JMAP { Ok(message) => { response.created.insert(id, message.into()); } - Err(err) if err.matches(trc::Cause::Limit(trc::LimitCause::Quota)) => { + Err(err) if err.matches(trc::EventType::Limit(trc::LimitEvent::Quota)) => { response.not_created.append( id, SetError::new(SetErrorType::OverQuota) diff --git a/crates/jmap/src/email/snippet.rs b/crates/jmap/src/email/snippet.rs index ae70afd2..17212bb4 100644 --- a/crates/jmap/src/email/snippet.rs +++ b/crates/jmap/src/email/snippet.rs @@ -82,7 +82,7 @@ impl JMAP { }; if email_ids.len() > self.core.jmap.snippet_max_results { - return Err(trc::JmapCause::RequestTooLarge.into_err()); + return Err(trc::JmapEvent::RequestTooLarge.into_err()); } for email_id in email_ids { diff --git a/crates/jmap/src/lib.rs b/crates/jmap/src/lib.rs index 0caa6a15..6adce71f 100644 --- a/crates/jmap/src/lib.rs +++ b/crates/jmap/src/lib.rs @@ -539,7 +539,7 @@ impl UpdateResults for QueryResponse { .collect::>(); Ok(()) } else { - Err(trc::JmapCause::AnchorNotFound.into_err()) + Err(trc::JmapEvent::AnchorNotFound.into_err()) } } } diff --git a/crates/jmap/src/mailbox/query.rs b/crates/jmap/src/mailbox/query.rs index 16bcaa66..3ad0718e 100644 --- a/crates/jmap/src/mailbox/query.rs +++ b/crates/jmap/src/mailbox/query.rs @@ -80,7 +80,7 @@ impl JMAP { } other => { - return Err(trc::JmapCause::UnsupportedFilter + return Err(trc::JmapEvent::UnsupportedFilter .into_err() .details(other.to_string())) } @@ -186,7 +186,7 @@ impl JMAP { } other => { - return Err(trc::JmapCause::UnsupportedSort + return Err(trc::JmapEvent::UnsupportedSort .into_err() .details(other.to_string())) } diff --git a/crates/jmap/src/principal/query.rs b/crates/jmap/src/principal/query.rs index f2e862ce..4ac800e5 100644 --- a/crates/jmap/src/principal/query.rs +++ b/crates/jmap/src/principal/query.rs @@ -65,7 +65,7 @@ impl JMAP { } Filter::Type(_) => {} other => { - return Err(trc::JmapCause::UnsupportedFilter + return Err(trc::JmapEvent::UnsupportedFilter .into_err() .details(other.to_string())) } diff --git a/crates/jmap/src/push/get.rs b/crates/jmap/src/push/get.rs index 888516d2..2feb52c6 100644 --- a/crates/jmap/src/push/get.rs +++ b/crates/jmap/src/push/get.rs @@ -83,7 +83,7 @@ impl JMAP { result.append(Property::Id, Value::Id(id)); } Property::Url | Property::Keys | Property::Value => { - return Err(trc::JmapCause::Forbidden.into_err().details( + return Err(trc::JmapEvent::Forbidden.into_err().details( "The 'url' and 'keys' properties are not readable".to_string(), )); } @@ -126,7 +126,7 @@ impl JMAP { }) .await? .ok_or_else(|| { - trc::StoreCause::NotFound + trc::StoreEvent::NotFound .into_err() .caused_by(trc::location!()) .document_id(document_id) @@ -137,7 +137,7 @@ impl JMAP { .get(&Property::Expires) .and_then(|p| p.as_date()) .ok_or_else(|| { - trc::StoreCause::Unexpected + trc::StoreEvent::UnexpectedError .caused_by(trc::location!()) .document_id(document_id) })? @@ -173,7 +173,7 @@ impl JMAP { .remove(&Property::Value) .and_then(|p| p.try_unwrap_string()) .ok_or_else(|| { - trc::StoreCause::Unexpected + trc::StoreEvent::UnexpectedError .caused_by(trc::location!()) .document_id(document_id) })?; @@ -182,7 +182,7 @@ impl JMAP { .remove(&Property::Url) .and_then(|p| p.try_unwrap_string()) .ok_or_else(|| { - trc::StoreCause::Unexpected + trc::StoreEvent::UnexpectedError .caused_by(trc::location!()) .document_id(document_id) })?; diff --git a/crates/jmap/src/quota/query.rs b/crates/jmap/src/quota/query.rs index 4511250d..a3e7dedb 100644 --- a/crates/jmap/src/quota/query.rs +++ b/crates/jmap/src/quota/query.rs @@ -62,7 +62,7 @@ impl JMAP { Filter::And | Filter::Or | Filter::Not | Filter::Close => { filters.push(cond.into()); } - other => return Err(trc::JmapCause::UnsupportedFilter.into_err().details(other.to_string())), + other => return Err(trc::JmapEvent::UnsupportedFilter.into_err().details(other.to_string())), } } @@ -87,7 +87,7 @@ impl JMAP { SortProperty::Used => { query::Comparator::field(Property::Used, comparator.is_ascending) } - other => return Err(trc::JmapCause::UnsupportedSort.into_err().details(other.to_string())), + other => return Err(trc::JmapEvent::UnsupportedSort.into_err().details(other.to_string())), }); } diff --git a/crates/jmap/src/services/ingest.rs b/crates/jmap/src/services/ingest.rs index db52740f..b8ad28ce 100644 --- a/crates/jmap/src/services/ingest.rs +++ b/crates/jmap/src/services/ingest.rs @@ -153,12 +153,12 @@ impl JMAP { ); match err.as_ref() { - trc::Cause::Limit(trc::LimitCause::Quota) => { + trc::EventType::Limit(trc::LimitEvent::Quota) => { *status = DeliveryResult::TemporaryFailure { reason: "Mailbox over quota.".into(), } } - trc::Cause::Ingest => { + trc::EventType::Store(trc::StoreEvent::IngestError) => { *status = DeliveryResult::PermanentFailure { code: err .value(trc::Key::Code) diff --git a/crates/jmap/src/services/state.rs b/crates/jmap/src/services/state.rs index bd3ac621..a1284104 100644 --- a/crates/jmap/src/services/state.rs +++ b/crates/jmap/src/services/state.rs @@ -387,10 +387,11 @@ impl JMAP { tx: change_tx, }, ] { - state_tx - .send(event) - .await - .map_err(|err| trc::Cause::Thread.reason(err).caused_by(trc::location!()))?; + state_tx.send(event).await.map_err(|err| { + trc::EventType::Server(trc::ServerEvent::ThreadError) + .reason(err) + .caused_by(trc::location!()) + })?; } Ok(change_rx) diff --git a/crates/jmap/src/sieve/get.rs b/crates/jmap/src/sieve/get.rs index a1882ace..acb671e4 100644 --- a/crates/jmap/src/sieve/get.rs +++ b/crates/jmap/src/sieve/get.rs @@ -192,7 +192,7 @@ impl JMAP { ) .await? .ok_or_else(|| { - trc::StoreCause::NotFound + trc::StoreEvent::NotFound .into_err() .caused_by(trc::location!()) .document_id(document_id) @@ -206,7 +206,7 @@ impl JMAP { .and_then(|v| v.as_blob_id()) .and_then(|v| (v.section.as_ref()?.size, v).into()) .ok_or_else(|| { - trc::StoreCause::NotFound + trc::StoreEvent::NotFound .into_err() .caused_by(trc::location!()) .document_id(document_id) @@ -217,7 +217,7 @@ impl JMAP { .get_blob(&blob_id.hash, 0..usize::MAX) .await? .ok_or_else(|| { - trc::StoreCause::NotFound + trc::StoreEvent::NotFound .into_err() .caused_by(trc::location!()) .document_id(document_id) @@ -233,7 +233,7 @@ impl JMAP { // Deserialization failed, probably because the script compiler version changed match self.core.sieve.untrusted_compiler.compile( script_bytes.get(0..script_offset).ok_or_else(|| { - trc::StoreCause::NotFound + trc::StoreEvent::NotFound .into_err() .caused_by(trc::location!()) .document_id(document_id) @@ -278,7 +278,7 @@ impl JMAP { Ok((sieve.inner, new_script_object)) } - Err(error) => Err(trc::StoreCause::Unexpected + Err(error) => Err(trc::StoreEvent::UnexpectedError .caused_by(trc::location!()) .reason(error) .details("Failed to compile Sieve script")), diff --git a/crates/jmap/src/sieve/ingest.rs b/crates/jmap/src/sieve/ingest.rs index 9587d521..19d424b6 100644 --- a/crates/jmap/src/sieve/ingest.rs +++ b/crates/jmap/src/sieve/ingest.rs @@ -47,7 +47,7 @@ impl JMAP { let message = if let Some(message) = MessageParser::new().parse(raw_message) { message } else { - return Err(trc::Cause::Ingest + return Err(trc::EventType::Store(trc::StoreEvent::IngestError) .ctx(trc::Key::Code, 550) .ctx(trc::Key::Reason, "Failed to parse e-mail message.")); }; @@ -331,6 +331,7 @@ impl JMAP { } }, message.raw_message.to_vec(), + 0, ) .queue_message() .await; @@ -462,7 +463,7 @@ impl JMAP { } if let Some(reject_reason) = reject_reason { - Err(trc::Cause::Ingest + Err(trc::EventType::Store(trc::StoreEvent::IngestError) .ctx(trc::Key::Code, 571) .ctx(trc::Key::Reason, reject_reason)) } else if has_delivered || last_temp_error.is_none() { diff --git a/crates/jmap/src/sieve/query.rs b/crates/jmap/src/sieve/query.rs index b14d0260..144ccd65 100644 --- a/crates/jmap/src/sieve/query.rs +++ b/crates/jmap/src/sieve/query.rs @@ -32,7 +32,7 @@ impl JMAP { filters.push(cond.into()); } other => { - return Err(trc::JmapCause::UnsupportedFilter + return Err(trc::JmapEvent::UnsupportedFilter .into_err() .details(other.to_string())) } @@ -61,7 +61,7 @@ impl JMAP { query::Comparator::field(Property::IsActive, comparator.is_ascending) } other => { - return Err(trc::JmapCause::UnsupportedSort + return Err(trc::JmapEvent::UnsupportedSort .into_err() .details(other.to_string())) } diff --git a/crates/jmap/src/sieve/set.rs b/crates/jmap/src/sieve/set.rs index 7569c788..ea83a8f4 100644 --- a/crates/jmap/src/sieve/set.rs +++ b/crates/jmap/src/sieve/set.rs @@ -159,7 +159,7 @@ impl JMAP { .inner .blob_id() .ok_or_else(|| { - trc::StoreCause::NotFound + trc::StoreEvent::NotFound .into_err() .caused_by(trc::location!()) .document_id(document_id) @@ -337,7 +337,7 @@ impl JMAP { ) .await? .ok_or_else(|| { - trc::StoreCause::NotFound + trc::StoreEvent::NotFound .into_err() .caused_by(trc::location!()) .document_id(document_id) @@ -356,7 +356,7 @@ impl JMAP { // Delete record let mut batch = BatchBuilder::new(); let blob_id = obj.inner.blob_id().ok_or_else(|| { - trc::StoreCause::NotFound + trc::StoreEvent::NotFound .into_err() .caused_by(trc::location!()) .document_id(document_id) diff --git a/crates/jmap/src/submission/query.rs b/crates/jmap/src/submission/query.rs index df43ef92..80ce88bc 100644 --- a/crates/jmap/src/submission/query.rs +++ b/crates/jmap/src/submission/query.rs @@ -60,7 +60,7 @@ impl JMAP { filters.push(cond.into()); } other => { - return Err(trc::JmapCause::UnsupportedFilter + return Err(trc::JmapEvent::UnsupportedFilter .into_err() .details(other.to_string())) } @@ -92,7 +92,7 @@ impl JMAP { query::Comparator::field(Property::SendAt, comparator.is_ascending) } other => { - return Err(trc::JmapCause::UnsupportedSort + return Err(trc::JmapEvent::UnsupportedSort .into_err() .details(other.to_string())) } diff --git a/crates/jmap/src/vacation/set.rs b/crates/jmap/src/vacation/set.rs index 76bc46ae..eaaf80ba 100644 --- a/crates/jmap/src/vacation/set.rs +++ b/crates/jmap/src/vacation/set.rs @@ -48,7 +48,7 @@ impl JMAP { let mut changes = None; match (request.create, request.update) { (Some(create), Some(update)) if !create.is_empty() && !update.is_empty() => { - return Err(trc::JmapCause::InvalidArguments + return Err(trc::JmapEvent::InvalidArguments .into_err() .details("Creating and updating on the same request is not allowed.")); } @@ -203,7 +203,7 @@ impl JMAP { value }) .ok_or_else(|| { - trc::StoreCause::NotFound + trc::StoreEvent::NotFound .into_err() .caused_by(trc::location!()) })? @@ -250,7 +250,7 @@ impl JMAP { if let Some(current) = obj.current() { let current_blob_id = current.inner.blob_id().ok_or_else(|| { - trc::StoreCause::NotFound + trc::StoreEvent::NotFound .into_err() .caused_by(trc::location!()) .document_id(document_id.unwrap_or(u32::MAX)) @@ -430,7 +430,7 @@ impl JMAP { Ok(script) } - Err(err) => Err(trc::StoreCause::Unexpected + Err(err) => Err(trc::StoreEvent::UnexpectedError .caused_by(trc::location!()) .reason(err) .details("Vacation Sieve Script failed to compile.")), diff --git a/crates/jmap/src/websocket/stream.rs b/crates/jmap/src/websocket/stream.rs index 32e21fc2..712a4d45 100644 --- a/crates/jmap/src/websocket/stream.rs +++ b/crates/jmap/src/websocket/stream.rs @@ -51,7 +51,7 @@ impl JMAP { { Ok(change_rx) => change_rx, Err(err) => { - tracing::debug!(parent: &span, error = ?err, "Failed to subscribe to state manager"); + tracing::debug!( error = ?err, "Failed to subscribe to state manager"); let _ = stream .send(Message::Text( @@ -103,17 +103,17 @@ impl JMAP { continue; } Err(err) => { - tracing::debug!(parent: &span, error = ?err, "Failed to parse WebSocket message"); + tracing::debug!( error = ?err, "Failed to parse WebSocket message"); WebSocketRequestError::from(err.to_request_error()).to_json() }, }; if let Err(err) = stream.send(Message::Text(response)).await { - tracing::debug!(parent: &span, error = ?err, "Failed to send text message"); + tracing::debug!( error = ?err, "Failed to send text message"); } } Message::Ping(bytes) => { if let Err(err) = stream.send(Message::Pong(bytes)).await { - tracing::debug!(parent: &span, error = ?err, "Failed to send pong message"); + tracing::debug!( error = ?err, "Failed to send pong message"); } } Message::Close(frame) => { @@ -127,7 +127,7 @@ impl JMAP { last_heartbeat = Instant::now(); } Ok(Some(Err(err))) => { - tracing::debug!(parent: &span, error = ?err, "Websocket error"); + tracing::debug!( error = ?err, "Websocket error"); break; } Ok(None) => break, @@ -135,7 +135,7 @@ impl JMAP { // Verify timeout if last_request.elapsed() > timeout { tracing::debug!( - parent: &span, + event = "disconnect", "Disconnecting idle client" ); @@ -160,7 +160,7 @@ impl JMAP { } } else { tracing::debug!( - parent: &span, + event = "channel-closed", "Disconnecting client, channel closed" ); @@ -174,7 +174,7 @@ impl JMAP { let elapsed = last_changes_sent.elapsed(); if elapsed >= throttle { if let Err(err) = stream.send(Message::Text(changes.to_json())).await { - tracing::debug!(parent: &span, error = ?err, "Failed to send state change message"); + tracing::debug!( error = ?err, "Failed to send state change message"); } changes.changed.clear(); last_changes_sent = Instant::now(); @@ -185,7 +185,7 @@ impl JMAP { } } else if last_heartbeat.elapsed() > heartbeat { if let Err(err) = stream.send(Message::Ping(vec![])).await { - tracing::debug!(parent: &span, error = ?err, "Failed to send ping message"); + tracing::debug!( error = ?err, "Failed to send ping message"); break; } last_heartbeat = Instant::now(); diff --git a/crates/jmap/src/websocket/upgrade.rs b/crates/jmap/src/websocket/upgrade.rs index b2494995..aefe992e 100644 --- a/crates/jmap/src/websocket/upgrade.rs +++ b/crates/jmap/src/websocket/upgrade.rs @@ -36,7 +36,7 @@ impl JMAP { .and_then(|h| h.to_str().ok()) != Some("websocket") { - return Err(trc::ResourceCause::BadParameters + return Err(trc::ResourceEvent::BadParameters .into_err() .details("WebSocket upgrade failed") .ctx( @@ -54,7 +54,7 @@ impl JMAP { ) { (Some(key), Some("13")) => derive_accept_key(key.as_bytes()), _ => { - return Err(trc::ResourceCause::BadParameters + return Err(trc::ResourceEvent::BadParameters .into_err() .details("WebSocket upgrade failed") .ctx( diff --git a/crates/managesieve/Cargo.toml b/crates/managesieve/Cargo.toml index eb3801f9..a54cb692 100644 --- a/crates/managesieve/Cargo.toml +++ b/crates/managesieve/Cargo.toml @@ -22,11 +22,10 @@ rustls-pemfile = "2.0" tokio = { version = "1.23", features = ["full"] } tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] } parking_lot = "0.12" -tracing = "0.1" ahash = { version = "0.8" } md5 = "0.7.0" bincode = "1.3.3" - +tracing = "0.1" [features] test_mode = [] diff --git a/crates/managesieve/src/core/client.rs b/crates/managesieve/src/core/client.rs index d00fb22d..53bb95a0 100644 --- a/crates/managesieve/src/core/client.rs +++ b/crates/managesieve/src/core/client.rs @@ -34,7 +34,7 @@ impl Session { let mut disconnect = err.must_disconnect(); if let Err(err) = self.write_error(err).await { - tracing::error!(parent: &self.span, event = "error", error = ?err); + tracing::error!( event = "error", error = ?err); disconnect = true; } @@ -52,7 +52,7 @@ impl Session { } Err(receiver::Error::Error { response }) => { if let Err(err) = self.write_error(response).await { - tracing::error!(parent: &self.span, event = "error", error = ?err); + tracing::error!( event = "error", error = ?err); return SessionResult::Close; } break; @@ -80,7 +80,7 @@ impl Session { } { Ok(response) => { if let Err(err) = self.write(&response).await { - tracing::error!(parent: &self.span, event = "error", error = ?err); + tracing::error!( event = "error", error = ?err); return SessionResult::Close; } @@ -94,7 +94,7 @@ impl Session { let mut disconnect = err.must_disconnect(); if let Err(err) = self.write_error(err).await { - tracing::error!(parent: &self.span, event = "error", error = ?err); + tracing::error!( event = "error", error = ?err); disconnect = true; } @@ -110,7 +110,7 @@ impl Session { .write(format!("OK Ready for {} bytes.\r\n", needs_literal).as_bytes()) .await { - tracing::error!(parent: &self.span, event = "error", error = ?err); + tracing::error!( event = "error", error = ?err); return SessionResult::Close; } } @@ -126,13 +126,13 @@ impl Session { if self.stream.is_tls() || self.jmap.core.imap.allow_plain_auth { Ok(command) } else { - Err(trc::Cause::ManageSieve + Err(trc::ManageSieveEvent::Error .into_err() .code(ResponseCode::EncryptNeeded) .details("Cannot authenticate over plain-text.")) } } else { - Err(trc::Cause::ManageSieve + Err(trc::ManageSieveEvent::Error .into_err() .details("Already authenticated.")) } @@ -141,7 +141,7 @@ impl Session { if !self.stream.is_tls() { Ok(command) } else { - Err(trc::Cause::ManageSieve + Err(trc::ManageSieveEvent::Error .into_err() .details("Already in TLS mode.")) } @@ -173,7 +173,7 @@ impl Session { { Ok(command) } else { - Err(trc::LimitCause::TooManyRequests + Err(trc::LimitEvent::TooManyRequests .into_err() .code(ResponseCode::TryLater)) } @@ -181,7 +181,7 @@ impl Session { Ok(command) } } else { - Err(trc::Cause::ManageSieve + Err(trc::ManageSieveEvent::Error .into_err() .details("Not authenticated.")) } @@ -193,43 +193,50 @@ impl Session { impl Session { #[inline(always)] pub async fn write(&mut self, bytes: &[u8]) -> trc::Result<()> { - self.stream - .write_all(bytes) - .await - .map_err(|err| trc::Cause::Network.reason(err).caused_by(trc::location!()))?; - self.stream - .flush() - .await - .map_err(|err| trc::Cause::Network.reason(err).caused_by(trc::location!()))?; + self.stream.write_all(bytes).await.map_err(|err| { + trc::NetworkEvent::WriteError + .into_err() + .reason(err) + .caused_by(trc::location!()) + })?; + self.stream.flush().await.map_err(|err| { + trc::NetworkEvent::FlushError + .into_err() + .reason(err) + .caused_by(trc::location!()) + })?; - tracing::trace!(parent: &self.span, + tracing::trace!( event = "write", - data = std::str::from_utf8(bytes).unwrap_or_default() , - size = bytes.len()); + data = std::str::from_utf8(bytes).unwrap_or_default(), + size = bytes.len() + ); Ok(()) } pub async fn write_error(&mut self, error: trc::Error) -> trc::Result<()> { - tracing::error!(parent: &self.span, event = "error", error = ?error); + tracing::error!( event = "error", error = ?error); self.write(&error.serialize()).await } #[inline(always)] pub async fn read(&mut self, bytes: &mut [u8]) -> trc::Result { - let len = self - .stream - .read(bytes) - .await - .map_err(|err| trc::Cause::Network.reason(err).caused_by(trc::location!()))?; + let len = self.stream.read(bytes).await.map_err(|err| { + trc::NetworkEvent::ReadError + .into_err() + .reason(err) + .caused_by(trc::location!()) + })?; - tracing::trace!(parent: &self.span, + tracing::trace!( event = "read", - data = bytes + data = bytes .get(0..len) .and_then(|bytes| std::str::from_utf8(bytes).ok()) .unwrap_or("[invalid UTF8]"), - size = len); + size = len + ); Ok(len) } @@ -250,7 +257,7 @@ impl Session { .caused_by(trc::location!()) .and_then(|results| { results.results.min().ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .code(ResponseCode::NonExistent) .reason("There is no script by that name") diff --git a/crates/managesieve/src/core/mod.rs b/crates/managesieve/src/core/mod.rs index 077453c0..3f9aadc1 100644 --- a/crates/managesieve/src/core/mod.rs +++ b/crates/managesieve/src/core/mod.rs @@ -23,7 +23,7 @@ pub struct Session { pub state: State, pub remote_addr: IpAddr, pub stream: T, - pub span: tracing::Span, + pub session_id: u64, pub in_flight: InFlight, } @@ -269,12 +269,12 @@ impl SerializeResponse for trc::Error { if let Some(code) = self .value_as_str(trc::Key::Code) .or_else(|| match self.as_ref() { - trc::Cause::Store(trc::StoreCause::NotFound) => { + trc::EventType::Store(trc::StoreEvent::NotFound) => { Some(ResponseCode::NonExistent.as_str()) } - trc::Cause::Store(_) => Some(ResponseCode::TryLater.as_str()), - trc::Cause::Limit(trc::LimitCause::Quota) => Some(ResponseCode::Quota.as_str()), - trc::Cause::Limit(_) => Some(ResponseCode::TryLater.as_str()), + trc::EventType::Store(_) => Some(ResponseCode::TryLater.as_str()), + trc::EventType::Limit(trc::LimitEvent::Quota) => Some(ResponseCode::Quota.as_str()), + trc::EventType::Limit(_) => Some(ResponseCode::TryLater.as_str()), _ => None, }) { diff --git a/crates/managesieve/src/core/session.rs b/crates/managesieve/src/core/session.rs index 78b927e1..f1b0012f 100644 --- a/crates/managesieve/src/core/session.rs +++ b/crates/managesieve/src/core/session.rs @@ -29,7 +29,7 @@ impl SessionManager for ManageSieveSessionManager { imap: self.imap.imap_inner, instance: session.instance, state: State::NotAuthenticated { auth_failures: 0 }, - span: session.span, + session_id: session.session_id, stream: session.stream, in_flight: session.in_flight, remote_addr: session.remote_ip, @@ -86,7 +86,7 @@ impl Session { } } else { tracing::debug!( - parent: &self.span, + event = "disconnect", reason = "peer", "Connection closed by peer." @@ -99,7 +99,7 @@ impl Session { } Err(_) => { tracing::debug!( - parent: &self.span, + event = "disconnect", reason = "timeout", "Connection timed out." @@ -114,7 +114,7 @@ impl Session { }, _ = shutdown_rx.changed() => { tracing::debug!( - parent: &self.span, + event = "disconnect", reason = "shutdown", "Server shutting down." @@ -129,13 +129,15 @@ impl Session { } pub async fn into_tls(self) -> Result>, ()> { - let span = self.span; Ok(Session { - stream: self.instance.tls_accept(self.stream, &span).await?, + stream: self + .instance + .tls_accept(self.stream, self.session_id) + .await?, state: self.state, instance: self.instance, in_flight: self.in_flight, - span, + session_id: self.session_id, jmap: self.jmap, imap: self.imap, receiver: self.receiver, diff --git a/crates/managesieve/src/op/authenticate.rs b/crates/managesieve/src/op/authenticate.rs index 82d57d16..5755d04d 100644 --- a/crates/managesieve/src/op/authenticate.rs +++ b/crates/managesieve/src/op/authenticate.rs @@ -23,14 +23,14 @@ use crate::core::{Command, Session, State, StatusResponse}; impl Session { pub async fn handle_authenticate(&mut self, request: Request) -> trc::Result> { if request.tokens.is_empty() { - return Err(trc::AuthCause::Error + return Err(trc::AuthEvent::Error .into_err() .details("Authentication mechanism missing.")); } let mut tokens = request.tokens.into_iter(); let mechanism = Mechanism::parse(&tokens.next().unwrap().unwrap_bytes()) - .map_err(|err| trc::AuthCause::Error.into_err().details(err))?; + .map_err(|err| trc::AuthEvent::Error.into_err().details(err))?; let mut params: Vec = tokens .filter_map(|token| token.unwrap_string().ok()) .collect(); @@ -40,7 +40,7 @@ impl Session { if !params.is_empty() { let challenge = base64_decode(params.pop().unwrap().as_bytes()).ok_or_else(|| { - trc::AuthCause::Error + trc::AuthEvent::Error .into_err() .details("Failed to decode challenge.") })?; @@ -49,7 +49,7 @@ impl Session { } else { decode_challenge_oauth(&challenge) } - .map_err(|err| trc::AuthCause::Error.into_err().details(err)))? + .map_err(|err| trc::AuthEvent::Error.into_err().details(err)))? } else { self.receiver.request = receiver::Request { tag: String::new(), @@ -61,7 +61,7 @@ impl Session { } } _ => { - return Err(trc::AuthCause::Error + return Err(trc::AuthEvent::Error .into_err() .details("Authentication mechanism not supported.")) } @@ -94,7 +94,7 @@ impl Session { } } .map_err(|err| { - if err.matches(trc::Cause::Auth(trc::AuthCause::Failed)) { + if err.matches(trc::EventType::Auth(trc::AuthEvent::Failed)) { match &self.state { State::NotAuthenticated { auth_failures } if *auth_failures < self.jmap.core.imap.max_auth_failures => @@ -104,7 +104,7 @@ impl Session { }; } _ => { - return trc::AuthCause::TooManyAttempts.into_err().caused_by(err); + return trc::AuthEvent::TooManyAttempts.into_err().caused_by(err); } } } @@ -120,7 +120,7 @@ impl Session { Some(Some(limiter)) => Some(limiter), None => None, Some(None) => { - return Err(trc::LimitCause::ConcurrentRequest.into_err()); + return Err(trc::LimitEvent::ConcurrentRequest.into_err()); } }; diff --git a/crates/managesieve/src/op/checkscript.rs b/crates/managesieve/src/op/checkscript.rs index 5d0bd9ca..229903af 100644 --- a/crates/managesieve/src/op/checkscript.rs +++ b/crates/managesieve/src/op/checkscript.rs @@ -12,7 +12,7 @@ use crate::core::{Command, Session, StatusResponse}; impl Session { pub async fn handle_checkscript(&mut self, request: Request) -> trc::Result> { if request.tokens.is_empty() { - return Err(trc::Cause::ManageSieve + return Err(trc::ManageSieveEvent::Error .into_err() .details("Expected script as a parameter.")); } @@ -23,6 +23,6 @@ impl Session { .untrusted_compiler .compile(&request.tokens.into_iter().next().unwrap().unwrap_bytes()) .map(|_| StatusResponse::ok("Script is valid.").into_bytes()) - .map_err(|err| trc::Cause::ManageSieve.into_err().details(err.to_string())) + .map_err(|err| trc::ManageSieveEvent::Error.into_err().details(err.to_string())) } } diff --git a/crates/managesieve/src/op/deletescript.rs b/crates/managesieve/src/op/deletescript.rs index f2ad1048..5f935db9 100644 --- a/crates/managesieve/src/op/deletescript.rs +++ b/crates/managesieve/src/op/deletescript.rs @@ -20,7 +20,7 @@ impl Session { .next() .and_then(|s| s.unwrap_string().ok()) .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Expected script name as a parameter.") })?; @@ -43,7 +43,7 @@ impl Session { Ok(StatusResponse::ok("Deleted.").into_bytes()) } else { - Err(trc::Cause::ManageSieve + Err(trc::ManageSieveEvent::Error .into_err() .details("You may not delete an active script") .code(ResponseCode::Active)) diff --git a/crates/managesieve/src/op/getscript.rs b/crates/managesieve/src/op/getscript.rs index ac3056aa..7c578913 100644 --- a/crates/managesieve/src/op/getscript.rs +++ b/crates/managesieve/src/op/getscript.rs @@ -23,7 +23,7 @@ impl Session { .next() .and_then(|s| s.unwrap_string().ok()) .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Expected script name as a parameter.") })?; @@ -40,7 +40,7 @@ impl Session { .await .caused_by(trc::location!())? .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Script not found") .code(ResponseCode::NonExistent) @@ -48,7 +48,7 @@ impl Session { .blob_id() .and_then(|id| (id.section.as_ref()?.clone(), id.hash.clone()).into()) .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Failed to retrieve blobId") .code(ResponseCode::TryLater) @@ -59,7 +59,7 @@ impl Session { .await .caused_by(trc::location!())? .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Script blob not found") .code(ResponseCode::NonExistent) diff --git a/crates/managesieve/src/op/havespace.rs b/crates/managesieve/src/op/havespace.rs index 5534b8d1..d9e61d35 100644 --- a/crates/managesieve/src/op/havespace.rs +++ b/crates/managesieve/src/op/havespace.rs @@ -17,7 +17,7 @@ impl Session { .next() .and_then(|s| s.unwrap_string().ok()) .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Expected script name as a parameter.") })?; @@ -25,13 +25,13 @@ impl Session { .next() .and_then(|s| s.unwrap_string().ok()) .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Expected script size as a parameter.") })? .parse::() .map_err(|_| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Invalid size parameter.") })?; @@ -53,7 +53,7 @@ impl Session { { Ok(StatusResponse::ok("").into_bytes()) } else { - Err(trc::Cause::ManageSieve + Err(trc::ManageSieveEvent::Error .into_err() .details("Quota exceeded.") .code(ResponseCode::QuotaMaxSize)) diff --git a/crates/managesieve/src/op/putscript.rs b/crates/managesieve/src/op/putscript.rs index 07847ece..2181532e 100644 --- a/crates/managesieve/src/op/putscript.rs +++ b/crates/managesieve/src/op/putscript.rs @@ -28,7 +28,7 @@ impl Session { .next() .and_then(|s| s.unwrap_string().ok()) .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Expected script name as a parameter.") })? @@ -37,7 +37,7 @@ impl Session { let mut script_bytes = tokens .next() .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Expected script as a parameter.") })? @@ -57,7 +57,7 @@ impl Session { .await .caused_by(trc::location!())? { - return Err(trc::Cause::ManageSieve + return Err(trc::ManageSieveEvent::Error .into_err() .details("Quota exceeded.") .code(ResponseCode::Quota)); @@ -72,7 +72,7 @@ impl Session { .unwrap_or(0) > self.jmap.core.jmap.sieve_max_scripts { - return Err(trc::Cause::ManageSieve + return Err(trc::ManageSieveEvent::Error .into_err() .details("Too many scripts.") .code(ResponseCode::QuotaMaxScripts)); @@ -91,12 +91,12 @@ impl Session { } Err(err) => { return Err(if let ErrorType::ScriptTooLong = &err.error_type() { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details(err.to_string()) .code(ResponseCode::QuotaMaxSize) } else { - trc::Cause::ManageSieve.into_err().details(err.to_string()) + trc::ManageSieveEvent::Error.into_err().details(err.to_string()) }); } } @@ -115,13 +115,13 @@ impl Session { .await .caused_by(trc::location!())? .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Script not found") .code(ResponseCode::NonExistent) })?; let prev_blob_id = script.inner.blob_id().ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Internal error while obtaining blobId") .code(ResponseCode::TryLater) @@ -229,15 +229,15 @@ impl Session { pub async fn validate_name(&self, account_id: u32, name: &str) -> trc::Result> { if name.is_empty() { - Err(trc::Cause::ManageSieve + Err(trc::ManageSieveEvent::Error .into_err() .details("Script name cannot be empty.")) } else if name.len() > self.jmap.core.jmap.sieve_max_script_name { - Err(trc::Cause::ManageSieve + Err(trc::ManageSieveEvent::Error .into_err() .details("Script name is too long.")) } else if name.eq_ignore_ascii_case("vacation") { - Err(trc::Cause::ManageSieve + Err(trc::ManageSieveEvent::Error .into_err() .details("The 'vacation' name is reserved, please use a different name.")) } else { diff --git a/crates/managesieve/src/op/renamescript.rs b/crates/managesieve/src/op/renamescript.rs index 48871e68..b8f76c1b 100644 --- a/crates/managesieve/src/op/renamescript.rs +++ b/crates/managesieve/src/op/renamescript.rs @@ -23,7 +23,7 @@ impl Session { .next() .and_then(|s| s.unwrap_string().ok()) .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Expected old script name as a parameter.") })? @@ -33,7 +33,7 @@ impl Session { .next() .and_then(|s| s.unwrap_string().ok()) .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Expected new script name as a parameter.") })? @@ -47,7 +47,7 @@ impl Session { let account_id = self.state.access_token().primary_id(); let document_id = self.get_script_id(account_id, &name).await?; if self.validate_name(account_id, &new_name).await?.is_some() { - return Err(trc::Cause::ManageSieve + return Err(trc::ManageSieveEvent::Error .into_err() .details(format!("A sieve script with name '{name}' already exists.",)) .code(ResponseCode::AlreadyExists)); @@ -65,7 +65,7 @@ impl Session { .await .caused_by(trc::location!())? .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Script not found") .code(ResponseCode::NonExistent) diff --git a/crates/managesieve/src/op/setactive.rs b/crates/managesieve/src/op/setactive.rs index 5cad960e..59a32d2b 100644 --- a/crates/managesieve/src/op/setactive.rs +++ b/crates/managesieve/src/op/setactive.rs @@ -20,7 +20,7 @@ impl Session { .next() .and_then(|s| s.unwrap_string().ok()) .ok_or_else(|| { - trc::Cause::ManageSieve + trc::ManageSieveEvent::Error .into_err() .details("Expected script name as a parameter.") })?; diff --git a/crates/pop3/Cargo.toml b/crates/pop3/Cargo.toml index 6a573d0e..7cce2d13 100644 --- a/crates/pop3/Cargo.toml +++ b/crates/pop3/Cargo.toml @@ -14,10 +14,10 @@ trc = { path = "../trc" } jmap_proto = { path = "../jmap-proto" } mail-parser = { version = "0.9", features = ["full_encoding", "ludicrous_mode"] } mail-send = { version = "0.4", default-features = false, features = ["cram-md5", "ring", "tls12"] } -tracing = "0.1" rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] } tokio = { version = "1.23", features = ["full"] } tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] } +tracing = "0.1" [features] test_mode = [] diff --git a/crates/pop3/src/client.rs b/crates/pop3/src/client.rs index 09556513..3bb3601a 100644 --- a/crates/pop3/src/client.rs +++ b/crates/pop3/src/client.rs @@ -47,7 +47,7 @@ impl Session { break; } Err(Error::Parse(err)) => { - requests.push(Err(trc::Cause::Pop3.into_err().details(err))); + requests.push(Err(trc::Pop3Event::Error.into_err().details(err))); } } } @@ -139,9 +139,9 @@ impl Session { .handle_sasl(mechanism, params) .await .map(|_| SessionResult::Continue), - Command::Apop { .. } => { - Err(trc::Cause::Pop3.into_err().details("APOP not supported.")) - } + Command::Apop { .. } => Err(trc::Pop3Event::Error + .into_err() + .details("APOP not supported.")), }, Err(err) => Err(err), }, @@ -180,17 +180,17 @@ impl Session { if !matches!(command, Command::Pass { .. }) || username.is_some() { Ok(command) } else { - Err(trc::Cause::Pop3 + Err(trc::Pop3Event::Error .into_err() .details("Username was not provided.")) } } else { - Err(trc::Cause::Pop3 + Err(trc::Pop3Event::Error .into_err() .details("Cannot authenticate over plain-text.")) } } else { - Err(trc::Cause::Pop3 + Err(trc::Pop3Event::Error .into_err() .details("Already authenticated.")) } @@ -199,7 +199,7 @@ impl Session { if let State::NotAuthenticated { .. } = &self.state { Ok(command) } else { - Err(trc::Cause::Pop3 + Err(trc::Pop3Event::Error .into_err() .details("Already authenticated.")) } @@ -208,7 +208,9 @@ impl Session { if !self.stream.is_tls() { Ok(command) } else { - Err(trc::Cause::Pop3.into_err().details("Already in TLS mode.")) + Err(trc::Pop3Event::Error + .into_err() + .details("Already in TLS mode.")) } } @@ -239,13 +241,15 @@ impl Session { { Ok(command) } else { - Err(trc::LimitCause::TooManyRequests.into_err()) + Err(trc::LimitEvent::TooManyRequests.into_err()) } } else { Ok(command) } } else { - Err(trc::Cause::Pop3.into_err().details("Not authenticated.")) + Err(trc::Pop3Event::Error + .into_err() + .details("Not authenticated.")) } } } diff --git a/crates/pop3/src/lib.rs b/crates/pop3/src/lib.rs index c973b848..6c0177d9 100644 --- a/crates/pop3/src/lib.rs +++ b/crates/pop3/src/lib.rs @@ -40,7 +40,7 @@ pub struct Session { pub stream: T, pub in_flight: InFlight, pub remote_addr: IpAddr, - pub span: tracing::Span, + pub session_id: u64, } pub enum State { diff --git a/crates/pop3/src/mailbox.rs b/crates/pop3/src/mailbox.rs index b3e1d06a..10accd12 100644 --- a/crates/pop3/src/mailbox.rs +++ b/crates/pop3/src/mailbox.rs @@ -74,7 +74,7 @@ impl Session { .caused_by(trc::location!())? .and_then(|obj| obj.get(&Property::Cid).as_uint()) .ok_or_else(|| { - trc::StoreCause::Unexpected + trc::StoreEvent::UnexpectedError .caused_by(trc::location!()) .details("Failed to obtain UID validity") .account_id(account_id) diff --git a/crates/pop3/src/op/authenticate.rs b/crates/pop3/src/op/authenticate.rs index 0d7fd203..faa0dc62 100644 --- a/crates/pop3/src/op/authenticate.rs +++ b/crates/pop3/src/op/authenticate.rs @@ -37,7 +37,7 @@ impl Session { decode_challenge_oauth(&challenge) } }) - .map_err(|err| trc::AuthCause::Error.into_err().details(err))?; + .map_err(|err| trc::AuthEvent::Error.into_err().details(err))?; self.handle_auth(credentials).await } else { @@ -54,7 +54,7 @@ impl Session { self.write_bytes("+\r\n").await } } - _ => Err(trc::AuthCause::Error + _ => Err(trc::AuthEvent::Error .into_err() .details("Authentication mechanism not supported.")), } @@ -83,7 +83,7 @@ impl Session { } } .map_err(|err| { - if err.matches(trc::Cause::Auth(trc::AuthCause::Failed)) { + if err.matches(trc::EventType::Auth(trc::AuthEvent::Failed)) { match &self.state { State::NotAuthenticated { auth_failures, @@ -95,7 +95,7 @@ impl Session { }; } _ => { - return trc::AuthCause::TooManyAttempts.into_err().caused_by(err); + return trc::AuthEvent::TooManyAttempts.into_err().caused_by(err); } } } @@ -111,7 +111,7 @@ impl Session { Some(Some(limiter)) => Some(limiter), None => None, Some(None) => { - return Err(trc::LimitCause::ConcurrentRequest.into_err()); + return Err(trc::LimitEvent::ConcurrentRequest.into_err()); } }; diff --git a/crates/pop3/src/op/fetch.rs b/crates/pop3/src/op/fetch.rs index 91f8043d..10a33be9 100644 --- a/crates/pop3/src/op/fetch.rs +++ b/crates/pop3/src/op/fetch.rs @@ -42,19 +42,19 @@ impl Session { ) .await } else { - Err(trc::Cause::Pop3 + Err(trc::Pop3Event::Error .into_err() .details("Failed to fetch message. Perhaps another session deleted it?") .caused_by(trc::location!())) } } else { - Err(trc::Cause::Pop3 + Err(trc::Pop3Event::Error .into_err() .details("Failed to fetch message. Perhaps another session deleted it?") .caused_by(trc::location!())) } } else { - Err(trc::Cause::Pop3 + Err(trc::Pop3Event::Error .into_err() .details("No such message.") .caused_by(trc::location!())) diff --git a/crates/pop3/src/op/list.rs b/crates/pop3/src/op/list.rs index ced3014d..a0f0985a 100644 --- a/crates/pop3/src/op/list.rs +++ b/crates/pop3/src/op/list.rs @@ -15,7 +15,7 @@ impl Session { if let Some(message) = mailbox.messages.get(msg.saturating_sub(1) as usize) { self.write_ok(format!("{} {}", msg, message.size)).await } else { - Err(trc::Cause::Pop3 + Err(trc::Pop3Event::Error .into_err() .details("No such message.") .caused_by(trc::location!())) @@ -36,7 +36,7 @@ impl Session { self.write_ok(format!("{} {}{}", msg, mailbox.uid_validity, message.uid)) .await } else { - Err(trc::Cause::Pop3 + Err(trc::Pop3Event::Error .into_err() .details("No such message.") .caused_by(trc::location!())) diff --git a/crates/pop3/src/session.rs b/crates/pop3/src/session.rs index c984b720..7a3fbd45 100644 --- a/crates/pop3/src/session.rs +++ b/crates/pop3/src/session.rs @@ -39,7 +39,7 @@ impl SessionManager for Pop3SessionManager { stream: session.stream, in_flight: session.in_flight, remote_addr: session.remote_ip, - span: session.span, + session_id: session.session_id, }; if session @@ -85,29 +85,29 @@ impl Session { return true; } SessionResult::Close => { - tracing::debug!(parent: &self.span, event = "disconnect", "Disconnecting client."); + tracing::debug!( event = "disconnect", "Disconnecting client."); break; } } } else { - tracing::debug!(parent: &self.span, event = "close", "POP3 connection closed by client."); + tracing::debug!( event = "close", "POP3 connection closed by client."); break; } }, Ok(Err(err)) => { - tracing::debug!(parent: &self.span, event = "error", reason = %err, "POP3 connection error."); + tracing::debug!( event = "error", reason = %err, "POP3 connection error."); break; }, Err(_) => { self.write_bytes(&b"-ERR Connection timed out.\r\n"[..]).await.ok(); - tracing::debug!(parent: &self.span, "POP3 connection timed out."); + tracing::debug!( "POP3 connection timed out."); break; } } }, _ = shutdown_rx.changed() => { self.write_bytes(&b"* BYE Server shutting down.\r\n"[..]).await.ok(); - tracing::debug!(parent: &self.span, event = "shutdown", "POP3 server shutting down."); + tracing::debug!( event = "shutdown", "POP3 server shutting down."); break; } }; @@ -118,13 +118,16 @@ impl Session { pub async fn into_tls(self) -> Result>, ()> { Ok(Session { - stream: self.instance.tls_accept(self.stream, &self.span).await?, + stream: self + .instance + .tls_accept(self.stream, self.session_id) + .await?, jmap: self.jmap, imap: self.imap, instance: self.instance, receiver: self.receiver, state: self.state, - span: self.span, + session_id: self.session_id, in_flight: self.in_flight, remote_addr: self.remote_addr, }) @@ -138,20 +141,23 @@ impl Session { let c = println!("{}", line); }*/ tracing::trace!( - parent: &self.span, event = "write", data = std::str::from_utf8(bytes).unwrap_or_default(), size = bytes.len() ); - self.stream - .write_all(bytes.as_ref()) - .await - .map_err(|err| trc::Cause::Network.reason(err).caused_by(trc::location!()))?; - self.stream - .flush() - .await - .map_err(|err| trc::Cause::Network.reason(err).caused_by(trc::location!())) + self.stream.write_all(bytes.as_ref()).await.map_err(|err| { + trc::NetworkEvent::WriteError + .into_err() + .reason(err) + .caused_by(trc::location!()) + })?; + self.stream.flush().await.map_err(|err| { + trc::NetworkEvent::WriteError + .into_err() + .reason(err) + .caused_by(trc::location!()) + }) } pub async fn write_ok(&mut self, message: impl Into>) -> trc::Result<()> { @@ -160,12 +166,12 @@ impl Session { } pub async fn write_err(&mut self, err: trc::Error) -> bool { - tracing::error!(parent: &self.span, "POP3 error: {}", err); + tracing::error!("POP3 error: {}", err); let disconnect = err.must_disconnect(); if err.should_write_err() { if let Err(err) = self.write_bytes(err.serialize()).await { - tracing::debug!(parent: &self.span, "Failed to write error: {}", err); + tracing::debug!("Failed to write error: {}", err); return false; } } diff --git a/crates/smtp/Cargo.toml b/crates/smtp/Cargo.toml index 077fffeb..354d1166 100644 --- a/crates/smtp/Cargo.toml +++ b/crates/smtp/Cargo.toml @@ -39,7 +39,6 @@ sha1 = "0.10" sha2 = "0.10.6" md5 = "0.7.0" rayon = "1.5" -tracing = "0.1" parking_lot = "0.12" regex = "1.7.0" dashmap = "6.0" @@ -54,6 +53,7 @@ num_cpus = "1.15.0" lazy_static = "1.4" bincode = "1.3.1" chrono = "0.4" +tracing = "0.1" [features] test_mode = [] diff --git a/crates/smtp/src/core/mod.rs b/crates/smtp/src/core/mod.rs index 03b07eb8..502cd5e2 100644 --- a/crates/smtp/src/core/mod.rs +++ b/crates/smtp/src/core/mod.rs @@ -108,7 +108,6 @@ pub struct Session { pub state: State, pub instance: Arc, pub core: SMTP, - pub span: Span, pub stream: T, pub data: SessionData, pub params: SessionParameters, @@ -116,6 +115,7 @@ pub struct Session { } pub struct SessionData { + pub session_id: u64, pub local_ip: IpAddr, pub local_ip_str: String, pub local_port: u16, @@ -188,8 +188,15 @@ pub struct SessionParameters { } impl SessionData { - pub fn new(local_ip: IpAddr, local_port: u16, remote_ip: IpAddr, remote_port: u16) -> Self { + pub fn new( + local_ip: IpAddr, + local_port: u16, + remote_ip: IpAddr, + remote_port: u16, + session_id: u64, + ) -> Self { SessionData { + session_id, local_ip, local_port, remote_ip, @@ -280,21 +287,6 @@ impl Session { state: State::None, instance, core, - span: tracing::info_span!( - "local_delivery", - "return_path" = - if let Some(addr) = data.mail_from.as_ref().map(|a| a.address_lcase.as_str()) { - if !addr.is_empty() { - addr - } else { - "<>" - } - } else { - "<>" - }, - "nrcpt" = data.rcpt_to.len(), - "size" = data.message.len(), - ), stream: common::listener::stream::NullIo::default(), data, params: SessionParameters { @@ -326,11 +318,12 @@ impl Session { mail_from: SessionAddress, rcpt_to: Vec, message: Vec, + session_id: u64, ) -> Self { Self::local( core, SIEVE.clone(), - SessionData::local(mail_from.into(), rcpt_to, message), + SessionData::local(mail_from.into(), rcpt_to, message, session_id), ) } @@ -354,6 +347,7 @@ impl SessionData { mail_from: Option, rcpt_to: Vec, message: Vec, + session_id: u64, ) -> Self { SessionData { local_ip: IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1)), @@ -362,6 +356,7 @@ impl SessionData { remote_ip_str: "127.0.0.1".to_string(), remote_port: 0, local_port: 0, + session_id, helo_domain: "localhost".into(), mail_from, rcpt_to, @@ -386,7 +381,7 @@ impl SessionData { impl Default for SessionData { fn default() -> Self { - Self::local(None, vec![], vec![]) + Self::local(None, vec![], vec![], 0) } } diff --git a/crates/smtp/src/core/params.rs b/crates/smtp/src/core/params.rs index 9d7a24e1..4e555a24 100644 --- a/crates/smtp/src/core/params.rs +++ b/crates/smtp/src/core/params.rs @@ -16,38 +16,50 @@ impl Session { self.data.bytes_left = self .core .core - .eval_if(&c.transfer_limit, self) + .eval_if(&c.transfer_limit, self, self.data.session_id) .await .unwrap_or(250 * 1024 * 1024); self.data.valid_until += self .core .core - .eval_if(&c.duration, self) + .eval_if(&c.duration, self, self.data.session_id) .await .unwrap_or_else(|| Duration::from_secs(15 * 60)); self.params.timeout = self .core .core - .eval_if(&c.timeout, self) + .eval_if(&c.timeout, self, self.data.session_id) .await .unwrap_or_else(|| Duration::from_secs(5 * 60)); self.params.spf_ehlo = self .core .core - .eval_if(&self.core.core.smtp.mail_auth.spf.verify_ehlo, self) + .eval_if( + &self.core.core.smtp.mail_auth.spf.verify_ehlo, + self, + self.data.session_id, + ) .await .unwrap_or(VerifyStrategy::Relaxed); self.params.spf_mail_from = self .core .core - .eval_if(&self.core.core.smtp.mail_auth.spf.verify_mail_from, self) + .eval_if( + &self.core.core.smtp.mail_auth.spf.verify_mail_from, + self, + self.data.session_id, + ) .await .unwrap_or(VerifyStrategy::Relaxed); self.params.iprev = self .core .core - .eval_if(&self.core.core.smtp.mail_auth.iprev.verify, self) + .eval_if( + &self.core.core.smtp.mail_auth.iprev.verify, + self, + self.data.session_id, + ) .await .unwrap_or(VerifyStrategy::Relaxed); @@ -56,13 +68,13 @@ impl Session { self.params.ehlo_require = self .core .core - .eval_if(&ec.require, self) + .eval_if(&ec.require, self, self.data.session_id) .await .unwrap_or(true); self.params.ehlo_reject_non_fqdn = self .core .core - .eval_if(&ec.reject_non_fqdn, self) + .eval_if(&ec.reject_non_fqdn, self, self.data.session_id) .await .unwrap_or(true); @@ -71,32 +83,32 @@ impl Session { self.params.auth_directory = self .core .core - .eval_if::(&ac.directory, self) + .eval_if::(&ac.directory, self, self.data.session_id) .await .and_then(|name| self.core.core.get_directory(&name)) .cloned(); self.params.auth_require = self .core .core - .eval_if(&ac.require, self) + .eval_if(&ac.require, self, self.data.session_id) .await .unwrap_or(false); self.params.auth_errors_max = self .core .core - .eval_if(&ac.errors_max, self) + .eval_if(&ac.errors_max, self, self.data.session_id) .await .unwrap_or(3); self.params.auth_errors_wait = self .core .core - .eval_if(&ac.errors_wait, self) + .eval_if(&ac.errors_wait, self, self.data.session_id) .await .unwrap_or_else(|| Duration::from_secs(30)); self.params.auth_match_sender = self .core .core - .eval_if(&ac.must_match_sender, self) + .eval_if(&ac.must_match_sender, self, self.data.session_id) .await .unwrap_or(true); @@ -105,13 +117,13 @@ impl Session { self.params.can_expn = self .core .core - .eval_if(&ec.expn, self) + .eval_if(&ec.expn, self, self.data.session_id) .await .unwrap_or(false); self.params.can_vrfy = self .core .core - .eval_if(&ec.vrfy, self) + .eval_if(&ec.vrfy, self, self.data.session_id) .await .unwrap_or(false); } @@ -122,19 +134,23 @@ impl Session { self.params.can_expn = self .core .core - .eval_if(&ec.expn, self) + .eval_if(&ec.expn, self, self.data.session_id) .await .unwrap_or(false); self.params.can_vrfy = self .core .core - .eval_if(&ec.vrfy, self) + .eval_if(&ec.vrfy, self, self.data.session_id) .await .unwrap_or(false); self.params.auth_match_sender = self .core .core - .eval_if(&self.core.core.smtp.session.auth.must_match_sender, self) + .eval_if( + &self.core.core.smtp.session.auth.must_match_sender, + self, + self.data.session_id, + ) .await .unwrap_or(true); } @@ -144,32 +160,40 @@ impl Session { self.params.rcpt_errors_max = self .core .core - .eval_if(&rc.errors_max, self) + .eval_if(&rc.errors_max, self, self.data.session_id) .await .unwrap_or(10); self.params.rcpt_errors_wait = self .core .core - .eval_if(&rc.errors_wait, self) + .eval_if(&rc.errors_wait, self, self.data.session_id) .await .unwrap_or_else(|| Duration::from_secs(30)); self.params.rcpt_max = self .core .core - .eval_if(&rc.max_recipients, self) + .eval_if(&rc.max_recipients, self, self.data.session_id) .await .unwrap_or(100); self.params.rcpt_dsn = self .core .core - .eval_if(&self.core.core.smtp.session.extensions.dsn, self) + .eval_if( + &self.core.core.smtp.session.extensions.dsn, + self, + self.data.session_id, + ) .await .unwrap_or(true); self.params.max_message_size = self .core .core - .eval_if(&self.core.core.smtp.session.data.max_message_size, self) + .eval_if( + &self.core.core.smtp.session.data.max_message_size, + self, + self.data.session_id, + ) .await .unwrap_or(25 * 1024 * 1024); } diff --git a/crates/smtp/src/core/throttle.rs b/crates/smtp/src/core/throttle.rs index e393acb1..60684edb 100644 --- a/crates/smtp/src/core/throttle.rs +++ b/crates/smtp/src/core/throttle.rs @@ -210,7 +210,7 @@ impl Session { || self .core .core - .eval_expr(&t.expr, self, "throttle") + .eval_expr(&t.expr, self, "throttle", self.data.session_id) .await .unwrap_or(false) { @@ -239,7 +239,7 @@ impl Session { self.in_flight.push(inflight); } else { tracing::debug!( - parent: &self.span, + context = "throttle", event = "too-many-requests", max_concurrent = limiter.max_concurrent, @@ -271,7 +271,7 @@ impl Session { .is_some() { tracing::debug!( - parent: &self.span, + context = "throttle", event = "rate-limit-exceeded", max_requests = rate.requests, diff --git a/crates/smtp/src/inbound/auth.rs b/crates/smtp/src/inbound/auth.rs index 052235e2..ab4153dc 100644 --- a/crates/smtp/src/inbound/auth.rs +++ b/crates/smtp/src/inbound/auth.rs @@ -178,7 +178,7 @@ impl Session { { Ok(principal) => { tracing::debug!( - parent: &self.span, + context = "auth", event = "authenticate", result = "success" @@ -196,9 +196,9 @@ impl Session { return Ok(false); } Err(err) => match err.as_ref() { - trc::Cause::Auth(trc::AuthCause::Failed) => { + trc::EventType::Auth(trc::AuthEvent::Failed) => { tracing::debug!( - parent: &self.span, + context = "auth", event = "authenticate", result = "failed" @@ -208,9 +208,9 @@ impl Session { .auth_error(b"535 5.7.8 Authentication credentials invalid.\r\n") .await; } - trc::Cause::Auth(trc::AuthCause::MissingTotp) => { + trc::EventType::Auth(trc::AuthEvent::MissingTotp) => { tracing::debug!( - parent: &self.span, + context = "auth", event = "authenticate", result = "missing-totp" @@ -222,9 +222,9 @@ impl Session { ) .await; } - trc::Cause::Auth(trc::AuthCause::Banned) => { + trc::EventType::Auth(trc::AuthEvent::Banned) => { tracing::debug!( - parent: &self.span, + context = "auth", event = "authenticate", result = "banned" @@ -237,7 +237,7 @@ impl Session { } } else { tracing::warn!( - parent: &self.span, + context = "auth", event = "error", "No lookup list configured for authentication." @@ -259,7 +259,7 @@ impl Session { self.write(b"421 4.3.0 Too many authentication errors, disconnecting.\r\n") .await?; tracing::debug!( - parent: &self.span, + event = "disconnect", reason = "auth-errors", "Too many authentication errors." diff --git a/crates/smtp/src/inbound/data.rs b/crates/smtp/src/inbound/data.rs index 6c5d7ed1..bfe4ad58 100644 --- a/crates/smtp/src/inbound/data.rs +++ b/crates/smtp/src/inbound/data.rs @@ -50,7 +50,7 @@ impl Session { ) { auth_message } else { - tracing::info!(parent: &self.span, + tracing::info!( context = "data", event = "parse-failed", size = raw_message.len()); @@ -69,11 +69,11 @@ impl Session { > self .core .core - .eval_if(&dc.max_received_headers, self) + .eval_if(&dc.max_received_headers, self, self.data.session_id) .await .unwrap_or(50) { - tracing::info!(parent: &self.span, + tracing::info!( context = "data", event = "loop-detected", return_path = self.data.mail_from.as_ref().unwrap().address, @@ -91,13 +91,13 @@ impl Session { let dkim = self .core .core - .eval_if(&ac.dkim.verify, self) + .eval_if(&ac.dkim.verify, self, self.data.session_id) .await .unwrap_or(VerifyStrategy::Relaxed); let dmarc = self .core .core - .eval_if(&ac.dmarc.verify, self) + .eval_if(&ac.dmarc.verify, self, self.data.session_id) .await .unwrap_or(VerifyStrategy::Relaxed); let dkim_output = if dkim.verify() || dmarc.verify() { @@ -115,7 +115,12 @@ impl Session { .any(|d| matches!(d.result(), DkimResult::Pass)); // Send reports for failed signatures - if let Some(rate) = self.core.core.eval_if::(&rc.dkim.send, self).await { + if let Some(rate) = self + .core + .core + .eval_if::(&rc.dkim.send, self, self.data.session_id) + .await + { for output in &dkim_output { if let Some(rcpt) = output.failure_report_addr() { self.send_dkim_report(rcpt, &auth_message, &rate, rejected, output) @@ -125,7 +130,7 @@ impl Session { } if rejected { - tracing::info!(parent: &self.span, + tracing::info!( context = "dkim", event = "failed", return_path = self.data.mail_from.as_ref().unwrap().address, @@ -146,7 +151,7 @@ impl Session { (&b"550 5.7.20 No passing DKIM signatures found.\r\n"[..]).into() }; } else { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "dkim", event = "verify", return_path = self.data.mail_from.as_ref().unwrap().address, @@ -162,13 +167,13 @@ impl Session { let arc = self .core .core - .eval_if(&ac.arc.verify, self) + .eval_if(&ac.arc.verify, self, self.data.session_id) .await .unwrap_or(VerifyStrategy::Relaxed); let arc_sealer = self .core .core - .eval_if::(&ac.arc.seal, self) + .eval_if::(&ac.arc.seal, self, self.data.session_id) .await .and_then(|name| self.core.core.get_arc_sealer(&name)); let arc_output = if arc.verify() || arc_sealer.is_some() { @@ -184,7 +189,7 @@ impl Session { if arc.is_strict() && !matches!(arc_output.result(), DkimResult::Pass | DkimResult::None) { - tracing::info!(parent: &self.span, + tracing::info!( context = "arc", event = "auth-failed", return_path = self.data.mail_from.as_ref().unwrap().address, @@ -201,7 +206,7 @@ impl Session { (&b"550 5.7.29 ARC validation failed.\r\n"[..]).into() }; } else { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "arc", event = "verify", return_path = self.data.mail_from.as_ref().unwrap().address, @@ -284,7 +289,7 @@ impl Session { let dmarc_policy = dmarc_output.policy(); if !rejected { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "dmarc", event = "verify", return_path = mail_from.address, @@ -292,7 +297,7 @@ impl Session { dkim_result = %dmarc_output.dkim_result(), spf_result = %dmarc_output.spf_result()); } else { - tracing::info!(parent: &self.span, + tracing::info!( context = "dmarc", event = "auth-failed", return_path = mail_from.address, @@ -345,7 +350,7 @@ impl Session { if self .core .core - .eval_if(&dc.add_received, self) + .eval_if(&dc.add_received, self, self.data.session_id) .await .unwrap_or(true) { @@ -356,7 +361,7 @@ impl Session { if self .core .core - .eval_if(&dc.add_auth_results, self) + .eval_if(&dc.add_auth_results, self, self.data.session_id) .await .unwrap_or(true) { @@ -368,7 +373,7 @@ impl Session { if self .core .core - .eval_if(&dc.add_received_spf, self) + .eval_if(&dc.add_received_spf, self, self.data.session_id) .await .unwrap_or(true) { @@ -391,7 +396,7 @@ impl Session { set.write_header(&mut headers); } Err(err) => { - tracing::info!(parent: &self.span, + tracing::info!( context = "arc", event = "seal-failed", return_path = mail_from.address_lcase, @@ -408,7 +413,7 @@ impl Session { Ok(modifications_) => { if !modifications_.is_empty() { tracing::debug!( - parent: &self.span, + context = "milter", event = "accept", modifications = modifications.iter().fold(String::new(), |mut s, m| { @@ -439,7 +444,7 @@ impl Session { Ok(modifications_) => { if !modifications_.is_empty() { tracing::debug!( - parent: &self.span, + context = "mta_hook", event = "accept", "MTAHook filter(s) accepted message."); @@ -469,14 +474,14 @@ impl Session { if let Some(command_) = self .core .core - .eval_if::(&pipe.command, self) + .eval_if::(&pipe.command, self, self.data.session_id) .await { let piped_message = edited_message.as_ref().unwrap_or(&raw_message).clone(); let timeout = self .core .core - .eval_if(&pipe.timeout, self) + .eval_if(&pipe.timeout, self, self.data.session_id) .await .unwrap_or_else(|| Duration::from_secs(30)); @@ -484,7 +489,7 @@ impl Session { for argument in self .core .core - .eval_if::, _>(&pipe.arguments, self) + .eval_if::, _>(&pipe.arguments, self, self.data.session_id) .await .unwrap_or_default() { @@ -514,21 +519,21 @@ impl Session { edited_message = output.stdout.into(); } - tracing::debug!(parent: &self.span, + tracing::debug!( context = "pipe", event = "success", command = command_, status = output.status.to_string()); } Ok(Err(err)) => { - tracing::warn!(parent: &self.span, + tracing::warn!( context = "pipe", event = "exec-error", command = command_, reason = %err); } Err(_) => { - tracing::warn!(parent: &self.span, + tracing::warn!( context = "pipe", event = "timeout", command = command_); @@ -536,28 +541,28 @@ impl Session { } } Ok(Err(err)) => { - tracing::warn!(parent: &self.span, + tracing::warn!( context = "pipe", event = "write-error", command = command_, reason = %err); } Err(_) => { - tracing::warn!(parent: &self.span, + tracing::warn!( context = "pipe", event = "stdin-timeout", command = command_); } } } else { - tracing::warn!(parent: &self.span, + tracing::warn!( context = "pipe", event = "stdin-failed", command = command_); } } Err(err) => { - tracing::warn!(parent: &self.span, + tracing::warn!( context = "pipe", event = "spawn-error", command = command_, @@ -571,7 +576,7 @@ impl Session { if let Some(script) = self .core .core - .eval_if::(&dc.script, self) + .eval_if::(&dc.script, self, self.data.session_id) .await .and_then(|name| self.core.core.get_sieve_script(&name)) { @@ -634,7 +639,7 @@ impl Session { modifications } ScriptResult::Reject(message) => { - tracing::info!(parent: &self.span, + tracing::info!( context = "sieve", event = "reject", reason = message); @@ -679,7 +684,7 @@ impl Session { if self .core .core - .eval_if(&dc.add_return_path, self) + .eval_if(&dc.add_return_path, self, self.data.session_id) .await .unwrap_or(true) { @@ -693,7 +698,7 @@ impl Session { && self .core .core - .eval_if(&dc.add_date, self) + .eval_if(&dc.add_date, self, self.data.session_id) .await .unwrap_or(true) { @@ -705,7 +710,7 @@ impl Session { && self .core .core - .eval_if(&dc.add_message_id, self) + .eval_if(&dc.add_message_id, self, self.data.session_id) .await .unwrap_or(true) { @@ -721,7 +726,7 @@ impl Session { for signer in self .core .core - .eval_if::, _>(&ac.dkim.sign, self) + .eval_if::, _>(&ac.dkim.sign, self, self.data.session_id) .await .unwrap_or_default() { @@ -731,7 +736,7 @@ impl Session { signature.write_header(&mut headers); } Err(err) => { - tracing::info!(parent: &self.span, + tracing::info!( context = "dkim", event = "sign-failed", return_path = message.return_path, @@ -780,10 +785,7 @@ impl Session { }); // Queue message - if message - .queue(Some(&headers), raw_message, &self.core, &self.span) - .await - { + if message.queue(Some(&headers), raw_message, &self.core).await { // Send webhook event if let Some(event) = webhook_event { self.core @@ -804,7 +806,7 @@ impl Session { } } else { tracing::warn!( - parent: &self.span, + context = "queue", event = "quota-exceeded", from = message.return_path, @@ -876,7 +878,7 @@ impl Session { let (num_intervals, next_notify) = self .core .core - .eval_if::, _>(&config.notify, &envelope) + .eval_if::, _>(&config.notify, &envelope, self.data.session_id) .await .and_then(|v| (v.len(), v.into_iter().next()?).into()) .unwrap_or_else(|| (1, Duration::from_secs(86400))); @@ -888,7 +890,7 @@ impl Session { + self .core .core - .eval_if(&config.expire, &envelope) + .eval_if(&config.expire, &envelope, self.data.session_id) .await .unwrap_or_else(|| Duration::from_secs(5 * 86400)) .as_secs(), @@ -902,7 +904,7 @@ impl Session { let expire = self .core .core - .eval_if(&config.expire, &envelope) + .eval_if(&config.expire, &envelope, self.data.session_id) .await .unwrap_or_else(|| Duration::from_secs(5 * 86400)); let expire_secs = expire.as_secs(); @@ -962,14 +964,18 @@ impl Session { < self .core .core - .eval_if(&self.core.core.smtp.session.data.max_messages, self) + .eval_if( + &self.core.core.smtp.session.data.max_messages, + self, + self.data.session_id, + ) .await .unwrap_or(10) { Ok(true) } else { tracing::debug!( - parent: &self.span, + context = "data", event = "too-many-messages", "Maximum number of messages per session exceeded." diff --git a/crates/smtp/src/inbound/ehlo.rs b/crates/smtp/src/inbound/ehlo.rs index 151d6371..1ff05f1e 100644 --- a/crates/smtp/src/inbound/ehlo.rs +++ b/crates/smtp/src/inbound/ehlo.rs @@ -21,7 +21,7 @@ impl Session { if domain != self.data.helo_domain { // Reject non-FQDN EHLO domains - simply checks that the hostname has at least one dot if self.params.ehlo_reject_non_fqdn && !domain.as_str().has_valid_labels() { - tracing::info!(parent: &self.span, + tracing::info!( context = "ehlo", event = "reject", reason = "invalid", @@ -43,7 +43,7 @@ impl Session { .verify_spf_helo(self.data.remote_ip, &self.data.helo_domain, &self.hostname) .await; - tracing::debug!(parent: &self.span, + tracing::debug!( context = "spf", event = "lookup", identity = "ehlo", @@ -67,7 +67,11 @@ impl Session { if let Some(script) = self .core .core - .eval_if::(&self.core.core.smtp.session.ehlo.script, self) + .eval_if::( + &self.core.core.smtp.session.ehlo.script, + self, + self.data.session_id, + ) .await .and_then(|name| self.core.core.get_sieve_script(&name)) { @@ -75,7 +79,7 @@ impl Session { .run_script(script.clone(), self.build_script_parameters("ehlo")) .await { - tracing::info!(parent: &self.span, + tracing::info!( context = "sieve", event = "reject", domain = &self.data.helo_domain, @@ -90,7 +94,7 @@ impl Session { // Milter filtering if let Err(message) = self.run_milters(Stage::Ehlo, None).await { - tracing::info!(parent: &self.span, + tracing::info!( context = "milter", event = "reject", domain = &self.data.helo_domain, @@ -104,7 +108,7 @@ impl Session { // MTAHook filtering if let Err(message) = self.run_mta_hooks(Stage::Ehlo, None).await { - tracing::info!(parent: &self.span, + tracing::info!( context = "mta_hook", event = "reject", domain = &self.data.helo_domain, @@ -116,7 +120,7 @@ impl Session { return self.write(message.message.as_bytes()).await; } - tracing::debug!(parent: &self.span, + tracing::debug!( context = "ehlo", event = "ehlo", domain = self.data.helo_domain, @@ -148,7 +152,7 @@ impl Session { if self .core .core - .eval_if(&ec.pipelining, self) + .eval_if(&ec.pipelining, self, self.data.session_id) .await .unwrap_or(true) { @@ -159,7 +163,7 @@ impl Session { if self .core .core - .eval_if(&ec.chunking, self) + .eval_if(&ec.chunking, self, self.data.session_id) .await .unwrap_or(true) { @@ -170,7 +174,7 @@ impl Session { if self .core .core - .eval_if(&ec.expn, self) + .eval_if(&ec.expn, self, self.data.session_id) .await .unwrap_or(false) { @@ -181,7 +185,7 @@ impl Session { if self .core .core - .eval_if(&ec.vrfy, self) + .eval_if(&ec.vrfy, self, self.data.session_id) .await .unwrap_or(false) { @@ -192,7 +196,7 @@ impl Session { if self .core .core - .eval_if(&ec.requiretls, self) + .eval_if(&ec.requiretls, self, self.data.session_id) .await .unwrap_or(true) { @@ -200,7 +204,13 @@ impl Session { } // DSN - if self.core.core.eval_if(&ec.dsn, self).await.unwrap_or(false) { + if self + .core + .core + .eval_if(&ec.dsn, self, self.data.session_id) + .await + .unwrap_or(false) + { response.capabilities |= EXT_DSN; } @@ -209,7 +219,7 @@ impl Session { response.auth_mechanisms = self .core .core - .eval_if::(&ac.mechanisms, self) + .eval_if::(&ac.mechanisms, self, self.data.session_id) .await .unwrap_or_default() .into(); @@ -222,7 +232,7 @@ impl Session { if let Some(value) = self .core .core - .eval_if::(&ec.future_release, self) + .eval_if::(&ec.future_release, self, self.data.session_id) .await { response.capabilities |= EXT_FUTURE_RELEASE; @@ -238,7 +248,7 @@ impl Session { if let Some(value) = self .core .core - .eval_if::(&ec.deliver_by, self) + .eval_if::(&ec.deliver_by, self, self.data.session_id) .await { response.capabilities |= EXT_DELIVER_BY; @@ -249,7 +259,7 @@ impl Session { if let Some(value) = self .core .core - .eval_if::(&ec.mt_priority, self) + .eval_if::(&ec.mt_priority, self, self.data.session_id) .await { response.capabilities |= EXT_MT_PRIORITY; @@ -260,7 +270,7 @@ impl Session { response.size = self .core .core - .eval_if(&dc.max_message_size, self) + .eval_if(&dc.max_message_size, self, self.data.session_id) .await .unwrap_or(25 * 1024 * 1024); if response.size > 0 { @@ -271,7 +281,7 @@ impl Session { if let Some(value) = self .core .core - .eval_if::(&ec.no_soliciting, self) + .eval_if::(&ec.no_soliciting, self, self.data.session_id) .await { response.capabilities |= EXT_NO_SOLICITING; diff --git a/crates/smtp/src/inbound/hooks/message.rs b/crates/smtp/src/inbound/hooks/message.rs index 8b6c1dac..c2b23d95 100644 --- a/crates/smtp/src/inbound/hooks/message.rs +++ b/crates/smtp/src/inbound/hooks/message.rs @@ -42,7 +42,7 @@ impl Session { || !self .core .core - .eval_if(&mta_hook.enable, self) + .eval_if(&mta_hook.enable, self, self.data.session_id) .await .unwrap_or(false) { @@ -136,7 +136,7 @@ impl Session { } Err(err) => { tracing::warn!( - parent: &self.span, + mta_hook.url = &mta_hook.url, context = "mta_hook", event = "error", diff --git a/crates/smtp/src/inbound/mail.rs b/crates/smtp/src/inbound/mail.rs index 0ffb6b27..d087ed11 100644 --- a/crates/smtp/src/inbound/mail.rs +++ b/crates/smtp/src/inbound/mail.rs @@ -45,7 +45,7 @@ impl Session { .verify_iprev(self.data.remote_ip) .await; - tracing::debug!(parent: &self.span, + tracing::debug!( context = "iprev", event = "lookup", result = %iprev.result, @@ -115,7 +115,11 @@ impl Session { if let Some(script) = self .core .core - .eval_if::(&self.core.core.smtp.session.mail.script, self) + .eval_if::( + &self.core.core.smtp.session.mail.script, + self, + self.data.session_id, + ) .await .and_then(|name| self.core.core.get_sieve_script(&name)) { @@ -125,7 +129,7 @@ impl Session { { ScriptResult::Accept { modifications } => { if !modifications.is_empty() { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "sieve", event = "modify", address = &self.data.mail_from.as_ref().unwrap().address, @@ -138,7 +142,7 @@ impl Session { } } ScriptResult::Reject(message) => { - tracing::info!(parent: &self.span, + tracing::info!( context = "sieve", event = "reject", address = &self.data.mail_from.as_ref().unwrap().address, @@ -152,7 +156,7 @@ impl Session { // Milter filtering if let Err(message) = self.run_milters(Stage::Mail, None).await { - tracing::info!(parent: &self.span, + tracing::info!( context = "milter", event = "reject", address = &self.data.mail_from.as_ref().unwrap().address, @@ -164,7 +168,7 @@ impl Session { // MTAHook filtering if let Err(message) = self.run_mta_hooks(Stage::Mail, None).await { - tracing::info!(parent: &self.span, + tracing::info!( context = "mta_hook", event = "reject", address = &self.data.mail_from.as_ref().unwrap().address, @@ -178,7 +182,11 @@ impl Session { if let Some(new_address) = self .core .core - .eval_if::(&self.core.core.smtp.session.mail.rewrite, self) + .eval_if::( + &self.core.core.smtp.session.mail.rewrite, + self, + self.data.session_id, + ) .await { let mail_from = self.data.mail_from.as_mut().unwrap(); @@ -200,7 +208,7 @@ impl Session { && !self .core .core - .eval_if(&config.requiretls, self) + .eval_if(&config.requiretls, self, self.data.session_id) .await .unwrap_or(false) { @@ -213,7 +221,7 @@ impl Session { if let Some(duration) = self .core .core - .eval_if::(&config.deliver_by, self) + .eval_if::(&config.deliver_by, self, self.data.session_id) .await { if from.by.checked_abs().unwrap_or(0) as u64 <= duration.as_secs() @@ -243,7 +251,7 @@ impl Session { if self .core .core - .eval_if::(&config.mt_priority, self) + .eval_if::(&config.mt_priority, self, self.data.session_id) .await .is_some() { @@ -265,7 +273,7 @@ impl Session { > self .core .core - .eval_if(&config_data.max_message_size, self) + .eval_if(&config_data.max_message_size, self, self.data.session_id) .await .unwrap_or(25 * 1024 * 1024) { @@ -278,7 +286,7 @@ impl Session { if let Some(max_hold) = self .core .core - .eval_if::(&config.future_release, self) + .eval_if::(&config.future_release, self, self.data.session_id) .await { let max_hold = max_hold.as_secs(); @@ -318,7 +326,7 @@ impl Session { && !self .core .core - .eval_if(&config.dsn, self) + .eval_if(&config.dsn, self, self.data.session_id) .await .unwrap_or(false) { @@ -362,7 +370,7 @@ impl Session { .await }; - tracing::debug!(parent: &self.span, + tracing::debug!( context = "spf", event = "lookup", identity = "mail-from", @@ -382,7 +390,7 @@ impl Session { } } - tracing::debug!(parent: &self.span, + tracing::debug!( context = "mail-from", event = "success", address = &self.data.mail_from.as_ref().unwrap().address); @@ -423,7 +431,11 @@ impl Session { spf_output.report_address(), self.core .core - .eval_if::(&self.core.core.smtp.report.spf.send, self) + .eval_if::( + &self.core.core.smtp.report.spf.send, + self, + self.data.session_id, + ) .await, ) { self.send_spf_report(recipient, &rate, !result, spf_output) diff --git a/crates/smtp/src/inbound/milter/client.rs b/crates/smtp/src/inbound/milter/client.rs index f5394f4a..34f3bb85 100644 --- a/crates/smtp/src/inbound/milter/client.rs +++ b/crates/smtp/src/inbound/milter/client.rs @@ -21,7 +21,7 @@ use super::{ const MILTER_CHUNK_SIZE: usize = 65535; impl MilterClient { - pub async fn connect(config: &Milter, span: tracing::Span) -> Result { + pub async fn connect(config: &Milter, session_id: u64) -> Result { tokio::time::timeout(config.timeout_command, async { let mut last_err = Error::Disconnected; for addr in &config.addrs { @@ -36,7 +36,7 @@ impl MilterClient { receiver: Receiver::with_max_frame_len(config.max_frame_len), options: 0, version: config.protocol_version, - span, + session_id, flags_actions: config.flags_actions.unwrap_or( SMFIF_ADDHDRS | SMFIF_CHGBODY @@ -83,7 +83,7 @@ impl MilterClient { bytes_read: self.bytes_read, options: self.options, version: self.version, - span: self.span, + session_id: self.session_id, flags_actions: self.flags_actions, flags_protocol: self.flags_protocol, }) @@ -307,7 +307,11 @@ impl MilterClient { async fn write(&mut self, action: Command<'_>) -> super::Result<()> { //let p = println!("Action: {}", action); - tracing::trace!(parent: &self.span, context = "milter", event = "write", "action" = action.to_string()); + tracing::trace!( + context = "milter", + event = "write", + "action" = action.to_string() + ); tokio::time::timeout(self.timeout_cmd, async { self.stream.write_all(action.serialize().as_ref()).await?; @@ -322,7 +326,11 @@ impl MilterClient { match self.receiver.read_frame(&self.buf[..self.bytes_read]) { FrameResult::Frame(frame) => { if let Some(response) = Response::deserialize(&frame) { - tracing::trace!(parent: &self.span, context = "milter", event = "read", "action" = response.to_string()); + tracing::trace!( + context = "milter", + event = "read", + "action" = response.to_string() + ); //let p = println!("Response: {}", response); return Ok(response); } else { diff --git a/crates/smtp/src/inbound/milter/message.rs b/crates/smtp/src/inbound/milter/message.rs index aa4f0ce0..51bd28d4 100644 --- a/crates/smtp/src/inbound/milter/message.rs +++ b/crates/smtp/src/inbound/milter/message.rs @@ -45,7 +45,7 @@ impl Session { || !self .core .core - .eval_if(&milter.enable, self) + .eval_if(&milter.enable, self, self.data.session_id) .await .unwrap_or(false) { @@ -71,7 +71,7 @@ impl Session { } Err(Rejection::Action(action)) => { tracing::info!( - parent: &self.span, + milter.host = &milter.hostname, milter.port = &milter.port, context = "milter", @@ -103,7 +103,7 @@ impl Session { } Err(Rejection::Error(err)) => { tracing::warn!( - parent: &self.span, + milter.host = &milter.hostname, milter.port = &milter.port, context = "milter", @@ -126,7 +126,7 @@ impl Session { message: Option<&AuthenticatedMessage<'_>>, ) -> Result, Rejection> { // Build client - let client = MilterClient::connect(milter, self.span.clone()).await?; + let client = MilterClient::connect(milter, self.data.session_id).await?; if !milter.tls { self.run(client, message).await } else { diff --git a/crates/smtp/src/inbound/milter/mod.rs b/crates/smtp/src/inbound/milter/mod.rs index a668ea48..bf2a3df3 100644 --- a/crates/smtp/src/inbound/milter/mod.rs +++ b/crates/smtp/src/inbound/milter/mod.rs @@ -29,7 +29,7 @@ pub struct MilterClient { options: u32, flags_actions: u32, flags_protocol: u32, - span: tracing::Span, + session_id: u64, } #[derive(Debug)] diff --git a/crates/smtp/src/inbound/rcpt.rs b/crates/smtp/src/inbound/rcpt.rs index 0b4b4b35..49cd4a8b 100644 --- a/crates/smtp/src/inbound/rcpt.rs +++ b/crates/smtp/src/inbound/rcpt.rs @@ -63,7 +63,11 @@ impl Session { let rcpt_script = self .core .core - .eval_if::(&self.core.core.smtp.session.rcpt.script, self) + .eval_if::( + &self.core.core.smtp.session.rcpt.script, + self, + self.data.session_id, + ) .await .and_then(|name| self.core.core.get_sieve_script(&name)) .cloned(); @@ -87,7 +91,7 @@ impl Session { { ScriptResult::Accept { modifications } => { if !modifications.is_empty() { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "sieve", event = "modify", address = self.data.rcpt_to.last().unwrap().address, @@ -102,7 +106,7 @@ impl Session { } } ScriptResult::Reject(message) => { - tracing::info!(parent: &self.span, + tracing::info!( context = "sieve", event = "reject", address = self.data.rcpt_to.last().unwrap().address, @@ -116,7 +120,7 @@ impl Session { // Milter filtering if let Err(message) = self.run_milters(Stage::Rcpt, None).await { - tracing::info!(parent: &self.span, + tracing::info!( context = "milter", event = "reject", address = self.data.rcpt_to.last().unwrap().address, @@ -128,7 +132,7 @@ impl Session { // MTAHook filtering if let Err(message) = self.run_mta_hooks(Stage::Rcpt, None).await { - tracing::info!(parent: &self.span, + tracing::info!( context = "mta_hook", event = "reject", address = self.data.rcpt_to.last().unwrap().address, @@ -142,7 +146,11 @@ impl Session { if let Some(new_address) = self .core .core - .eval_if::(&self.core.core.smtp.session.rcpt.rewrite, self) + .eval_if::( + &self.core.core.smtp.session.rcpt.rewrite, + self, + self.data.session_id, + ) .await { let rcpt = self.data.rcpt_to.last_mut().unwrap(); @@ -166,7 +174,11 @@ impl Session { if let Some(directory) = self .core .core - .eval_if::(&self.core.core.smtp.session.rcpt.directory, self) + .eval_if::( + &self.core.core.smtp.session.rcpt.directory, + self, + self.data.session_id, + ) .await .and_then(|name| self.core.core.get_directory(&name)) { @@ -176,7 +188,7 @@ impl Session { self.core.core.rcpt(directory, &rcpt.address_lcase).await { if !is_local_address { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "rcpt", event = "error", address = &rcpt.address_lcase, @@ -188,7 +200,7 @@ impl Session { .await; } } else { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "rcpt", event = "error", address = &rcpt.address_lcase, @@ -202,11 +214,15 @@ impl Session { } else if !self .core .core - .eval_if(&self.core.core.smtp.session.rcpt.relay, self) + .eval_if( + &self.core.core.smtp.session.rcpt.relay, + self, + self.data.session_id, + ) .await .unwrap_or(false) { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "rcpt", event = "error", address = &rcpt.address_lcase, @@ -216,7 +232,7 @@ impl Session { return self.rcpt_error(b"550 5.1.2 Relay not allowed.\r\n").await; } } else { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "rcpt", event = "error", address = &rcpt.address_lcase, @@ -230,11 +246,15 @@ impl Session { } else if !self .core .core - .eval_if(&self.core.core.smtp.session.rcpt.relay, self) + .eval_if( + &self.core.core.smtp.session.rcpt.relay, + self, + self.data.session_id, + ) .await .unwrap_or(false) { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "rcpt", event = "error", address = &rcpt.address_lcase, @@ -245,7 +265,7 @@ impl Session { } if self.is_allowed().await { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "rcpt", event = "success", address = &self.data.rcpt_to.last().unwrap().address); @@ -269,7 +289,7 @@ impl Session { self.write(b"421 4.3.0 Too many errors, disconnecting.\r\n") .await?; tracing::debug!( - parent: &self.span, + context = "rcpt", event = "disconnect", reason = "too-many-errors", diff --git a/crates/smtp/src/inbound/session.rs b/crates/smtp/src/inbound/session.rs index 28fddf74..c1804be4 100644 --- a/crates/smtp/src/inbound/session.rs +++ b/crates/smtp/src/inbound/session.rs @@ -83,6 +83,7 @@ impl Session { .eval_if::( &self.core.core.smtp.session.auth.mechanisms, self, + self.data.session_id, ) .await .unwrap_or_default() @@ -293,7 +294,7 @@ impl Session { State::DataTooLarge(receiver) => { if receiver.ingest(&mut iter) { tracing::debug!( - parent: &self.span, + context = "data", event = "too-large", "Message is too large." @@ -340,7 +341,7 @@ impl Session { let err = match self.stream.write_all(bytes).await { Ok(_) => match self.stream.flush().await { Ok(_) => { - tracing::trace!(parent: &self.span, + tracing::trace!( event = "write", data = std::str::from_utf8(bytes).unwrap_or_default() , size = bytes.len()); @@ -351,7 +352,7 @@ impl Session { Err(err) => err, }; - tracing::trace!(parent: &self.span, + tracing::trace!( event = "error", "Failed to write to stream: {:?}", err); Err(()) @@ -361,7 +362,7 @@ impl Session { pub async fn read(&mut self, bytes: &mut [u8]) -> Result { match self.stream.read(bytes).await { Ok(len) => { - tracing::trace!(parent: &self.span, + tracing::trace!( event = "read", data = if matches!(self.state, State::Request(_)) {bytes .get(0..len) @@ -372,7 +373,7 @@ impl Session { } Err(err) => { tracing::trace!( - parent: &self.span, + event = "error", "Failed to read from stream: {:?}", err ); diff --git a/crates/smtp/src/inbound/spawn.rs b/crates/smtp/src/inbound/spawn.rs index 9902bbaf..abb744ca 100644 --- a/crates/smtp/src/inbound/spawn.rs +++ b/crates/smtp/src/inbound/spawn.rs @@ -29,7 +29,6 @@ impl SessionManager for SmtpSessionManager { core: self.inner.into(), instance: session.instance, state: State::default(), - span: session.span, stream: session.stream, in_flight: vec![session.in_flight], data: SessionData::new( @@ -37,6 +36,7 @@ impl SessionManager for SmtpSessionManager { session.local_port, session.remote_ip, session.remote_port, + session.session_id, ), params: SessionParameters::default(), }; @@ -86,7 +86,7 @@ impl Session { if let Some(script) = self .core .core - .eval_if::(&config.script, self) + .eval_if::(&config.script, self, self.data.session_id) .await .and_then(|name| self.core.core.get_sieve_script(&name)) { @@ -94,10 +94,11 @@ impl Session { .run_script(script.clone(), self.build_script_parameters("connect")) .await { - tracing::debug!(parent: &self.span, - context = "connect", - event = "sieve-reject", - reason = message); + tracing::debug!( + context = "connect", + event = "sieve-reject", + reason = message + ); let _ = self.write(message.as_bytes()).await; return false; @@ -106,20 +107,22 @@ impl Session { // Milter filtering if let Err(message) = self.run_milters(Stage::Connect, None).await { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "connect", event = "milter-reject", - reason = message.message.as_ref()); + reason = message.message.as_ref() + ); let _ = self.write(message.message.as_bytes()).await; return false; } // MTAHook filtering if let Err(message) = self.run_mta_hooks(Stage::Connect, None).await { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "connect", event = "mta_hook-reject", - reason = message.message.as_ref()); + reason = message.message.as_ref() + ); let _ = self.write(message.message.as_bytes()).await; return false; } @@ -128,11 +131,11 @@ impl Session { self.hostname = self .core .core - .eval_if::(&config.hostname, self) + .eval_if::(&config.hostname, self, self.data.session_id) .await .unwrap_or_default(); if self.hostname.is_empty() { - tracing::warn!(parent: &self.span, + tracing::warn!( context = "connect", event = "hostname", "No hostname configured, using 'localhost'." @@ -144,7 +147,7 @@ impl Session { let greeting = self .core .core - .eval_if::(&config.greeting, self) + .eval_if::(&config.greeting, self, self.data.session_id) .await .filter(|g| !g.is_empty()) .map(|g| format!("220 {}\r\n", g)) @@ -186,7 +189,7 @@ impl Session { .await .ok(); tracing::debug!( - parent: &self.span, + event = "disconnect", reason = "transfer-limit", "Client exceeded incoming transfer limit." @@ -198,7 +201,7 @@ impl Session { .await .ok(); tracing::debug!( - parent: &self.span, + event = "disconnect", reason = "loiter", "Session open for too long." @@ -207,7 +210,7 @@ impl Session { } } else { tracing::debug!( - parent: &self.span, + event = "disconnect", reason = "peer", "Connection closed by peer." @@ -220,7 +223,7 @@ impl Session { } Err(_) => { tracing::debug!( - parent: &self.span, + event = "disconnect", reason = "timeout", "Connection timed out." @@ -235,7 +238,7 @@ impl Session { }, _ = shutdown_rx.changed() => { tracing::debug!( - parent: &self.span, + event = "disconnect", reason = "shutdown", "Server shutting down." @@ -250,17 +253,18 @@ impl Session { } pub async fn into_tls(self) -> Result>, ()> { - let span = self.span; Ok(Session { hostname: self.hostname, - stream: self.instance.tls_accept(self.stream, &span).await?, + stream: self + .instance + .tls_accept(self.stream, self.data.session_id) + .await?, state: self.state, data: self.data, instance: self.instance, core: self.core, in_flight: self.in_flight, params: self.params, - span, }) } } diff --git a/crates/smtp/src/inbound/vrfy.rs b/crates/smtp/src/inbound/vrfy.rs index bf6126fa..4e7d959b 100644 --- a/crates/smtp/src/inbound/vrfy.rs +++ b/crates/smtp/src/inbound/vrfy.rs @@ -14,7 +14,11 @@ impl Session { match self .core .core - .eval_if::(&self.core.core.smtp.session.rcpt.directory, self) + .eval_if::( + &self.core.core.smtp.session.rcpt.directory, + self, + self.data.session_id, + ) .await .and_then(|name| self.core.core.get_directory(&name)) { @@ -36,7 +40,7 @@ impl Session { ); } - tracing::debug!(parent: &self.span, + tracing::debug!( context = "vrfy", event = "success", address = &address); @@ -44,7 +48,7 @@ impl Session { self.write(result.as_bytes()).await } Ok(_) => { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "vrfy", event = "not-found", address = &address); @@ -52,12 +56,12 @@ impl Session { self.write(b"550 5.1.2 Address not found.\r\n").await } Err(err) => { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "vrfy", event = "temp-fail", address = &address); - if !err.matches(trc::Cause::Store(trc::StoreCause::NotSupported)) { + if !err.matches(trc::EventType::Store(trc::StoreEvent::NotSupported)) { self.write(b"252 2.4.3 Unable to verify address at this time.\r\n") .await } else { @@ -67,7 +71,7 @@ impl Session { } } _ => { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "vrfy", event = "forbidden", address = &address); @@ -81,7 +85,11 @@ impl Session { match self .core .core - .eval_if::(&self.core.core.smtp.session.rcpt.directory, self) + .eval_if::( + &self.core.core.smtp.session.rcpt.directory, + self, + self.data.session_id, + ) .await .and_then(|name| self.core.core.get_directory(&name)) { @@ -102,14 +110,14 @@ impl Session { value ); } - tracing::debug!(parent: &self.span, + tracing::debug!( context = "expn", event = "success", address = &address); self.write(result.as_bytes()).await } Ok(_) => { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "expn", event = "not-found", address = &address); @@ -117,12 +125,12 @@ impl Session { self.write(b"550 5.1.2 Mailing list not found.\r\n").await } Err(err) => { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "expn", event = "temp-fail", address = &address); - if !err.matches(trc::Cause::Store(trc::StoreCause::NotSupported)) { + if !err.matches(trc::EventType::Store(trc::StoreEvent::NotSupported)) { self.write(b"252 2.4.3 Unable to expand mailing list at this time.\r\n") .await } else { @@ -132,7 +140,7 @@ impl Session { } } _ => { - tracing::debug!(parent: &self.span, + tracing::debug!( context = "expn", event = "forbidden", address = &address); diff --git a/crates/smtp/src/outbound/dane/verify.rs b/crates/smtp/src/outbound/dane/verify.rs index f119223c..c77d0ffc 100644 --- a/crates/smtp/src/outbound/dane/verify.rs +++ b/crates/smtp/src/outbound/dane/verify.rs @@ -15,7 +15,7 @@ use crate::queue::{Error, ErrorDetails, Status}; pub trait TlsaVerify { fn verify( &self, - span: &tracing::Span, + session_id: u64, hostname: &str, certificates: Option<&[CertificateDer<'_>]>, ) -> Result<(), Status<(), Error>>; @@ -24,7 +24,7 @@ pub trait TlsaVerify { impl TlsaVerify for Tlsa { fn verify( &self, - span: &tracing::Span, + session_id: u64, hostname: &str, certificates: Option<&[CertificateDer<'_>]>, ) -> Result<(), Status<(), Error>> { @@ -32,7 +32,7 @@ impl TlsaVerify for Tlsa { certificates } else { tracing::info!( - parent: span, + context = "dane", event = "no-server-certs-found", mx = hostname, @@ -52,7 +52,7 @@ impl TlsaVerify for Tlsa { Ok((_, certificate)) => certificate, Err(err) => { tracing::debug!( - parent: span, + context = "dane", event = "cert-parse-error", "Failed to parse X.509 certificate for host {}: {}", @@ -96,7 +96,7 @@ impl TlsaVerify for Tlsa { if hash == record.data { tracing::debug!( - parent: span, + context = "dane", event = "info", mx = hostname, @@ -132,7 +132,7 @@ impl TlsaVerify for Tlsa { && (self.has_intermediates == matched_intermediate)) { tracing::info!( - parent: span, + context = "dane", event = "authenticated", mx = hostname, @@ -141,7 +141,7 @@ impl TlsaVerify for Tlsa { Ok(()) } else { tracing::warn!( - parent: span, + context = "dane", event = "auth-failure", mx = hostname, diff --git a/crates/smtp/src/outbound/delivery.rs b/crates/smtp/src/outbound/delivery.rs index 876275b2..9e556994 100644 --- a/crates/smtp/src/outbound/delivery.rs +++ b/crates/smtp/src/outbound/delivery.rs @@ -75,10 +75,10 @@ impl DeliveryAttempt { ); // Check that the message still has recipients to be delivered - let has_pending_delivery = message.has_pending_delivery(&span); + let has_pending_delivery = message.has_pending_delivery(); // Send any due Delivery Status Notifications - core.send_dsn(&mut message, &span).await; + core.send_dsn(&mut message).await; if has_pending_delivery { // Re-queue the message if its not yet due for delivery @@ -106,7 +106,7 @@ impl DeliveryAttempt { // Throttle sender for throttle in &core.core.smtp.queue.throttle.sender { if let Err(err) = core - .is_allowed(throttle, &message, &mut self.in_flight, &span) + .is_allowed(throttle, &message, &mut self.in_flight, message.id) .await { let event = match err { @@ -157,7 +157,6 @@ impl DeliveryAttempt { // Create new span for domain let span = tracing::info_span!( - parent: &span, "attempt", domain = domain.domain, attempt_number = domain.retry.inner, @@ -170,7 +169,7 @@ impl DeliveryAttempt { let mut in_flight = Vec::new(); for throttle in &queue_config.throttle.rcpt { if let Err(err) = core - .is_allowed(throttle, &envelope, &mut in_flight, &span) + .is_allowed(throttle, &envelope, &mut in_flight, message.id) .await { message.domains[domain_idx].set_throttle_error(err, &mut on_hold); @@ -181,7 +180,7 @@ impl DeliveryAttempt { // Obtain next hop let (mut remote_hosts, is_smtp) = match core .core - .eval_if::(&queue_config.next_hop, &envelope) + .eval_if::(&queue_config.next_hop, &envelope, message.id) .await .and_then(|name| core.core.get_relay_host(&name)) { @@ -191,14 +190,13 @@ impl DeliveryAttempt { .deliver_local( recipients.iter_mut().filter(|r| r.domain_idx == domain_idx), &core.inner.ipc.delivery_tx, - &span, ) .await; // Update status for the current domain and continue with the next one let schedule = core .core - .eval_if::, _>(&queue_config.retry, &envelope) + .eval_if::, _>(&queue_config.retry, &envelope, message.id) .await .unwrap_or_else(|| vec![Duration::from_secs(60)]); message.domains[domain_idx].set_status(delivery_result, &schedule); @@ -215,21 +213,21 @@ impl DeliveryAttempt { let mut tls_strategy = TlsStrategy { mta_sts: core .core - .eval_if(&queue_config.tls.mta_sts, &envelope) + .eval_if(&queue_config.tls.mta_sts, &envelope, message.id) .await .unwrap_or(RequireOptional::Optional), ..Default::default() }; let allow_invalid_certs = core .core - .eval_if(&queue_config.tls.invalid_certs, &envelope) + .eval_if(&queue_config.tls.invalid_certs, &envelope, message.id) .await .unwrap_or(false); // Obtain TLS reporting let tls_report = match core .core - .eval_if(&core.core.smtp.report.tls.send, &envelope) + .eval_if(&core.core.smtp.report.tls.send, &envelope, message.id) .await .unwrap_or(AggregateFrequency::Never) { @@ -247,7 +245,7 @@ impl DeliveryAttempt { .await { Ok(record) => { - tracing::debug!(parent: &span, + tracing::debug!( context = "tlsrpt", event = "record-fetched", record = ?record); @@ -256,7 +254,6 @@ impl DeliveryAttempt { } Err(err) => { tracing::debug!( - parent: &span, context = "tlsrpt", "Failed to retrieve TLSRPT record: {}", err @@ -274,7 +271,7 @@ impl DeliveryAttempt { .lookup_mta_sts_policy( &domain.domain, core.core - .eval_if(&queue_config.timeout.mta_sts, &envelope) + .eval_if(&queue_config.timeout.mta_sts, &envelope, message.id) .await .unwrap_or_else(|| Duration::from_secs(10 * 60)), ) @@ -282,7 +279,7 @@ impl DeliveryAttempt { { Ok(mta_sts_policy) => { tracing::debug!( - parent: &span, + context = "sts", event = "policy-fetched", policy = ?mta_sts_policy, @@ -326,7 +323,6 @@ impl DeliveryAttempt { if tls_strategy.is_mta_sts_required() { tracing::info!( - parent: &span, context = "sts", event = "policy-fetch-failure", "Failed to retrieve MTA-STS policy: {}", @@ -334,14 +330,17 @@ impl DeliveryAttempt { ); let schedule = core .core - .eval_if::, _>(&queue_config.retry, &envelope) + .eval_if::, _>( + &queue_config.retry, + &envelope, + message.id, + ) .await .unwrap_or_else(|| vec![Duration::from_secs(60)]); message.domains[domain_idx].set_status(err, &schedule); continue 'next_domain; } else { tracing::debug!( - parent: &span, context = "sts", event = "policy-fetch-failure", "Failed to retrieve MTA-STS policy: {}", @@ -364,14 +363,18 @@ impl DeliveryAttempt { Ok(mx) => mx, Err(err) => { tracing::info!( - parent: &span, + context = "dns", event = "mx-lookup-failed", reason = %err, ); let schedule = core .core - .eval_if::, _>(&queue_config.retry, &envelope) + .eval_if::, _>( + &queue_config.retry, + &envelope, + message.id, + ) .await .unwrap_or_else(|| vec![Duration::from_secs(60)]); message.domains[domain_idx].set_status(err, &schedule); @@ -382,21 +385,20 @@ impl DeliveryAttempt { if let Some(remote_hosts_) = mx_list.to_remote_hosts( &domain.domain, core.core - .eval_if(&queue_config.max_mx, &envelope) + .eval_if(&queue_config.max_mx, &envelope, message.id) .await .unwrap_or(5), ) { remote_hosts = remote_hosts_; } else { tracing::info!( - parent: &span, context = "dns", event = "null-mx", reason = "Domain does not accept messages (mull MX)", ); let schedule = core .core - .eval_if::, _>(&queue_config.retry, &envelope) + .eval_if::, _>(&queue_config.retry, &envelope, message.id) .await .unwrap_or_else(|| vec![Duration::from_secs(60)]); message.domains[domain_idx].set_status( @@ -412,7 +414,7 @@ impl DeliveryAttempt { // Try delivering message let max_multihomed = core .core - .eval_if(&queue_config.max_multihomed, &envelope) + .eval_if(&queue_config.max_multihomed, &envelope, message.id) .await .unwrap_or(2); let mut last_status = Status::Scheduled; @@ -437,7 +439,6 @@ impl DeliveryAttempt { } tracing::warn!( - parent: &span, context = "sts", event = "policy-error", mx = envelope.mx, @@ -455,13 +456,13 @@ impl DeliveryAttempt { // Obtain source and remote IPs let resolve_result = match core - .resolve_host(remote_host, &envelope, max_multihomed) + .resolve_host(remote_host, &envelope, max_multihomed, message.id) .await { Ok(result) => result, Err(status) => { tracing::info!( - parent: &span, + context = "dns", event = "ip-lookup-failed", mx = envelope.mx, @@ -476,12 +477,12 @@ impl DeliveryAttempt { // Update TLS strategy tls_strategy.dane = core .core - .eval_if(&queue_config.tls.dane, &envelope) + .eval_if(&queue_config.tls.dane, &envelope, message.id) .await .unwrap_or(RequireOptional::Optional); tls_strategy.tls = core .core - .eval_if(&queue_config.tls.start, &envelope) + .eval_if(&queue_config.tls.start, &envelope, message.id) .await .unwrap_or(RequireOptional::Optional); @@ -491,7 +492,7 @@ impl DeliveryAttempt { Ok(Some(tlsa)) => { if tlsa.has_end_entities { tracing::debug!( - parent: &span, + context = "dane", event = "record-fetched", mx = envelope.mx, @@ -501,7 +502,6 @@ impl DeliveryAttempt { tlsa.into() } else { tracing::info!( - parent: &span, context = "dane", event = "no-tlsa-records", mx = envelope.mx, @@ -556,7 +556,6 @@ impl DeliveryAttempt { } tracing::info!( - parent: &span, context = "dane", event = "tlsa-dnssec-missing", mx = envelope.mx, @@ -575,7 +574,6 @@ impl DeliveryAttempt { Err(err) => { if tls_strategy.is_dane_required() { tracing::info!( - parent: &span, context = "dane", event = "tlsa-missing", mx = envelope.mx, @@ -636,7 +634,7 @@ impl DeliveryAttempt { envelope.remote_ip = remote_ip; for throttle in &queue_config.throttle.host { if let Err(err) = core - .is_allowed(throttle, &envelope, &mut in_flight_host, &span) + .is_allowed(throttle, &envelope, &mut in_flight_host, message.id) .await { message.domains[domain_idx].set_throttle_error(err, &mut on_hold); @@ -647,7 +645,7 @@ impl DeliveryAttempt { // Connect let conn_timeout = core .core - .eval_if(&queue_config.timeout.connect, &envelope) + .eval_if(&queue_config.timeout.connect, &envelope, message.id) .await .unwrap_or_else(|| Duration::from_secs(5 * 60)); let mut smtp_client = match if let Some(ip_addr) = source_ip { @@ -666,7 +664,7 @@ impl DeliveryAttempt { } { Ok(smtp_client) => { tracing::debug!( - parent: &span, + context = "connect", event = "success", mx = envelope.mx, @@ -679,7 +677,7 @@ impl DeliveryAttempt { } Err(err) => { tracing::info!( - parent: &span, + context = "connect", event = "failed", mx = envelope.mx, @@ -693,11 +691,11 @@ impl DeliveryAttempt { // Obtain session parameters let local_hostname = core .core - .eval_if::(&queue_config.hostname, &envelope) + .eval_if::(&queue_config.hostname, &envelope, message.id) .await .filter(|s| !s.is_empty()) .unwrap_or_else(|| { - tracing::warn!(parent: &span, + tracing::warn!( context = "queue", event = "ehlo", "No outbound hostname configured, using 'local.host'." @@ -713,22 +711,22 @@ impl DeliveryAttempt { local_hostname: &local_hostname, timeout_ehlo: core .core - .eval_if(&queue_config.timeout.ehlo, &envelope) + .eval_if(&queue_config.timeout.ehlo, &envelope, message.id) .await .unwrap_or_else(|| Duration::from_secs(5 * 60)), timeout_mail: core .core - .eval_if(&queue_config.timeout.mail, &envelope) + .eval_if(&queue_config.timeout.mail, &envelope, message.id) .await .unwrap_or_else(|| Duration::from_secs(5 * 60)), timeout_rcpt: core .core - .eval_if(&queue_config.timeout.rcpt, &envelope) + .eval_if(&queue_config.timeout.rcpt, &envelope, message.id) .await .unwrap_or_else(|| Duration::from_secs(5 * 60)), timeout_data: core .core - .eval_if(&queue_config.timeout.data, &envelope) + .eval_if(&queue_config.timeout.data, &envelope, message.id) .await .unwrap_or_else(|| Duration::from_secs(5 * 60)), }; @@ -749,13 +747,13 @@ impl DeliveryAttempt { // Read greeting smtp_client.timeout = core .core - .eval_if(&queue_config.timeout.greeting, &envelope) + .eval_if(&queue_config.timeout.greeting, &envelope, message.id) .await .unwrap_or_else(|| Duration::from_secs(5 * 60)); if let Err(status) = read_greeting(&mut smtp_client, envelope.mx).await { tracing::info!( - parent: &span, + context = "greeting", event = "invalid", mx = envelope.mx, @@ -771,7 +769,7 @@ impl DeliveryAttempt { Ok(capabilities) => capabilities, Err(status) => { tracing::info!( - parent: &span, + context = "ehlo", event = "rejected", mx = envelope.mx, @@ -787,7 +785,7 @@ impl DeliveryAttempt { if tls_strategy.try_start_tls() { smtp_client.timeout = core .core - .eval_if(&queue_config.timeout.tls, &envelope) + .eval_if(&queue_config.timeout.tls, &envelope, message.id) .await .unwrap_or_else(|| Duration::from_secs(3 * 60)); match try_start_tls( @@ -800,7 +798,7 @@ impl DeliveryAttempt { { StartTlsResult::Success { smtp_client } => { tracing::debug!( - parent: &span, + context = "tls", event = "success", mx = envelope.mx, @@ -811,7 +809,7 @@ impl DeliveryAttempt { // Verify DANE if let Some(dane_policy) = &dane_policy { if let Err(status) = dane_policy.verify( - &span, + message.id, envelope.mx, smtp_client.tls_connection().peer_certificates(), ) { @@ -876,7 +874,6 @@ impl DeliveryAttempt { }); tracing::info!( - parent: &span, context = "tls", event = "unavailable", mx = envelope.mx, @@ -919,7 +916,7 @@ impl DeliveryAttempt { } StartTlsResult::Error { error } => { tracing::info!( - parent: &span, + context = "tls", event = "failed", mx = envelope.mx, @@ -958,7 +955,6 @@ impl DeliveryAttempt { } else { // TLS has been disabled tracing::info!( - parent: &span, context = "tls", event = "disabled", mx = envelope.mx, @@ -979,7 +975,7 @@ impl DeliveryAttempt { // Start TLS smtp_client.timeout = core .core - .eval_if(&queue_config.timeout.tls, &envelope) + .eval_if(&queue_config.timeout.tls, &envelope, message.id) .await .unwrap_or_else(|| Duration::from_secs(3 * 60)); let mut smtp_client = @@ -987,7 +983,7 @@ impl DeliveryAttempt { Ok(smtp_client) => smtp_client, Err(error) => { tracing::info!( - parent: &span, + context = "tls", event = "failed", mx = envelope.mx, @@ -1002,13 +998,13 @@ impl DeliveryAttempt { // Read greeting smtp_client.timeout = core .core - .eval_if(&queue_config.timeout.greeting, &envelope) + .eval_if(&queue_config.timeout.greeting, &envelope, message.id) .await .unwrap_or_else(|| Duration::from_secs(5 * 60)); if let Err(status) = read_greeting(&mut smtp_client, envelope.mx).await { tracing::info!( - parent: &span, + context = "greeting", event = "invalid", mx = envelope.mx, @@ -1032,7 +1028,7 @@ impl DeliveryAttempt { // Update status for the current domain and continue with the next one let schedule = core .core - .eval_if::, _>(&queue_config.retry, &envelope) + .eval_if::, _>(&queue_config.retry, &envelope, message.id) .await .unwrap_or_else(|| vec![Duration::from_secs(60)]); message.domains[domain_idx].set_status(delivery_result, &schedule); @@ -1043,7 +1039,7 @@ impl DeliveryAttempt { // Update status let schedule = core .core - .eval_if::, _>(&queue_config.retry, &envelope) + .eval_if::, _>(&queue_config.retry, &envelope, message.id) .await .unwrap_or_else(|| vec![Duration::from_secs(60)]); message.domains[domain_idx].set_status(last_status, &schedule); @@ -1051,7 +1047,7 @@ impl DeliveryAttempt { message.recipients = recipients; // Send Delivery Status Notifications - core.send_dsn(&mut message, &span).await; + core.send_dsn(&mut message).await; // Notify queue manager let span = span; @@ -1061,7 +1057,6 @@ impl DeliveryAttempt { message.save_changes(&core, None, None).await; tracing::info!( - parent: &span, context = "queue", event = "requeue", reason = "concurrency-limited", @@ -1080,7 +1075,6 @@ impl DeliveryAttempt { .await; tracing::info!( - parent: &span, context = "queue", event = "requeue", reason = "delivery-incomplete", @@ -1093,7 +1087,6 @@ impl DeliveryAttempt { message.remove(&core, self.event.due).await; tracing::info!( - parent: &span, context = "queue", event = "completed", "Delivery completed." @@ -1102,10 +1095,7 @@ impl DeliveryAttempt { Event::Reload }; if core.inner.queue_tx.send(result).await.is_err() { - tracing::warn!( - parent: &span, - "Channel closed while trying to notify queue manager." - ); + tracing::warn!("Channel closed while trying to notify queue manager."); } }); } @@ -1113,7 +1103,7 @@ impl DeliveryAttempt { impl Message { /// Marks as failed all domains that reached their expiration time - pub fn has_pending_delivery(&mut self, span: &tracing::Span) -> bool { + pub fn has_pending_delivery(&mut self) -> bool { let now = now(); let mut has_pending_delivery = false; @@ -1121,7 +1111,7 @@ impl Message { match &domain.status { Status::TemporaryFailure(err) if domain.expires <= now => { tracing::info!( - parent: span, + event = "delivery-expired", domain = domain.domain, reason = %err, @@ -1139,7 +1129,6 @@ impl Message { } Status::Scheduled if domain.expires <= now => { tracing::info!( - parent: span, event = "delivery-expired", domain = domain.domain, reason = "Queue rate limit exceeded.", diff --git a/crates/smtp/src/outbound/local.rs b/crates/smtp/src/outbound/local.rs index ac7c74c1..2508ce9c 100644 --- a/crates/smtp/src/outbound/local.rs +++ b/crates/smtp/src/outbound/local.rs @@ -17,7 +17,6 @@ impl Message { &self, recipients: impl Iterator, delivery_tx: &mpsc::Sender, - span: &tracing::Span, ) -> Status<(), Error> { // Prepare recipients list let mut total_rcpt = 0; @@ -59,7 +58,6 @@ impl Message { Ok(delivery_result) => delivery_result, Err(_) => { tracing::warn!( - parent: span, context = "deliver_local", event = "error", reason = "result channel closed", @@ -70,7 +68,6 @@ impl Message { } Err(_) => { tracing::warn!( - parent: span, context = "deliver_local", event = "error", reason = "tx channel closed", @@ -85,7 +82,6 @@ impl Message { match result { DeliveryResult::Success => { tracing::info!( - parent: span, context = "deliver_local", event = "delivered", rcpt = rcpt.address, @@ -103,7 +99,6 @@ impl Message { } DeliveryResult::TemporaryFailure { reason } => { tracing::info!( - parent: span, context = "deliver_local", event = "deferred", rcpt = rcpt.address, @@ -123,7 +118,6 @@ impl Message { } DeliveryResult::PermanentFailure { code, reason } => { tracing::info!( - parent: span, context = "deliver_local", event = "rejected", rcpt = rcpt.address, diff --git a/crates/smtp/src/outbound/lookup.rs b/crates/smtp/src/outbound/lookup.rs index 7e8e77e5..8b8ba8f5 100644 --- a/crates/smtp/src/outbound/lookup.rs +++ b/crates/smtp/src/outbound/lookup.rs @@ -87,12 +87,13 @@ impl SMTP { remote_host: &NextHop<'_>, envelope: &impl ResolveVariable, max_multihomed: usize, + session_id: u64, ) -> Result> { let remote_ips = self .ip_lookup( remote_host.fqdn_hostname().as_ref(), self.core - .eval_if(&self.core.smtp.queue.ip_strategy, envelope) + .eval_if(&self.core.smtp.queue.ip_strategy, envelope, session_id) .await .unwrap_or(IpLookupStrategy::Ipv4thenIpv6), max_multihomed, @@ -122,7 +123,11 @@ impl SMTP { // Obtain source IPv4 address let source_ips = self .core - .eval_if::, _>(&self.core.smtp.queue.source_ip.ipv4, envelope) + .eval_if::, _>( + &self.core.smtp.queue.source_ip.ipv4, + envelope, + session_id, + ) .await .unwrap_or_default(); match source_ips.len().cmp(&1) { @@ -140,7 +145,11 @@ impl SMTP { // Obtain source IPv6 address let source_ips = self .core - .eval_if::, _>(&self.core.smtp.queue.source_ip.ipv6, envelope) + .eval_if::, _>( + &self.core.smtp.queue.source_ip.ipv6, + envelope, + session_id, + ) .await .unwrap_or_default(); match source_ips.len().cmp(&1) { diff --git a/crates/smtp/src/queue/dsn.rs b/crates/smtp/src/queue/dsn.rs index 52b87d98..37917b8e 100644 --- a/crates/smtp/src/queue/dsn.rs +++ b/crates/smtp/src/queue/dsn.rs @@ -26,13 +26,13 @@ use super::{ }; impl SMTP { - pub async fn send_dsn(&self, message: &mut Message, span: &tracing::Span) { + pub async fn send_dsn(&self, message: &mut Message) { // Send webhook event self.send_dsn_webhook(message).await; if !message.return_path.is_empty() { // Build DSN - if let Some(dsn) = message.build_dsn(self, span).await { + if let Some(dsn) = message.build_dsn(self).await { let mut dsn_message = self.new_message("", "", ""); dsn_message .add_recipient_parts( @@ -45,17 +45,15 @@ impl SMTP { // Sign message let signature = self - .sign_message(message, &self.core.smtp.queue.dsn.sign, &dsn, span) + .sign_message(message, &self.core.smtp.queue.dsn.sign, &dsn) .await; // Queue DSN - dsn_message - .queue(signature.as_deref(), &dsn, self, span) - .await; + dsn_message.queue(signature.as_deref(), &dsn, self).await; } } else { // Handle double bounce - message.handle_double_bounce(span); + message.handle_double_bounce(); } } @@ -177,7 +175,7 @@ impl SMTP { } impl Message { - pub async fn build_dsn(&mut self, core: &SMTP, span: &tracing::Span) -> Option> { + pub async fn build_dsn(&mut self, core: &SMTP) -> Option> { let config = &core.core.smtp.queue; let now = now(); @@ -341,7 +339,7 @@ impl Message { if let Some(next_notify) = core .core - .eval_if::, _>(&config.notify, &envelope) + .eval_if::, _>(&config.notify, &envelope, self.id) .await .and_then(|notify| { notify.into_iter().nth((domain.notify.inner + 1) as usize) @@ -364,17 +362,17 @@ impl Message { // Obtain hostname and sender addresses let from_name = core .core - .eval_if(&config.dsn.name, self) + .eval_if(&config.dsn.name, self, self.id) .await .unwrap_or_else(|| String::from("Mail Delivery Subsystem")); let from_addr = core .core - .eval_if(&config.dsn.address, self) + .eval_if(&config.dsn.address, self, self.id) .await .unwrap_or_else(|| String::from("MAILER-DAEMON@localhost")); let reporting_mta = core .core - .eval_if(&core.core.smtp.report.submitter, self) + .eval_if(&core.core.smtp.report.submitter, self, self.id) .await .unwrap_or_else(|| String::from("localhost")); @@ -418,7 +416,6 @@ impl Message { } Ok(None) => { tracing::error!( - parent: span, context = "queue", event = "error", "Failed to open blob {:?}: not found", @@ -428,7 +425,6 @@ impl Message { } Err(err) => { tracing::error!( - parent: span, context = "queue", event = "error", "Failed to open blob {:?}: {}", @@ -465,7 +461,7 @@ impl Message { .into() } - fn handle_double_bounce(&mut self, span: &tracing::Span) { + fn handle_double_bounce(&mut self) { let mut is_double_bounce = Vec::with_capacity(0); for rcpt in &mut self.recipients { @@ -500,7 +496,7 @@ impl Message { if !is_double_bounce.is_empty() { tracing::info!( - parent: span, + context = "queue", event = "double-bounce", id = self.id, diff --git a/crates/smtp/src/queue/quota.rs b/crates/smtp/src/queue/quota.rs index c181b20c..ca052bbc 100644 --- a/crates/smtp/src/queue/quota.rs +++ b/crates/smtp/src/queue/quota.rs @@ -21,7 +21,7 @@ impl SMTP { if !self.core.smtp.queue.quota.sender.is_empty() { for quota in &self.core.smtp.queue.quota.sender { if !self - .check_quota(quota, message, message.size, 0, &mut quota_keys) + .check_quota(quota, message, message.size, 0, &mut quota_keys, message.id) .await { return false; @@ -38,6 +38,7 @@ impl SMTP { message.size, ((domain_idx + 1) << 32) as u64, &mut quota_keys, + message.id, ) .await { @@ -55,6 +56,7 @@ impl SMTP { message.size, (rcpt_idx + 1) as u64, &mut quota_keys, + message.id, ) .await { @@ -75,11 +77,12 @@ impl SMTP { size: usize, id: u64, refs: &mut Vec, + session_id: u64, ) -> bool { if !quota.expr.is_empty() && self .core - .eval_expr("a.expr, envelope, "check_quota") + .eval_expr("a.expr, envelope, "check_quota", session_id) .await .unwrap_or(false) { diff --git a/crates/smtp/src/queue/spool.rs b/crates/smtp/src/queue/spool.rs index e3ea8f10..37d78017 100644 --- a/crates/smtp/src/queue/spool.rs +++ b/crates/smtp/src/queue/spool.rs @@ -175,7 +175,6 @@ impl Message { raw_headers: Option<&[u8]>, raw_message: &[u8], core: &SMTP, - span: &tracing::Span, ) -> bool { // Write blob let message = if let Some(raw_headers) = raw_headers { @@ -205,7 +204,6 @@ impl Message { ); if let Err(err) = core.core.storage.data.write(batch.build()).await { tracing::error!( - parent: span, context = "queue", event = "error", "Failed to write to data store: {}", @@ -221,7 +219,6 @@ impl Message { .await { tracing::error!( - parent: span, context = "queue", event = "error", "Failed to write to blob store: {}", @@ -231,7 +228,6 @@ impl Message { } tracing::info!( - parent: span, context = "queue", event = "scheduled", id = self.id, @@ -294,7 +290,6 @@ impl Message { if let Err(err) = core.core.storage.data.write(batch.build()).await { tracing::error!( - parent: span, context = "queue", event = "error", "Failed to write to store: {}", @@ -306,7 +301,6 @@ impl Message { // Queue the message if core.inner.queue_tx.send(Event::Reload).await.is_err() { tracing::warn!( - parent: span, context = "queue", event = "error", "Queue channel closed: Message queued but won't be sent until next restart." @@ -340,7 +334,11 @@ impl Message { let expires = core .core - .eval_if(&core.core.smtp.queue.expire, &QueueEnvelope::new(self, idx)) + .eval_if( + &core.core.smtp.queue.expire, + &QueueEnvelope::new(self, idx), + self.id, + ) .await .unwrap_or_else(|| Duration::from_secs(5 * 86400)); diff --git a/crates/smtp/src/queue/throttle.rs b/crates/smtp/src/queue/throttle.rs index e5e60a33..ce7939b4 100644 --- a/crates/smtp/src/queue/throttle.rs +++ b/crates/smtp/src/queue/throttle.rs @@ -28,12 +28,12 @@ impl SMTP { throttle: &'x Throttle, envelope: &impl ResolveVariable, in_flight: &mut Vec, - span: &tracing::Span, + session_id: u64, ) -> Result<(), Error> { if throttle.expr.is_empty() || self .core - .eval_expr(&throttle.expr, envelope, "throttle") + .eval_expr(&throttle.expr, envelope, "throttle", session_id) .await .unwrap_or(false) { @@ -48,7 +48,6 @@ impl SMTP { .await { tracing::info!( - parent: span, context = "throttle", event = "rate-limit-exceeded", max_requests = rate.requests, @@ -69,7 +68,6 @@ impl SMTP { in_flight.push(inflight); } else { tracing::info!( - parent: span, context = "throttle", event = "too-many-requests", max_concurrent = limiter.max_concurrent, diff --git a/crates/smtp/src/reporting/dkim.rs b/crates/smtp/src/reporting/dkim.rs index be5f885b..5aa2cdba 100644 --- a/crates/smtp/src/reporting/dkim.rs +++ b/crates/smtp/src/reporting/dkim.rs @@ -31,7 +31,6 @@ impl Session { // Throttle recipient if !self.throttle_rcpt(rcpt, rate, "dkim").await { tracing::debug!( - parent: &self.span, context = "report", report = "dkim", event = "throttle", @@ -44,7 +43,7 @@ impl Session { let from_addr = self .core .core - .eval_if(&config.address, self) + .eval_if(&config.address, self, self.data.session_id) .await .unwrap_or_else(|| "MAILER-DAEMON@localhost".to_string()); let mut report = Vec::with_capacity(128); @@ -62,7 +61,7 @@ impl Session { ( self.core .core - .eval_if(&config.name, self) + .eval_if(&config.name, self, self.data.session_id) .await .unwrap_or_else(|| "Mail Delivery Subsystem".to_string()) .as_str(), @@ -72,7 +71,7 @@ impl Session { &self .core .core - .eval_if(&config.subject, self) + .eval_if(&config.subject, self, self.data.session_id) .await .unwrap_or_else(|| "DKIM Report".to_string()), &mut report, @@ -80,7 +79,6 @@ impl Session { .ok(); tracing::info!( - parent: &self.span, context = "report", report = "dkim", event = "queue", @@ -90,14 +88,7 @@ impl Session { // Send report self.core - .send_report( - &from_addr, - [rcpt].into_iter(), - report, - &config.sign, - &self.span, - true, - ) + .send_report(&from_addr, [rcpt].into_iter(), report, &config.sign, true) .await; } } diff --git a/crates/smtp/src/reporting/dmarc.rs b/crates/smtp/src/reporting/dmarc.rs index 09cd1e9d..ce86c6dd 100644 --- a/crates/smtp/src/reporting/dmarc.rs +++ b/crates/smtp/src/reporting/dmarc.rs @@ -7,7 +7,10 @@ use std::collections::hash_map::Entry; use ahash::AHashMap; -use common::{config::smtp::report::AggregateFrequency, listener::SessionStream}; +use common::{ + config::smtp::{report::AggregateFrequency, session}, + listener::SessionStream, +}; use mail_auth::{ common::verify::VerifySignature, dmarc::{self, URI}, @@ -51,7 +54,10 @@ impl Session { // Send failure report if let (Some(failure_rate), Some(report_options)) = ( - self.core.core.eval_if::(&config.send, self).await, + self.core + .core + .eval_if::(&config.send, self, self.data.session_id) + .await, dmarc_output.failure_report(), ) { // Verify that any external reporting addresses are authorized @@ -78,7 +84,7 @@ impl Session { } else { if !dmarc_record.ruf().is_empty() { tracing::debug!( - parent: &self.span, + context = "report", report = "dkim", event = "unauthorized-ruf", @@ -91,7 +97,7 @@ impl Session { } None => { tracing::debug!( - parent: &self.span, + context = "report", report = "dmarc", event = "dns-failure", @@ -108,7 +114,7 @@ impl Session { let from_addr = self .core .core - .eval_if(&config.address, self) + .eval_if(&config.address, self, self.data.session_id) .await .unwrap_or_else(|| "MAILER-DAEMON@localhost".to_string()); let mut auth_failure = self @@ -192,7 +198,7 @@ impl Session { ( self.core .core - .eval_if(&config.name, self) + .eval_if(&config.name, self, self.data.session_id) .await .unwrap_or_else(|| "Mail Delivery Subsystem".to_string()) .as_str(), @@ -202,7 +208,7 @@ impl Session { &self .core .core - .eval_if(&config.subject, self) + .eval_if(&config.subject, self, self.data.session_id) .await .unwrap_or_else(|| "DMARC Report".to_string()), &mut report, @@ -210,7 +216,7 @@ impl Session { .ok(); tracing::info!( - parent: &self.span, + context = "report", report = "dmarc", event = "queue", @@ -220,18 +226,11 @@ impl Session { // Send report self.core - .send_report( - &from_addr, - rcpts.into_iter(), - report, - &config.sign, - &self.span, - true, - ) + .send_report(&from_addr, rcpts.into_iter(), report, &config.sign, true) .await; } else { tracing::debug!( - parent: &self.span, + context = "report", report = "dmarc", event = "throttle", @@ -244,7 +243,11 @@ impl Session { let interval = self .core .core - .eval_if(&self.core.core.smtp.report.dmarc_aggregate.send, self) + .eval_if( + &self.core.core.smtp.report.dmarc_aggregate.send, + self, + self.data.session_id, + ) .await .unwrap_or(AggregateFrequency::Never); @@ -297,36 +300,38 @@ impl SMTP { ); // Generate report + let todo = "generate session id"; + let session_id = 0; let mut serialized_size = serde_json::Serializer::new(SerializedSize::new( self.core .eval_if( &self.core.smtp.report.dmarc_aggregate.max_size, &RecipientDomain::new(event.domain.as_str()), + session_id, ) .await .unwrap_or(25 * 1024 * 1024), )); let mut rua = Vec::new(); let report = match self - .generate_dmarc_aggregate_report(&event, &mut rua, Some(&mut serialized_size)) + .generate_dmarc_aggregate_report( + &event, + &mut rua, + Some(&mut serialized_size), + session_id, + ) .await { Ok(Some(report)) => report, Ok(None) => { tracing::warn!( - parent: &span, event = "missing", "Failed to read DMARC report: Report not found" ); return; } Err(err) => { - tracing::warn!( - parent: &span, - event = "error", - "Failed to read DMARC records: {}", - err - ); + tracing::warn!(event = "error", "Failed to read DMARC records: {}", err); return; } }; @@ -348,7 +353,7 @@ impl SMTP { .collect::>() } else { tracing::info!( - parent: &span, + event = "failed", reason = "unauthorized-rua", rua = ?rua, @@ -360,7 +365,7 @@ impl SMTP { } None => { tracing::info!( - parent: &span, + event = "failed", reason = "dns-failure", rua = ?rua, @@ -378,6 +383,7 @@ impl SMTP { .eval_if( &config.address, &RecipientDomain::new(event.domain.as_str()), + session_id, ) .await .unwrap_or_else(|| "MAILER-DAEMON@localhost".to_string()); @@ -388,12 +394,17 @@ impl SMTP { .eval_if( &self.core.smtp.report.submitter, &RecipientDomain::new(event.domain.as_str()), + session_id, ) .await .unwrap_or_else(|| "localhost".to_string()), ( self.core - .eval_if(&config.name, &RecipientDomain::new(event.domain.as_str())) + .eval_if( + &config.name, + &RecipientDomain::new(event.domain.as_str()), + session_id, + ) .await .unwrap_or_else(|| "Mail Delivery Subsystem".to_string()) .as_str(), @@ -404,7 +415,7 @@ impl SMTP { ); // Send report - self.send_report(&from_addr, rua.iter(), message, &config.sign, &span, false) + self.send_report(&from_addr, rua.iter(), message, &config.sign, false) .await; self.delete_dmarc_report(event).await; @@ -415,6 +426,7 @@ impl SMTP { event: &ReportEvent, rua: &mut Vec, mut serialized_size: Option<&mut serde_json::Serializer>, + session_id: u64, ) -> trc::Result> { // Deserialize report let dmarc = match self @@ -445,6 +457,7 @@ impl SMTP { .eval_if( &config.address, &RecipientDomain::new(event.domain.as_str()), + session_id, ) .await .unwrap_or_else(|| "MAILER-DAEMON@localhost".to_string()), @@ -454,6 +467,7 @@ impl SMTP { .eval_if::( &config.org_name, &RecipientDomain::new(event.domain.as_str()), + session_id, ) .await { @@ -464,6 +478,7 @@ impl SMTP { .eval_if::( &config.contact_info, &RecipientDomain::new(event.domain.as_str()), + session_id, ) .await { diff --git a/crates/smtp/src/reporting/mod.rs b/crates/smtp/src/reporting/mod.rs index 6d3f320e..71788444 100644 --- a/crates/smtp/src/reporting/mod.rs +++ b/crates/smtp/src/reporting/mod.rs @@ -119,7 +119,6 @@ impl SMTP { rcpts: impl Iterator>, report: Vec, sign_config: &IfBlock, - span: &tracing::Span, deliver_now: bool, ) { // Build message @@ -131,9 +130,7 @@ impl SMTP { } // Sign message - let signature = self - .sign_message(&mut message, sign_config, &report, span) - .await; + let signature = self.sign_message(&mut message, sign_config, &report).await; // Schedule delivery at a random time between now and the next 3 hours if !deliver_now { @@ -189,9 +186,7 @@ impl SMTP { } // Queue message - message - .queue(signature.as_deref(), &report, self, span) - .await; + message.queue(signature.as_deref(), &report, self).await; } pub async fn schedule_report(&self, report: impl Into) { @@ -205,11 +200,10 @@ impl SMTP { message: &mut Message, config: &IfBlock, bytes: &[u8], - span: &tracing::Span, ) -> Option> { let signers = self .core - .eval_if::, _>(config, message) + .eval_if::, _>(config, message, message.id) .await .unwrap_or_default(); if !signers.is_empty() { @@ -221,7 +215,7 @@ impl SMTP { signature.write_header(&mut headers); } Err(err) => { - tracing::warn!(parent: span, + tracing::warn!( context = "dkim", event = "sign-failed", reason = %err); diff --git a/crates/smtp/src/reporting/spf.rs b/crates/smtp/src/reporting/spf.rs index f7354b24..f5ab7444 100644 --- a/crates/smtp/src/reporting/spf.rs +++ b/crates/smtp/src/reporting/spf.rs @@ -21,7 +21,6 @@ impl Session { // Throttle recipient if !self.throttle_rcpt(rcpt, rate, "spf").await { tracing::debug!( - parent: &self.span, context = "report", report = "spf", event = "throttle", @@ -35,7 +34,7 @@ impl Session { let from_addr = self .core .core - .eval_if(&config.address, self) + .eval_if(&config.address, self, self.data.session_id) .await .unwrap_or_else(|| "MAILER-DAEMON@localhost".to_string()); let mut report = Vec::with_capacity(128); @@ -62,7 +61,7 @@ impl Session { ( self.core .core - .eval_if(&config.name, self) + .eval_if(&config.name, self, self.data.session_id) .await .unwrap_or_else(|| "Mailer Daemon".to_string()) .as_str(), @@ -72,7 +71,7 @@ impl Session { &self .core .core - .eval_if(&config.subject, self) + .eval_if(&config.subject, self, self.data.session_id) .await .unwrap_or_else(|| "SPF Report".to_string()), &mut report, @@ -80,7 +79,6 @@ impl Session { .ok(); tracing::info!( - parent: &self.span, context = "report", report = "spf", event = "queue", @@ -90,14 +88,7 @@ impl Session { // Send report self.core - .send_report( - &from_addr, - [rcpt].into_iter(), - report, - &config.sign, - &self.span, - true, - ) + .send_report(&from_addr, [rcpt].into_iter(), report, &config.sign, true) .await; } } diff --git a/crates/smtp/src/reporting/tls.rs b/crates/smtp/src/reporting/tls.rs index 248373d4..78140cf6 100644 --- a/crates/smtp/src/reporting/tls.rs +++ b/crates/smtp/src/reporting/tls.rs @@ -11,6 +11,7 @@ use common::{ config::smtp::{ report::AggregateFrequency, resolver::{Mode, MxPattern}, + session, }, USER_AGENT, }; @@ -64,6 +65,9 @@ impl SMTP { range_to = event_to, ); + let todo = "generate session id"; + let session_id = 0; + // Generate report let mut rua = Vec::new(); let mut serialized_size = serde_json::Serializer::new(SerializedSize::new( @@ -71,32 +75,29 @@ impl SMTP { .eval_if( &self.core.smtp.report.tls.max_size, &RecipientDomain::new(domain_name), + session_id, ) .await .unwrap_or(25 * 1024 * 1024), )); let report = match self - .generate_tls_aggregate_report(&events, &mut rua, Some(&mut serialized_size)) + .generate_tls_aggregate_report( + &events, + &mut rua, + Some(&mut serialized_size), + session_id, + ) .await { Ok(Some(report)) => report, Ok(None) => { // This should not happen - tracing::warn!( - parent: &span, - event = "empty-report", - "No policies found in report" - ); + tracing::warn!(event = "empty-report", "No policies found in report"); self.delete_tls_report(events).await; return; } Err(err) => { - tracing::warn!( - parent: &span, - event = "error", - "Failed to read TLS report: {}", - err - ); + tracing::warn!(event = "error", "Failed to read TLS report: {}", err); return; } }; @@ -108,12 +109,7 @@ impl SMTP { { Ok(report) => report, Err(err) => { - tracing::error!( - parent: &span, - event = "error", - "Failed to compress report: {}", - err - ); + tracing::error!(event = "error", "Failed to compress report: {}", err); self.delete_tls_report(events).await; return; } @@ -145,17 +141,12 @@ impl SMTP { { Ok(response) => { if response.status().is_success() { - tracing::info!( - parent: &span, - context = "http", - event = "success", - url = uri, - ); + tracing::info!(context = "http", event = "success", url = uri,); self.delete_tls_report(events).await; return; } else { tracing::debug!( - parent: &span, + context = "http", event = "invalid-response", url = uri, @@ -165,7 +156,7 @@ impl SMTP { } Err(err) => { tracing::debug!( - parent: &span, + context = "http", event = "error", url = uri, @@ -186,7 +177,11 @@ impl SMTP { let config = &self.core.smtp.report.tls; let from_addr = self .core - .eval_if(&config.address, &RecipientDomain::new(domain_name)) + .eval_if( + &config.address, + &RecipientDomain::new(domain_name), + session_id, + ) .await .unwrap_or_else(|| "MAILER-DAEMON@localhost".to_string()); let mut message = Vec::with_capacity(2048); @@ -197,12 +192,13 @@ impl SMTP { .eval_if( &self.core.smtp.report.submitter, &RecipientDomain::new(domain_name), + session_id, ) .await .unwrap_or_else(|| "localhost".to_string()), ( self.core - .eval_if(&config.name, &RecipientDomain::new(domain_name)) + .eval_if(&config.name, &RecipientDomain::new(domain_name), session_id) .await .unwrap_or_else(|| "Mail Delivery Subsystem".to_string()) .as_str(), @@ -214,18 +210,10 @@ impl SMTP { ); // Send report - self.send_report( - &from_addr, - rcpts.iter(), - message, - &config.sign, - &span, - false, - ) - .await; + self.send_report(&from_addr, rcpts.iter(), message, &config.sign, false) + .await; } else { tracing::info!( - parent: &span, event = "delivery-failed", "No valid recipients found to deliver report to." ); @@ -238,6 +226,7 @@ impl SMTP { events: &[ReportEvent], rua: &mut Vec, mut serialized_size: Option<&mut serde_json::Serializer>, + session_id: u64, ) -> trc::Result> { let (domain_name, event_from, event_to, policy) = events .first() @@ -247,7 +236,11 @@ impl SMTP { let mut report = TlsReport { organization_name: self .core - .eval_if(&config.org_name, &RecipientDomain::new(domain_name)) + .eval_if( + &config.org_name, + &RecipientDomain::new(domain_name), + session_id, + ) .await .clone(), date_range: DateRange { @@ -256,7 +249,11 @@ impl SMTP { }, contact_info: self .core - .eval_if(&config.contact_info, &RecipientDomain::new(domain_name)) + .eval_if( + &config.contact_info, + &RecipientDomain::new(domain_name), + session_id, + ) .await .clone(), report_id: format!("{}_{}", event_from, policy), diff --git a/crates/smtp/src/scripts/event_loop.rs b/crates/smtp/src/scripts/event_loop.rs index a10709ab..e1eeb5e7 100644 --- a/crates/smtp/src/scripts/event_loop.rs +++ b/crates/smtp/src/scripts/event_loop.rs @@ -26,7 +26,7 @@ impl SMTP { &self, script: Arc, params: ScriptParameters<'_>, - span: tracing::Span, + session_id: u64, ) -> ScriptResult { // Create filter instance let mut instance = self @@ -56,7 +56,6 @@ impl SMTP { input = false.into(); } else { tracing::warn!( - parent: &span, context = "sieve", event = "script-not-found", script = name.as_str() @@ -90,7 +89,6 @@ impl SMTP { } } else { tracing::debug!( - parent: &span, context = "sieve", event = "list-not-found", list = list, @@ -104,7 +102,7 @@ impl SMTP { .run_plugin( id, PluginContext { - span: &span, + session_id, core: &self.core, cache: &self.inner.script_cache, message: instance.message(), @@ -152,7 +150,6 @@ impl SMTP { } Recipient::List(list) => { tracing::warn!( - parent: &span, context = "sieve", event = "send-failed", reason = format!("Lookup {list:?} not supported.") @@ -261,7 +258,7 @@ impl SMTP { signature.write_header(&mut headers); } Err(err) => { - tracing::warn!(parent: &span, + tracing::warn!( context = "dkim", event = "sign-failed", reason = %err); @@ -282,12 +279,10 @@ impl SMTP { }; if self.has_quota(&mut message).await { - message - .queue(headers.as_deref(), raw_message, self, &span) - .await; + message.queue(headers.as_deref(), raw_message, self).await; } else { tracing::warn!( - parent: &span, + context = "sieve", event = "send-message", error = "quota-exceeded", @@ -313,7 +308,6 @@ impl SMTP { } unsupported => { tracing::warn!( - parent: &span, context = "sieve", event = "runtime-error", reason = format!("Unsupported event: {unsupported:?}") @@ -322,7 +316,7 @@ impl SMTP { } }, Err(err) => { - tracing::warn!(parent: &span, + tracing::warn!( context = "sieve", event = "runtime-error", reason = %err diff --git a/crates/smtp/src/scripts/exec.rs b/crates/smtp/src/scripts/exec.rs index d7887fc5..3b16472b 100644 --- a/crates/smtp/src/scripts/exec.rs +++ b/crates/smtp/src/scripts/exec.rs @@ -126,8 +126,10 @@ impl Session { self.core .run_script( script, - params.with_envelope(&self.core.core, self).await, - self.span.clone(), + params + .with_envelope(&self.core.core, self, self.data.session_id) + .await, + self.data.session_id, ) .await } diff --git a/crates/smtp/src/scripts/mod.rs b/crates/smtp/src/scripts/mod.rs index 68972b34..ee3c3ca7 100644 --- a/crates/smtp/src/scripts/mod.rs +++ b/crates/smtp/src/scripts/mod.rs @@ -56,17 +56,22 @@ impl<'x> ScriptParameters<'x> { } } - pub async fn with_envelope(mut self, core: &Core, vars: &impl ResolveVariable) -> Self { + pub async fn with_envelope( + mut self, + core: &Core, + vars: &impl ResolveVariable, + session_id: u64, + ) -> Self { for (variable, expr) in [ (&mut self.from_addr, &core.sieve.from_addr), (&mut self.from_name, &core.sieve.from_name), (&mut self.return_path, &core.sieve.return_path), ] { - if let Some(value) = core.eval_if(expr, vars).await { + if let Some(value) = core.eval_if(expr, vars, session_id).await { *variable = value; } } - if let Some(value) = core.eval_if(&core.sieve.sign, vars).await { + if let Some(value) = core.eval_if(&core.sieve.sign, vars, session_id).await { self.sign = value; } self diff --git a/crates/store/src/backend/elastic/mod.rs b/crates/store/src/backend/elastic/mod.rs index abcf1ba0..1d0c239a 100644 --- a/crates/store/src/backend/elastic/mod.rs +++ b/crates/store/src/backend/elastic/mod.rs @@ -111,7 +111,7 @@ impl ElasticSearchStore { .exists(IndicesExistsParts::Index(&[INDEX_NAMES[0]])) .send() .await - .map_err(|err| trc::StoreCause::ElasticSearch.reason(err))?; + .map_err(|err| trc::StoreEvent::ElasticSearchError.reason(err))?; if exists.status_code() == StatusCode::NOT_FOUND { let response = self @@ -183,11 +183,11 @@ pub(crate) async fn assert_success(response: Result) -> trc::Re if status.is_success() { Ok(response) } else { - Err(trc::StoreCause::ElasticSearch + Err(trc::StoreEvent::ElasticSearchError .reason(response.text().await.unwrap_or_default()) .ctx(trc::Key::Code, status.as_u16())) } } - Err(err) => Err(trc::StoreCause::ElasticSearch.reason(err)), + Err(err) => Err(trc::StoreEvent::ElasticSearchError.reason(err)), } } diff --git a/crates/store/src/backend/elastic/query.rs b/crates/store/src/backend/elastic/query.rs index 624ae8a5..73367049 100644 --- a/crates/store/src/backend/elastic/query.rs +++ b/crates/store/src/backend/elastic/query.rs @@ -107,14 +107,14 @@ impl ElasticSearchStore { let json: Value = response .json() .await - .map_err(|err| trc::StoreCause::ElasticSearch.reason(err))?; + .map_err(|err| trc::StoreEvent::ElasticSearchError.reason(err))?; let mut results = RoaringBitmap::new(); for hit in json["hits"]["hits"].as_array().ok_or_else(|| { - trc::StoreCause::ElasticSearch.reason("Invalid response from ElasticSearch") + trc::StoreEvent::ElasticSearchError.reason("Invalid response from ElasticSearch") })? { results.insert(hit["_source"]["document_id"].as_u64().ok_or_else(|| { - trc::StoreCause::ElasticSearch.reason("Invalid response from ElasticSearch") + trc::StoreEvent::ElasticSearchError.reason("Invalid response from ElasticSearch") })? as u32); } diff --git a/crates/store/src/backend/foundationdb/mod.rs b/crates/store/src/backend/foundationdb/mod.rs index 52a28f7f..ffb831bd 100644 --- a/crates/store/src/backend/foundationdb/mod.rs +++ b/crates/store/src/backend/foundationdb/mod.rs @@ -77,7 +77,7 @@ impl TimedTransaction { #[inline(always)] fn into_error(error: FdbError) -> trc::Error { - trc::StoreCause::FoundationDB + trc::StoreEvent::FoundationDBError .reason(error.message()) .ctx(trc::Key::Code, error.code()) } diff --git a/crates/store/src/backend/foundationdb/write.rs b/crates/store/src/backend/foundationdb/write.rs index 9fd10f75..7ae68fac 100644 --- a/crates/store/src/backend/foundationdb/write.rs +++ b/crates/store/src/backend/foundationdb/write.rs @@ -94,10 +94,11 @@ impl FdbStore { *key.last_mut().unwrap() += 1; } else { trx.cancel(); - return Err(trc::StoreCause::FoundationDB.ctx( - trc::Key::Reason, - "Value is too large", - )); + return Err(trc::StoreEvent::FoundationDBError + .ctx( + trc::Key::Reason, + "Value is too large", + )); } } } @@ -257,7 +258,7 @@ impl FdbStore { if !matches { trx.cancel(); - return Err(trc::StoreCause::AssertValue.into()); + return Err(trc::StoreEvent::AssertValueFailed.into()); } } } diff --git a/crates/store/src/backend/fs/mod.rs b/crates/store/src/backend/fs/mod.rs index bc522c1b..fe106cbd 100644 --- a/crates/store/src/backend/fs/mod.rs +++ b/crates/store/src/backend/fs/mod.rs @@ -121,5 +121,5 @@ impl FsStore { } fn into_error(err: std::io::Error) -> trc::Error { - trc::StoreCause::Filesystem.reason(err) + trc::StoreEvent::FilesystemError.reason(err) } diff --git a/crates/store/src/backend/mysql/mod.rs b/crates/store/src/backend/mysql/mod.rs index fa28d1bc..9571fcd4 100644 --- a/crates/store/src/backend/mysql/mod.rs +++ b/crates/store/src/backend/mysql/mod.rs @@ -20,5 +20,5 @@ pub struct MysqlStore { #[inline(always)] fn into_error(err: impl Display) -> trc::Error { - trc::StoreCause::MySQL.reason(err) + trc::StoreEvent::MySQLError.reason(err) } diff --git a/crates/store/src/backend/mysql/write.rs b/crates/store/src/backend/mysql/write.rs index ca20ba20..7d570ae1 100644 --- a/crates/store/src/backend/mysql/write.rs +++ b/crates/store/src/backend/mysql/write.rs @@ -46,7 +46,7 @@ impl MysqlStore { && start.elapsed() < MAX_COMMIT_TIME => {} Err(CommitError::Retry) => { if retry_count > MAX_COMMIT_ATTEMPTS || start.elapsed() > MAX_COMMIT_TIME { - return Err(trc::StoreCause::AssertValue.into()); + return Err(trc::StoreEvent::AssertValueFailed.into()); } } Err(CommitError::Mysql(err)) => { @@ -135,7 +135,9 @@ impl MysqlStore { Ok(_) => { if exists.is_some() && trx.affected_rows() == 0 { trx.rollback().await?; - return Err(trc::StoreCause::AssertValue.into_err().into()); + return Err(trc::StoreEvent::AssertValueFailed + .into_err() + .into()); } } Err(err) => { @@ -308,7 +310,7 @@ impl MysqlStore { .unwrap_or_else(|| (false, assert_value.is_none())); if !matches { trx.rollback().await?; - return Err(trc::StoreCause::AssertValue.into_err().into()); + return Err(trc::StoreEvent::AssertValueFailed.into_err().into()); } asserted_values.insert(key, exists); } diff --git a/crates/store/src/backend/postgres/mod.rs b/crates/store/src/backend/postgres/mod.rs index 63093154..157d06f2 100644 --- a/crates/store/src/backend/postgres/mod.rs +++ b/crates/store/src/backend/postgres/mod.rs @@ -21,5 +21,5 @@ pub struct PostgresStore { #[inline(always)] fn into_error(err: impl Display) -> trc::Error { - trc::StoreCause::PostgreSQL.reason(err) + trc::StoreEvent::PostgreSQLError.reason(err) } diff --git a/crates/store/src/backend/postgres/write.rs b/crates/store/src/backend/postgres/write.rs index aaf4e825..0a22eb34 100644 --- a/crates/store/src/backend/postgres/write.rs +++ b/crates/store/src/backend/postgres/write.rs @@ -50,7 +50,7 @@ impl PostgresStore { ) if retry_count < MAX_COMMIT_ATTEMPTS && start.elapsed() < MAX_COMMIT_TIME => {} Some(&SqlState::UNIQUE_VIOLATION) => { - return Err(trc::StoreCause::AssertValue.into()); + return Err(trc::StoreEvent::AssertValueFailed.into()); } _ => return Err(into_error(err)), }, @@ -59,7 +59,7 @@ impl PostgresStore { if retry_count > MAX_COMMIT_ATTEMPTS || start.elapsed() > MAX_COMMIT_TIME { - return Err(trc::StoreCause::AssertValue.into()); + return Err(trc::StoreEvent::AssertValueFailed.into()); } } } @@ -148,7 +148,7 @@ impl PostgresStore { .await? == 0 { - return Err(trc::StoreCause::AssertValue.into_err().into()); + return Err(trc::StoreEvent::AssertValueFailed.into_err().into()); } } ValueOp::AtomicAdd(by) => { @@ -322,7 +322,7 @@ impl PostgresStore { }) .unwrap_or_else(|| (false, assert_value.is_none())); if !matches { - return Err(trc::StoreCause::AssertValue.into_err().into()); + return Err(trc::StoreEvent::AssertValueFailed.into_err().into()); } asserted_values.insert(key, exists); } diff --git a/crates/store/src/backend/redis/mod.rs b/crates/store/src/backend/redis/mod.rs index 6ce007e2..f4c31260 100644 --- a/crates/store/src/backend/redis/mod.rs +++ b/crates/store/src/backend/redis/mod.rs @@ -184,5 +184,5 @@ fn build_pool( #[inline(always)] fn into_error(err: impl Display) -> trc::Error { - trc::StoreCause::Redis.reason(err) + trc::StoreEvent::RedisError.reason(err) } diff --git a/crates/store/src/backend/redis/pool.rs b/crates/store/src/backend/redis/pool.rs index c322584e..f8f31da9 100644 --- a/crates/store/src/backend/redis/pool.rs +++ b/crates/store/src/backend/redis/pool.rs @@ -21,7 +21,7 @@ impl managed::Manager for RedisConnectionManager { .await { Ok(conn) => conn.map_err(into_error), - Err(_) => Err(trc::StoreCause::Redis.ctx(trc::Key::Details, "Connection Timeout")), + Err(_) => Err(trc::StoreEvent::RedisError.ctx(trc::Key::Details, "Connection Timeout")), } } @@ -44,7 +44,7 @@ impl managed::Manager for RedisClusterConnectionManager { async fn create(&self) -> Result { match tokio::time::timeout(self.timeout, self.client.get_async_connection()).await { Ok(conn) => conn.map_err(into_error), - Err(_) => Err(trc::StoreCause::Redis.ctx(trc::Key::Details, "Connection Timeout")), + Err(_) => Err(trc::StoreEvent::RedisError.ctx(trc::Key::Details, "Connection Timeout")), } } diff --git a/crates/store/src/backend/rocksdb/main.rs b/crates/store/src/backend/rocksdb/main.rs index 0135ab88..8aad4bee 100644 --- a/crates/store/src/backend/rocksdb/main.rs +++ b/crates/store/src/backend/rocksdb/main.rs @@ -154,7 +154,7 @@ impl RocksDbStore { match rx.await { Ok(result) => result, - Err(err) => Err(trc::Cause::Thread.reason(err)), + Err(err) => Err(trc::EventType::Server(trc::ServerEvent::ThreadError).reason(err)), } } } diff --git a/crates/store/src/backend/rocksdb/mod.rs b/crates/store/src/backend/rocksdb/mod.rs index 78b80e86..b6ca584d 100644 --- a/crates/store/src/backend/rocksdb/mod.rs +++ b/crates/store/src/backend/rocksdb/mod.rs @@ -38,5 +38,5 @@ pub struct RocksDbStore { #[inline(always)] fn into_error(err: rocksdb::Error) -> trc::Error { - trc::StoreCause::RocksDB.reason(err) + trc::StoreEvent::RocksDBError.reason(err) } diff --git a/crates/store/src/backend/rocksdb/write.rs b/crates/store/src/backend/rocksdb/write.rs index d8c47b2b..1642b629 100644 --- a/crates/store/src/backend/rocksdb/write.rs +++ b/crates/store/src/backend/rocksdb/write.rs @@ -308,7 +308,7 @@ impl<'x> RocksDBTransaction<'x> { if !matches { txn.rollback()?; - return Err(CommitError::Internal(trc::StoreCause::AssertValue.into())); + return Err(CommitError::Internal(trc::StoreEvent::AssertValueFailed.into())); } } } diff --git a/crates/store/src/backend/s3/mod.rs b/crates/store/src/backend/s3/mod.rs index dee52205..cfbc4e61 100644 --- a/crates/store/src/backend/s3/mod.rs +++ b/crates/store/src/backend/s3/mod.rs @@ -90,7 +90,7 @@ impl S3Store { match response.status_code() { 200..=299 => Ok(Some(response.to_vec())), 404 => Ok(None), - code => Err(trc::StoreCause::S3 + code => Err(trc::StoreEvent::S3Error .reason(String::from_utf8_lossy(response.as_slice())) .ctx(trc::Key::Code, code)), } @@ -105,7 +105,7 @@ impl S3Store { match response.status_code() { 200..=299 => Ok(()), - code => Err(trc::StoreCause::S3 + code => Err(trc::StoreEvent::S3Error .reason(String::from_utf8_lossy(response.as_slice())) .ctx(trc::Key::Code, code)), } @@ -121,7 +121,7 @@ impl S3Store { match response.status_code() { 200..=299 => Ok(true), 404 => Ok(false), - code => Err(trc::StoreCause::S3 + code => Err(trc::StoreEvent::S3Error .reason(String::from_utf8_lossy(response.as_slice())) .ctx(trc::Key::Code, code)), } @@ -142,5 +142,5 @@ impl S3Store { #[inline(always)] fn into_error(err: impl Display) -> trc::Error { - trc::StoreCause::S3.reason(err) + trc::StoreEvent::S3Error.reason(err) } diff --git a/crates/store/src/backend/sqlite/main.rs b/crates/store/src/backend/sqlite/main.rs index 55fc9b42..805763d2 100644 --- a/crates/store/src/backend/sqlite/main.rs +++ b/crates/store/src/backend/sqlite/main.rs @@ -168,7 +168,7 @@ impl SqliteStore { match rx.await { Ok(result) => result, - Err(err) => Err(trc::Cause::Thread.reason(err)), + Err(err) => Err(trc::EventType::Server(trc::ServerEvent::ThreadError).reason(err)), } } } diff --git a/crates/store/src/backend/sqlite/mod.rs b/crates/store/src/backend/sqlite/mod.rs index 3bc632f8..4f3089df 100644 --- a/crates/store/src/backend/sqlite/mod.rs +++ b/crates/store/src/backend/sqlite/mod.rs @@ -24,5 +24,5 @@ pub struct SqliteStore { #[inline(always)] fn into_error(err: impl Display) -> trc::Error { - trc::StoreCause::SQLite.reason(err) + trc::StoreEvent::SQLiteError.reason(err) } diff --git a/crates/store/src/backend/sqlite/write.rs b/crates/store/src/backend/sqlite/write.rs index c07f42df..1e9280d7 100644 --- a/crates/store/src/backend/sqlite/write.rs +++ b/crates/store/src/backend/sqlite/write.rs @@ -245,7 +245,7 @@ impl SqliteStore { .unwrap_or_else(|| assert_value.is_none()); if !matches { trx.rollback().map_err(into_error)?; - return Err(trc::StoreCause::AssertValue.into()); + return Err(trc::StoreEvent::AssertValueFailed.into()); } } } diff --git a/crates/store/src/dispatch/blob.rs b/crates/store/src/dispatch/blob.rs index 146e35c9..cc2d24cd 100644 --- a/crates/store/src/dispatch/blob.rs +++ b/crates/store/src/dispatch/blob.rs @@ -6,7 +6,7 @@ use std::{borrow::Cow, ops::Range}; -use trc::{AddContext, Cause, StoreCause}; +use trc::{AddContext, StoreEvent}; use utils::config::utils::ParseValue; use crate::{BlobBackend, BlobStore, CompressionAlgo, Store}; @@ -30,7 +30,7 @@ impl BlobStore { Store::MySQL(store) => store.get_blob(key, read_range).await, #[cfg(feature = "rocks")] Store::RocksDb(store) => store.get_blob(key, read_range).await, - Store::None => Err(trc::StoreCause::NotConfigured.into()), + Store::None => Err(trc::StoreEvent::NotConfigured.into()), }, BlobBackend::Fs(store) => store.get_blob(key, read_range).await, #[cfg(feature = "s3")] @@ -47,17 +47,14 @@ impl BlobStore { data.get(..data.len() - 1).unwrap_or_default(), ) .map_err(|err| { - trc::StoreCause::Decompress + trc::StoreEvent::DecompressError .reason(err) .ctx(trc::Key::Key, key) .ctx(trc::Key::CausedBy, trc::location!()) })? } Some(data) => { - trc::event!( - Error(Cause::Store(StoreCause::BlobMissingMarker)), - Key = key, - ); + trc::event!(Store(StoreEvent::BlobMissingMarker), Key = key,); data } None => return Ok(None), @@ -99,7 +96,7 @@ impl BlobStore { Store::MySQL(store) => store.put_blob(key, data.as_ref()).await, #[cfg(feature = "rocks")] Store::RocksDb(store) => store.put_blob(key, data.as_ref()).await, - Store::None => Err(trc::StoreCause::NotConfigured.into()), + Store::None => Err(trc::StoreEvent::NotConfigured.into()), }, BlobBackend::Fs(store) => store.put_blob(key, data.as_ref()).await, #[cfg(feature = "s3")] @@ -121,7 +118,7 @@ impl BlobStore { Store::MySQL(store) => store.delete_blob(key).await, #[cfg(feature = "rocks")] Store::RocksDb(store) => store.delete_blob(key).await, - Store::None => Err(trc::StoreCause::NotConfigured.into()), + Store::None => Err(trc::StoreEvent::NotConfigured.into()), }, BlobBackend::Fs(store) => store.delete_blob(key).await, #[cfg(feature = "s3")] diff --git a/crates/store/src/dispatch/lookup.rs b/crates/store/src/dispatch/lookup.rs index a00e6879..4a4194c9 100644 --- a/crates/store/src/dispatch/lookup.rs +++ b/crates/store/src/dispatch/lookup.rs @@ -32,11 +32,11 @@ impl LookupStore { LookupStore::Store(Store::PostgreSQL(store)) => store.query(query, ¶ms).await, #[cfg(feature = "mysql")] LookupStore::Store(Store::MySQL(store)) => store.query(query, ¶ms).await, - _ => Err(trc::StoreCause::NotSupported.into_err()), + _ => Err(trc::StoreEvent::NotSupported.into_err()), }; trc::event!( - SqlQuery, + Store(trc::StoreEvent::SqlQuery), Query = query.to_string(), Parameters = params.as_slice(), Result = &result, @@ -76,7 +76,7 @@ impl LookupStore { ) .await .map(|_| ()), - LookupStore::Memory(_) => Err(trc::StoreCause::NotSupported.into_err()), + LookupStore::Memory(_) => Err(trc::StoreEvent::NotSupported.into_err()), } .caused_by(trc::location!()) } @@ -125,7 +125,7 @@ impl LookupStore { #[cfg(feature = "redis")] LookupStore::Redis(store) => store.key_incr(key, value, expires).await, LookupStore::Query(_) | LookupStore::Memory(_) => { - Err(trc::StoreCause::NotSupported.into_err()) + Err(trc::StoreEvent::NotSupported.into_err()) } } .caused_by(trc::location!()) @@ -144,7 +144,7 @@ impl LookupStore { #[cfg(feature = "redis")] LookupStore::Redis(store) => store.key_delete(key).await, LookupStore::Query(_) | LookupStore::Memory(_) => { - Err(trc::StoreCause::NotSupported.into_err()) + Err(trc::StoreEvent::NotSupported.into_err()) } } .caused_by(trc::location!()) @@ -163,7 +163,7 @@ impl LookupStore { #[cfg(feature = "redis")] LookupStore::Redis(store) => store.key_delete(key).await, LookupStore::Query(_) | LookupStore::Memory(_) => { - Err(trc::StoreCause::NotSupported.into_err()) + Err(trc::StoreEvent::NotSupported.into_err()) } } .caused_by(trc::location!()) @@ -212,7 +212,7 @@ impl LookupStore { #[cfg(feature = "redis")] LookupStore::Redis(store) => store.counter_get(key).await, LookupStore::Query(_) | LookupStore::Memory(_) => { - Err(trc::StoreCause::NotSupported.into_err()) + Err(trc::StoreEvent::NotSupported.into_err()) } } .caused_by(trc::location!()) diff --git a/crates/store/src/dispatch/store.rs b/crates/store/src/dispatch/store.rs index badccd41..1588a965 100644 --- a/crates/store/src/dispatch/store.rs +++ b/crates/store/src/dispatch/store.rs @@ -43,7 +43,7 @@ impl Store { Self::MySQL(store) => store.get_value(key).await, #[cfg(feature = "rocks")] Self::RocksDb(store) => store.get_value(key).await, - Self::None => Err(trc::StoreCause::NotConfigured.into()), + Self::None => Err(trc::StoreEvent::NotConfigured.into()), } .caused_by(trc::location!()) } @@ -63,7 +63,7 @@ impl Store { Self::MySQL(store) => store.get_bitmap(key).await, #[cfg(feature = "rocks")] Self::RocksDb(store) => store.get_bitmap(key).await, - Self::None => Err(trc::StoreCause::NotConfigured.into()), + Self::None => Err(trc::StoreEvent::NotConfigured.into()), } .caused_by(trc::location!()) } @@ -106,7 +106,7 @@ impl Store { Self::MySQL(store) => store.iterate(params, cb).await, #[cfg(feature = "rocks")] Self::RocksDb(store) => store.iterate(params, cb).await, - Self::None => Err(trc::StoreCause::NotConfigured.into()), + Self::None => Err(trc::StoreEvent::NotConfigured.into()), } .caused_by(trc::location!()) } @@ -126,7 +126,7 @@ impl Store { Self::MySQL(store) => store.get_counter(key).await, #[cfg(feature = "rocks")] Self::RocksDb(store) => store.get_counter(key).await, - Self::None => Err(trc::StoreCause::NotConfigured.into()), + Self::None => Err(trc::StoreEvent::NotConfigured.into()), } .caused_by(trc::location!()) } @@ -189,7 +189,7 @@ impl Store { Self::MySQL(store) => store.write(batch).await, #[cfg(feature = "rocks")] Self::RocksDb(store) => store.write(batch).await, - Self::None => Err(trc::StoreCause::NotConfigured.into()), + Self::None => Err(trc::StoreEvent::NotConfigured.into()), } .caused_by(trc::location!())?; @@ -231,7 +231,7 @@ impl Store { Self::MySQL(store) => store.write(batch).await, #[cfg(feature = "rocks")] Self::RocksDb(store) => store.write(batch).await, - Self::None => Err(trc::StoreCause::NotConfigured.into()), + Self::None => Err(trc::StoreEvent::NotConfigured.into()), } } @@ -277,7 +277,7 @@ impl Store { Self::MySQL(store) => store.purge_store().await, #[cfg(feature = "rocks")] Self::RocksDb(store) => store.purge_store().await, - Self::None => Err(trc::StoreCause::NotConfigured.into()), + Self::None => Err(trc::StoreEvent::NotConfigured.into()), } .caused_by(trc::location!()) } @@ -294,7 +294,7 @@ impl Store { Self::MySQL(store) => store.delete_range(from, to).await, #[cfg(feature = "rocks")] Self::RocksDb(store) => store.delete_range(from, to).await, - Self::None => Err(trc::StoreCause::NotConfigured.into()), + Self::None => Err(trc::StoreEvent::NotConfigured.into()), } .caused_by(trc::location!()) } @@ -447,7 +447,7 @@ impl Store { Self::MySQL(store) => store.get_blob(key, range).await, #[cfg(feature = "rocks")] Self::RocksDb(store) => store.get_blob(key, range).await, - Self::None => Err(trc::StoreCause::NotConfigured.into()), + Self::None => Err(trc::StoreEvent::NotConfigured.into()), } .caused_by(trc::location!()) } @@ -464,7 +464,7 @@ impl Store { Self::MySQL(store) => store.put_blob(key, data).await, #[cfg(feature = "rocks")] Self::RocksDb(store) => store.put_blob(key, data).await, - Self::None => Err(trc::StoreCause::NotConfigured.into()), + Self::None => Err(trc::StoreEvent::NotConfigured.into()), } .caused_by(trc::location!()) } @@ -481,7 +481,7 @@ impl Store { Self::MySQL(store) => store.delete_blob(key).await, #[cfg(feature = "rocks")] Self::RocksDb(store) => store.delete_blob(key).await, - Self::None => Err(trc::StoreCause::NotConfigured.into()), + Self::None => Err(trc::StoreEvent::NotConfigured.into()), } .caused_by(trc::location!()) } diff --git a/crates/store/src/query/acl.rs b/crates/store/src/query/acl.rs index 53d5c088..79629584 100644 --- a/crates/store/src/query/acl.rs +++ b/crates/store/src/query/acl.rs @@ -149,7 +149,7 @@ impl Deserialize for AclItem { to_account_id: bytes.deserialize_be_u32(U32_LEN)?, to_collection: *bytes .get(U32_LEN * 2) - .ok_or_else(|| trc::StoreCause::DataCorruption.caused_by(trc::location!()))?, + .ok_or_else(|| trc::StoreEvent::DataCorruption.caused_by(trc::location!()))?, to_document_id: bytes.deserialize_be_u32((U32_LEN * 2) + 1)?, permissions: 0, }) diff --git a/crates/store/src/write/key.rs b/crates/store/src/write/key.rs index fff9a816..975d2b1c 100644 --- a/crates/store/src/write/key.rs +++ b/crates/store/src/write/key.rs @@ -102,13 +102,13 @@ impl DeserializeBigEndian for &[u8] { fn deserialize_be_u32(&self, index: usize) -> trc::Result { self.get(index..index + U32_LEN) .ok_or_else(|| { - trc::StoreCause::DataCorruption + trc::StoreEvent::DataCorruption .caused_by(trc::location!()) .ctx(trc::Key::Value, *self) }) .and_then(|bytes| { bytes.try_into().map_err(|_| { - trc::StoreCause::DataCorruption + trc::StoreEvent::DataCorruption .caused_by(trc::location!()) .ctx(trc::Key::Value, *self) }) @@ -119,13 +119,13 @@ impl DeserializeBigEndian for &[u8] { fn deserialize_be_u64(&self, index: usize) -> trc::Result { self.get(index..index + U64_LEN) .ok_or_else(|| { - trc::StoreCause::DataCorruption + trc::StoreEvent::DataCorruption .caused_by(trc::location!()) .ctx(trc::Key::Value, *self) }) .and_then(|bytes| { bytes.try_into().map_err(|_| { - trc::StoreCause::DataCorruption + trc::StoreEvent::DataCorruption .caused_by(trc::location!()) .ctx(trc::Key::Value, *self) }) @@ -644,7 +644,7 @@ impl Deserialize for ReportEvent { .and_then(|domain| std::str::from_utf8(domain).ok()) .map(|s| s.to_string()) .ok_or_else(|| { - trc::StoreCause::DataCorruption + trc::StoreEvent::DataCorruption .caused_by(trc::location!()) .ctx(trc::Key::Key, key) })?, diff --git a/crates/store/src/write/mod.rs b/crates/store/src/write/mod.rs index f59fdc0f..29b1d022 100644 --- a/crates/store/src/write/mod.rs +++ b/crates/store/src/write/mod.rs @@ -346,7 +346,7 @@ impl Deserialize for String { impl Deserialize for u64 { fn deserialize(bytes: &[u8]) -> trc::Result { Ok(u64::from_be_bytes(bytes.try_into().map_err(|_| { - trc::StoreCause::DataCorruption.caused_by(trc::location!()) + trc::StoreEvent::DataCorruption.caused_by(trc::location!()) })?)) } } @@ -354,7 +354,7 @@ impl Deserialize for u64 { impl Deserialize for i64 { fn deserialize(bytes: &[u8]) -> trc::Result { Ok(i64::from_be_bytes(bytes.try_into().map_err(|_| { - trc::StoreCause::DataCorruption.caused_by(trc::location!()) + trc::StoreEvent::DataCorruption.caused_by(trc::location!()) })?)) } } @@ -362,7 +362,7 @@ impl Deserialize for i64 { impl Deserialize for u32 { fn deserialize(bytes: &[u8]) -> trc::Result { Ok(u32::from_be_bytes(bytes.try_into().map_err(|_| { - trc::StoreCause::DataCorruption.caused_by(trc::location!()) + trc::StoreEvent::DataCorruption.caused_by(trc::location!()) })?)) } } @@ -456,12 +456,12 @@ impl Deserialize for Vec { let mut bytes = bytes.iter(); let len: usize = bytes .next_leb128() - .ok_or_else(|| trc::StoreCause::DataCorruption.caused_by(trc::location!()))?; + .ok_or_else(|| trc::StoreEvent::DataCorruption.caused_by(trc::location!()))?; let mut list = Vec::with_capacity(len); for _ in 0..len { list.push( T::deserialize_from(&mut bytes) - .ok_or_else(|| trc::StoreCause::DataCorruption.caused_by(trc::location!()))?, + .ok_or_else(|| trc::StoreEvent::DataCorruption.caused_by(trc::location!()))?, ); } Ok(list) @@ -686,13 +686,13 @@ impl De fn deserialize(bytes: &[u8]) -> trc::Result { lz4_flex::decompress_size_prepended(bytes) .map_err(|err| { - trc::StoreCause::Decompress + trc::StoreEvent::DecompressError .caused_by(trc::location!()) .reason(err) }) .and_then(|result| { bincode::deserialize(&result).map_err(|err| { - trc::StoreCause::DataCorruption + trc::StoreEvent::DataCorruption .caused_by(trc::location!()) .reason(err) }) @@ -724,7 +724,7 @@ impl AssignedIds { pub fn get_document_id(&self, idx: usize) -> trc::Result { self.document_ids.get(idx).copied().ok_or_else(|| { - trc::StoreCause::Unexpected + trc::StoreEvent::UnexpectedError .caused_by(trc::location!()) .ctx(trc::Key::Reason, "No document ids were created") }) @@ -736,7 +736,7 @@ impl AssignedIds { pub fn last_document_id(&self) -> trc::Result { self.document_ids.last().copied().ok_or_else(|| { - trc::StoreCause::Unexpected + trc::StoreEvent::UnexpectedError .caused_by(trc::location!()) .ctx(trc::Key::Reason, "No document ids were created") }) @@ -744,7 +744,7 @@ impl AssignedIds { pub fn last_counter_id(&self) -> trc::Result { self.counter_ids.last().copied().ok_or_else(|| { - trc::StoreCause::Unexpected + trc::StoreEvent::UnexpectedError .caused_by(trc::location!()) .ctx(trc::Key::Reason, "No document ids were created") }) diff --git a/crates/trc/Cargo.toml b/crates/trc/Cargo.toml index fbe69793..9aa1963c 100644 --- a/crates/trc/Cargo.toml +++ b/crates/trc/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" resolver = "2" [dependencies] +mail-auth = { version = "0.4" } base64 = "0.22.1" serde_json = "1.0.120" reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]} diff --git a/crates/trc/src/collector.rs b/crates/trc/src/collector.rs index b3eb03e4..a56745d1 100644 --- a/crates/trc/src/collector.rs +++ b/crates/trc/src/collector.rs @@ -18,7 +18,7 @@ use arc_swap::ArcSwap; use crate::{ channel::{EVENT_COUNT, EVENT_RXS}, subscriber::{Subscriber, SUBSCRIBER_UPDATE}, - Event, EventType, Level, + Event, EventType, Level, ServerEvent, }; pub(crate) static TRACING_LEVEL: AtomicUsize = AtomicUsize::new(Level::Info as usize); @@ -84,7 +84,7 @@ impl Collector { } pub fn shutdown() { - Event::new(EventType::Error(crate::Cause::Thread), Level::Disable, 0).send() + Event::new(EventType::Server(ServerEvent::Shutdown), Level::Disable, 0).send() } } diff --git a/crates/trc/src/conv.rs b/crates/trc/src/conv.rs index fe3946c7..328e0a03 100644 --- a/crates/trc/src/conv.rs +++ b/crates/trc/src/conv.rs @@ -8,8 +8,8 @@ use std::{borrow::Cow, fmt::Debug}; use crate::*; -impl AsRef for Error { - fn as_ref(&self) -> &Cause { +impl AsRef for Error { + fn as_ref(&self) -> &EventType { &self.inner } } @@ -83,21 +83,21 @@ impl From for Value { } } -impl From for Error { - fn from(value: Cause) -> Self { +impl From for Error { + fn from(value: EventType) -> Self { Error::new(value) } } -impl From for Error { - fn from(value: StoreCause) -> Self { - Error::new(Cause::Store(value)) +impl From for Error { + fn from(value: StoreEvent) -> Self { + Error::new(EventType::Store(value)) } } -impl From for Error { - fn from(value: AuthCause) -> Self { - Error::new(Cause::Auth(value)) +impl From for Error { + fn from(value: AuthEvent) -> Self { + Error::new(EventType::Auth(value)) } } @@ -158,7 +158,7 @@ where } } -impl Cause { +impl EventType { pub fn from_io_error(self, err: std::io::Error) -> Error { self.reason(err).details("I/O error") } @@ -188,18 +188,95 @@ impl Cause { } } +impl From for Error { + fn from(err: mail_auth::Error) -> Self { + match err { + mail_auth::Error::ParseError => { + EventType::MailAuth(MailAuthEvent::ParseError).into_err() + } + mail_auth::Error::MissingParameters => { + EventType::MailAuth(MailAuthEvent::MissingParameters).into_err() + } + mail_auth::Error::NoHeadersFound => { + EventType::MailAuth(MailAuthEvent::NoHeadersFound).into_err() + } + mail_auth::Error::CryptoError(details) => EventType::MailAuth(MailAuthEvent::Crypto) + .into_err() + .details(details), + mail_auth::Error::Io(details) => EventType::MailAuth(MailAuthEvent::Io) + .into_err() + .details(details), + mail_auth::Error::Base64 => EventType::MailAuth(MailAuthEvent::Base64).into_err(), + mail_auth::Error::UnsupportedVersion => { + EventType::Dkim(DkimEvent::UnsupportedVersion).into_err() + } + mail_auth::Error::UnsupportedAlgorithm => { + EventType::Dkim(DkimEvent::UnsupportedAlgorithm).into_err() + } + mail_auth::Error::UnsupportedCanonicalization => { + EventType::Dkim(DkimEvent::UnsupportedCanonicalization).into_err() + } + mail_auth::Error::UnsupportedKeyType => { + EventType::Dkim(DkimEvent::UnsupportedKeyType).into_err() + } + mail_auth::Error::FailedBodyHashMatch => { + EventType::Dkim(DkimEvent::FailedBodyHashMatch).into_err() + } + mail_auth::Error::FailedVerification => { + EventType::Dkim(DkimEvent::FailedVerification).into_err() + } + mail_auth::Error::FailedAuidMatch => { + EventType::Dkim(DkimEvent::FailedAuidMatch).into_err() + } + mail_auth::Error::RevokedPublicKey => { + EventType::Dkim(DkimEvent::RevokedPublicKey).into_err() + } + mail_auth::Error::IncompatibleAlgorithms => { + EventType::Dkim(DkimEvent::IncompatibleAlgorithms).into_err() + } + mail_auth::Error::SignatureExpired => { + EventType::Dkim(DkimEvent::SignatureExpired).into_err() + } + mail_auth::Error::SignatureLength => { + EventType::Dkim(DkimEvent::SignatureLength).into_err() + } + mail_auth::Error::DnsError(details) => EventType::MailAuth(MailAuthEvent::DnsError) + .into_err() + .details(details), + mail_auth::Error::DnsRecordNotFound(code) => { + EventType::MailAuth(MailAuthEvent::DnsRecordNotFound) + .into_err() + .code(code.to_str()) + } + mail_auth::Error::ArcChainTooLong => EventType::Arc(ArcEvent::ChainTooLong).into_err(), + mail_auth::Error::ArcInvalidInstance(instance) => { + EventType::Arc(ArcEvent::InvalidInstance).ctx(Key::Id, instance) + } + mail_auth::Error::ArcInvalidCV => EventType::Arc(ArcEvent::InvalidCV).into_err(), + mail_auth::Error::ArcHasHeaderTag => EventType::Arc(ArcEvent::HasHeaderTag).into_err(), + mail_auth::Error::ArcBrokenChain => EventType::Arc(ArcEvent::BrokenChain).into_err(), + mail_auth::Error::NotAligned => { + EventType::MailAuth(MailAuthEvent::PolicyNotAligned).into_err() + } + mail_auth::Error::InvalidRecordType => { + EventType::MailAuth(MailAuthEvent::DnsInvalidRecordType).into_err() + } + } + } +} + pub trait AssertSuccess where Self: Sized, { fn assert_success( self, - cause: Cause, + cause: EventType, ) -> impl std::future::Future> + Send; } impl AssertSuccess for reqwest::Response { - async fn assert_success(self, cause: Cause) -> crate::Result { + async fn assert_success(self, cause: EventType) -> crate::Result { let status = self.status(); if status.is_success() { Ok(self) diff --git a/crates/trc/src/imple.rs b/crates/trc/src/imple.rs index 257d6e4e..51425e34 100644 --- a/crates/trc/src/imple.rs +++ b/crates/trc/src/imple.rs @@ -4,7 +4,7 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ -use std::{borrow::Cow, cmp::Ordering, fmt::Display}; +use std::{borrow::Cow, cmp::Ordering, fmt::Display, str::FromStr}; use crate::*; @@ -32,7 +32,7 @@ impl Event { } impl Error { - pub fn new(inner: Cause) -> Self { + pub fn new(inner: EventType) -> Self { Self { inner, keys: Vec::with_capacity(5), @@ -45,6 +45,14 @@ impl Error { self } + #[inline(always)] + pub fn ctx_unique(mut self, key: Key, value: impl Into) -> Self { + if self.keys.iter().all(|(k, _)| *k != key) { + self.keys.push((key, value.into())); + } + self + } + pub fn ctx_opt(self, key: Key, value: Option>) -> Self { match value { Some(value) => self.ctx(key, value), @@ -53,7 +61,7 @@ impl Error { } #[inline(always)] - pub fn matches(&self, inner: Cause) -> bool { + pub fn matches(&self, inner: EventType) -> bool { self.inner == inner } @@ -128,14 +136,14 @@ impl Error { } pub fn corrupted_key(key: &[u8], value: Option<&[u8]>, caused_by: &'static str) -> Error { - Cause::Store(StoreCause::DataCorruption) + EventType::Store(StoreEvent::DataCorruption) .ctx(Key::Key, key) .ctx_opt(Key::Value, value) .ctx(Key::CausedBy, caused_by) } } -impl Cause { +impl EventType { #[inline(always)] pub fn ctx(self, key: Key, value: impl Into) -> Error { self.into_err().ctx(key, value) @@ -158,27 +166,24 @@ impl Cause { pub fn message(&self) -> &'static str { match self { - Self::Store(cause) => cause.message(), - Self::Jmap(cause) => cause.message(), - Self::Imap => "IMAP error", - Self::ManageSieve => "ManageSieve error", - Self::Pop3 => "POP3 error", - Self::Smtp => "SMTP error", - Self::Thread => "Thread error", - Self::Acme => "ACME error", - Self::Dns => "DNS error", - Self::Ingest => "Message Ingest error", - Self::Network => "Network error", - Self::Limit(cause) => cause.message(), - Self::Manage(cause) => cause.message(), - Self::Auth(cause) => cause.message(), - Self::Configuration => "Configuration error", - Self::Resource(cause) => cause.message(), + EventType::Store(cause) => cause.message(), + EventType::Jmap(cause) => cause.message(), + EventType::Imap(_) => "IMAP error", + EventType::ManageSieve(_) => "ManageSieve error", + EventType::Pop3(_) => "POP3 error", + EventType::Smtp(_) => "SMTP error", + EventType::Network(_) => "Network error", + EventType::Limit(cause) => cause.message(), + EventType::Manage(cause) => cause.message(), + EventType::Auth(cause) => cause.message(), + EventType::Config(_) => "Configuration error", + EventType::Resource(cause) => cause.message(), + _ => "Internal server error", } } } -impl StoreCause { +impl StoreEvent { #[inline(always)] pub fn ctx(self, key: Key, value: impl Into) -> Error { self.into_err().ctx(key, value) @@ -196,37 +201,39 @@ impl StoreCause { #[inline(always)] pub fn into_err(self) -> Error { - Error::new(Cause::Store(self)) + Error::new(EventType::Store(self)) } pub fn message(&self) -> &'static str { match self { - Self::AssertValue => "Another process has modified the value", + Self::AssertValueFailed => "Another process has modified the value", Self::BlobMissingMarker => "Blob is missing marker", - Self::FoundationDB => "FoundationDB error", - Self::MySQL => "MySQL error", - Self::PostgreSQL => "PostgreSQL error", - Self::RocksDB => "RocksDB error", - Self::SQLite => "SQLite error", - Self::Ldap => "LDAP error", - Self::ElasticSearch => "ElasticSearch error", - Self::Redis => "Redis error", - Self::S3 => "S3 error", - Self::Filesystem => "Filesystem error", - Self::Pool => "Connection pool error", + Self::FoundationDBError => "FoundationDB error", + Self::MySQLError => "MySQL error", + Self::PostgreSQLError => "PostgreSQL error", + Self::RocksDBError => "RocksDB error", + Self::SQLiteError => "SQLite error", + Self::LdapError => "LDAP error", + Self::ElasticSearchError => "ElasticSearch error", + Self::RedisError => "Redis error", + Self::S3Error => "S3 error", + Self::FilesystemError => "Filesystem error", + Self::PoolError => "Connection pool error", Self::DataCorruption => "Data corruption", - Self::Decompress => "Decompression error", - Self::Deserialize => "Deserialization error", + Self::DecompressError => "Decompression error", + Self::DeserializeError => "Deserialization error", Self::NotFound => "Not found", Self::NotConfigured => "Not configured", Self::NotSupported => "Operation not supported", - Self::Unexpected => "Unexpected error", - Self::Crypto => "Crypto error", + Self::UnexpectedError => "Unexpected error", + Self::CryptoError => "Crypto error", + Self::IngestError => "Message Ingest error", + _ => "Store error", } } } -impl AuthCause { +impl AuthEvent { #[inline(always)] pub fn ctx(self, key: Key, value: impl Into) -> Error { self.into_err().ctx(key, value) @@ -244,7 +251,7 @@ impl AuthCause { #[inline(always)] pub fn into_err(self) -> Error { - Error::new(Cause::Auth(self)) + Error::new(EventType::Auth(self)) } pub fn message(&self) -> &'static str { @@ -261,7 +268,7 @@ impl AuthCause { } } -impl ManageCause { +impl ManageEvent { #[inline(always)] pub fn ctx(self, key: Key, value: impl Into) -> Error { self.into_err().ctx(key, value) @@ -279,7 +286,7 @@ impl ManageCause { #[inline(always)] pub fn into_err(self) -> Error { - Error::new(Cause::Manage(self)) + Error::new(EventType::Manage(self)) } pub fn message(&self) -> &'static str { @@ -294,7 +301,7 @@ impl ManageCause { } } -impl JmapCause { +impl JmapEvent { #[inline(always)] pub fn ctx(self, key: Key, value: impl Into) -> Error { self.into_err().ctx(key, value) @@ -312,7 +319,7 @@ impl JmapCause { #[inline(always)] pub fn into_err(self) -> Error { - Error::new(Cause::Jmap(self)) + Error::new(EventType::Jmap(self)) } pub fn message(&self) -> &'static str { @@ -339,7 +346,7 @@ impl JmapCause { } } -impl LimitCause { +impl LimitEvent { #[inline(always)] pub fn ctx(self, key: Key, value: impl Into) -> Error { self.into_err().ctx(key, value) @@ -357,7 +364,7 @@ impl LimitCause { #[inline(always)] pub fn into_err(self) -> Error { - Error::new(Cause::Limit(self)) + Error::new(EventType::Limit(self)) } pub fn message(&self) -> &'static str { @@ -374,7 +381,7 @@ impl LimitCause { } } -impl ResourceCause { +impl ResourceEvent { #[inline(always)] pub fn ctx(self, key: Key, value: impl Into) -> Error { self.into_err().ctx(key, value) @@ -392,7 +399,7 @@ impl ResourceCause { #[inline(always)] pub fn into_err(self) -> Error { - Error::new(Cause::Resource(self)) + Error::new(EventType::Resource(self)) } pub fn message(&self) -> &'static str { @@ -404,22 +411,94 @@ impl ResourceCause { } } +impl SmtpEvent { + #[inline(always)] + pub fn ctx(self, key: Key, value: impl Into) -> Error { + self.into_err().ctx(key, value) + } + + #[inline(always)] + pub fn into_err(self) -> Error { + Error::new(EventType::Smtp(self)) + } +} + +impl ImapEvent { + #[inline(always)] + pub fn ctx(self, key: Key, value: impl Into) -> Error { + self.into_err().ctx(key, value) + } + + #[inline(always)] + pub fn into_err(self) -> Error { + Error::new(EventType::Imap(self)) + } + + #[inline(always)] + pub fn caused_by(self, error: impl Into) -> Error { + self.into_err().caused_by(error) + } + + #[inline(always)] + pub fn reason(self, error: impl Display) -> Error { + self.into_err().reason(error) + } +} + +impl Pop3Event { + #[inline(always)] + pub fn ctx(self, key: Key, value: impl Into) -> Error { + self.into_err().ctx(key, value) + } + + #[inline(always)] + pub fn into_err(self) -> Error { + Error::new(EventType::Pop3(self)) + } +} + +impl ManageSieveEvent { + #[inline(always)] + pub fn ctx(self, key: Key, value: impl Into) -> Error { + self.into_err().ctx(key, value) + } + + #[inline(always)] + pub fn into_err(self) -> Error { + Error::new(EventType::ManageSieve(self)) + } +} + +impl NetworkEvent { + #[inline(always)] + pub fn ctx(self, key: Key, value: impl Into) -> Error { + self.into_err().ctx(key, value) + } + + #[inline(always)] + pub fn into_err(self) -> Error { + Error::new(EventType::Network(self)) + } +} + impl Error { #[inline(always)] - pub fn wrap(self, cause: Cause) -> Self { + pub fn wrap(self, cause: EventType) -> Self { Error::new(cause).caused_by(self) } #[inline(always)] pub fn is_assertion_failure(&self) -> bool { - self.inner == Cause::Store(StoreCause::AssertValue) + self.inner == EventType::Store(StoreEvent::AssertValueFailed) } #[inline(always)] pub fn is_jmap_method_error(&self) -> bool { !matches!( self.inner, - Cause::Jmap(JmapCause::UnknownCapability | JmapCause::NotJSON | JmapCause::NotRequest) + EventType::Jmap( + JmapEvent::UnknownCapability | JmapEvent::NotJSON | JmapEvent::NotRequest + ) ) } @@ -427,15 +506,18 @@ impl Error { pub fn must_disconnect(&self) -> bool { matches!( self.inner, - Cause::Network - | Cause::Auth(AuthCause::TooManyAttempts | AuthCause::Banned) - | Cause::Limit(LimitCause::ConcurrentRequest | LimitCause::TooManyRequests) + EventType::Network(_) + | EventType::Auth(AuthEvent::TooManyAttempts | AuthEvent::Banned) + | EventType::Limit(LimitEvent::ConcurrentRequest | LimitEvent::TooManyRequests) ) } #[inline(always)] pub fn should_write_err(&self) -> bool { - !matches!(self.inner, Cause::Network | Cause::Auth(AuthCause::Banned)) + !matches!( + self.inner, + EventType::Network(_) | EventType::Auth(AuthEvent::Banned) + ) } } @@ -572,57 +654,147 @@ impl PartialEq for Error { } } +impl FromStr for Level { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match s.to_ascii_lowercase().as_str() { + "disable" => Ok(Self::Disable), + "trace" => Ok(Self::Trace), + "debug" => Ok(Self::Debug), + "info" => Ok(Self::Info), + "warn" => Ok(Self::Warn), + "error" => Ok(Self::Error), + _ => Err(s.to_string()), + } + } +} + +impl Level { + pub fn as_str(&self) -> &'static str { + match self { + Self::Disable => "DISABLE", + Self::Trace => "TRACE", + Self::Debug => "DEBUG", + Self::Info => "INFO", + Self::Warn => "WARN", + Self::Error => "ERROR", + } + } +} + +impl Display for Level { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.as_str().fmt(f) + } +} + impl Eq for Error {} impl EventType { pub fn level(&self) -> Level { match self { - EventType::Error(error) => match error { - Cause::Store(_) => Level::Error, - Cause::Jmap(_) => Level::Debug, - Cause::Imap => Level::Debug, - Cause::ManageSieve => Level::Debug, - Cause::Pop3 => Level::Debug, - Cause::Smtp => Level::Debug, - Cause::Thread => Level::Error, - Cause::Acme => Level::Error, - Cause::Dns => Level::Error, - Cause::Ingest => Level::Error, - Cause::Network => Level::Debug, - Cause::Limit(cause) => match cause { - LimitCause::SizeRequest => Level::Debug, - LimitCause::SizeUpload => Level::Debug, - LimitCause::CallsIn => Level::Debug, - LimitCause::ConcurrentRequest => Level::Debug, - LimitCause::ConcurrentUpload => Level::Debug, - LimitCause::Quota => Level::Debug, - LimitCause::BlobQuota => Level::Debug, - LimitCause::TooManyRequests => Level::Warn, - }, - Cause::Manage(_) => Level::Debug, - Cause::Auth(cause) => match cause { - AuthCause::Failed => Level::Debug, - AuthCause::MissingTotp => Level::Trace, - AuthCause::TooManyAttempts => Level::Warn, - AuthCause::Banned => Level::Warn, - AuthCause::Error => Level::Error, - }, - Cause::Configuration => Level::Error, - Cause::Resource(cause) => match cause { - ResourceCause::NotFound => Level::Debug, - ResourceCause::BadParameters => Level::Error, - ResourceCause::Error => Level::Error, - }, + EventType::Store(event) => match event { + StoreEvent::SqlQuery | StoreEvent::LdapQuery => Level::Trace, + _ => Level::Error, }, - EventType::NewConnection => Level::Info, - EventType::SqlQuery => Level::Trace, - EventType::LdapQuery => Level::Trace, + EventType::Jmap(_) => Level::Debug, + EventType::Imap(event) => match event { + ImapEvent::Error => Level::Debug, + }, + EventType::ManageSieve(event) => match event { + ManageSieveEvent::Error => Level::Debug, + }, + EventType::Pop3(event) => match event { + Pop3Event::Error => Level::Debug, + }, + EventType::Smtp(event) => match event { + SmtpEvent::Error => Level::Debug, + }, + EventType::Network(event) => match event { + NetworkEvent::ReadError + | NetworkEvent::WriteError + | NetworkEvent::FlushError + | NetworkEvent::Closed => Level::Trace, + NetworkEvent::Timeout => Level::Debug, + }, + EventType::Limit(cause) => match cause { + LimitEvent::SizeRequest => Level::Debug, + LimitEvent::SizeUpload => Level::Debug, + LimitEvent::CallsIn => Level::Debug, + LimitEvent::ConcurrentRequest => Level::Debug, + LimitEvent::ConcurrentUpload => Level::Debug, + LimitEvent::Quota => Level::Debug, + LimitEvent::BlobQuota => Level::Debug, + LimitEvent::TooManyRequests => Level::Warn, + }, + EventType::Manage(_) => Level::Debug, + EventType::Auth(cause) => match cause { + AuthEvent::Failed => Level::Debug, + AuthEvent::MissingTotp => Level::Trace, + AuthEvent::TooManyAttempts => Level::Warn, + AuthEvent::Banned => Level::Warn, + AuthEvent::Error => Level::Error, + }, + EventType::Config(cause) => match cause { + ConfigEvent::ParseError => Level::Error, + ConfigEvent::BuildError => Level::Error, + ConfigEvent::MacroError => Level::Error, + ConfigEvent::WriteError => Level::Error, + ConfigEvent::FetchError => Level::Error, + ConfigEvent::DefaultApplied => Level::Debug, + ConfigEvent::MissingSetting => Level::Debug, + ConfigEvent::UnusedSetting => Level::Debug, + ConfigEvent::ParseWarning => Level::Debug, + ConfigEvent::BuildWarning => Level::Debug, + }, + EventType::Resource(cause) => match cause { + ResourceEvent::NotFound => Level::Debug, + ResourceEvent::BadParameters => Level::Error, + ResourceEvent::Error => Level::Error, + }, + EventType::Arc(_) => Level::Debug, + EventType::Dkim(_) => Level::Debug, + EventType::MailAuth(_) => Level::Debug, EventType::Purge(event) => match event { PurgeEvent::Started => Level::Debug, PurgeEvent::Finished => Level::Debug, PurgeEvent::Running => Level::Info, PurgeEvent::Error => Level::Error, }, + EventType::Eval(event) => match event { + EvalEvent::Result => Level::Trace, + EvalEvent::Error => Level::Error, + }, + EventType::Server(event) => match event { + ServerEvent::Startup => Level::Info, + ServerEvent::Shutdown => Level::Info, + ServerEvent::Licensing => Level::Info, + ServerEvent::StartupError => Level::Error, + ServerEvent::ThreadError => Level::Error, + }, + EventType::Acme(event) => match event { + AcmeEvent::DnsRecordCreated => Level::Info, + AcmeEvent::DnsRecordNotPropagated => Level::Debug, + AcmeEvent::DnsRecordLookupFailed => Level::Debug, + AcmeEvent::DnsRecordPropagated => Level::Info, + AcmeEvent::DnsRecordPropagationTimeout => Level::Warn, + AcmeEvent::AuthStart => Level::Info, + AcmeEvent::AuthPending => Level::Info, + AcmeEvent::AuthValid => Level::Info, + AcmeEvent::AuthCompleted => Level::Info, + AcmeEvent::ProcessCert => Level::Info, + AcmeEvent::OrderProcessing => Level::Info, + AcmeEvent::OrderReady => Level::Info, + AcmeEvent::OrderValid => Level::Info, + AcmeEvent::OrderInvalid => Level::Warn, + AcmeEvent::RenewBackoff => Level::Debug, + AcmeEvent::Error => Level::Error, + AcmeEvent::AuthError => Level::Warn, + AcmeEvent::AuthTooManyAttempts => Level::Warn, + AcmeEvent::DnsRecordCreationFailed => Level::Warn, + AcmeEvent::DnsRecordDeletionFailed => Level::Debug, + }, } } } diff --git a/crates/trc/src/lib.rs b/crates/trc/src/lib.rs index 1f8976fe..772ec146 100644 --- a/crates/trc/src/lib.rs +++ b/crates/trc/src/lib.rs @@ -18,12 +18,12 @@ pub type Result = std::result::Result; #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] #[repr(usize)] pub enum Level { - Disable = 0, - Trace = 1, - Debug = 2, - Info = 3, - Warn = 4, - Error = 5, + Disable, + Trace, + Debug, + Info, + Warn, + Error, } #[derive(Debug, Default, Clone)] @@ -33,6 +33,7 @@ pub enum Value { UInt(u64), Int(i64), Float(f64), + Timestamp(u64), Bytes(Vec), Bool(bool), Ipv4(Ipv4Addr), @@ -66,18 +67,104 @@ pub enum Key { Property, Path, Url, + Name, DocumentId, Collection, AccountId, + SessionId, + Hostname, + ValidFrom, + ValidTo, + Origin, + Expected, + Renewal, + Attempt, + NextRetry, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum EventType { - NewConnection, - Error(Cause), - SqlQuery, - LdapQuery, + Server(ServerEvent), Purge(PurgeEvent), + Eval(EvalEvent), + Acme(AcmeEvent), + Store(StoreEvent), + Jmap(JmapEvent), + Imap(ImapEvent), + ManageSieve(ManageSieveEvent), + Pop3(Pop3Event), + Smtp(SmtpEvent), + Network(NetworkEvent), + Limit(LimitEvent), + Manage(ManageEvent), + Auth(AuthEvent), + Config(ConfigEvent), + Resource(ResourceEvent), + Arc(ArcEvent), + Dkim(DkimEvent), + MailAuth(MailAuthEvent), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ImapEvent { + Error, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Pop3Event { + Error, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ManageSieveEvent { + Error, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum SmtpEvent { + Error, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum NetworkEvent { + ReadError, + WriteError, + FlushError, + Timeout, + Closed, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ServerEvent { + Startup, + Shutdown, + StartupError, + ThreadError, + Licensing, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum AcmeEvent { + AuthStart, + AuthPending, + AuthValid, + AuthCompleted, + AuthError, + AuthTooManyAttempts, + ProcessCert, + OrderProcessing, + OrderReady, + OrderValid, + OrderInvalid, + RenewBackoff, + DnsRecordCreated, + DnsRecordCreationFailed, + DnsRecordDeletionFailed, + DnsRecordNotPropagated, + DnsRecordLookupFailed, + DnsRecordPropagated, + DnsRecordPropagationTimeout, + Error, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -89,111 +176,157 @@ pub enum PurgeEvent { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Cause { - Store(StoreCause), - Jmap(JmapCause), - Imap, - ManageSieve, - Pop3, - Smtp, - Thread, - Acme, - Dns, - Ingest, - Network, - Limit(LimitCause), - Manage(ManageCause), - Auth(AuthCause), - Configuration, - Resource(ResourceCause), +pub enum EvalEvent { + Result, + Error, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum StoreCause { - AssertValue = 0, - BlobMissingMarker = 1, - FoundationDB = 2, - MySQL = 3, - PostgreSQL = 4, - RocksDB = 5, - SQLite = 6, - Ldap = 7, - ElasticSearch = 8, - Redis = 9, - S3 = 10, - Filesystem = 11, - Pool = 12, - DataCorruption = 13, - Decompress = 14, - Deserialize = 15, - NotFound = 16, - NotConfigured = 17, - NotSupported = 18, - Unexpected = 19, - Crypto = 20, +pub enum ConfigEvent { + ParseError, + BuildError, + MacroError, + WriteError, + FetchError, + DefaultApplied, + MissingSetting, + UnusedSetting, + ParseWarning, + BuildWarning, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum JmapCause { +pub enum ArcEvent { + ChainTooLong, + InvalidInstance, + InvalidCV, + HasHeaderTag, + BrokenChain, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum DkimEvent { + UnsupportedVersion, + UnsupportedAlgorithm, + UnsupportedCanonicalization, + UnsupportedKeyType, + FailedBodyHashMatch, + FailedVerification, + FailedAuidMatch, + RevokedPublicKey, + IncompatibleAlgorithms, + SignatureExpired, + SignatureLength, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum MailAuthEvent { + ParseError, + MissingParameters, + NoHeadersFound, + Crypto, + Io, + Base64, + DnsError, + DnsRecordNotFound, + DnsInvalidRecordType, + PolicyNotAligned, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum StoreEvent { + // Errors + IngestError, + AssertValueFailed, + FoundationDBError, + MySQLError, + PostgreSQLError, + RocksDBError, + SQLiteError, + LdapError, + ElasticSearchError, + RedisError, + S3Error, + FilesystemError, + PoolError, + DataCorruption, + DecompressError, + DeserializeError, + NotFound, + NotConfigured, + NotSupported, + UnexpectedError, + CryptoError, + + // Warnings + BlobMissingMarker, + + // Traces + SqlQuery, + LdapQuery, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum JmapEvent { // Method errors - InvalidArguments = 0, - RequestTooLarge = 1, - StateMismatch = 2, - AnchorNotFound = 3, - UnsupportedFilter = 4, - UnsupportedSort = 5, - UnknownMethod = 6, - InvalidResultReference = 7, - Forbidden = 8, - AccountNotFound = 9, - AccountNotSupportedByMethod = 10, - AccountReadOnly = 11, - NotFound = 12, - CannotCalculateChanges = 13, - UnknownDataType = 14, + InvalidArguments, + RequestTooLarge, + StateMismatch, + AnchorNotFound, + UnsupportedFilter, + UnsupportedSort, + UnknownMethod, + InvalidResultReference, + Forbidden, + AccountNotFound, + AccountNotSupportedByMethod, + AccountReadOnly, + NotFound, + CannotCalculateChanges, + UnknownDataType, // Request errors - UnknownCapability = 15, - NotJSON = 16, - NotRequest = 17, + UnknownCapability, + NotJSON, + NotRequest, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum LimitCause { - SizeRequest = 0, - SizeUpload = 1, - CallsIn = 2, - ConcurrentRequest = 3, - ConcurrentUpload = 4, - Quota = 5, - BlobQuota = 6, - TooManyRequests = 7, +pub enum LimitEvent { + SizeRequest, + SizeUpload, + CallsIn, + ConcurrentRequest, + ConcurrentUpload, + Quota, + BlobQuota, + TooManyRequests, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum ManageCause { - MissingParameter = 0, - AlreadyExists = 1, - AssertFailed = 2, - NotFound = 3, - NotSupported = 4, - Error = 5, +pub enum ManageEvent { + MissingParameter, + AlreadyExists, + AssertFailed, + NotFound, + NotSupported, + Error, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum AuthCause { - Failed = 0, - MissingTotp = 1, - TooManyAttempts = 2, - Banned = 3, - Error = 4, +pub enum AuthEvent { + Failed, + MissingTotp, + TooManyAttempts, + Banned, + Error, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum ResourceCause { - NotFound = 0, - BadParameters = 1, - Error = 2, +pub enum ResourceEvent { + NotFound, + BadParameters, + Error, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -208,7 +341,7 @@ pub enum Protocol { #[derive(Debug, Clone)] pub struct Error { - inner: Cause, + inner: EventType, keys: Vec<(Key, Value)>, } diff --git a/crates/trc/src/subscriber.rs b/crates/trc/src/subscriber.rs index 6442ae7e..72714025 100644 --- a/crates/trc/src/subscriber.rs +++ b/crates/trc/src/subscriber.rs @@ -10,7 +10,7 @@ use ahash::AHashSet; use parking_lot::Mutex; use tokio::sync::mpsc::{self, error::TrySendError}; -use crate::{channel::ChannelError, Event, EventType, Level}; +use crate::{channel::ChannelError, Event, EventType, Level, ServerEvent}; const MAX_BATCH_SIZE: usize = 32768; @@ -93,7 +93,7 @@ impl SubscriberBuilder { }); // Notify collector - Event::new(EventType::Error(crate::Cause::Thread), Level::Info, 0).send(); + Event::new(EventType::Server(ServerEvent::Startup), Level::Info, 0).send(); rx } diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml index 4cf0e1d6..ef1b386b 100644 --- a/crates/utils/Cargo.toml +++ b/crates/utils/Cargo.toml @@ -12,7 +12,6 @@ rustls-pki-types = { version = "1" } tokio = { version = "1.23", features = ["net", "macros"] } tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] } serde = { version = "1.0", features = ["derive"]} -tracing = "0.1" mail-auth = { version = "0.4" } smtp-proto = { version = "0.1" } mail-send = { version = "0.4", default-features = false, features = ["cram-md5", "ring", "tls12"] } diff --git a/crates/utils/src/config/mod.rs b/crates/utils/src/config/mod.rs index 356cdbd7..3f98807c 100644 --- a/crates/utils/src/config/mod.rs +++ b/crates/utils/src/config/mod.rs @@ -173,19 +173,22 @@ impl Config { pub fn log_errors(&self, use_stderr: bool) { for (key, err) in &self.errors { - let message = match err { - ConfigError::Parse { error } => { - format!("Failed to parse setting {key:?}: {error}") - } - ConfigError::Build { error } => { - format!("Build error for key {key:?}: {error}") - } - ConfigError::Macro { error } => { - format!("Macro expansion error for setting {key:?}: {error}") - } + let (cause, message) = match err { + ConfigError::Parse { error } => ( + trc::ConfigEvent::ParseError, + format!("Failed to parse setting {key:?}: {error}"), + ), + ConfigError::Build { error } => ( + trc::ConfigEvent::BuildError, + format!("Build error for key {key:?}: {error}"), + ), + ConfigError::Macro { error } => ( + trc::ConfigEvent::MacroError, + format!("Macro expansion error for setting {key:?}: {error}"), + ), }; if !use_stderr { - tracing::error!("{}", message); + trc::event!(Config(cause), Details = message); } else { eprintln!("ERROR: {message}"); } @@ -197,23 +200,30 @@ impl Config { self.warn_unread_keys(); for (key, warn) in &self.warnings { - let message = match warn { - ConfigWarning::AppliedDefault { default } => { - format!("WARNING: Missing setting {key:?}, applied default {default:?}") - } - ConfigWarning::Missing => { - format!("WARNING: Missing setting {key:?}") - } - ConfigWarning::Unread { value } => { - format!("WARNING: Unused setting {key:?} with value {value:?}") - } - ConfigWarning::Parse { error } => { - format!("WARNING: Failed to parse {key:?}: {error}") - } - ConfigWarning::Build { error } => format!("WARNING for {key:?}: {error}"), + let (cause, message) = match warn { + ConfigWarning::AppliedDefault { default } => ( + trc::ConfigEvent::DefaultApplied, + format!("WARNING: Missing setting {key:?}, applied default {default:?}"), + ), + ConfigWarning::Missing => ( + trc::ConfigEvent::MissingSetting, + format!("WARNING: Missing setting {key:?}"), + ), + ConfigWarning::Unread { value } => ( + trc::ConfigEvent::UnusedSetting, + format!("WARNING: Unused setting {key:?} with value {value:?}"), + ), + ConfigWarning::Parse { error } => ( + trc::ConfigEvent::ParseWarning, + format!("WARNING: Failed to parse {key:?}: {error}"), + ), + ConfigWarning::Build { error } => ( + trc::ConfigEvent::BuildWarning, + format!("WARNING for {key:?}: {error}"), + ), }; if !use_stderr { - tracing::debug!("{}", message); + trc::event!(Config(cause), Details = message); } else { eprintln!("{}", message); } diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 35359d7a..7b7f6cf9 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -91,7 +91,10 @@ impl UnwrapFailure for Option { match self { Some(result) => result, None => { - tracing::error!("{message}"); + trc::event!( + Server(trc::ServerEvent::StartupError), + Details = message.to_string() + ); eprintln!("{message}"); std::process::exit(1); } @@ -104,7 +107,11 @@ impl UnwrapFailure for Result { match self { Ok(result) => result, Err(err) => { - tracing::error!("{message}: {err}"); + trc::event!( + Server(trc::ServerEvent::StartupError), + Details = message.to_string(), + Reason = err.to_string() + ); #[cfg(feature = "test_mode")] panic!("{message}: {err}"); @@ -120,36 +127,48 @@ impl UnwrapFailure for Result { } pub fn failed(message: &str) -> ! { - tracing::error!("{message}"); + trc::event!( + Server(trc::ServerEvent::StartupError), + Details = message.to_string(), + ); eprintln!("{message}"); std::process::exit(1); } pub async fn wait_for_shutdown(message: &str) { #[cfg(not(target_env = "msvc"))] - { + let signal = { use tokio::signal::unix::{signal, SignalKind}; let mut h_term = signal(SignalKind::terminate()).failed("start signal handler"); let mut h_int = signal(SignalKind::interrupt()).failed("start signal handler"); tokio::select! { - _ = h_term.recv() => tracing::debug!("Received SIGTERM."), - _ = h_int.recv() => tracing::debug!("Received SIGINT."), - }; - } + _ = h_term.recv() => "SIGTERM", + _ = h_int.recv() => "SIGINT", + } + }; #[cfg(target_env = "msvc")] - { + let signal = { match tokio::signal::ctrl_c().await { - Ok(()) => {} + Ok(()) => "SIGINT", Err(err) => { - eprintln!("Unable to listen for shutdown signal: {}", err); + trc::event!( + Server(trc::ServerEvent::Error), + Details = "Unable to listen for shutdown signal", + Reason = err.to_string(), + ); + "Error" } } - } + }; - tracing::info!(message); + trc::event!( + Server(trc::ServerEvent::Shutdown), + Details = message.to_string(), + CausedBy = signal + ); } pub fn rustls_client_config(allow_invalid_certs: bool) -> ClientConfig { diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 1fd16a7e..b85de775 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -46,7 +46,6 @@ rayon = { version = "1.5.1" } flate2 = { version = "1.0.17", features = ["zlib"], default-features = false } serde = { version = "1.0", features = ["derive"]} serde_json = "1.0" -tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "multipart", "http2"]} bytes = "1.4.0" diff --git a/tests/src/directory/smtp.rs b/tests/src/directory/smtp.rs index abc30fb9..92415e4b 100644 --- a/tests/src/directory/smtp.rs +++ b/tests/src/directory/smtp.rs @@ -88,7 +88,7 @@ async fn lmtp_directory() { Item::Verify(v) => match core.vrfy(&handle, v).await { Ok(v) => v.into(), Err(e) => { - if e.matches(trc::Cause::Store(trc::StoreCause::NotSupported)) { + if e.matches(trc::EventType::Store(trc::StoreEvent::NotSupported)) { LookupResult::False } else { panic!("Unexpected error: {e:?}") @@ -98,7 +98,7 @@ async fn lmtp_directory() { Item::Expand(v) => match core.expn(&handle, v).await { Ok(v) => v.into(), Err(e) => { - if e.matches(trc::Cause::Store(trc::StoreCause::NotSupported)) { + if e.matches(trc::EventType::Store(trc::StoreEvent::NotSupported)) { LookupResult::False } else { panic!("Unexpected error: {e:?}") @@ -132,7 +132,7 @@ async fn lmtp_directory() { Item::Verify(v) => match core.vrfy(&handle, v).await { Ok(v) => v.into(), Err(e) => { - if e.matches(trc::Cause::Store(trc::StoreCause::NotSupported)) { + if e.matches(trc::EventType::Store(trc::StoreEvent::NotSupported)) { LookupResult::False } else { panic!("Unexpected error: {e:?}") @@ -142,7 +142,7 @@ async fn lmtp_directory() { Item::Expand(v) => match core.expn(&handle, v).await { Ok(v) => v.into(), Err(e) => { - if e.matches(trc::Cause::Store(trc::StoreCause::NotSupported)) { + if e.matches(trc::EventType::Store(trc::StoreEvent::NotSupported)) { LookupResult::False } else { panic!("Unexpected error: {e:?}") diff --git a/tests/src/imap/mod.rs b/tests/src/imap/mod.rs index b3ba31c4..ef7a5033 100644 --- a/tests/src/imap/mod.rs +++ b/tests/src/imap/mod.rs @@ -414,7 +414,8 @@ async fn init_imap_tests(store_id: &str, delete_if_exists: bool) -> IMAPTest { #[tokio::test] pub async fn imap_tests() { if let Ok(level) = std::env::var("LOG") { - tracing::subscriber::set_global_default( + let todo = "implement"; + /*tracing::subscriber::set_global_default( tracing_subscriber::FmtSubscriber::builder() .with_env_filter( tracing_subscriber::EnvFilter::builder() @@ -425,7 +426,7 @@ pub async fn imap_tests() { ) .finish(), ) - .unwrap(); + .unwrap();*/ } // Prepare settings diff --git a/tests/src/jmap/mod.rs b/tests/src/jmap/mod.rs index faa3afb7..db7a7593 100644 --- a/tests/src/jmap/mod.rs +++ b/tests/src/jmap/mod.rs @@ -286,7 +286,9 @@ throttle = "100ms" #[tokio::test(flavor = "multi_thread")] pub async fn jmap_tests() { if let Ok(level) = std::env::var("LOG") { - tracing::subscriber::set_global_default( + let todo = "implement"; + + /*tracing::subscriber::set_global_default( tracing_subscriber::FmtSubscriber::builder() .with_env_filter( tracing_subscriber::EnvFilter::builder() @@ -297,7 +299,7 @@ pub async fn jmap_tests() { ) .finish(), ) - .unwrap(); + .unwrap();*/ } let delete = true; @@ -344,7 +346,9 @@ pub async fn jmap_tests() { #[ignore] pub async fn jmap_stress_tests() { if let Ok(level) = std::env::var("LOG") { - tracing::subscriber::set_global_default( + let todo = "implement"; + + /*tracing::subscriber::set_global_default( tracing_subscriber::FmtSubscriber::builder() .with_env_filter( tracing_subscriber::EnvFilter::builder() @@ -355,7 +359,7 @@ pub async fn jmap_stress_tests() { ) .finish(), ) - .unwrap(); + .unwrap();*/ } let params = init_jmap_tests( diff --git a/tests/src/smtp/config.rs b/tests/src/smtp/config.rs index 722e57e2..786096ac 100644 --- a/tests/src/smtp/config.rs +++ b/tests/src/smtp/config.rs @@ -428,8 +428,9 @@ async fn eval_if() { }], default: Expression::from(false), } - .eval(&envelope, &core, &key) + .eval(&envelope, &core) .await + .unwrap() .to_bool(), expected_result.parse::().unwrap(), "failed for {key:?}" @@ -478,7 +479,7 @@ async fn eval_dynvalue() { .unwrap_or_else(|| panic!("Missing expect for test {test_name:?}")); assert_eq!( - String::try_from(if_block.eval(&envelope, &core, test_name.as_str()).await).ok(), + String::try_from(if_block.eval(&envelope, &core).await.unwrap()).ok(), expected, "failed for test {test_name:?}" ); diff --git a/tests/src/smtp/inbound/antispam.rs b/tests/src/smtp/inbound/antispam.rs index b49148f0..544b5499 100644 --- a/tests/src/smtp/inbound/antispam.rs +++ b/tests/src/smtp/inbound/antispam.rs @@ -265,7 +265,6 @@ async fn antispam() { .join("resources") .join("smtp") .join("antispam"); - let span = tracing::info_span!("sieve_antispam"); for &test_name in tests.iter().chain(&["combined"]) { /*if test_name != "combined" { continue; @@ -418,10 +417,9 @@ async fn antispam() { } // Run script - let span = span.clone(); let core_ = core.clone(); let script = script.clone(); - match core_.run_script(script, params, span).await { + match core_.run_script(script, params, 0).await { ScriptResult::Accept { modifications } => { if modifications.len() != expected_headers.len() { panic!( diff --git a/tests/src/smtp/inbound/milter.rs b/tests/src/smtp/inbound/milter.rs index 38f269b9..03412384 100644 --- a/tests/src/smtp/inbound/milter.rs +++ b/tests/src/smtp/inbound/milter.rs @@ -379,6 +379,7 @@ fn milter_address_modifications() { 0, "127.0.0.1".parse().unwrap(), 0, + 0, ); // ChangeFrom @@ -484,6 +485,7 @@ fn milter_message_modifications() { 0, "127.0.0.1".parse().unwrap(), 0, + 0, ); for test in tests { @@ -566,7 +568,7 @@ async fn milter_client_test() { flags_protocol: None, run_on_stage: AHashSet::from([Stage::Data]), }, - tracing::span!(tracing::Level::TRACE, "hi"), + 0, ) .await .unwrap(); diff --git a/tests/src/smtp/inbound/scripts.rs b/tests/src/smtp/inbound/scripts.rs index 3775ed4a..a35683ae 100644 --- a/tests/src/smtp/inbound/scripts.rs +++ b/tests/src/smtp/inbound/scripts.rs @@ -153,7 +153,6 @@ async fn sieve_scripts() { assert!(!session.init_conn().await); // Run tests - let span = tracing::info_span!("sieve_scripts"); for (name, script) in &core.core.sieve.scripts { if name.starts_with("stage_") || name.ends_with("_include") { continue; @@ -162,11 +161,10 @@ async fn sieve_scripts() { let params = session .build_script_parameters("data") .set_variable("from", "john.doe@example.org") - .with_envelope(&core.core, &session) + .with_envelope(&core.core, &session, 0) .await; - let span = span.clone(); let core_ = core.clone(); - match core_.run_script(script, params, span).await { + match core_.run_script(script, params, 0).await { ScriptResult::Accept { .. } => (), ScriptResult::Reject(message) => panic!("{}", message), err => { diff --git a/tests/src/smtp/lookup/sql.rs b/tests/src/smtp/lookup/sql.rs index 416057f9..14082f73 100644 --- a/tests/src/smtp/lookup/sql.rs +++ b/tests/src/smtp/lookup/sql.rs @@ -190,7 +190,7 @@ async fn lookup_sql() { let e = Expression::try_parse(&mut config, ("test", test_name, "expr"), &token_map).unwrap(); assert_eq!( - core.eval_expr::(&e, &RecipientDomain::new("test.org"), "text") + core.eval_expr::(&e, &RecipientDomain::new("test.org"), "text", 0) .await .unwrap(), config.value(("test", test_name, "expect")).unwrap(), diff --git a/tests/src/smtp/lookup/utils.rs b/tests/src/smtp/lookup/utils.rs index 6f2a107a..b5546ebd 100644 --- a/tests/src/smtp/lookup/utils.rs +++ b/tests/src/smtp/lookup/utils.rs @@ -86,6 +86,7 @@ async fn lookup_ip() { &NextHop::MX("mx.foobar.org"), &RecipientDomain::new("envelope"), 2, + 0, ) .await .unwrap(); @@ -121,6 +122,7 @@ async fn lookup_ip() { &NextHop::MX("mx.foobar.org"), &RecipientDomain::new("envelope"), 2, + 0, ) .await .unwrap(); diff --git a/tests/src/smtp/outbound/dane.rs b/tests/src/smtp/outbound/dane.rs index abc691ff..dc809efc 100644 --- a/tests/src/smtp/outbound/dane.rs +++ b/tests/src/smtp/outbound/dane.rs @@ -349,15 +349,12 @@ async fn dane_test() { .unwrap() .unwrap(); - assert_eq!( - tlsa.verify(&tracing::info_span!("test_span"), &host, Some(&certs)), - Ok(()) - ); + assert_eq!(tlsa.verify(0, &host, Some(&certs)), Ok(())); // Failed DANE verification certs.remove(0); assert_eq!( - tlsa.verify(&tracing::info_span!("test_span"), &host, Some(&certs)), + tlsa.verify(0, &host, Some(&certs)), Err(Status::PermanentFailure(Error::DaneError(ErrorDetails { entity: host.to_string(), details: "No matching certificates found in TLSA records".to_string() diff --git a/tests/src/smtp/outbound/throttle.rs b/tests/src/smtp/outbound/throttle.rs index 472110fb..89972a1f 100644 --- a/tests/src/smtp/outbound/throttle.rs +++ b/tests/src/smtp/outbound/throttle.rs @@ -90,7 +90,6 @@ async fn throttle_outbound() { assert_eq!(local.qr.last_queued_due().await as i64 - now() as i64, 0); // Throttle sender - let span = tracing::info_span!("test"); let mut in_flight = vec![]; let throttle = &core.core.smtp.queue.throttle; for t in &throttle.sender { @@ -98,7 +97,7 @@ async fn throttle_outbound() { t, &QueueEnvelope::test(&test_message, 0, ""), &mut in_flight, - &span, + 0, ) .await .unwrap(); @@ -123,7 +122,7 @@ async fn throttle_outbound() { t, &QueueEnvelope::test(&test_message, 0, ""), &mut in_flight, - &span, + 0, ) .await .unwrap(); @@ -157,7 +156,7 @@ async fn throttle_outbound() { t, &QueueEnvelope::test(&test_message, 0, ""), &mut in_flight, - &span, + 0, ) .await .unwrap(); @@ -194,7 +193,7 @@ async fn throttle_outbound() { t, &QueueEnvelope::test(&test_message, 1, ""), &mut in_flight, - &span, + 0, ) .await .unwrap(); @@ -245,7 +244,7 @@ async fn throttle_outbound() { t, &QueueEnvelope::test(&test_message, 2, "mx.test.org"), &mut in_flight, - &span, + 0, ) .await .unwrap(); @@ -282,7 +281,7 @@ async fn throttle_outbound() { t, &QueueEnvelope::test(&test_message, 1, "mx.test.net"), &mut in_flight, - &span, + 0, ) .await .unwrap(); diff --git a/tests/src/smtp/queue/dsn.rs b/tests/src/smtp/queue/dsn.rs index b88abe79..b009e146 100644 --- a/tests/src/smtp/queue/dsn.rs +++ b/tests/src/smtp/queue/dsn.rs @@ -86,7 +86,6 @@ async fn generate_dsn() { blob_hash: BlobHash::from(dsn_original.as_bytes()), quota_keys: vec![], }; - let span = tracing::span!(tracing::Level::INFO, "hi"); // Load config let mut local = TestServer::new("smtp_dsn_test", CONFIG.to_string() + SIGNATURES, true).await; @@ -100,13 +99,13 @@ async fn generate_dsn() { .unwrap(); // Disabled DSN - core.send_dsn(&mut message, &span).await; + core.send_dsn(&mut message).await; qr.assert_no_events(); qr.assert_queue_is_empty().await; // Failure DSN message.recipients[0].flags = flags; - core.send_dsn(&mut message, &span).await; + core.send_dsn(&mut message).await; let dsn_message = qr.expect_message().await; qr.compare_dsn(dsn_message, "failure.eml").await; @@ -126,7 +125,7 @@ async fn generate_dsn() { flags, orcpt: None, }); - core.send_dsn(&mut message, &span).await; + core.send_dsn(&mut message).await; let dsn_message = qr.expect_message().await; qr.compare_dsn(dsn_message, "success.eml").await; @@ -139,7 +138,7 @@ async fn generate_dsn() { flags, orcpt: "jdoe@example.org".to_string().into(), }); - core.send_dsn(&mut message, &span).await; + core.send_dsn(&mut message).await; let dsn_message = qr.expect_message().await; qr.compare_dsn(dsn_message, "delay.eml").await; @@ -148,7 +147,7 @@ async fn generate_dsn() { rcpt.flags = flags; } message.domains[0].notify.due = now(); - core.send_dsn(&mut message, &span).await; + core.send_dsn(&mut message).await; let dsn_message = qr.expect_message().await; qr.compare_dsn(dsn_message, "mixed.eml").await; diff --git a/tests/src/smtp/session.rs b/tests/src/smtp/session.rs index a163427b..aa1b926b 100644 --- a/tests/src/smtp/session.rs +++ b/tests/src/smtp/session.rs @@ -100,7 +100,6 @@ impl TestSession for Session { state: State::default(), instance: Arc::new(ServerInstance::test_with_shutdown(shutdown_rx)), core, - span: tracing::info_span!("test"), stream: DummyIo { rx_buf: vec![], tx_buf: vec![], @@ -111,6 +110,7 @@ impl TestSession for Session { 0, "127.0.0.1".parse().unwrap(), 0, + 0, ), params: SessionParameters::default(), in_flight: vec![],