Skip to content
AB

Privacy-Safe Observability in a Health Application

Preserve enough context to diagnose production failures without turning logs and error tracking into stores of sensitive user data.

Ashish BhakhandPublished

Health data, chat messages, notes, and authentication tokens are useful when debugging. That is exactly why careless logging is dangerous: logs are copied, indexed, retained, and viewed by more systems than the primary database.

I start with an allow-list mindset. Record operational metadata, not content.

Code
logger.info(
    'chat.turn.completed',
    extra={
        'event': 'chat.turn.completed',
        'request_id': request_id,
        'duration_ms': duration_ms,
        'tool_rounds': tool_rounds,
        'outcome': 'success',
    },
)

This can answer whether a turn was slow without storing what the user said.

Keep identifiers joinable without exposing them#

Operational investigations often need to connect several events for one user. A stable one-way representation provides joinability:

Code
def log_user_id(user_id: str) -> str:
    digest = hashlib.sha256(user_id.encode()).hexdigest()[:12]
    return f'u_{digest}'

This is pseudonymization, not anonymity. Protect the logs accordingly, but avoid copying raw account identifiers everywhere.

Redact more than headers#

A useful redaction policy covers:

  • authorization, cookies, and API keys;
  • request and response bodies;
  • prompts, messages, notes, and transcripts;
  • query strings that may contain search terms;
  • exception-local variables containing tokens or secrets;
  • Sentry users, tags, breadcrumbs, and contexts.

Apply sanitization before data leaves the process. A dashboard filter added later cannot remove secrets already ingested.

Separate events from payloads#

Prefer fields such as schema version, body size, date range, record count, provider status, and a content hash. These often identify the failure without reproducing the sensitive data.

Test privacy behavior#

Create log records and error events containing known sentinel secrets, then assert the serialized output does not contain them. Test suffix patterns such as _token and _secret, not only a fixed list.

Observability should make the system explainable. In sensitive products, the design challenge is retaining causal and performance evidence while minimizing the personal content that reaches operational tools.

← Back to all writing