Structured Logging
FAuth uses structlog for structured logging across all security-sensitive operations. FAuth does not call structlog.configure() — your application owns the processor pipeline. If you never configure structlog, the default dev renderer is used (coloured, human-readable text).
Configuring log output
Configure structlog once in your application startup — FAuth (and any other structlog-based library) will follow:
import structlog
# Development — human-readable coloured text
structlog.configure(
processors=[
structlog.processors.add_log_level,
structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False),
structlog.dev.ConsoleRenderer(),
],
)
# Production — JSON lines for log aggregators (Datadog, ELK, etc.)
structlog.configure(
processors=[
structlog.processors.add_log_level,
structlog.processors.TimeStamper(fmt="iso", utc=True),
structlog.processors.JSONRenderer(),
],
)
What gets logged
| Event | Level | Context |
|---|---|---|
login_token_issued |
info |
sub |
token_decoded |
debug |
sub, token_type |
user_authenticated |
debug |
sub |
authentication_failed |
warning |
reason (missing_token, token_expired, invalid_token, user_not_found) |
authorization_failed |
warning |
reason (inactive_user, missing_role, missing_permission) |
Example log output
With ConsoleRenderer() (default):
2026-04-01 10:30:15 [info ] login_token_issued sub=user-123
2026-04-01 10:30:16 [debug ] token_decoded sub=user-123 token_type=access
2026-04-01 10:31:00 [warning ] authentication_failed reason=token_expired
With JSONRenderer():