diff --git a/Cargo.lock b/Cargo.lock index 9bb78d4..fee71d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,6 +219,15 @@ dependencies = [ "url", ] +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -372,6 +381,21 @@ dependencies = [ "anyhow", ] +[[package]] +name = "backtrace" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.0" @@ -498,6 +522,33 @@ dependencies = [ "syn", ] +[[package]] +name = "color-eyre" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ebf286c900a6d5867aeff75cfee3192857bb7f24b547d4f0df2ed6baa812c90" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "config" version = "0.12.0" @@ -734,6 +785,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "eyre" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9289ed2c0440a6536e65119725cf91fc2c6b5e513bfd2e36e1134d7cca6ca12f" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -926,6 +987,12 @@ dependencies = [ "wasi 0.10.2+wasi-snapshot-preview1", ] +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + [[package]] name = "h2" version = "0.3.12" @@ -1122,6 +1189,12 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "indexmap" version = "1.8.0" @@ -1403,6 +1476,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.10.0" @@ -1489,6 +1571,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "owo-colors" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e72e30578e0d0993c8ae20823dd9cff2bc5517d2f586a8aef462a581e8a03eb" + [[package]] name = "parking_lot" version = "0.11.2" @@ -1621,6 +1709,7 @@ dependencies = [ "awc", "base64", "clap", + "color-eyre", "config", "console-subscriber", "dashmap", @@ -1997,6 +2086,12 @@ dependencies = [ "url", ] +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc_version" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index aea8f57..d27e3dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ async-trait = "0.1.51" awc = { version = "3.0.0", default-features = false, features = ["rustls"] } base64 = "0.13.0" clap = { version = "3.1.6", features = ["derive"] } +color-eyre = "0.6" config = "0.12.0" console-subscriber = "0.1" dashmap = "5.1.0" @@ -76,9 +77,9 @@ uuid = { version = "0.8.2", features = ["v4", "serde"] } [dependencies.tracing-actix-web] version = "0.5.0" default-features = false -features = ["emit_event_on_error", "opentelemetry_0_17"] +features = ["opentelemetry_0_17"] [dependencies.tracing-awc] version = "0.1.0" default-features = false -features = ["emit_event_on_error", "opentelemetry_0_17"] +features = ["opentelemetry_0_17"] diff --git a/src/config.rs b/src/config.rs index eb4901f..93e8e6a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -13,7 +13,7 @@ pub(crate) use commandline::Operation; pub(crate) use file::{ConfigFile as Configuration, OpenTelemetry, Repo, Sled, Tracing}; pub(crate) use primitives::{Filesystem, ImageFormat, LogFormat, ObjectStorage, Store}; -pub(crate) fn configure() -> anyhow::Result<(Configuration, Operation)> { +pub(crate) fn configure() -> color_eyre::Result<(Configuration, Operation)> { let Output { config_format, operation, diff --git a/src/config/file.rs b/src/config/file.rs index f8cded8..10cd8dc 100644 --- a/src/config/file.rs +++ b/src/config/file.rs @@ -2,7 +2,7 @@ use crate::{ config::primitives::{ImageFormat, LogFormat, Store, Targets}, serde_str::Serde, }; -use std::{collections::HashSet, net::SocketAddr, path::PathBuf}; +use std::{collections::BTreeSet, net::SocketAddr, path::PathBuf}; use url::Url; #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] @@ -94,7 +94,7 @@ pub(crate) struct Media { pub(crate) enable_silent_video: bool, - pub(crate) filters: HashSet, + pub(crate) filters: BTreeSet, #[serde(skip_serializing_if = "Option::is_none")] pub(crate) format: Option, diff --git a/src/error.rs b/src/error.rs index 34d30db..60b33ac 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,50 +1,31 @@ use actix_web::{http::StatusCode, HttpResponse, ResponseError}; -use tracing_error::SpanTrace; +use color_eyre::Report; pub(crate) struct Error { - context: SpanTrace, - kind: UploadError, + inner: color_eyre::Report, +} + +impl Error { + fn kind(&self) -> Option<&UploadError> { + self.inner.downcast_ref() + } } impl std::fmt::Debug for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "{}", self.kind) + std::fmt::Debug::fmt(&self.inner, f) } } impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "{}", self.kind)?; - writeln!(f)?; - - writeln!(f, "Chain:")?; - fmt_chain(f, &self.kind)?; - - writeln!(f)?; - writeln!(f, "Spantrace:")?; - std::fmt::Display::fmt(&self.context, f) + std::fmt::Display::fmt(&self.inner, f) } } -fn fmt_chain( - f: &mut std::fmt::Formatter<'_>, - err: &dyn std::error::Error, -) -> Result { - let count = if let Some(source) = std::error::Error::source(err) { - fmt_chain(f, source)? - } else { - 0 - }; - - write!(f, "\t{}. ", count)?; - writeln!(f, "{}", err)?; - - Ok(count + 1) -} - impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.kind.source() + self.inner.source() } } @@ -54,8 +35,7 @@ where { fn from(error: T) -> Self { Error { - kind: UploadError::from(error), - context: SpanTrace::capture(), + inner: Report::from(UploadError::from(error)), } } } @@ -158,25 +138,38 @@ impl From for UploadError { impl ResponseError for Error { fn status_code(&self) -> StatusCode { - match self.kind { - UploadError::DuplicateAlias - | UploadError::Limit(_) - | UploadError::NoFiles - | UploadError::Upload(_) => StatusCode::BAD_REQUEST, - UploadError::Sled(crate::repo::sled::SledError::Missing) - | UploadError::MissingAlias => StatusCode::NOT_FOUND, - UploadError::InvalidToken => StatusCode::FORBIDDEN, - UploadError::Range => StatusCode::RANGE_NOT_SATISFIABLE, + match self.kind() { + Some( + UploadError::DuplicateAlias + | UploadError::Limit(_) + | UploadError::NoFiles + | UploadError::Upload(_), + ) => StatusCode::BAD_REQUEST, + Some( + UploadError::Sled(crate::repo::sled::SledError::Missing) + | UploadError::MissingAlias, + ) => StatusCode::NOT_FOUND, + Some(UploadError::InvalidToken) => StatusCode::FORBIDDEN, + Some(UploadError::Range) => StatusCode::RANGE_NOT_SATISFIABLE, _ => StatusCode::INTERNAL_SERVER_ERROR, } } fn error_response(&self) -> HttpResponse { - HttpResponse::build(self.status_code()) - .content_type("application/json") - .body( - serde_json::to_string(&serde_json::json!({ "msg": self.kind.to_string() })) - .unwrap_or_else(|_| r#"{"msg":"Request failed"}"#.to_string()), - ) + if let Some(kind) = self.kind() { + HttpResponse::build(self.status_code()) + .content_type("application/json") + .body( + serde_json::to_string(&serde_json::json!({ "msg": kind.to_string() })) + .unwrap_or_else(|_| r#"{"msg":"Request failed"}"#.to_string()), + ) + } else { + HttpResponse::build(self.status_code()) + .content_type("application/json") + .body( + serde_json::to_string(&serde_json::json!({ "msg": "Unknown error" })) + .unwrap_or_else(|_| r#"{"msg":"Request failed"}"#.to_string()), + ) + } } } diff --git a/src/init_tracing.rs b/src/init_tracing.rs index 9840391..c586b41 100644 --- a/src/init_tracing.rs +++ b/src/init_tracing.rs @@ -12,7 +12,9 @@ use tracing_subscriber::{ fmt::format::FmtSpan, layer::SubscriberExt, registry::LookupSpan, Layer, Registry, }; -pub(super) fn init_tracing(tracing: &Tracing) -> anyhow::Result<()> { +pub(super) fn init_tracing(tracing: &Tracing) -> color_eyre::Result<()> { + color_eyre::install()?; + LogTracer::init()?; opentelemetry::global::set_text_map_propagator(TraceContextPropagator::new()); @@ -28,7 +30,7 @@ pub(super) fn init_tracing(tracing: &Tracing) -> anyhow::Result<()> { } } -fn with_format(format_layer: F, tracing: &Tracing) -> anyhow::Result<()> +fn with_format(format_layer: F, tracing: &Tracing) -> color_eyre::Result<()> where F: Layer + Send + Sync, { @@ -53,7 +55,7 @@ where } } -fn with_subscriber(subscriber: S, otel: &OpenTelemetry) -> anyhow::Result<()> +fn with_subscriber(subscriber: S, otel: &OpenTelemetry) -> color_eyre::Result<()> where S: SubscriberExt + Send + Sync, for<'a> S: LookupSpan<'a>, diff --git a/src/main.rs b/src/main.rs index 91f6883..147edc3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use futures_util::{ }; use once_cell::sync::Lazy; use std::{ - collections::HashSet, + collections::BTreeSet, future::ready, path::PathBuf, pin::Pin, @@ -263,7 +263,7 @@ type ProcessQuery = Vec<(String, String)>; fn prepare_process( query: web::Query, ext: &str, - filters: &HashSet, + filters: &BTreeSet, ) -> Result<(ImageFormat, Alias, PathBuf, Vec), Error> { let (alias, operations) = query @@ -306,7 +306,7 @@ async fn process_details( ext: web::Path, manager: web::Data, store: web::Data, - filters: web::Data>, + filters: web::Data>, ) -> Result { let (_, alias, thumbnail_path, _) = prepare_process(query, ext.as_str(), &filters)?; @@ -330,7 +330,7 @@ async fn process( ext: web::Path, manager: web::Data, store: web::Data, - filters: web::Data>, + filters: web::Data>, ) -> Result { let (format, alias, thumbnail_path, thumbnail_args) = prepare_process(query, ext.as_str(), &filters)?; @@ -635,7 +635,7 @@ fn build_reqwest_client() -> reqwest::Result { async fn launch( manager: UploadManager, store: S, -) -> anyhow::Result<()> { +) -> color_eyre::Result<()> { // Create a new Multipart Form validator // // This form is expecting a single array field, 'images' with at most 10 files in it @@ -769,7 +769,7 @@ async fn migrate_inner( repo: &Repo, from: S1, to: &config::Store, -) -> anyhow::Result<()> +) -> color_eyre::Result<()> where S1: Store, { @@ -806,7 +806,7 @@ where } #[actix_rt::main] -async fn main() -> anyhow::Result<()> { +async fn main() -> color_eyre::Result<()> { init_tracing(&CONFIG.tracing)?; let repo = Repo::open(CONFIG.repo.clone())?; diff --git a/src/migrate.rs b/src/migrate.rs index f33ffb5..5548340 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -1,14 +1,14 @@ -use crate::UploadError; +use crate::Error; use std::path::PathBuf; mod s034; -type SledIter = Box, Vec), UploadError>>>; +type SledIter = Box, Vec), Error>>>; trait SledDb { type SledTree: SledTree; - fn open_tree(&self, name: &str) -> Result; + fn open_tree(&self, name: &str) -> Result; fn self_tree(&self) -> &Self::SledTree; } @@ -19,7 +19,7 @@ where { type SledTree = T::SledTree; - fn open_tree(&self, name: &str) -> Result { + fn open_tree(&self, name: &str) -> Result { (*self).open_tree(name) } @@ -29,11 +29,11 @@ where } trait SledTree { - fn get(&self, key: K) -> Result>, UploadError> + fn get(&self, key: K) -> Result>, Error> where K: AsRef<[u8]>; - fn insert(&self, key: K, value: V) -> Result<(), UploadError> + fn insert(&self, key: K, value: V) -> Result<(), Error> where K: AsRef<[u8]>, V: AsRef<[u8]>; @@ -45,7 +45,7 @@ trait SledTree { K: AsRef<[u8]>, R: std::ops::RangeBounds; - fn flush(&self) -> Result<(), UploadError>; + fn flush(&self) -> Result<(), Error>; } pub(crate) struct LatestDb { @@ -60,7 +60,7 @@ impl LatestDb { LatestDb { root_dir, version } } - pub(crate) fn migrate(self) -> Result { + pub(crate) fn migrate(self) -> Result { let LatestDb { root_dir, version } = self; loop { @@ -89,7 +89,7 @@ impl DbVersion { DbVersion::Fresh } - fn migrate(self, root: PathBuf) -> Result { + fn migrate(self, root: PathBuf) -> Result { match self { DbVersion::Sled034 | DbVersion::Fresh => s034::open(root), } diff --git a/src/migrate/s034.rs b/src/migrate/s034.rs index 5bcad24..fde33a2 100644 --- a/src/migrate/s034.rs +++ b/src/migrate/s034.rs @@ -1,6 +1,6 @@ use crate::{ + error::Error, migrate::{SledDb, SledIter, SledTree}, - UploadError, }; use sled as sled034; use std::path::PathBuf; @@ -26,7 +26,7 @@ pub(crate) fn migrating(base: PathBuf) -> bool { true } -pub(crate) fn open(mut base: PathBuf) -> Result { +pub(crate) fn open(mut base: PathBuf) -> Result { base.push("sled"); base.push(SLED_034); @@ -41,7 +41,7 @@ pub(crate) fn open(mut base: PathBuf) -> Result { impl SledDb for sled034::Db { type SledTree = sled034::Tree; - fn open_tree(&self, name: &str) -> Result { + fn open_tree(&self, name: &str) -> Result { Ok(sled034::Db::open_tree(self, name)?) } @@ -51,14 +51,14 @@ impl SledDb for sled034::Db { } impl SledTree for sled034::Tree { - fn get(&self, key: K) -> Result>, UploadError> + fn get(&self, key: K) -> Result>, Error> where K: AsRef<[u8]>, { Ok(sled034::Tree::get(self, key)?.map(|v| Vec::from(v.as_ref()))) } - fn insert(&self, key: K, value: V) -> Result<(), UploadError> + fn insert(&self, key: K, value: V) -> Result<(), Error> where K: AsRef<[u8]>, V: AsRef<[u8]>, @@ -69,7 +69,7 @@ impl SledTree for sled034::Tree { fn iter(&self) -> SledIter { Box::new(sled034::Tree::iter(self).map(|res| { res.map(|(k, v)| (k.as_ref().to_vec(), v.as_ref().to_vec())) - .map_err(UploadError::from) + .map_err(Error::from) })) } @@ -80,13 +80,11 @@ impl SledTree for sled034::Tree { { Box::new(sled034::Tree::range(self, range).map(|res| { res.map(|(k, v)| (k.as_ref().to_vec(), v.as_ref().to_vec())) - .map_err(UploadError::from) + .map_err(Error::from) })) } - fn flush(&self) -> Result<(), UploadError> { - sled034::Tree::flush(self) - .map(|_| ()) - .map_err(UploadError::from) + fn flush(&self) -> Result<(), Error> { + sled034::Tree::flush(self).map(|_| ()).map_err(Error::from) } } diff --git a/src/processor.rs b/src/processor.rs index bf7c749..9e264ec 100644 --- a/src/processor.rs +++ b/src/processor.rs @@ -24,7 +24,7 @@ pub(crate) fn build_chain( args: &[(String, String)], ext: &str, ) -> Result<(PathBuf, Vec), Error> { - fn parse(key: &str, value: &str) -> Result, UploadError> { + fn parse(key: &str, value: &str) -> Result, Error> { if key == P::NAME { return Ok(Some(P::parse(key, value).ok_or(UploadError::ParsePath)?)); } diff --git a/src/repo.rs b/src/repo.rs index 802eda6..8cc0115 100644 --- a/src/repo.rs +++ b/src/repo.rs @@ -120,7 +120,7 @@ pub(crate) trait AliasRepo { } impl Repo { - pub(crate) fn open(config: config::Repo) -> anyhow::Result { + pub(crate) fn open(config: config::Repo) -> color_eyre::Result { match config { config::Repo::Sled(config::Sled { mut path, @@ -139,7 +139,7 @@ impl Repo { } #[tracing::instrument(skip_all)] - pub(crate) async fn from_db(&self, db: ::sled::Db) -> anyhow::Result<()> { + pub(crate) async fn from_db(&self, db: ::sled::Db) -> color_eyre::Result<()> { if self.has_migrated().await? { return Ok(()); } @@ -161,13 +161,13 @@ impl Repo { Ok(()) } - async fn has_migrated(&self) -> anyhow::Result { + async fn has_migrated(&self) -> color_eyre::Result { match self { Self::Sled(repo) => Ok(repo.get(REPO_MIGRATION_O1).await?.is_some()), } } - async fn mark_migrated(&self) -> anyhow::Result<()> { + async fn mark_migrated(&self) -> color_eyre::Result<()> { match self { Self::Sled(repo) => { repo.set(REPO_MIGRATION_O1, b"1".to_vec().into()).await?; @@ -182,7 +182,7 @@ const REPO_MIGRATION_O1: &[u8] = b"repo-migration-01"; const STORE_MIGRATION_PROGRESS: &[u8] = b"store-migration-progress"; const GENERATOR_KEY: &[u8] = b"last-path"; -async fn migrate_hash(repo: &T, old: &old::Old, hash: ::sled::IVec) -> anyhow::Result<()> +async fn migrate_hash(repo: &T, old: &old::Old, hash: ::sled::IVec) -> color_eyre::Result<()> where T: IdentifierRepo + HashRepo + AliasRepo + SettingsRepo, { diff --git a/src/repo/old.rs b/src/repo/old.rs index 584db76..e6a3ac2 100644 --- a/src/repo/old.rs +++ b/src/repo/old.rs @@ -17,9 +17,19 @@ // - Settings Tree // - store-migration-progress -> Path Tree Key +use super::{Alias, DeleteToken, Details}; use std::path::PathBuf; -use super::{Alias, DeleteToken, Details}; +#[derive(Debug)] +struct OldDbError(&'static str); + +impl std::fmt::Display for OldDbError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl std::error::Error for OldDbError {} pub(super) struct Old { alias_tree: ::sled::Tree, @@ -32,7 +42,7 @@ pub(super) struct Old { } impl Old { - pub(super) fn open(db: sled::Db) -> anyhow::Result { + pub(super) fn open(db: sled::Db) -> color_eyre::Result { Ok(Self { alias_tree: db.open_tree("alias")?, filename_tree: db.open_tree("filename")?, @@ -44,7 +54,7 @@ impl Old { }) } - pub(super) fn setting(&self, key: &[u8]) -> anyhow::Result> { + pub(super) fn setting(&self, key: &[u8]) -> color_eyre::Result> { Ok(self.settings_tree.get(key)?) } @@ -55,11 +65,14 @@ impl Old { .filter_map(|res| res.ok()) } - pub(super) fn details(&self, hash: &sled::IVec) -> anyhow::Result> { + pub(super) fn details( + &self, + hash: &sled::IVec, + ) -> color_eyre::Result> { let filename = self .main_tree .get(hash)? - .ok_or_else(|| anyhow::anyhow!("missing filename"))?; + .ok_or(OldDbError("Missing filename"))?; let filename = String::from_utf8_lossy(&filename); @@ -81,22 +94,26 @@ impl Old { .collect()) } - pub(super) fn main_identifier(&self, hash: &sled::IVec) -> anyhow::Result { + pub(super) fn main_identifier(&self, hash: &sled::IVec) -> color_eyre::Result { let filename = self .main_tree .get(hash)? - .ok_or_else(|| anyhow::anyhow!("Missing filename"))?; + .ok_or(OldDbError("Missing filename"))?; - self.identifier_tree + Ok(self + .identifier_tree .get(filename)? - .ok_or_else(|| anyhow::anyhow!("Missing identifier")) + .ok_or(OldDbError("Missing identifier"))?) } - pub(super) fn variants(&self, hash: &sled::IVec) -> anyhow::Result> { + pub(super) fn variants( + &self, + hash: &sled::IVec, + ) -> color_eyre::Result> { let filename = self .main_tree .get(hash)? - .ok_or_else(|| anyhow::anyhow!("Missing filename"))?; + .ok_or(OldDbError("Missing filename"))?; let filename_string = String::from_utf8_lossy(&filename); @@ -126,11 +143,11 @@ impl Old { pub(super) fn motion_identifier( &self, hash: &sled::IVec, - ) -> anyhow::Result> { + ) -> color_eyre::Result> { let filename = self .main_tree .get(hash)? - .ok_or_else(|| anyhow::anyhow!("Missing filename"))?; + .ok_or(OldDbError("Missing filename"))?; let filename_string = String::from_utf8_lossy(&filename); @@ -151,7 +168,7 @@ impl Old { .collect() } - pub(super) fn delete_token(&self, alias: &Alias) -> anyhow::Result> { + pub(super) fn delete_token(&self, alias: &Alias) -> color_eyre::Result> { let key = format!("{}/delete", alias); if let Some(ivec) = self.alias_tree.get(key)? { diff --git a/src/store/object_store.rs b/src/store/object_store.rs index 9734b3a..dcd09f1 100644 --- a/src/store/object_store.rs +++ b/src/store/object_store.rs @@ -122,6 +122,9 @@ impl Store for ObjectStore { let request_span = tracing::info_span!(parent: None, "Get Object"); + // NOTE: isolating reqwest in it's own span is to prevent the request's span from getting + // smuggled into a long-lived task. Unfortunately, I am unable to create a minimal + // reproduction of this problem so I can't open a bug about it. let request = request_span.in_scope(|| { Client::request( &self.client,