Lessons in this course (8)

7. Audit logging vs diagnostic logging

Intermediate★ Must knowLesson 7 of 8
Diagnostic logsAudit logs
PurposeTroubleshooting, monitoringCompliance, security, accountability
ContentTechnical events, errors, timingsWho, what, when, where, before/after values
RetentionDays–weeksYears (regulation-driven)
IntegrityBest effort; may sample/dropMust be complete, tamper-evident
StorageLog platformsDatabase tables / immutable storage
csharp
// EF Core SaveChanges interceptor writing audit rows for changed entities
public sealed class AuditInterceptor(ICurrentUser user) : SaveChangesInterceptor
{
    public override ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData e, InterceptionResult<int> result, CancellationToken ct = default)
    {
        var db = e.Context!;
        var audits = db.ChangeTracker.Entries()
            .Where(x => x.State is EntityState.Added or EntityState.Modified or EntityState.Deleted && x.Entity is not AuditEntry)
            .Select(x => new AuditEntry
            {
                Table = x.Metadata.GetTableName()!, Action = x.State.ToString(), User = user.Name, Utc = DateTime.UtcNow,
                Changes = JsonSerializer.Serialize(x.Properties.Where(p => p.IsModified || x.State != EntityState.Modified)
                            .ToDictionary(p => p.Metadata.Name, p => new { Old = p.OriginalValue, New = p.CurrentValue }))
            }).ToList();
        db.Set<AuditEntry>().AddRange(audits);
        return base.SavingChangesAsync(e, result, ct);
    }
}

SQL Server alternatives: temporal tables (automatic row history), SQL Server Audit, Change Data Capture.