Design at: #13822 ## Summary `distinct_values_*` metadata streams existed to serve one reader: the `_values` API. They are a redundant — and lossier — materialization of what the tantivy secondary index already holds, and the index has the collectors needed to replace them outright (`SimpleTopN` / `SimpleDistinct`). This PR removes the distinct streams from the write and read paths and lets the `_values` API be served by the tantivy index optimizer. ### 1. Treat distinct value fields as secondary index fields (read-time union) - `get_stream_setting_index_fields()` — the single accessor used by both the index build side (ingester parquet/pack jobs, compactor merge) and the query side (leader/follower index optimizers) — now unions `distinct_value_fields` into the effective index field set, gated on `enable_distinct_fields`. Fields that cannot be secondary-indexed (full text search keys, partition keys, reserved columns) are skipped; the values API falls back to a normal scan for those. - The distinct list is deliberately **not merged into `settings.index_fields`**: the two stay independent, so removing a distinct value field (or disabling `enable_distinct_fields`) cleanly stops its indexing with no residue, and the user-managed `index_fields` list is never mutated behind their back. - Correctness gate: a distinct-only field is considered indexed since its `added_ts` (`get_stream_setting_index_updated_at_for_fields`), so parquet files older than that are served by DataFusion scan instead of the index (`split_file_list_by_time_range`). `added_ts` is set on add and reset when `enable_distinct_fields` is re-enabled (existing behavior). For streams configured before this release the fields only start being indexed at upgrade time, so `added_ts` is additionally clamped by a release-wide cutoff `/tantivy/distinct_fields/updated_at` — a lazy marker initialized to the first access after upgrade, following the existing `ttv_secondary_index_updated_at` pattern. No data migration and no `DB_SCHEMA_VERSION` bump needed. ### 2. `_values` API always queries the original stream - Removed `can_use_distinct_stream()` and the `distinct_values_*` / `SUM(count)` / `StreamType::Metadata` rewrite from `values_inner` (GET `/_values`, formerly `values_v1`) and `build_search_request_per_field` (POST `/_values_stream`). - The generated SQL shapes are exactly what the index optimizer detects: - `SELECT f AS zo_sql_key, COUNT(*) AS zo_sql_num FROM s GROUP BY zo_sql_key ORDER BY zo_sql_num DESC, zo_sql_key ASC` + limit → `SimpleTopN` - `no_count`: `SELECT f AS zo_sql_key FROM s GROUP BY zo_sql_key ORDER BY zo_sql_key ASC` + limit → `SimpleDistinct` - The `keyword` filter (`str_match_ignore_case`) is a valid index condition, so keyword-filtered values queries stay on the index path too. ### 3. Remove distinct values generation - Dropped the per-record distinct value collection in logs and traces ingestion and the whole `core::metadata` module (channel, mem-table, flush job, shutdown hook). - Removed the now-unused `DISTINCT_FIELDS` static and the `ZO_FEATURE_DISTINCT_EXTRA_FIELDS` / `ZO_DISTINCT_VALUES_INTERVAL` / `ZO_DISTINCT_VALUES_HOURLY` config knobs, including the `SUM(count)` merge rollup the last one gated — legacy `distinct_values_*` streams now compact as ordinary metadata streams. The default fields `DISTINCT_FIELDS` carried (`service_name`, `operation_name`) are already default secondary index fields via `SQL_SECONDARY_INDEX_SEARCH_FIELDS`, so traces `_values` queries on them remain index-served. - Renamed `values_v1` to `values_inner`: the `v2` variant was removed long ago (#5087) and the distinct stream switch inside `v1` is gone now too, so the version suffix was pure history. ### 4. Default fields after this change - `service_name`, `operation_name`: default secondary index fields (unchanged, via `SQL_SECONDARY_INDEX_SEARCH_FIELDS`). - `trace_id`: now also a built-in default **bloom filter** field (`BLOOM_FILTER_DEFAULT_FIELDS`, gated on `ZO_FEATURE_DEFAULT_INDEX_FIELDS_ENABLED`), in addition to being a default index field — bloom sits on top of the secondary index and prunes files for high-cardinality equality lookups. - There is no "default distinct fields" concept anymore. ### 5. Fix surfaced by e2e: SimpleDistinct returned null values as `""` The tantivy index encodes null/missing field values as empty strings (`index_builder` adds `""` for null docs), so the `SimpleDistinct` term-dictionary walk returned `""` as a distinct value — sorted first in ascending order, it surfaced as a blank first option in dashboard variable dropdowns, which the DataFusion `GROUP BY` path never returns (its null group sorts last). This was exposed once distinct fields became index-served; `handle_simple_distinct` now skips empty terms (with a unit test). ### 6. Drive-by: fix the failing `api_fuzz_tests` CI job `CreateAlertRequestSchema` was an untagged documentation union with two identical variants, producing `oneOf: [CreateAlertRequestBody, CreateAlertRequestBody]` in the OpenAPI spec. Under `oneOf` semantics (exactly one branch must match) no instance can ever validate, so schemathesis filtered out every generated example and `api_fuzz_tests` failed on `POST /api/v2/{org_id}/alerts` on every CI run since that schema landed. The handler deserializes `CreateAlertRequestBody` directly, so the annotation now documents exactly that type; runtime behavior is unchanged. ## What stays (intentionally) - `distinct_value_fields` / `enable_distinct_fields` in stream settings: still the user-facing way to declare values-API fields; the list now drives the read-time index-field union described above. - The `distinct_value_fields` DB table that tracks dashboard/report usage of these fields (still gates removal in the settings API). - `DISTINCT_STREAM_PREFIX` helpers, retention sync and stream-deletion cleanup for existing `distinct_values_*` streams — legacy stream data keeps compacting (as ordinary metadata streams) and ages out via retention; no new records are written to them. ## Testing - `cargo check --workspace --all-targets` and `cargo clippy --workspace --all-targets` clean. - Enterprise build verified with `Cargo.toml.openobserve` (`cargo check --all-targets`). - New unit tests for the index-field union (skip rules for FTS/partition/reserved fields, `enable_distinct_fields` gating) and the `added_ts` / release-cutoff indexed-since resolution; schema, infra, config and api-search unit tests pass. A few pre-existing failures on a clean tree (config `ssrf_guard`, one flaky sqlite-backed destinations test, one `.env`-dependent index-fields test) are local-environment issues and unrelated. Closes #13822
Open source Datadog alternative for logs, metrics, traces, and frontend monitoring. Modern observability platform: 10x easier, 140x lower storage cost, high performance, petabyte scale.
Cloud · Documentation · Slack · Quickstart
OpenObserve (O2) is a cloud-native observability platform for logs, metrics, traces, analytics, Real User Monitoring (RUM), and AI/LLM observability. It's a cost-effective alternative to Datadog, Splunk, and Elasticsearch for teams that need full observability without the complexity or cost — with Parquet columnar storage and an S3-native design that cuts storage costs by up to 140x.
Table of Contents
- Why OpenObserve?
- Quick Start
- Product Tour
- Architecture
- Comparisons
- Production Ready
- Security & Compliance
- Enterprise Edition
- Community & Support
- Contributing
- FAQ
- License
- SBOM
Why OpenObserve?
A single platform for all of your observability signals. Here's why teams choose OpenObserve:
| Benefit | Description |
|---|---|
| 140x lower storage cost | Parquet columnar storage + S3-native architecture dramatically reduce costs vs Elasticsearch |
| Single binary deployment | Up and running in under 2 minutes — no complex cluster setup required |
| OpenTelemetry native | Built on the OpenTelemetry standard — no vendor lock-in |
| Unified platform | Logs, metrics, traces, RUM, dashboards, alerts, and incidents in one tool |
| High performance | Better query performance than Elasticsearch on a quarter of the hardware |
| SQL + PromQL | Query logs and traces with SQL, metrics with SQL or PromQL — no proprietary query language |
| Built in Rust | Memory-safe, high-performance, single binary |
Cost comparison: OpenObserve vs Elasticsearch
Quick Start
OpenObserve Cloud (fastest way)
Get started in minutes without managing infrastructure. The free tier includes up to 50 GB/day of ingestion.
🐳 Docker
docker run -d \
--name openobserve \
-v $PWD/data:/data \
-p 5080:5080 \
-e ZO_ROOT_USER_EMAIL="root@example.com" \
-e ZO_ROOT_USER_PASSWORD="Complexpass#123" \
public.ecr.aws/zinclabs/openobserve:latest
Then open http://localhost:5080 and log in with the credentials above.
For other installation methods, see the quickstart documentation. For clustered deployments, see the High Availability deployment guide.
Product Tour
OpenObserve ships with a powerful, unified web UI for every signal — logs, traces, metrics, dashboards, RUM, alerts, incidents, pipelines, and AI observability.
🏠 Unified Overview
A single home for your workspace — active incidents, service health (error rate, latency, requests), anomalies, and recent events at a glance.
📊 Logs
Centralized log management with full-text search, SQL queries, quick filters, and a visual query builder. Instantly search across all your logs, build dashboards from log data, and set up alerts — all on Parquet columnar storage for 140x lower storage cost than Elasticsearch. Read more →
🔍 Distributed Tracing
Powered by OpenTelemetry, tracing helps you follow requests across services and pinpoint performance bottlenecks. Explore the full request flow with waterfalls, flame graphs, and Gantt charts; click any span to drill into the trace. Read more →
🕸️ Service Graph
Visualize service-to-service dependencies and request flow across your system, with per-edge request counts and health-based coloring (healthy, degraded, warning, critical) to spot problem hotspots at a glance.
📈 Metrics
Explore metrics from your infrastructure and applications, then query them with SQL or PromQL. Browse thousands of metrics with faceted filters, preview them inline, combine multiple queries with formulae, and visualize the results with 19+ chart types. Read more →
📉 Dashboards
Build custom dashboards from any signal with 19+ built-in chart types and 200+ visualization variations, a drag-and-drop panel builder, template variables, and geo maps. Read more →
👀 Frontend Monitoring (RUM)
Real User Monitoring with Core Web Vitals, error tracking, performance analytics, and full session replay — so you can see exactly what your users experience. Read more →
🔔 Alerts
Get notified when something unusual happens on any signal — logs, metrics, or traces. Define thresholds, scheduled or real-time alerts, and notification channels, with alert history and anomaly detection to catch issues early. Read more →
🚨 Incidents
Correlate related alerts into incidents and track them through their lifecycle — open, acknowledged, and resolved — with severity and dimension context for faster response.
🔀 Pipelines
Enrich, redact, reduce, or normalize data at ingest time with a visual editor. Build stream-processing flows — including logs-to-metrics conversion — from source, transform (VRL functions and conditions), and destination nodes. No external tools required. Read more →
🤖 AI Observability
Monitor your GenAI and LLM applications: track cost, tokens, latency percentiles, and error rates across models, with agent graphs, session traces, and evaluation/quality scoring.
✨ O2 AI Assistant
An in-product assistant that writes your SQL, VRL, and PromQL and walks you through logs, traces, metrics, and incidents — turning natural-language questions into queries, dashboards, and alerts.
For the full feature list, see the documentation.
Architecture
OpenObserve achieves 140x lower storage costs and high performance through a modern, cloud-native architecture:
- Parquet columnar storage — efficient compression and fast analytical queries
- S3-native design — inexpensive object storage with intelligent caching
- Built in Rust — memory-safe, high-performance, single binary
- Partitioning, indexing, and smart caching — reduces search space by up to 99% for most queries
- Native multi-tenancy — organizations and streams as first-class concepts with complete data isolation
- Stateless architecture — rapid scaling and low RPO/RTO for disaster recovery
Scale & Deployment
- Thousands of concurrent users can query a single cluster simultaneously
- Single binary scales to terabytes — unique in the observability space
- High Availability mode scales to petabytes for the most demanding workloads
- Multi-region deployments with cluster federation via Super Cluster architecture (Enterprise)
- Federated search across regions and clusters (Enterprise)
High Availability & Disaster Recovery
Deploy in High Availability mode with clustering for mission-critical workloads requiring maximum uptime. OpenObserve's stateless architecture with S3-backed storage enables very low Recovery Point Objective (RPO) and Recovery Time Objective (RTO): stateless nodes restart rapidly, and durability is guaranteed by S3's 99.999999999% (11 nines).
Read the architecture documentation → · Read the enterprise deployment guide →
Comparisons
OpenObserve vs Datadog
| Aspect | OpenObserve | Datadog |
|---|---|---|
| Deployment | Self-hosted or Cloud | SaaS only |
| Pricing model | Per-GB (free up to 200 GB/day) | Per-host + per-GB |
| Open source | Yes (AGPL-3.0) | No |
| OpenTelemetry | Native OTLP | Supported |
| Query language | SQL + PromQL | Proprietary |
| Vendor lock-in | None | High |
OpenObserve vs Elasticsearch
| Aspect | OpenObserve | Elasticsearch |
|---|---|---|
| Storage cost | 140x lower | High (hot/warm/cold tiers) |
| Setup complexity | Single binary | Complex cluster management |
| Query language | SQL | Lucene/KQL |
| Hardware requirements | ~1/4 the resources | High memory/CPU |
OpenObserve vs Splunk
| Aspect | OpenObserve | Splunk |
|---|---|---|
| Licensing | Open source | Expensive enterprise licensing |
| Deployment | Single binary or HA cluster | Complex |
| Query language | SQL + PromQL | SPL (proprietary) |
| Cost | Predictable, low | Unpredictable, high |
OpenObserve vs Grafana/Loki/Prometheus Stack
| Aspect | OpenObserve | Grafana Stack |
|---|---|---|
| Components | Single platform | Multiple tools (Grafana + Loki + Prometheus + Tempo) |
| Management | One binary | Multiple deployments |
| High cardinality | Full support | Loki struggles with high cardinality |
| Query performance | Fast on large volumes | Loki slow on large data |
Production Ready
OpenObserve is battle-tested in production environments worldwide:
- Thousands of active deployments across diverse industries
- Largest deployment: 2+ PB/day ingestion
- Single binary scales to terabytes — unique in the observability space
Security & Compliance
Security Features
- Secure by design with hardened container images
- Data encryption at rest and in transit
- Sensitive Data Redaction (SDR) — automatically redact sensitive data at ingestion and query time (Enterprise)
- Single Sign-On (SSO) — OIDC, OAuth, SAML, LDAP/AD integration (Enterprise)
- Role-Based Access Control (RBAC) — granular permissions (Enterprise) — Learn more →
Compliance Certifications
- ✅ SOC 2 Type II certified
- ✅ ISO 27001 certified
- ✅ GDPR compliant
- ✅ HIPAA ready (BAA available with Enterprise contracts)
OpenObserve meets the stringent security and compliance requirements of regulated industries including finance, healthcare, and government.
Enterprise Edition
OpenObserve is a true open source project. The open source edition is feature-complete and production-ready — logs, metrics, traces, dashboards, alerts, pipelines, and everything you need to run observability at scale. It will always remain actively maintained and free to use without restrictions.
For organizations that need enterprise-grade features and support, an Enterprise edition adds:
Enterprise features
- Single Sign-On (SSO) — OIDC, OAuth, SAML 2.0, LDAP/AD, and major identity providers (Okta, Azure Entra, Google, GitHub, GitLab, Keycloak)
- Advanced RBAC — granular role-based access control with custom roles — Learn more →
- Audit trails — comprehensive immutable audit logs with configurable retention
- Federated search — query across multiple clusters and regions with Super Cluster
- Sensitive Data Redaction (SDR) — automatically redact PII at ingestion and query time
- Advanced encryption — AES-256 SIV cipher keys with Google Tink KeySet and Akeyless integration
- Query & workload management (QoS) — control query resource usage and priorities in multi-tenant environments
Support & SLAs
- Dedicated support with contractual SLA guarantees and priority response times
- Technical account management, architecture review, and deployment assistance
- Migration support from existing tools, plus training and onboarding
Pricing
- Free tier: up to 50 GB/day of ingestion (~1.5 TB/month), including full commercial use (registration required at 50 GB/day)
- Volume discounts and multi-year contracts available
- View the complete feature comparison →
For enterprise inquiries and custom deployments, contact our sales team.
Community & Support
The best way to get help, share ideas, and connect with other OpenObserve users is through our community channels.
🔗 Join us on Slack
Our Slack community is the most active place for installation and configuration help, sharing best practices, discussing the roadmap, and connecting with the core team.
📱 Join the OpenObserve community on WeChat
Other ways to connect
- 💬 GitHub Discussions — longer-form discussions and Q&A
- 🐛 GitHub Issues — report bugs or request features
- 📖 Documentation — guides, tutorials, and API references
Contributing
We welcome contributions from the community! Whether you're fixing bugs, adding features, improving documentation, or sharing feedback, your help makes OpenObserve better for everyone.
To get started, read our Contributing Guide, which covers setting up your development environment, code standards, submitting pull requests, and reporting issues.
FAQ
How does OpenObserve achieve 140x lower storage costs?
Through a combination of Parquet columnar storage (efficient compression) and an S3-native architecture (inexpensive object storage). See the cost comparison chart in the Why OpenObserve? section.
What are the limitations?
All data in OpenObserve is immutable — once ingested, it cannot be modified or deleted (only entire retention periods can be dropped). This is by design and is a feature for logs and compliance use cases, ensuring data integrity and audit trails.
Is this production-ready?
Yes. OpenObserve runs in production across thousands of deployments worldwide, including environments processing in excess of 2 PB/day. See our customer stories for real-world examples.
How does query performance compare to Elasticsearch?
OpenObserve delivers better performance than Elasticsearch for most workloads, with faster search and significantly faster analytics — while using about a quarter of the hardware. The columnar Parquet format is particularly effective for complex aggregations and analytics.
Is there a steep learning curve?
No. OpenObserve is designed to be intuitive from day one:
- Familiar query languages — SQL for logs and traces, PromQL for metrics; no proprietary query language to learn
- Easy-to-use GUI — an intuitive interface with a drag-and-drop dashboard builder
- No complex tuning — unlike Elasticsearch, there are no shards, replicas, or heap sizes to manage. Just install and go.
Most users are productive within hours, not weeks.
License
Open Source Edition — licensed under AGPL-3.0. We chose AGPL to ensure that improvements to OpenObserve remain open source and benefit the entire community, while still allowing free commercial use. Why AGPL, and why it's good for the community →
Enterprise Edition — licensed under a commercial Enterprise License Agreement (not AGPL), which provides additional flexibility for enterprise deployments.
SBOM
Software Bill of Materials for OpenObserve. You can analyze either SBOM with Dependency-Track.
Rust
The SBOM is available here. To regenerate it:
cargo install cargo-cyclonedx
cargo-cyclonedx cyclonedx
JavaScript
The SBOM is available here. To regenerate it:
npm install --global @cyclonedx/cyclonedx-npm
cd web
cyclonedx-npm > sbom.json














