Approach: wrap the external call so we emit structured logs before and after, measure latency, and sanitize any PII. Use a logger that accepts dicts (converted to JSON by handler) and ensure we do not log raw user data — only pseudonymized IDs or hashes and non-sensitive metadata.python
import time
import hashlib
import logging
import json
import requests
# Simple JSON-emitting logger
logger = logging.getLogger("svc")
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter('%(message)s'))
logger.addHandler(handler)
logger.setLevel(logging.INFO)
def pseudonymize(value: str) -> str:
"""Non-reversible hash to avoid logging raw PII."""
return hashlib.sha256(value.encode()).hexdigest()[:16]
def call_external_service(user_id: str, request_id: str, url: str, payload: dict):
ctx = {
"user_id": pseudonymize(user_id), # pseudonymized
"request_id": request_id,
"service": "external-service-x",
"endpoint": url
}
# Log before call
logger.info(json.dumps({**ctx, "event": "external_call_start", "timestamp": time.time()}))
start = time.time()
try:
resp = requests.post(url, json=payload, timeout=5)
latency_ms = int((time.time() - start) * 1000)
result = {"status": resp.status_code, "latency_ms": latency_ms}
logger.info(json.dumps({**ctx, "event": "external_call_end", **result, "timestamp": time.time()}))
resp.raise_for_status()
return resp.json()
except Exception as e:
latency_ms = int((time.time() - start) * 1000)
logger.error(json.dumps({
**ctx,
"event": "external_call_error",
"error_type": type(e).__name__,
"message": str(e)[:200], # truncate to avoid long payloads
"latency_ms": latency_ms,
"timestamp": time.time()
}))
raise
Why this helps troubleshooting and avoids PII leaks:- Structured logs (JSON) make it easy to filter by request_id, user_id hash, status, or latency in log aggregators.- Pre/post events show request lifecycle and timings to identify slow or failing external calls.- Pseudonymization (hashing user_id) preserves the ability to correlate activity without exposing raw PII.- We avoid logging request/response bodies or sensitive headers; truncate messages and log only non-sensitive error types and short messages.- Correlating request_id across services enables tracing; latency_ms and status pinpoint performance or error patterns for alerting and incident investigation.