Audit logs are one of those features everyone agrees are important and most teams implement badly. The two common failures: logging too much (so nobody can find anything) or logging too little (so you can’t answer the question when it matters).
What a useful audit log answers
A good audit log answers one question: who did what, when, to what, from where?
- Who: subject — user ID, service ID, or API key ID
- What: action —
user.login,permission.granted,post.deleted - When: timestamp — UTC, millisecond precision
- To what: object — the entity acted upon (user ID, post ID, workspace ID)
- From where: context — IP, user agent, session ID, request ID
If every log entry has all five, you can answer nearly any investigative question. If even one is missing, you have a gap you’ll regret.
What to log
The must-haves for any SaaS:
- Authentication events: login, logout, login failure, MFA success/failure, password reset, email change
- Session events: session created, session terminated (by user or admin)
- Permission changes: role grants and revokes, permission edits, workspace membership changes
- Destructive actions: deletes of anything the user couldn’t recover in 30 seconds
- Admin actions: impersonation, bulk updates, API key creation
What to skip:
- Read events unless you’re in healthcare or finance. Logging every page view drowns the signal.
- Internal system events that aren’t user-attributable. Those go in app logs, not audit logs.
Structure
JSON. Every field above. One entry per event. Don’t combine events (“user logged in and changed email”) into a single row — make them two rows with a correlation ID.
{
"timestamp": "2026-04-20T14:32:11.421Z",
"subject": {"type": "user", "id": "usr_abc123"},
"tenant_id": "tenant_xyz",
"action": "user.email_changed",
"object": {"type": "user", "id": "usr_abc123"},
"context": {
"ip": "1.2.3.4",
"user_agent": "Mozilla/5.0...",
"session_id": "sess_def456",
"request_id": "req_ghi789"
},
"metadata": {
"old_email": "jane@old.com",
"new_email": "jane@new.com"
}
}
Storage
Audit logs are append-only and high-volume. Store them separately from your main database:
- A dedicated Postgres schema with write-only access from your main app, or
- An object store (S3) with date-partitioned files, or
- A log analytics system (Datadog, Splunk, Honeycomb)
Retention: 1 year minimum for most SaaS, 7 years for regulated industries. Check your compliance framework.
Make them queryable
Logs nobody can query are compliance theater. Admins and support reps need a UI:
- Filter by subject, action, time range
- Full-text search on metadata
- Export to CSV for investigations
This is not optional. You’ll be glad you built it the first time a customer asks “who changed our workspace name last Tuesday?”