Add business spans and silence the frontend health poll

Manual INTERNAL spans for the business steps the auto-instrumentation
can't name: fraud.score_transaction, sanctions.lookup_watchlist,
ledger.settle and insights.aggregate_120d, with ledgerline.* attributes
(account, amount, risk score, match outcome). holder_name stays off the
spans. Each span starts after its handler's chaos flag reads and
injection points, and no chaos-derived values become attributes.

The gateway's /api/health/all fan-out now runs under
suppress_instrumentation: with the route excluded, its five downstream
/healthz calls were each a parentless root trace.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Movses Aslanyan
2026-10-13 18:11:38 +03:30
co-authored by Claude Opus 5.5
parent d1c158c835
commit d52a19965a
5 changed files with 88 additions and 48 deletions
+8 -1
View File
@@ -3,6 +3,7 @@ import asyncio
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from opentelemetry import trace
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
@@ -15,6 +16,7 @@ from .repository import is_match
SERVICE_NAME = "sanctions"
logger = configure_logging(SERVICE_NAME)
tracer = trace.get_tracer(__name__)
setup_telemetry(service_name=SERVICE_NAME)
app = FastAPI(title=SERVICE_NAME)
@@ -66,7 +68,12 @@ async def lookup(body: LookupRequest):
logger.info(f"slow_sanctions chaos sleeping {delay:.3f}s for request_id={body.request_id}")
await asyncio.sleep(delay)
match = await is_match(body.holder_name)
# holder_name is PII: it stays off the span; only the outcome is recorded.
with tracer.start_as_current_span("sanctions.lookup_watchlist") as span:
match = await is_match(body.holder_name)
span.set_attribute("ledgerline.sanctions.matched", match is not None)
if match:
span.set_attribute("ledgerline.sanctions.list_source", match["list_source"])
if match:
return {"matched": True, **match}
return {"matched": False, "country": None, "list_source": None}