Observability query languages compared: Discover, LogQL, SPL, DDL.
Every major observability platform invented its own query language. Sentry Discover, Datadog Query Language, Splunk SPL, and Grafana Loki LogQL each reflect the indexing model and data shape of the tool that built it. This guide maps what each language does, where each wins, where each breaks down, and how the same question looks across all four syntaxes.
20 seconds. Discover is a key:value filter language for event and issue data. DDL is a faceted filter language with metric-vs-log awareness. SPL is a pipe-stage transformation language for arbitrary text and structured data. LogQL is a label-selector plus pipeline language for log streams. Each reflects the indexing model of the tool that built it.
60 seconds. The observability query language landscape fragmented because each vendor solved a different primary problem. Sentry solved error grouping and triage; Discover encodes that problem in a filter-and-aggregate syntax. Datadog solved cross-signal correlation across metrics, logs, traces, and synthetics; DDL unifies those surfaces behind a common facet model. Splunk solved arbitrary log ingestion and text mining for security and ops teams; SPL grew into a full pipeline language that can transform any structured or unstructured data. Grafana Loki solved cheap log storage by indexing only labels; LogQL reflects that design by requiring label selectors before any line filter runs.
The practical implication: picking a query language is picking an indexing model and a primary workflow. The language is the interface to the backend's data structure. Switching languages without switching backends means rewriting queries to fit a model the backend was not designed for. Understand what each language indexes, and the syntax stops being arbitrary.
Why each tool invented its own query language
When Splunk shipped in 2004, the problem it solved was log ingestion at machine scale. System administrators and security teams received raw text from hundreds of sources with no consistent schema. The first question was always a search: find the lines that match this pattern. The second question was always a transformation: now count them, or extract a field, or join against another search. SPL emerged from that two-step workflow. Search first, then pipe the results into transforms. The pipeline model follows directly from the problem: raw text has no fixed schema, so the transformation step cannot be separated from the search step.
Datadog arrived a decade later with a different primary problem. SaaS teams already had structured metrics from StatsD and Graphite. Logs came in alongside them. The question was not "find lines matching a pattern" but "show me the metric correlated with this log attribute." Datadog built around facets: indexed fields that appear consistently across events. The query language became a filter on those facets, with rollup aggregations that mirror the metric aggregations the team already understood.
Grafana Loki started from a storage cost problem. Elasticsearch-based log stacks indexed every field in every log line. At high volume, the index grew to match or exceed the raw log data. Loki chose to index only labels, storing log line bodies as compressed chunks. The LogQL language reflects that constraint directly: every query must begin with a label selector, because the label selector is the only mechanism that locates the relevant chunk files. Queries that cannot use labels to narrow the dataset cannot be fast.
Sentry Discover was built for a data model that is neither logs nor metrics nor raw text: grouped error events. The events have known fields (exception type, stack trace, release, environment, user), and the grouping has already happened before the query runs. Discover syntax reflects that: field-based filters, aggregate functions over event counts, and scoping that lets the user switch between event-level and issue-level views. There is no need for a pipe stage, because the transformation model (count, group, percentile) is baked into the aggregate functions.
The early trade-off each tool made: SQL-like syntax is expressive but requires a well-defined schema and a planner capable of reordering operations for efficiency. Key-value filter syntax is limited in expressivity but fast to parse, easy to type, and legible without SQL knowledge. SPL chose a middle path: keyword search first, then SQL-like aggregation piped from the search result. Each choice bound the language to the indexing model it needed to be efficient on.
Sentry Discover syntax overview
Discover is Sentry's query language for the event explorer. It operates on a flat event index where each record corresponds to a single occurrence of a transaction or error, carrying known fields: event.type, project, environment, release, user.id, http.status_code, transaction, error.type, error.value, and a set of tag fields set by the SDK.
The basic unit is a key:value filter. Filters combine with AND and OR boolean logic. The default operator between terms is AND:
http.status_code:500 AND transaction:/api/v1/checkout
Wildcards work on string fields:
error.type:CardDeclined* environment:production
Comparisons work on numeric and timestamp fields:
http.status_code:>=500 http.status_code:<600
The negation operator is the exclamation mark prefix:
!event.type:transaction environment:production
The scoping distinction matters: the same filter syntax applies to both event-level queries (individual occurrences, accessed via the Events tab) and issue-level queries (grouped failures, accessed via the Issues list). On the Issues list, times_seen, first_seen, and last_seen are aggregate fields on the group, not on individual events. On the Events explorer, every field maps to a single occurrence record.
Aggregate functions apply to the event index and return grouped results. The common ones:
count()— total event countcount_unique(user.id)— distinct user countp50(transaction.duration),p95(transaction.duration),p99(transaction.duration)avg(transaction.duration)failure_rate()— fraction of events with status ERROR or status UNKNOWNapdex(300)— Apdex score with a 300 ms threshold
Grouping uses the GROUPBY clause in the Discover UI, which maps to a field parameter in the underlying API call. Discover expresses a grouped aggregation as: "for each distinct value of this field, compute this aggregate over the filtered events." The result set is a table, not a raw event list.
The Discover query language is the practical standard for error-tracking queries because it ships with every Sentry SDK integration and because the underlying API endpoint (/api/0/organizations/{org}/events/) is what Sentry's own dashboards and alerts use. Any tool that reimplements that endpoint must understand Discover syntax to parse inbound queries correctly.
Datadog Query Language (DDL) overview
Datadog Query Language (DDL) is not a single language but a consistent filter syntax used across Datadog's log, metric, trace, and infrastructure search surfaces. The core model is the facet: a field that Datadog has indexed across all ingested events of that type. For logs, facets are extracted from the log body during processing via Grok patterns or JSON parsing. For metrics, facets correspond to tags on the metric series.
The basic filter uses a key:value form familiar from Discover, but with an important naming distinction for log attributes. Datadog distinguishes reserved attributes (always indexed: status, host, service, source, env, version) from custom attributes, which are prefixed with @:
service:checkout-api status:error @http.status_code:500
Without the @ prefix, Datadog searches the full-text index of the log message body. With the @ prefix, it filters on the parsed attribute. This distinction matters for performance: full-text search scans message bodies; attribute search uses the facet index.
Boolean logic follows the same AND/OR/NOT pattern:
service:checkout-api (@http.status_code:500 OR @http.status_code:503) env:production
For metric queries, the language shifts to a metric name plus tag filter syntax, separate from the log search syntax. A metric query specifying a sum with a rollup looks like this in the Datadog metrics graph editor:
sum:http.server.requests{service:checkout-api,http.status_code:5*}.rollup(sum, 60)
The rollup(method, seconds) aggregation controls how raw metric points collapse into graph buckets. This syntax is distinct from the log query syntax and lives in a separate query field in the UI.
The metric-vs-log split in the language is real and has practical consequences. A dashboard that combines log counts (from a log facet query) with a metric (from a metric query) uses two different query fields with two different syntaxes that look superficially similar but are not interchangeable. Teams moving from a metric-only monitoring setup to a combined metrics-and-logs Datadog setup encounter this split early.
Splunk SPL overview
Splunk's Search Processing Language is a pipeline language where each stage of the pipe receives the output of the previous stage and passes its own output to the next. The first stage is always a search against the raw event index. Every subsequent stage transforms the result set.
The basic search returns events matching a keyword or field filter:
index=web sourcetype=access_combined status=500 uri_path="/api/v1/checkout"
Pipe the result into a stats command to aggregate:
index=web sourcetype=access_combined status=500 uri_path="/api/v1/checkout"
| stats count by uri_path
Pipe again to sort:
index=web sourcetype=access_combined status=500 uri_path="/api/v1/checkout"
| stats count by uri_path
| sort -count
The SPL command set is large. Common commands: stats (aggregate), eval (compute derived fields), where (filter a result set), rex (extract fields via regex from the raw event string), timechart (time-bucketed aggregation), join (join two search results), transaction (group events into transactions by a shared field), lookup (enrich events from a CSV or KV store lookup table).
The pipeline model is what gives SPL its power. A sequence of pipe stages can extract a field from unstructured text, filter on that field, compute a ratio, round the result, and format the output for a dashboard, all in a single query. No other observability query language supports this level of in-query transformation.
SPL also became a market position. Security information and event management (SIEM) buyers evaluated vendors partly on SPL compatibility because their analysts had years of existing queries. Splunk's own Cloud and Enterprise products, plus a community of SPL-fluent operators, gave the language durability beyond what its raw design merits might have earned.
Grafana Loki LogQL overview
LogQL is Grafana Loki's query language for log streams. Its design reflects Loki's indexing decision: only labels are indexed, not the log line bodies. Every LogQL query must begin with a stream selector that specifies which label set to query. The selector is not optional; without it, the query has no efficient path into the chunk store.
A stream selector uses curly-brace syntax with label matchers:
{service="checkout-api", env="production"}
This selector returns all log lines from all streams where service equals checkout-api and env equals production. Label matchers support equality (=), inequality (!=), and regex (=~, !~).
After the selector, a pipeline of filter and parser stages transforms the stream. A line filter uses the pipe symbol:
{service="checkout-api", env="production"} |= "status=500"
A JSON parser extracts fields from structured log bodies:
{service="checkout-api", env="production"} | json | http_status_code=`500`
Range aggregations compute a metric from a log stream over a time window. A rate() aggregation counts log lines per second:
rate({service="checkout-api", env="production"} |= "status=500" [5m])
The unwrap operator extracts a numeric field from parsed log records and makes it available for aggregation:
quantile_over_time(0.95, {service="checkout-api"} | json | unwrap response_time_ms [5m])
Label cardinality is the primary operational constraint in LogQL. Every label value combination creates a distinct stream. A label like user_id with millions of distinct values creates millions of streams, each requiring its own index entry and chunk file. This exhausts Loki's memory and index storage. The design discipline for Loki is to keep label cardinality low (service, environment, host, log level) and push high-cardinality fields into the log body where the JSON parser can extract them at query time, not at index time.
Where each language wins
Discover wins on error-context queries. When the question is "which transactions are generating the most 500 errors in production this week, broken down by release," Discover's flat event model and aggregate functions answer it directly. The data is already grouped, already deduplicated, already indexed by the fields that matter for error triage. A Discover query for this question is two filter terms and one group-by. The same question in SPL requires a well-structured log source and a stats pipeline. In LogQL it requires the right labels and a JSON parser stage for every log that carries a release field.
DDL wins on cross-signal correlation inside Datadog. When the question involves correlating a spike in log error rate with a metric anomaly and the traces that overlap the time window, DDL's unified facet model means the same service name and environment tag are consistent across all three signal surfaces. The Datadog UI can pivot from a metric graph to correlated logs to correlated traces using the same tag filters. No query language outside of Datadog can reproduce this within a single tool, because the cross-signal index is Datadog's proprietary infrastructure.
SPL wins on arbitrary text mining. When the question involves unstructured data, regex extraction, multi-source joins, or complex derived fields that require several transformation steps, SPL's pipeline model handles it without forcing the data into a rigid schema upfront. Security analysts who correlate authentication logs, DNS logs, and endpoint telemetry in a single query use SPL for exactly this reason. The command surface is large enough to express operations that other languages require external tooling to perform.
LogQL wins on cheap label-scoped log search at scale. When the question is "show me all log lines from the payment service in the last hour that contain ERROR," and the label set is properly configured, LogQL answers it by reading a small set of compressed chunks rather than scanning an index of every field in every log line. At log volumes where Elasticsearch-based stacks become expensive, Loki's chunk model with LogQL selectors is a real cost advantage.
Where each language is awkward
Discover is awkward when the question requires multi-step transformation. There is no pipe stage. You cannot take the result of one Discover query and feed it into another. A question like "for each route, compute the ratio of 500 errors to total requests" requires either the backend to support it as a first-class aggregate function (Sentry has failure_rate() for this) or the client to run two queries and compute the ratio externally. Discover also does not parse unstructured fields. If an error message contains a useful identifier embedded in a string, Discover cannot extract and group on that identifier without the backend having already indexed it as a tag.
DDL is awkward outside of Datadog. The facet model depends on Datadog's processing pipeline, which is proprietary. A Grok pattern written to extract a log field into a Datadog facet runs nowhere else. DDL queries written against processed Datadog facets cannot be ported to another backend without rewriting both the processing pipeline and the query syntax. The language is also split: log queries and metric queries use different syntaxes that are similar but not identical, which creates inconsistency for users who work across both surfaces.
SPL is awkward for simple cases because the required syntax is verbose. A basic count of ERROR log lines from a service in the last hour requires specifying the index, sourcetype, and at least one filter before the pipe, then a stats command, even if the natural language question is a single sentence. Teams that come from a SQL background also find the non-standard command names and pipeline order unintuitive. The learning curve for SPL is real, and the proprietary nature of the language means the investment does not transfer to other platforms.
LogQL is awkward when high-cardinality data needs to be a query dimension. If the question is "show me all errors grouped by user ID," and user IDs are not in the label set (because putting them there would create cardinality problems), LogQL requires the JSON parser to extract user IDs at query time and then group on the parsed field. This works, but it runs slower than a label-based query because it cannot use the chunk index and must scan line bodies. LogQL also has no join operator. Correlating two log streams by a shared field requires external tooling or a Grafana dashboard query that merges two separate LogQL results.
The same query in four languages
The question: find all 500 errors from the checkout service in the last hour, grouped by route, sorted by count descending.
In Sentry Discover:
http.status_code:500 project:checkout-api
Group by transaction, aggregate with count(), sort by count() descending. In the Discover UI this maps to a field configuration. In the API it maps to query parameters on the events endpoint:
GET /api/0/organizations/{org}/events/
?query=http.status_code%3A500%20project%3Acheckout-api
&field=transaction
&field=count()
&sort=-count
&statsPeriod=1h
In Datadog Query Language (log search):
service:checkout-api @http.status_code:500
Grouped by @http.route in the Datadog Logs Analytics view. In the Datadog API this maps to an aggregation call with a group_by field and a compute field for count, filtered to the last hour.
In Splunk SPL:
index=web sourcetype=access_combined service=checkout-api status=500 earliest=-1h
| stats count by uri_path
| sort -count
In Grafana Loki LogQL:
sum by (http_route) (
count_over_time(
{service="checkout-api", env="production"} | json | http_status_code=`500` [1h]
)
)
The SPL version is the shortest in terms of conceptual stages but requires the data to already be in the right Splunk index and sourcetype. The LogQL version is the longest because it requires the label selector, the JSON parser stage, the field filter on the parsed field, and then the metric aggregation wrapper. The Discover version is the most compact for this query class because the event model already knows what http.status_code and transaction are. The DDL version is similarly compact because @http.status_code is a facet the processing pipeline already extracted.
The OpenTelemetry query gap
OpenTelemetry defines wire protocols (OTLP), semantic conventions for attribute names, and SDK APIs for instrumentation. It does not define a query language. This is a deliberate choice: the OTel project is a vendor-neutral instrumentation and transport standard, not a backend. Defining a query language would require defining a query execution model, which is the backend's job.
The consequence is a gap in portability. An application instrumented with the OTel SDK and configured to export to OTLP can switch backends by changing an endpoint. The SDK changes are zero. But the queries, dashboards, and alerts built on the previous backend's query language cannot move. A team that migrated from Jaeger to Tempo kept the same OTLP pipeline but rewrote every dashboard because TraceQL (Tempo's query language) is not compatible with Jaeger's API query parameters.
Several working groups within the OpenTelemetry community have discussed a standardized query language. The OpenTelemetry Query Language (OTQL) proposal has appeared in SIG discussions but has not advanced to a specification. As of May 2026, there is no OTel query standard and no timeline for one.
What this means in practice: when you adopt a backend for OTel data, you adopt that backend's query language as the interface to your telemetry. The backend cannot be swapped without rewriting the query surface. The instrumentation can. Keeping instrumentation portable (using OTel SDKs and OTLP) while accepting query language lock-in is the current working model for most teams.
The gap also creates a problem for tooling that spans multiple backends. A Grafana installation that queries both Loki (LogQL) and Tempo (TraceQL) and Prometheus (PromQL) requires engineers to learn three distinct languages for three related questions about the same system. Unified query layers that translate between these languages exist (Grafana's own query federation, for example), but the translation is lossy. Features available in one language are often not expressible in another.
Where urgentry sits
urgentry's primary query surface is the Sentry Discover syntax, delivered through the compatible /api/0/organizations/{org}/events/ endpoint. This covers 218 of 218 Sentry REST API operations, which means existing Sentry dashboards, alert rules, and API integrations that use Discover query syntax continue to work when the DSN changes from Sentry's ingest to urgentry's ingest. No query rewrites are required for the error-tracking workflow.
For OTLP logs (received at /v1/logs), urgentry exposes a compatible query interface designed to keep log-querying tooling and dashboards functional. The goal is to cover the query surface that error-tracking teams use most often when working with logs alongside their errors and traces.
What urgentry does not try to be: a SPL-compatible text mining platform, a DDL-compatible cross-signal correlation engine, or a full LogQL backend for arbitrary log pipelines. These are real products that solve real problems. urgentry is an errors-first tool. The query language it implements reflects that. Discover syntax is expressive enough for the error-tracking queries that drive triage, alerting, and release health monitoring. Trying to support SPL's full command surface or DDL's metric-and-log split would mean building a different product.
The honest statement for teams evaluating urgentry: if your primary query workflow is error triage, release health, and transaction performance on OTel or Sentry SDK data, urgentry's Discover-compatible query surface covers it. If your primary workflow is arbitrary text mining across heterogeneous log sources, you want SPL and Splunk. If you need Datadog's cross-signal correlation tied to their processing pipeline, DDL is designed for exactly that. These are not hidden limitations; they are product scope decisions.
What to optimize for when picking a tool by its query language
Start with the queries your team writes most often. Not the queries that appear in vendor demos, but the queries that appear in your runbooks, your on-call procedures, and your weekly review dashboards. Write five of them down. Then evaluate which language expresses those five queries most directly, with the least friction. A language that handles 95% of your queries cleanly is better than a language that handles 100% of possible queries with high cognitive overhead.
Consider the join surface your work requires. SPL's join and transaction commands exist because security and operations workflows routinely need to correlate events from multiple data sources in a single query. If your team regularly correlates authentication logs with application events and network flows, a language with in-query join support matters. If your team asks "how many 500 errors did this service produce in the last hour," join support is irrelevant.
Match the language to the indexing model the backend can sustain. LogQL is cheap for low-cardinality label-scoped queries and expensive for high-cardinality parsed-field queries. If your primary questions involve high-cardinality dimensions (user ID, request ID, checkout session ID), LogQL is the wrong indexing model. If your primary questions involve service, environment, and severity, LogQL is efficient. The query language is the interface to the index. A query that the index cannot serve efficiently will be slow and expensive, regardless of how elegantly the syntax expresses it.
Factor in the portability cost honestly. DDL queries are Datadog-only. SPL queries are Splunk-only. LogQL queries work in any Loki-compatible backend. Discover queries work in Sentry and in backends that implement the Sentry API, including urgentry. If your team changes backends every two years or runs a multi-vendor observability stack, the portability of the query language is a real operational cost, not just a theoretical concern.
Frequently asked questions
Is Sentry Discover syntax the same as SQL?
No. Discover uses a key:value filter syntax rather than SQL clauses. It supports AND/OR boolean logic, field comparisons, and aggregate functions like count() and p95(), but there is no FROM clause, no JOIN, and no pipe stage. It is a filter-and-aggregate language designed for the Sentry event index. SQL is more expressive; Discover is faster to type and easier to embed in UI filter bars.
Can I use LogQL to query error data?
LogQL queries log streams selected by label sets. You can filter log records by severity and parse structured fields from the body, but LogQL has no concept of an error fingerprint, issue lifecycle, or occurrence count. You can count log lines that contain error strings, but that is not the same as a grouped, deduplicated issue with a regression detection lifecycle. LogQL is the right tool for log search and metric derivation from logs; it is the wrong tool for error triage workflows.
Does OpenTelemetry define a query language?
No. The OpenTelemetry project defines wire protocols, semantic conventions, and SDK instrumentation APIs. It does not specify a query language for the data those protocols carry. Each backend that accepts OTLP data chooses its own query interface. Discussions about a standardized OTel query language have occurred in the OTel community SIGs but have not produced a specification as of May 2026.
Is SPL only for Splunk?
SPL is Splunk-proprietary. Some third-party tools have implemented partial SPL compatibility for migration purposes, but the language is not an open standard and is not maintained by a vendor-neutral body. Queries written in SPL are not portable to Datadog, Grafana Loki, or Sentry without rewriting. The investment in SPL fluency does not transfer to other platforms.
Does urgentry support LogQL for log queries?
urgentry's primary query surface uses Sentry Discover syntax for error and event queries via the compatible /api/0/organizations/{org}/events/ endpoint. For OTLP logs received at /v1/logs, urgentry exposes a compatible query interface to keep log-querying tooling functional. The goal is coverage of the query surface that error-tracking teams use most often, rather than full LogQL compatibility with the complete label cardinality and pipeline model that Loki implements.
Sources
- Sentry Discover query documentation — the reference for Discover filter syntax, aggregate functions, and event vs. issue scoping in the Sentry product.
- Datadog log search syntax — the reference for the
key:valuefilter syntax, the@attributefacet prefix, and boolean logic in Datadog log search. - Datadog metrics query syntax — documents the
metric_name{tag:value}.rollup()aggregation model and the distinction between log and metric query surfaces. - Splunk SPL Search Reference — the canonical reference for SPL commands, including
stats,eval,rex,timechart, andtransaction. - Grafana Loki LogQL documentation — the reference for stream selectors, line filters, parser stages, and range aggregations including
rate(),count_over_time(), andunwrap. - OpenTelemetry query language discussion (GitHub) — the OTel community SIG thread on a standardized query language, documenting the absence of a specification as of 2026.
- urgentry compatibility matrix — the full table of Sentry REST API operations covered by urgentry, including the Discover-query-compatible events endpoint.
- FSL-1.1-Apache-2.0 license — the Functional Source License under which urgentry ships, converting to Apache 2.0 after two years.
Discover-compatible queries. Zero SDK changes.
urgentry covers 218 of 218 Sentry REST API operations, including the Discover-query-compatible events endpoint. Change the DSN. Keep the dashboards. One Go binary at 52 MB resident on a $5 VPS.