Observability Cost Optimization: 12 Tactics That Actually Work

Getting Started with OpenObserve

Try OpenObserve Cloud today for more efficient and performant observability.

Most observability bills don't grow because engineers "used too much monitoring." They grow because nobody is filtering, sampling, or tiering data before it lands in an expensive index. The fix isn't turning visibility down, it's being deliberate about what gets stored at full fidelity, what gets sampled, and what gets dropped.
This guide is a working list of 12 config-level tactics for observability cost optimization, covering logs, metrics, and traces, with the actual settings and rough before/after numbers for each. None of these require ripping out your instrumentation.
This article covers: where observability spend actually comes from, 12 tactics you can apply directly to your pipeline, and how ingest-time pipelines and retention tiers compound the savings.
Quick start: If you need savings this week, do tactics 1 and 2 first, drop DEBUG logs and enable tail sampling. Both are config-only changes.
Before tuning anything, it helps to know which lever you're pulling. Observability cost is a function of three variables multiplied together:
Volume (how many logs/spans/metric points you emit) × Cardinality (how many unique label combinations exist) × Retention (how long you keep it at full fidelity).
Most teams try to cut cost by reducing volume alone. The bigger wins usually come from cardinality and retention, because a single high-cardinality field (like a raw user ID on every metric) can multiply your indexed data far more than trimming a percentage of log lines.
Application logging defaults often ship with DEBUG or TRACE enabled. These levels are useful in development and almost never queried in production incidents.
processors:
filter:
logs:
log_record:
- 'severity_text == "DEBUG"'
- 'severity_text == "TRACE"'
Typical impact: 30-60% reduction in log volume, since DEBUG/TRACE often outnumber ERROR/WARN/INFO combined in verbose services.
Head sampling decides before a trace completes and can miss rare failures. Tail sampling decides after, so you can keep every error and sample the rest.
processors:
tail_sampling:
decision_wait: 10s
num_traces: 50000
policies:
- name: errors
type: status_code
status_code:
status_codes: [ERROR]
- name: slow-traces
type: latency
latency:
threshold_ms: 1000
- name: healthy-traffic
type: probabilistic
probabilistic:
sampling_percentage: 5
Typical impact: 85-95% reduction in trace volume with no loss of error visibility.
Some INFO logs (health checks, cache hits, per-request access logs) fire constantly and add little diagnostic value at 100% retention. Sample these separately from business-relevant INFO logs.
Typical impact: 20-40% additional log reduction on top of DEBUG/TRACE removal, depending on how chatty your access logging is.
Retry loops, connection-pool warnings, and flapping health checks can produce thousands of near-identical lines. Aggregate identical messages into a count instead of storing each occurrence.
Typical impact: Highly variable, but can be the single largest reduction during incidents, when repeated errors spike volume 10-100x in a short window.
Full URLs, session IDs, raw user IDs, and request IDs are useful in a trace payload but expensive as indexed metric labels or searchable log fields.
processors:
attributes:
actions:
- key: http.url
action: delete
- key: session.id
action: delete
- key: user.id
action: hash
Typical impact: Cardinality-driven costs (custom metrics, per-field indexing) can drop 50%+ once the highest-cardinality fields are removed or hashed.
Filtering after data is already ingested doesn't save money, you've already been billed for it. Ingest-time pipelines let you inspect, transform, drop, and route data before it touches your index.
OpenObserve's pipeline feature applies VRL (Vector Remap Language) transformations to logs, metrics, and traces as they arrive, so you can drop noisy fields, redact sensitive data, and route different severities to different destinations, all before storage costs are incurred.
Typical impact: Depends on what you route away, but this is the mechanism that makes tactics 1, 3, 5, and 8 enforceable in production rather than aspirational.
Most observability data is queried within the first 1-2 weeks after ingestion. Keeping everything at full fidelity for 90+ days is rarely necessary.
A practical tiering pattern:
| Tier | Window | Fidelity |
|---|---|---|
| Hot | 7-14 days | Full fidelity, fast query |
| Warm | 15-90 days | Downsampled metrics, sampled traces, ERROR/WARN logs only |
| Cold/archive | 90+ days | Aggregates only, or deleted |
Typical impact: 50%+ storage reduction, since the bulk of stored volume typically sits in windows nobody queries.
High-resolution metrics (1s or 10s scrape intervals) are useful for real-time dashboards but rarely needed at that resolution after a few days. Aggregate to 1-minute or 5-minute rollups once data ages out of the hot tier.
Typical impact: 70-90% reduction in stored metric data points for anything older than a few days.
Uncompressed, unbatched exports increase network overhead and, in some pricing models, ingestion cost. Batch spans/logs/metrics at the collector level and compress before sending.
processors:
batch:
timeout: 10s
send_batch_size: 2048
Typical impact: Smaller effect on stored cost, but reduces network and export overhead, especially at high throughput.
Many agents ship with dozens of integrations enabled by default (process monitoring, unused cloud service checks, verbose network flow logs). Each one adds volume whether or not anyone looks at it.
Typical impact: 10-25% reduction in ingested volume for teams that haven't audited default integrations in over a year.
Two teams emitting identical telemetry volume can pay drastically different amounts depending on backend architecture. Per-GB pricing tied to proprietary indexed storage scales cost linearly with volume. Object-storage-backed architectures (columnar formats like Parquet, compute billed separately from storage) generally have a lower base rate, so every tactic above compounds on a cheaper starting point.
| Example scenario | Datadog-style pricing | OpenObserve list pricing |
|---|---|---|
| 500GB/day | ~$19,050/month (@$1.27/GB) | ~$7,500/month (@$0.50/GB) |
Compression ratios on structured telemetry vary by data shape and cardinality; a practical range is 50-200x, with approximately 140x lower storage costs achievable in typical log workloads compared to Elasticsearch-based stacks (see our 1.1 TB-scale benchmark for the underlying numbers), but actual results vary based on data entropy and cardinality.
Cost creep is usually incremental: a new service, a new default integration, a verbose new log statement. Treat the 11 tactics above as a recurring checklist, not a one-time project. Re-check volume, cardinality, and retention settings after any release that adds new services or instrumentation.
Filtering after ingestion. If a vendor has already indexed the data, you're usually already billed for it. Filter and sample at the collector or pipeline layer, before storage.
Using head sampling for traces. Head sampling decides too early and can miss the rare failures you actually need during an incident. Use tail sampling in production.
Dropping ERROR/WARN logs to save volume. Sample or filter INFO and DEBUG, not the severities you rely on during incidents.
Treating this as a one-time project. Volume and cardinality creep back in with every release. Re-audit periodically (tactic 12) instead of tuning once and forgetting.
Cost optimization isn't free of trade-offs. In a few situations, applying these tactics as written can cost you more than the storage bill they save.
Compliance and audit requirements. If regulations (SOC 2, HIPAA, PCI-DSS) or a legal hold mandate full-fidelity retention for a fixed period, sampling or downsampling that data isn't a config choice, it's a violation. Check retention requirements before tiering or dropping anything.
Security and forensic investigations. Tail sampling and log-level filtering assume you know in advance what's "healthy" traffic. During an active incident response or breach investigation, the sampled-away 95% is often exactly what you need. Keep raw, unsampled data in cold storage for a longer window than your operational retention, even if it's rarely queried.
Low volume environments. If you're ingesting a few GB a day, the engineering time to build pipelines, tune sampling policies, and maintain retention tiers can cost more than the savings. Do the free, config-only changes (tactic 1, tactic 10) and stop there.
Early-stage or unstable systems. If a service is new, recently rearchitected, or still failing in ways you don't understand yet, aggressive sampling or DEBUG-level filtering removes the signal you need to establish a baseline. Optimize after the system is well understood, not before.
Debugging rare, non-deterministic issues. Intermittent bugs that don't reproduce reliably (race conditions, memory leaks, flaky downstream dependencies) often need full-fidelity data over a long window to catch. Sampling can make these effectively undebuggable. Consider a temporary full-fidelity capture window instead of permanent sampling for services with known intermittent issues.
Observability cost optimization isn't about turning visibility down, it's about being deliberate at three points: what you sample, what you tier, and what backend architecture you're paying to store it on. The 12 tactics above are config-level changes: sampling policies, pipeline filters, retention windows, and cardinality controls, that don't require re-instrumenting your applications.
A pragmatic rollout order:
Related reading:
Apply these 12 tactics on live traffic with O2 Cloud:
Start O2 Cloud Free No credit card required. Keep your existing pipeline and sampling config, and switch your destination incrementally.
Questions? Join OpenObserve Community Slack or GitHub.