Module 8 of 9 · Lesson 22 of 26
Trace requests with redacted structured logs
Work through trace requests with redacted structured logs using a runnable reference, a focused regression check and a local extension.
Read in any order. All lessons stay open, including after an unanswered or incorrect check.
It does not log Authorization, raw query strings, bodies or the raw path containing record identifiers. A route pattern such as /rentals/{identifier} also keeps metric labels bounded as users and records grow. An unmatched path uses one shared label instead of creating a new series for every typo or attack string. JSON encoding prevents newline characters from becoming separate fabricated log entries. Correlation ids identify traces, not accounts, and cannot authorize a request. Choose additional fields deliberately, with redaction and retention review, rather than dumping a request object. The reference records a numeric status and duration so you can follow a failure before investigating deeper application evidence.
Run lesson22. A request includes a secret-like query value, a bearer header and an invalid correlation id. The response must contain a valid UUID, while the captured structured log contains neither secret-like value. Inspect the allow-list in the middleware rather than relying on a blacklist of known password names.
class RequestSignals:
def __init__(self, app, counters):
self.app = app
self.counters = counters
async def __call__(self, scope, receive, send):
if scope["type"] != "http":
return await self.app(scope, receive, send)
raw = dict(scope.get("headers", [])).get(b"x-request-id", b"")
try:
request_id = str(uuid.UUID(raw.decode("ascii")))
except (ValueError, UnicodeError):
request_id = str(uuid.uuid4())
scope.setdefault("state", {})["request_id"] = request_id
status = 500
started = time.monotonic()
async def traced_send(message):
nonlocal status
if message["type"] == "http.response.start":
status = message["status"]
message["headers"].append((b"x-request-id", request_id.encode()))
await send(message)
try:
await self.app(scope, receive, traced_send)
finally:
route = getattr(scope.get("route"), "path", "unmatched")
method = (
scope["method"]
if scope["method"]
in {"GET", "POST", "PATCH", "DELETE", "PUT", "OPTIONS", "HEAD"}
else "OTHER"
)
self.counters[(method, route, f"{status // 100}xx")] += 1
logger.info(
json.dumps(
{
"request_id": request_id,
"method": method,
"route": route,
"status": status,
"duration_ms": round((time.monotonic() - started) * 1000, 2),
}
)
)
python run_checks.py -k lesson22
Expected result The selected lesson test passes against a new temporary PostgreSQL database; the container is removed afterward.
Keep for reference
Equipment Rental lab and lesson checks
ZIP containing Python source, real Alembic migrations, 26 lesson checks, a dependency lock and text instructions. Extract it before following the local exercise.
Practise locally
Send a valid UUID correlation id and assert it is echoed and logged. Add a request with a newline-containing invalid id and confirm the output remains one JSON record. Test that a rental UUID appears only in the response contract, not as a unique metrics label or raw logged route.
The lesson check verifies the reference behavior. Add your own assertions for your change. Local practice is not uploaded or scored by this learning release.
Pause and reflect
What failure does this lesson prevent, and which assertion in lesson22 would expose it?
Use a concrete input, expected result and limitation from your local work. Saving a reflection does not certify the project.
Optional knowledge check
Which field is appropriate for request metrics and logs here?
The matched route pattern, without raw query values or bearer tokens.
Correct. Patterns keep labels bounded and avoid copying sensitive request details.
The full URL and Authorization header for every request.
Try another answer. Raw URLs and credentials can disclose private values and create unbounded labels.
Log only raw request paths; they never contain identifying values.
Try another answer. Paths can contain record ids; prefer matched route patterns.
This practice does not assess your project or award a certificate.
Your reading progress
Progress is saved in this browser when storage is available.