From 2622fa3089d1df249276083d157e43b080a59100 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 23 Feb 2026 23:52:13 +0900 Subject: feat(tracing): instrument network requests with tracing spans Add #[tracing::instrument] and debug logs to all HTTP-calling functions in mozart-registry and mozart-vcs for request-level observability (URL, status code, cache hits, download size). Co-Authored-By: Claude Opus 4.6 --- crates/mozart-registry/Cargo.toml | 1 + crates/mozart-registry/src/downloader.rs | 6 ++++++ crates/mozart-registry/src/packagist.rs | 12 ++++++++++++ crates/mozart-vcs/Cargo.toml | 1 + crates/mozart-vcs/src/driver/bitbucket.rs | 4 ++++ crates/mozart-vcs/src/driver/forgejo.rs | 3 +++ crates/mozart-vcs/src/driver/github.rs | 4 ++++ crates/mozart-vcs/src/driver/gitlab.rs | 3 +++ 8 files changed, 34 insertions(+) (limited to 'crates') diff --git a/crates/mozart-registry/Cargo.toml b/crates/mozart-registry/Cargo.toml index 87d3c69..af65026 100644 --- a/crates/mozart-registry/Cargo.toml +++ b/crates/mozart-registry/Cargo.toml @@ -20,4 +20,5 @@ sha1.workspace = true tar.workspace = true tempfile.workspace = true tokio.workspace = true +tracing.workspace = true zip.workspace = true diff --git a/crates/mozart-registry/src/downloader.rs b/crates/mozart-registry/src/downloader.rs index 8bd99c7..6660188 100644 --- a/crates/mozart-registry/src/downloader.rs +++ b/crates/mozart-registry/src/downloader.rs @@ -79,6 +79,7 @@ impl DownloadProgress { /// the `Content-Length` response header. /// If `files_cache` is provided, the downloaded bytes are cached by URL; cache hits skip /// the network request entirely. +#[tracing::instrument(skip(expected_shasum, progress, files_cache))] pub async fn download_dist( url: &str, expected_shasum: Option<&str>, @@ -100,10 +101,12 @@ pub async fn download_dist( hasher.update(&cached_bytes); let computed = format!("{:x}", hasher.finalize()); if computed == shasum { + tracing::debug!("cache hit"); return Ok(cached_bytes); } // Checksum mismatch — discard cache, re-download } else { + tracing::debug!("cache hit"); return Ok(cached_bytes); } } @@ -112,6 +115,7 @@ pub async fn download_dist( .user_agent(mozart_core::http::user_agent()) .build()?; let response = client.get(url).send().await?; + tracing::debug!(status = %response.status(), "received response"); if !response.status().is_success() { anyhow::bail!( @@ -137,6 +141,8 @@ pub async fn download_dist( response.bytes().await?.to_vec() }; + tracing::debug!(size = bytes.len(), "download complete"); + // Verify SHA-1 checksum if provided if let Some(shasum) = expected_shasum && !shasum.is_empty() diff --git a/crates/mozart-registry/src/packagist.rs b/crates/mozart-registry/src/packagist.rs index 9ff608c..8a5f205 100644 --- a/crates/mozart-registry/src/packagist.rs +++ b/crates/mozart-registry/src/packagist.rs @@ -215,6 +215,7 @@ pub fn parse_p2_response(json: &str, package_name: &str) -> anyhow::Result, @@ -226,15 +227,18 @@ pub async fn fetch_package_versions( if let Some(cache) = repo_cache && let Some(cached) = cache.read(&cache_key) { + tracing::debug!("cache hit"); return parse_p2_response(&cached, package_name); } // Cache miss — fetch from Packagist let url = format!("https://repo.packagist.org/p2/{package_name}.json"); + tracing::debug!(%url, "fetching package metadata"); let client = reqwest::Client::builder() .user_agent(mozart_core::http::user_agent()) .build()?; let response = client.get(&url).send().await?; + tracing::debug!(status = %response.status(), "received response"); if !response.status().is_success() { anyhow::bail!( @@ -303,6 +307,7 @@ fn url_encode(s: &str) -> String { /// /// Fetches up to `SEARCH_MAX_PAGES` pages of results and returns the full list. /// An optional `package_type` filter can narrow results (e.g. `"library"`). +#[tracing::instrument(fields(type_filter = package_type))] pub async fn search_packages( query: &str, package_type: Option<&str>, @@ -318,7 +323,9 @@ pub async fn search_packages( loop { let response: SearchResponse = if let Some(ref url) = next_url { + tracing::debug!(%url, page, "fetching next page"); let resp = client.get(url).send().await?; + tracing::debug!(status = %resp.status(), "received response"); if !resp.status().is_success() { anyhow::bail!("Packagist search request failed (HTTP {})", resp.status()); } @@ -331,7 +338,9 @@ pub async fn search_packages( url.push_str(&url_encode(t)); } + tracing::debug!(%url, "fetching search results"); let resp = client.get(&url).send().await?; + tracing::debug!(status = %resp.status(), "received response"); if !resp.status().is_success() { anyhow::bail!("Packagist search request failed (HTTP {})", resp.status()); } @@ -415,6 +424,7 @@ pub struct SecurityAdvisoriesResponse { /// /// If the package list is very large (500+), requests are batched in chunks of /// 500 names per request and the results are merged. +#[tracing::instrument(skip(package_names), fields(package_count = package_names.len()))] pub async fn fetch_security_advisories( package_names: &[&str], ) -> anyhow::Result>> { @@ -433,12 +443,14 @@ pub async fn fetch_security_advisories( .collect::>() .join("&"); + tracing::debug!(chunk_size = chunk.len(), "fetching security advisories"); let response = client .post("https://packagist.org/api/security-advisories/") .header("Content-Type", "application/x-www-form-urlencoded") .body(body) .send() .await?; + tracing::debug!(status = %response.status(), "received response"); if !response.status().is_success() { anyhow::bail!( diff --git a/crates/mozart-vcs/Cargo.toml b/crates/mozart-vcs/Cargo.toml index 61fd57e..dc6dfc3 100644 --- a/crates/mozart-vcs/Cargo.toml +++ b/crates/mozart-vcs/Cargo.toml @@ -14,6 +14,7 @@ serde.workspace = true serde_json.workspace = true sha1.workspace = true tokio.workspace = true +tracing.workspace = true url.workspace = true [dev-dependencies] diff --git a/crates/mozart-vcs/src/driver/bitbucket.rs b/crates/mozart-vcs/src/driver/bitbucket.rs index dc7d2cf..d47987d 100644 --- a/crates/mozart-vcs/src/driver/bitbucket.rs +++ b/crates/mozart-vcs/src/driver/bitbucket.rs @@ -62,6 +62,7 @@ impl BitbucketDriver { ) } + #[tracing::instrument(skip(self))] async fn api_get(&self, path: &str) -> Result { let url = self.api_url(path); let mut req = self @@ -76,6 +77,7 @@ impl BitbucketDriver { } let response = req.send().await?; + tracing::debug!(status = %response.status(), %url, "Bitbucket API response"); if !response.status().is_success() { bail!( "Bitbucket API request to {} failed: {}", @@ -86,6 +88,7 @@ impl BitbucketDriver { Ok(response.json().await?) } + #[tracing::instrument(skip(self))] async fn api_get_paginated(&self, path: &str) -> Result> { let mut items = Vec::new(); let mut next_url = Some(self.api_url(path)); @@ -101,6 +104,7 @@ impl BitbucketDriver { req = req.header(AUTHORIZATION, format!("Basic {key}:{secret}")); } let response = req.send().await?; + tracing::debug!(status = %response.status(), %url, "Bitbucket API paginated response"); if !response.status().is_success() { break; } diff --git a/crates/mozart-vcs/src/driver/forgejo.rs b/crates/mozart-vcs/src/driver/forgejo.rs index 0447422..ec2ca14 100644 --- a/crates/mozart-vcs/src/driver/forgejo.rs +++ b/crates/mozart-vcs/src/driver/forgejo.rs @@ -76,6 +76,7 @@ impl ForgejoDriver { ) } + #[tracing::instrument(skip(self))] async fn api_get(&self, path: &str) -> Result { let url = self.api_url(path); let mut req = self @@ -87,6 +88,7 @@ impl ForgejoDriver { req = req.header(AUTHORIZATION, format!("token {token}")); } let response = req.send().await?; + tracing::debug!(status = %response.status(), %url, "Forgejo API response"); if !response.status().is_success() { bail!( "Forgejo API request to {} failed: {}", @@ -97,6 +99,7 @@ impl ForgejoDriver { Ok(response.json().await?) } + #[tracing::instrument(skip(self))] async fn api_get_paginated(&self, path: &str) -> Result> { let mut items = Vec::new(); let mut page = 1; diff --git a/crates/mozart-vcs/src/driver/github.rs b/crates/mozart-vcs/src/driver/github.rs index 724cb35..c47c2fe 100644 --- a/crates/mozart-vcs/src/driver/github.rs +++ b/crates/mozart-vcs/src/driver/github.rs @@ -65,6 +65,7 @@ impl GitHubDriver { ) } + #[tracing::instrument(skip(self))] async fn api_get(&self, path: &str) -> Result { let url = self.api_url(path); let mut req = self @@ -78,6 +79,7 @@ impl GitHubDriver { } let response = req.send().await?; + tracing::debug!(status = %response.status(), %url, "GitHub API response"); if !response.status().is_success() { bail!( "GitHub API request to {} failed with status {}", @@ -88,6 +90,7 @@ impl GitHubDriver { Ok(response.json().await?) } + #[tracing::instrument(skip(self))] async fn api_get_paginated(&self, path: &str) -> Result> { let mut items = Vec::new(); let mut page = 1; @@ -107,6 +110,7 @@ impl GitHubDriver { } let response = req.send().await?; + tracing::debug!(status = %response.status(), %url, "GitHub API paginated response"); if !response.status().is_success() { bail!("GitHub API paginated request failed: {}", response.status()); } diff --git a/crates/mozart-vcs/src/driver/gitlab.rs b/crates/mozart-vcs/src/driver/gitlab.rs index 7b1a93b..f96c078 100644 --- a/crates/mozart-vcs/src/driver/gitlab.rs +++ b/crates/mozart-vcs/src/driver/gitlab.rs @@ -80,6 +80,7 @@ impl GitLabDriver { ) } + #[tracing::instrument(skip(self))] async fn api_get(&self, path: &str) -> Result { let url = self.api_url(path); let mut req = self @@ -93,6 +94,7 @@ impl GitLabDriver { } let response = req.send().await?; + tracing::debug!(status = %response.status(), %url, "GitLab API response"); if !response.status().is_success() { bail!( "GitLab API request to {} failed with status {}", @@ -103,6 +105,7 @@ impl GitLabDriver { Ok(response.json().await?) } + #[tracing::instrument(skip(self))] async fn api_get_paginated(&self, path: &str) -> Result> { let mut items = Vec::new(); let mut page = 1; -- cgit v1.3.1