Log Management for Cloud Infrastructure: ELK vs Loki vs Datadog, Structured Logging, and Cost Control

Published 14 min read
loggingelklokidatadogstructured-loggingobservabilitycost-optimization

Logs are the most fundamental observability signal but also the most expensive to store and query at scale. The average production application generates 10-50 GB of logs per day, and uncontrolled log growth is the primary driver of observability costs. This guide compares ELK (Elasticsearch, Logstash, Kibana), Grafana Loki, and Datadog for log management, covers structured logging implementation, and provides cost optimization strategies.

The 2025 Datadog State of Cloud Costs report found that log management accounts for 35-45% of total observability spending. Organizations that implement structured logging, appropriate log levels, and tiered retention reduce log costs by 60-70% without losing diagnostic capability.

---

Platform Comparison

FeatureELK (Self-Hosted)Grafana LokiDatadog

PriceInfrastructure costInfrastructure cost$0.10/GB ingested + $1.70/M events
Storage modelFull-text indexLabel index + chunksManaged (opaque)
Query languageKQL / LuceneLogQLCustom query syntax
Storage per GB1.5-2x raw size (indexed)0.8-1.2x raw size (compressed)N/A (managed)
Query speedSub-second (indexed fields)Seconds (grep-like on chunks)Sub-second
Operational complexityHigh (cluster management)Low-MediumZero (SaaS)
Best forFull-text search at scaleCost-effective K8s loggingTeams with budget, no ops

ELK Stack Architecture

<h1>Filebeat -> Logstash -> Elasticsearch -> Kibana</h1>

<h1>filebeat.yml</h1>

filebeat.inputs:

<ul><li>type: container</li>

</ul> paths:

- /var/log/containers/*.log

processors:

- add_kubernetes_metadata:

host: ${NODE_NAME}

output.logstash:

hosts: ["logstash:5044"]

Grafana Loki with Promtail

<h1>promtail-config.yaml</h1>

server:

http_listen_port: 9080

positions:

filename: /tmp/positions.yaml

clients:

- url: http://loki:3100/loki/api/v1/push

scrape_configs:

- job_name: containers

static_configs:

- targets:

- localhost

labels:

job: containerlogs

__path__: /var/log/containers/*.log

pipeline_stages:

- json:

expressions:

level: level

message: msg

- labels:

level:

---

Structured Logging

Structured logging outputs machine-parseable JSON instead of unstructured text. This enables fast field-based queries and automated analysis.

<h1>Python: structlog for structured logging</h1>

import structlog

structlog.configure(

processors=[

structlog.processors.TimeStamper(fmt="iso"),

structlog.processors.add_log_level,

structlog.processors.JSONRenderer(),

],

)

logger = structlog.get_logger()

<h1>Structured log entry</h1>

logger.info("order_processed",

order_id=12345,

user_id=789,

amount=99.99,

payment_method="card",

processing_time_ms=142

)

<h1>Output:</h1>

<h1>{"event": "order_processed", "order_id": 12345, "user_id": 789,</h1>

<h1> "amount": 99.99, "payment_method": "card", "processing_time_ms": 142,</h1>

<h1> "level": "info", "timestamp": "2026-03-10T14:30:00Z"}</h1>

// Node.js: pino for structured logging

const pino = require("pino");

const logger = pino({ level: "info" });

logger.info({

event: "order_processed",

orderId: 12345,

userId: 789,

amount: 99.99,

processingTimeMs: 142

}, "Order processed successfully");

---

Log Levels

LevelPurposeProduction VolumeExample

ERRORUnexpected failures requiring actionLow (< 1%)Database connection failed
WARNDegraded behavior, not failureLow (1-5%)Retry succeeded on third attempt
INFOBusiness events and state changesMedium (10-30%)Order created, user logged in
DEBUGDiagnostic detail for developmentHigh (50-80%)SQL query text, request body
TRACEExtremely verbose debuggingVery highFunction entry/exit

<h1>Production: INFO and above</h1>

<h1>Staging: DEBUG and above</h1>

<h1>Development: TRACE and above</h1>

import os

import structlog

LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")

structlog.configure(wrapper_class=structlog.make_filtering_bound_logger(LOG_LEVEL))

---

Retention Policies

Log TypeHot StorageWarm StorageCold/ArchiveTotal

Application errors30 days90 days1 year1 year
Access logs7 days30 days90 days90 days
Debug logs3 daysNoneNone3 days
Audit logs90 days1 year7 years7 years
Security logs30 days1 year3 years3 years

<h1>Elasticsearch ILM (Index Lifecycle Management) policy</h1>

PUT _ilm/policy/app-logs-policy

{

"policy": {

"phases": {

"hot": {

"min_age": "0ms",

"actions": {

"rollover": { "max_size": "50gb", "max_age": "1d" }

}

},

"warm": {

"min_age": "7d",

"actions": {

"shrink": { "number_of_shards": 1 },

"forcemerge": { "max_num_segments": 1 }

}

},

"cold": {

"min_age": "30d",

"actions": {

"freeze": {}

}

},

"delete": {

"min_age": "90d",

"actions": { "delete": {} }

}

}

}

}

---

Cost Optimization

StrategySavingsImplementation

Drop debug logs in production40-60%Set LOG_LEVEL=INFO
Sample high-volume logs20-40%Log 1 in 10 health checks
Compress before shipping15-25%Enable gzip in shipper
Tiered retention30-50%Hot/warm/cold lifecycle
Drop noisy fields10-20%Strip stack traces from INFO
Use Loki instead of ELK50-70%Label-based vs full-text index

For distributed tracing that complements your log management, see our distributed tracing guide. Teams building alerting on log patterns should read our alerting best practices guide. For the metrics layer of your observability stack, check our Kubernetes observability stack guide.

---

Frequently Asked Questions

Should I use ELK or Loki?

Use Loki if you primarily query logs by label (service name, namespace, log level) and occasionally grep through log content. Loki costs 50-70% less than ELK because it does not index log content. Use ELK if you need fast full-text search across all log fields, complex aggregations, or if your team already has Elasticsearch expertise.

How do I prevent log volume from growing uncontrollably?

Three techniques: (1) Set LOG_LEVEL to INFO in production and DEBUG only in staging. (2) Sample high-volume, low-value logs (health checks, heartbeats) at 1-in-100 rate. (3) Implement log quotas per service, and alert when a service exceeds its daily budget. The most common log explosion comes from error retry loops that log the same error thousands of times.

Is Datadog worth the cost?

Datadog is worth it for teams under 20 engineers who want zero operational overhead. Above 20 engineers or 100 GB/day log volume, the cost becomes significant ($3,000-10,000 per month for logs alone). At that scale, self-hosted Loki or ELK with dedicated ops support is more cost-effective.

How do I handle multiline log entries?

Structured JSON logging eliminates the multiline problem because each log entry is a single JSON line. For legacy applications that output multiline stack traces, configure your log shipper (Filebeat, Promtail) with multiline rules that join lines starting with whitespace or specific patterns back to the previous log entry.

Should I log request and response bodies?

Log request bodies at DEBUG level only, and never in production. Never log response bodies containing user data. For debugging API issues, log a hash of the request body at INFO level so you can correlate requests without storing sensitive data. For compliance-sensitive systems (healthcare, finance), consult your security team before logging any request data.