DEV Community

GrimLabs
GrimLabs

Posted on

Application Logs Are Not Audit Logs. I Learned This the Hard Way.

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
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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>;
}
Enter fullscreen mode Exit fullscreen mode

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)