From 67d6a937ae65d5476d5779c641127638e2462f0c Mon Sep 17 00:00:00 2001 From: Sharang Parnerkar Date: Tue, 10 Mar 2026 17:08:13 +0100 Subject: [PATCH] feat: add OpenTelemetry trace spans to all handlers and pipeline functions Add #[tracing::instrument(skip_all)] to 44 functions: - 19 API handlers in mod.rs - 3 chat handlers, 6 DAST handlers, 7 graph handlers - 2 pipeline orchestrator functions - 7 scanner functions (sbom, semgrep, gitleaks, cve, lint, patterns) This generates trace spans for SigNoz visibility into request latency, scan pipeline stages, and error tracking. Co-Authored-By: Claude Opus 4.6 --- compliance-agent/src/api/handlers/chat.rs | 3 +++ compliance-agent/src/api/handlers/dast.rs | 6 ++++++ compliance-agent/src/api/handlers/graph.rs | 7 +++++++ compliance-agent/src/api/handlers/mod.rs | 19 +++++++++++++++++++ compliance-agent/src/pipeline/cve.rs | 1 + compliance-agent/src/pipeline/gitleaks.rs | 1 + compliance-agent/src/pipeline/lint.rs | 1 + compliance-agent/src/pipeline/orchestrator.rs | 2 ++ compliance-agent/src/pipeline/patterns.rs | 2 ++ compliance-agent/src/pipeline/sbom.rs | 1 + compliance-agent/src/pipeline/semgrep.rs | 1 + 11 files changed, 44 insertions(+) diff --git a/compliance-agent/src/api/handlers/chat.rs b/compliance-agent/src/api/handlers/chat.rs index 0fafe85..c3f72b2 100644 --- a/compliance-agent/src/api/handlers/chat.rs +++ b/compliance-agent/src/api/handlers/chat.rs @@ -17,6 +17,7 @@ use super::ApiResponse; type AgentExt = Extension>; /// POST /api/v1/chat/:repo_id — Send a chat message with RAG context +#[tracing::instrument(skip_all)] pub async fn chat( Extension(agent): AgentExt, Path(repo_id): Path, @@ -126,6 +127,7 @@ pub async fn chat( } /// POST /api/v1/chat/:repo_id/build-embeddings — Trigger embedding build +#[tracing::instrument(skip_all)] pub async fn build_embeddings( Extension(agent): AgentExt, Path(repo_id): Path, @@ -226,6 +228,7 @@ pub async fn build_embeddings( } /// GET /api/v1/chat/:repo_id/status — Get latest embedding build status +#[tracing::instrument(skip_all)] pub async fn embedding_status( Extension(agent): AgentExt, Path(repo_id): Path, diff --git a/compliance-agent/src/api/handlers/dast.rs b/compliance-agent/src/api/handlers/dast.rs index e8e5839..199bedd 100644 --- a/compliance-agent/src/api/handlers/dast.rs +++ b/compliance-agent/src/api/handlers/dast.rs @@ -42,6 +42,7 @@ fn default_rate_limit() -> u32 { } /// GET /api/v1/dast/targets — List DAST targets +#[tracing::instrument(skip_all)] pub async fn list_targets( Extension(agent): AgentExt, Query(params): Query, @@ -73,6 +74,7 @@ pub async fn list_targets( } /// POST /api/v1/dast/targets — Add a new DAST target +#[tracing::instrument(skip_all)] pub async fn add_target( Extension(agent): AgentExt, Json(req): Json, @@ -99,6 +101,7 @@ pub async fn add_target( } /// POST /api/v1/dast/targets/:id/scan — Trigger DAST scan +#[tracing::instrument(skip_all)] pub async fn trigger_scan( Extension(agent): AgentExt, Path(id): Path, @@ -138,6 +141,7 @@ pub async fn trigger_scan( } /// GET /api/v1/dast/scan-runs — List DAST scan runs +#[tracing::instrument(skip_all)] pub async fn list_scan_runs( Extension(agent): AgentExt, Query(params): Query, @@ -170,6 +174,7 @@ pub async fn list_scan_runs( } /// GET /api/v1/dast/findings — List DAST findings +#[tracing::instrument(skip_all)] pub async fn list_findings( Extension(agent): AgentExt, Query(params): Query, @@ -202,6 +207,7 @@ pub async fn list_findings( } /// GET /api/v1/dast/findings/:id — Finding detail with evidence +#[tracing::instrument(skip_all)] pub async fn get_finding( Extension(agent): AgentExt, Path(id): Path, diff --git a/compliance-agent/src/api/handlers/graph.rs b/compliance-agent/src/api/handlers/graph.rs index a797ee7..d228b4e 100644 --- a/compliance-agent/src/api/handlers/graph.rs +++ b/compliance-agent/src/api/handlers/graph.rs @@ -33,6 +33,7 @@ fn default_search_limit() -> usize { } /// GET /api/v1/graph/:repo_id — Full graph data +#[tracing::instrument(skip_all)] pub async fn get_graph( Extension(agent): AgentExt, Path(repo_id): Path, @@ -88,6 +89,7 @@ pub async fn get_graph( } /// GET /api/v1/graph/:repo_id/nodes — List nodes (paginated) +#[tracing::instrument(skip_all)] pub async fn get_nodes( Extension(agent): AgentExt, Path(repo_id): Path, @@ -109,6 +111,7 @@ pub async fn get_nodes( } /// GET /api/v1/graph/:repo_id/communities — List detected communities +#[tracing::instrument(skip_all)] pub async fn get_communities( Extension(agent): AgentExt, Path(repo_id): Path, @@ -158,6 +161,7 @@ pub struct CommunityInfo { } /// GET /api/v1/graph/:repo_id/impact/:finding_id — Impact analysis +#[tracing::instrument(skip_all)] pub async fn get_impact( Extension(agent): AgentExt, Path((repo_id, finding_id)): Path<(String, String)>, @@ -179,6 +183,7 @@ pub async fn get_impact( } /// GET /api/v1/graph/:repo_id/search — BM25 symbol search +#[tracing::instrument(skip_all)] pub async fn search_symbols( Extension(agent): AgentExt, Path(repo_id): Path, @@ -211,6 +216,7 @@ pub async fn search_symbols( } /// GET /api/v1/graph/:repo_id/file-content — Read source file from cloned repo +#[tracing::instrument(skip_all)] pub async fn get_file_content( Extension(agent): AgentExt, Path(repo_id): Path, @@ -272,6 +278,7 @@ pub struct FileContent { } /// POST /api/v1/graph/:repo_id/build — Trigger graph rebuild +#[tracing::instrument(skip_all)] pub async fn trigger_build( Extension(agent): AgentExt, Path(repo_id): Path, diff --git a/compliance-agent/src/api/handlers/mod.rs b/compliance-agent/src/api/handlers/mod.rs index 497a737..02af141 100644 --- a/compliance-agent/src/api/handlers/mod.rs +++ b/compliance-agent/src/api/handlers/mod.rs @@ -179,10 +179,12 @@ pub struct SbomVersionDiff { type AgentExt = Extension>; type ApiResult = Result>, StatusCode>; +#[tracing::instrument(skip_all)] pub async fn health() -> Json { Json(serde_json::json!({ "status": "ok" })) } +#[tracing::instrument(skip_all)] pub async fn stats_overview(Extension(agent): AgentExt) -> ApiResult { let db = &agent.db; @@ -253,6 +255,7 @@ pub async fn stats_overview(Extension(agent): AgentExt) -> ApiResult, @@ -283,6 +286,7 @@ pub async fn list_repositories( })) } +#[tracing::instrument(skip_all)] pub async fn add_repository( Extension(agent): AgentExt, Json(req): Json, @@ -329,6 +333,7 @@ pub async fn add_repository( })) } +#[tracing::instrument(skip_all)] pub async fn get_ssh_public_key( Extension(agent): AgentExt, ) -> Result, StatusCode> { @@ -337,6 +342,7 @@ pub async fn get_ssh_public_key( Ok(Json(serde_json::json!({ "public_key": public_key.trim() }))) } +#[tracing::instrument(skip_all)] pub async fn trigger_scan( Extension(agent): AgentExt, Path(id): Path, @@ -351,6 +357,7 @@ pub async fn trigger_scan( Ok(Json(serde_json::json!({ "status": "scan_triggered" }))) } +#[tracing::instrument(skip_all)] pub async fn delete_repository( Extension(agent): AgentExt, Path(id): Path, @@ -397,6 +404,7 @@ pub async fn delete_repository( Ok(Json(serde_json::json!({ "status": "deleted" }))) } +#[tracing::instrument(skip_all)] pub async fn list_findings( Extension(agent): AgentExt, Query(filter): Query, @@ -465,6 +473,7 @@ pub async fn list_findings( })) } +#[tracing::instrument(skip_all)] pub async fn get_finding( Extension(agent): AgentExt, Path(id): Path, @@ -485,6 +494,7 @@ pub async fn get_finding( })) } +#[tracing::instrument(skip_all)] pub async fn update_finding_status( Extension(agent): AgentExt, Path(id): Path, @@ -505,6 +515,7 @@ pub async fn update_finding_status( Ok(Json(serde_json::json!({ "status": "updated" }))) } +#[tracing::instrument(skip_all)] pub async fn bulk_update_finding_status( Extension(agent): AgentExt, Json(req): Json, @@ -534,6 +545,7 @@ pub async fn bulk_update_finding_status( )) } +#[tracing::instrument(skip_all)] pub async fn update_finding_feedback( Extension(agent): AgentExt, Path(id): Path, @@ -554,6 +566,7 @@ pub async fn update_finding_feedback( Ok(Json(serde_json::json!({ "status": "updated" }))) } +#[tracing::instrument(skip_all)] pub async fn sbom_filters( Extension(agent): AgentExt, ) -> Result, StatusCode> { @@ -585,6 +598,7 @@ pub async fn sbom_filters( }))) } +#[tracing::instrument(skip_all)] pub async fn list_sbom( Extension(agent): AgentExt, Query(filter): Query, @@ -640,6 +654,7 @@ pub async fn list_sbom( })) } +#[tracing::instrument(skip_all)] pub async fn export_sbom( Extension(agent): AgentExt, Query(params): Query, @@ -771,6 +786,7 @@ const COPYLEFT_LICENSES: &[&str] = &[ "MPL-2.0", ]; +#[tracing::instrument(skip_all)] pub async fn license_summary( Extension(agent): AgentExt, Query(params): Query, @@ -816,6 +832,7 @@ pub async fn license_summary( })) } +#[tracing::instrument(skip_all)] pub async fn sbom_diff( Extension(agent): AgentExt, Query(params): Query, @@ -905,6 +922,7 @@ pub async fn sbom_diff( })) } +#[tracing::instrument(skip_all)] pub async fn list_issues( Extension(agent): AgentExt, Query(params): Query, @@ -936,6 +954,7 @@ pub async fn list_issues( })) } +#[tracing::instrument(skip_all)] pub async fn list_scan_runs( Extension(agent): AgentExt, Query(params): Query, diff --git a/compliance-agent/src/pipeline/cve.rs b/compliance-agent/src/pipeline/cve.rs index 0a8e8b1..2b3b77c 100644 --- a/compliance-agent/src/pipeline/cve.rs +++ b/compliance-agent/src/pipeline/cve.rs @@ -21,6 +21,7 @@ impl CveScanner { } } + #[tracing::instrument(skip_all)] pub async fn scan_dependencies( &self, repo_id: &str, diff --git a/compliance-agent/src/pipeline/gitleaks.rs b/compliance-agent/src/pipeline/gitleaks.rs index 5010e39..9daa1a2 100644 --- a/compliance-agent/src/pipeline/gitleaks.rs +++ b/compliance-agent/src/pipeline/gitleaks.rs @@ -17,6 +17,7 @@ impl Scanner for GitleaksScanner { ScanType::SecretDetection } + #[tracing::instrument(skip_all)] async fn scan(&self, repo_path: &Path, repo_id: &str) -> Result { let output = tokio::process::Command::new("gitleaks") .args([ diff --git a/compliance-agent/src/pipeline/lint.rs b/compliance-agent/src/pipeline/lint.rs index 721357c..7b69213 100644 --- a/compliance-agent/src/pipeline/lint.rs +++ b/compliance-agent/src/pipeline/lint.rs @@ -22,6 +22,7 @@ impl Scanner for LintScanner { ScanType::Lint } + #[tracing::instrument(skip_all)] async fn scan(&self, repo_path: &Path, repo_id: &str) -> Result { let mut all_findings = Vec::new(); diff --git a/compliance-agent/src/pipeline/orchestrator.rs b/compliance-agent/src/pipeline/orchestrator.rs index b377c32..abd2b2b 100644 --- a/compliance-agent/src/pipeline/orchestrator.rs +++ b/compliance-agent/src/pipeline/orchestrator.rs @@ -50,6 +50,7 @@ impl PipelineOrchestrator { } } + #[tracing::instrument(skip_all)] pub async fn run(&self, repo_id: &str, trigger: ScanTrigger) -> Result<(), AgentError> { // Look up the repository let repo = self @@ -108,6 +109,7 @@ impl PipelineOrchestrator { result.map(|_| ()) } + #[tracing::instrument(skip_all)] async fn run_pipeline( &self, repo: &TrackedRepository, diff --git a/compliance-agent/src/pipeline/patterns.rs b/compliance-agent/src/pipeline/patterns.rs index 27afe88..3c224aa 100644 --- a/compliance-agent/src/pipeline/patterns.rs +++ b/compliance-agent/src/pipeline/patterns.rs @@ -82,6 +82,7 @@ impl Scanner for GdprPatternScanner { ScanType::Gdpr } + #[tracing::instrument(skip_all)] async fn scan(&self, repo_path: &Path, repo_id: &str) -> Result { let findings = scan_with_patterns( repo_path, @@ -146,6 +147,7 @@ impl Scanner for OAuthPatternScanner { ScanType::OAuth } + #[tracing::instrument(skip_all)] async fn scan(&self, repo_path: &Path, repo_id: &str) -> Result { let findings = scan_with_patterns( repo_path, diff --git a/compliance-agent/src/pipeline/sbom.rs b/compliance-agent/src/pipeline/sbom.rs index e404b3c..1254a44 100644 --- a/compliance-agent/src/pipeline/sbom.rs +++ b/compliance-agent/src/pipeline/sbom.rs @@ -15,6 +15,7 @@ impl Scanner for SbomScanner { ScanType::Sbom } + #[tracing::instrument(skip_all)] async fn scan(&self, repo_path: &Path, repo_id: &str) -> Result { let mut entries = Vec::new(); diff --git a/compliance-agent/src/pipeline/semgrep.rs b/compliance-agent/src/pipeline/semgrep.rs index 6a595b4..02e6d9b 100644 --- a/compliance-agent/src/pipeline/semgrep.rs +++ b/compliance-agent/src/pipeline/semgrep.rs @@ -17,6 +17,7 @@ impl Scanner for SemgrepScanner { ScanType::Sast } + #[tracing::instrument(skip_all)] async fn scan(&self, repo_path: &Path, repo_id: &str) -> Result { let output = tokio::process::Command::new("semgrep") .args(["--config=auto", "--json", "--quiet"])