From 35ae25672948f377bff6aa6441608cce5ce51cfb Mon Sep 17 00:00:00 2001 From: Ray Winkelman Date: Tue, 1 Sep 2026 15:25:20 +0700 Subject: [PATCH] feat: add structured logging to scan API routes (#199) Log verify/scan/stop/scan-csv entry points and outcomes for easier debugging. MCP was removed per #306; this covers the equivalent HTTP scan surface. --- agentic_security/routes/scan.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/agentic_security/routes/scan.py b/agentic_security/routes/scan.py index 6c4a0bc..319b06a 100644 --- a/agentic_security/routes/scan.py +++ b/agentic_security/routes/scan.py @@ -29,17 +29,25 @@ router = APIRouter() async def verify( info: LLMInfo, secrets: InMemorySecrets = Depends(get_in_memory_secrets) ) -> dict[str, int | str | float]: + logger.info("verify: checking LLM spec connectivity") spec = LLMSpec.from_string(info.spec) try: r = await spec.verify() except InvalidHTTPSpecError as e: + logger.warning("verify: invalid HTTP spec: %s", e) raise HTTPException(status_code=400, detail=str(e)) except Exception as e: - logger.exception(e) + logger.exception("verify: unexpected failure") raise HTTPException(status_code=400, detail=str(e)) if r.status_code >= 400: + logger.warning("verify: upstream returned HTTP %s", r.status_code) raise HTTPException(status_code=r.status_code, detail=r.text) + logger.info( + "verify: success status=%s elapsed=%.2fs", + r.status_code, + r.elapsed.total_seconds(), + ) return dict( status_code=r.status_code, body=r.text, @@ -70,6 +78,12 @@ async def scan( background_tasks: BackgroundTasks, secrets: InMemorySecrets = Depends(get_in_memory_secrets), ) -> StreamingResponse: + logger.info( + "scan: starting stream maxBudget=%s optimize=%s multiStep=%s", + scan_parameters.maxBudget, + scan_parameters.optimize, + scan_parameters.enableMultiStepAttack, + ) scan_parameters.with_secrets(secrets) return StreamingResponse( streaming_response_generator(scan_parameters), media_type="application/json" @@ -78,6 +92,7 @@ async def scan( @router.post("/stop") async def stop_scan() -> dict[str, str]: + logger.info("stop: scan stop requested") get_stop_event().set() return {"status": "Scan stopped"} @@ -103,8 +118,15 @@ async def scan_csv( {"name": dataset.dataset_name, "prompts": dataset.prompts} ) except ValueError as e: + logger.warning("scan-csv: failed to parse CSV upload: %s", e) raise HTTPException(status_code=400, detail=str(e)) from e + logger.info( + "scan-csv: starting stream rows=%s maxBudget=%s optimize=%s", + len(inline_datasets[0]["prompts"]) if inline_datasets else 0, + maxBudget, + optimize, + ) scan_parameters = Scan( llmSpec=llm_spec, optimize=optimize,