When our auditor asked to see our audit logs, i pulled up Kibana and showed him our ELK stack. Beautiful dashboards. Millions of log entries. Full request/response logging. Structured JSON. The works.
He looked at it for about 30 seconds and said, "These are application logs. Where are your audit logs?"
I said, "That's... that's what these are."
He said, "No, they're not."
That was a fun conversation.
The Fundamental Difference
So basically the distinction comes down to purpose and guarantees. Application logs exist to help developers debug problems. Audit logs exist to provide a tamper-evident record of who did what and when.
Here's a comparison that would have saved me a lot of embarrassment:
| Property | Application Logs | Audit Logs |
|---|---|---|
| Purpose | Debugging, monitoring | Compliance, accountability |
| Audience | Developers, SREs | Auditors, legal, compliance |
| Retention | Days to weeks | Months to years |
| Mutability | Can be modified/deleted | Must be immutable |
| Completeness | Best effort | Must capture every event |
| Structure | Varies | Standardized schema |
| Access | Dev team | Restricted, audited itself |
| Integrity | Not verified | Cryptographically proven |
I had been conflating these for years. And honestly most developers i talk to make the same mistake. Datadog, ELK, Splunk, CloudWatch. These are great tools for application observability. They are not audit logging solutions.
Why ELK/Datadog Fails the Audit Test
Let me walk through the specific ways our ELK stack failed the audit:
1. No Guarantee of Completeness
Application logs are typically "best effort." If the logging pipeline gets backed up, messages get dropped. If a service crashes before flushing its log buffer, those events are lost. This is acceptable for debugging. If you miss one error log out of ten thousand, no big deal.
For audit logs, missing even one event is a compliance failure. If a user deleted a sensitive record and the audit event was dropped because your logging pipeline was overloaded, you have no record of who did it.
// Application logging: dropped messages are acceptable
logger.info('User accessed dashboard', { userId: user.id });
// If this fails silently, nobody cares
// Audit logging: dropped messages are NOT acceptable
await auditLog.record({
eventType: 'data.accessed',
actor: user,
resource: { type: 'dashboard', id: 'dash_123' },
timestamp: new Date(),
});
// If this fails, you need to know about it and retry
2. No Immutability
In ELK, anyone with write access to Elasticsearch can modify or delete log entries. There's no built-in mechanism to prevent tampering. An admin (or an attacker who compromises an admin account) can alter the historical record.
According to NIST SP 800-92 Guide to Computer Security Log Management, audit logs must be protected against unauthorized modification. ELK doesn't provide this out of the box.
Our Datadog logs were even worse. They have a retention policy that automatically deletes logs after 15 days on the standard plan. An auditor asking about an event from 6 months ago would get nothing.
3. No Who-Did-What Context
Application logs capture what happened at the system level. Request received. Database query executed. Response returned. But they dont consistently capture the business-level context that auditors care about.
// What ELK captured:
{
"level": "info",
"message": "PUT /api/users/usr_456 200 OK",
"timestamp": "2026-03-15T10:30:00Z",
"request_id": "req_abc",
"duration_ms": 45
}
// What the auditor wanted:
{
"event_type": "user.permissions_changed",
"actor": {
"id": "usr_123",
"email": "admin@company.com",
"role": "super_admin"
},
"target": {
"type": "user",
"id": "usr_456",
"email": "employee@company.com"
},
"changes": [
{
"field": "role",
"from": "viewer",
"to": "editor"
}
],
"reason": "Promoted to project lead",
"timestamp": "2026-03-15T10:30:00Z"
}
The application log tells you a PUT request was made. The audit log tells you that admin@company.com changed employee@company.com's role from viewer to editor because they were promoted. Thats a completely different level of information.
4. No Tenant Isolation
In a multi-tenant SaaS app, audit logs for different customers must be strictly isolated. Customer A should never see Customer B's audit events. In ELK, achieving this requires careful index management and access control configuration that most teams dont set up correctly.
5. Logs Rotate, Audit Trails Don't
Application logs rotate. You keep the last 30 days, maybe 90 days if you're generous, and then they're gone. Storage is expensive and most of those logs are noise.
Audit logs need to stick around. SOC 2 typically requires 12 months minimum. HIPAA can require 6 years. Financial regulations might require 7+ years. Your ELK cluster is not going to retain years of searchable data at a reasonable cost.
What You Actually Need
If your building a system that needs real audit logging, here's what the architecture should look like:
// Separate audit logging pipeline
// Not your application logging pipeline
interface AuditPipeline {
// Capture: guaranteed delivery, no dropped events
capture(event: AuditEvent): Promise<void>;
// Store: append-only, immutable, with integrity verification
store: {
write(events: AuditEvent[]): Promise<void>;
// No update() or delete() methods. On purpose.
};
// Query: fast search across long time ranges
query(filter: AuditFilter): Promise<AuditEvent[]>;
// Export: for auditors and SIEM integration
export(filter: AuditFilter, format: 'json' | 'csv'): Promise<ReadableStream>;
// Verify: prove logs haven't been tampered with
verify(timeRange: DateRange): Promise<IntegrityReport>;
}
Notice what's missing? There's no update() or delete() on the store. Thats intentional. An audit store should be append-only by design.
The Datadog Trap
I want to call out Datadog specifically because so many teams fall into this trap. Datadog is excellent for application monitoring. But when someone asks "do you have audit logging?" and you point to Datadog, heres what your actually saying:
- "Our audit logs are retained for 15 days" (standard plan)
- "Our audit logs can be modified by anyone with Datadog admin access"
- "Our audit logs don't have business-context about who did what"
- "We'd need to pay $2.55/million log events for longer retention"
- "Our audit data lives in a third-party system we don't control"
None of that satisfies an auditor. According to the AICPA Trust Services Criteria, audit logging controls require specificity about what's logged, how its protected, how long its retained, and who can access it.
The Practical Path Forward
You dont need to throw away your ELK stack or cancel Datadog. Those tools are great at what they do. You just need to add a separate audit logging layer that has the properties auditors actually require.
Keep application logs in ELK/Datadog for debugging. Build or buy a separate audit trail for compliance. They can coexist. They should coexist.
The mistake i made was thinking one system could serve both purposes. It cant. Different purposes, different requirements, different architectures.
I wish someone had told me that before i sat in front of an auditor with a Kibana dashboard and a confident smile. Would have saved me a lot of scrambling.
Top comments (0)