<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Elastic Observability Labs - Articles by Cauê Marcondes</title>
        <link>https://www.elastic.co/observability-labs</link>
        <description>Trusted security news &amp; research from the team at Elastic.</description>
        <lastBuildDate>Tue, 12 May 2026 14:43:08 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Elastic Observability Labs - Articles by Cauê Marcondes</title>
            <url>https://www.elastic.co/observability-labs/assets/observability-labs-thumbnail.png</url>
            <link>https://www.elastic.co/observability-labs</link>
        </image>
        <copyright>© 2026. Elasticsearch B.V. All Rights Reserved</copyright>
        <item>
            <title><![CDATA[Piping Hot: Bringing ES|QL to Your Grafana Dashboards Using the Elasticsearch Plugin]]></title>
            <link>https://www.elastic.co/observability-labs/blog/esql-grafana-elasticsearch-plugin</link>
            <guid isPermaLink="false">esql-grafana-elasticsearch-plugin</guid>
            <pubDate>Tue, 12 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[You can now write ES|QL queries in Grafana with the Elasticsearch plugin. Learn how to enable it and write pipe-based queries directly in the Grafana UI.]]></description>
            <content:encoded><![CDATA[<p>The Elasticsearch data source is one of the most popular plugins in the Grafana ecosystem, and it now ships ES|QL support as an experimental feature, available starting in Grafana 13.0. ES|QL is Elasticsearch's modern pipe-based query language that enables querying logs, metrics, and traces, and using Elasticsearch as a native <a href="https://www.elastic.co/observability-labs/blog/elasticsearch-supports-promql">Prometheus PromQL</a> data source, all directly from the Grafana query editor. Built by Elastic in collaboration with Grafana Labs and contributed upstream to the Grafana open source project, this integration is enabled through a single feature flag (<code>elasticsearchESQLQuery = true</code>) that unlocks a Monaco-powered editor with syntax highlighting, autocompletion, and inline error messages. We'll walk through how to enable it and write your first queries for log analysis, time series visualization, and metrics aggregation.</p>
<h2>Context</h2>
<p>Elasticsearch is one of the top plugins used with the Grafana UI.
Until now, the Elasticsearch plugin only supported Lucene and raw Query DSL for querying.
<a href="https://www.elastic.co/docs/reference/query-languages/esql">ES|QL</a> is Elastic's modern pipe-based query language, designed for analytics on log, metrics, and trace data. Its intuitive syntax makes it easier to filter, aggregate, and transform data compared to Query DSL or Lucene.</p>
<p>This has been tracked as a community request since 2024: <a href="https://github.com/grafana/grafana/issues/81765">grafana/grafana#81765</a>.</p>
<h2>How to enable ES|QL support in Grafana</h2>
<p>The feature is behind the <code>elasticsearchESQLQuery</code> feature flag.
To turn it on, add the following to your <code>grafana.ini</code>:</p>
<pre><code class="language-ini">[feature_toggles]
elasticsearchESQLQuery = true
</code></pre>
<p>Restart Grafana after saving.
The feature is available starting with Grafana 13.0.</p>
<h2>ES|QL in the Grafana query editor</h2>
<p>Once the flag is enabled, the Elasticsearch query editor gains a <strong>Query language</strong> selector.
You can switch between Lucene, Raw DSL, and ES|QL from the same editor panel.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/esql-grafana-elasticsearch-plugin/esql-query-language-selector.png" alt="ES|QL query language selector in the Grafana Elasticsearch plugin, showing the dropdown with ES|QL selected" /></p>
<p>When you select ES|QL, the editor switches to a Monaco-powered code editor, the same engine that powers VS Code.
You get syntax highlighting, error highlighting, and basic autocompletion out of the box.</p>
<p><strong>Smart index pre-population</strong> makes getting started quick: if an index pattern is configured in your data source settings, clicking into the ES|QL editor for the first time auto-inserts <code>FROM &lt;index&gt;</code>.
You can change or delete it freely.
If no index is configured, the <code>FROM</code> clause is left blank.</p>
<h2>Running your first queries</h2>
<h3>Count log entries by severity</h3>
<p>This is a good first query to confirm ES|QL is working and to get a feel for the syntax.</p>
<pre><code class="language-esql">FROM logs*
| STATS count = COUNT(*) BY log.level
| SORT count DESC
</code></pre>
<p>Run it in the <strong>Raw Data</strong> panel type to see a table with counts per log level:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/esql-grafana-elasticsearch-plugin/esql-count-by-log-level.png" alt="ES|QL query counting log entries by severity level, displayed as a table in Grafana Raw Data view" /></p>
<h3>Browse the latest errors</h3>
<p><code>WHERE</code>, <code>KEEP</code>, <code>SORT</code>, and <code>LIMIT</code> make it easy to filter down to exactly the fields and rows you care about.</p>
<pre><code class="language-esql">FROM logs*
| WHERE log.level == &quot;ERROR&quot;
| KEEP @timestamp, message, host.name
| SORT @timestamp DESC
| LIMIT 20
</code></pre>
<p><img src="https://www.elastic.co/observability-labs/assets/images/esql-grafana-elasticsearch-plugin/esql-filter-errors.png" alt="ES|QL query filtering error-level log entries and displaying timestamp, message, and host name columns" /></p>
<h3>Log volume over time</h3>
<p>Use <code>BUCKET</code> to group log counts into hourly intervals.
This works well with the <strong>Metrics</strong> panel type, which can render it as a time series graph.</p>
<pre><code class="language-esql">FROM logs*
| STATS count = COUNT(*) BY bucket = BUCKET(@timestamp, 1 hour)
| SORT bucket ASC
</code></pre>
<p><img src="https://www.elastic.co/observability-labs/assets/images/esql-grafana-elasticsearch-plugin/esql-log-volume-time-series.png" alt="ES|QL query aggregating log volume into hourly buckets, rendered as a line graph in Grafana Metrics view" /></p>
<h3>Top hosts by log activity</h3>
<p>Identifying the most active hosts is a common operations task.
<code>STATS</code> with <code>BY</code> and <code>LIMIT</code> makes it concise.</p>
<pre><code class="language-esql">FROM logs*
| STATS log_count = COUNT(*) BY host.name
| SORT log_count DESC
| LIMIT 10
</code></pre>
<p><img src="https://www.elastic.co/observability-labs/assets/images/esql-grafana-elasticsearch-plugin/esql-top-hosts.png" alt="ES|QL query returning top 10 hosts by log count, displayed as a table in Grafana Metrics view" /></p>
<h3>The TS command for time series metrics</h3>
<p>For metrics data in &lt;a href=&quot;https://www.elastic.co/docs/manage-data/data-store/data-streams/time-series-data-stream-tsds&quot;&gt;Time Series Data Streams (TSDS)&lt;/a&gt;, the <code>TS</code> source command in ES|QL enables metrics analytics and time series aggregation.</p>
<p>Examples:</p>
<ul>
<li><code>RATE()</code>: rate of change over time</li>
<li><code>AVG_OVER_TIME()</code>: average value over a sliding window</li>
<li><code>INCREASE()</code>: total increase over a period</li>
<li><code>DELTA()</code>: difference between first and last value</li>
<li><code>LAST_OVER_TIME()</code>: most recent value in a window</li>
</ul>
<p>The pattern follows a two-level aggregation: an inner function applied per individual time series, then an outer function aggregating across groups (for example, per host or per service).</p>
<pre><code class="language-esql">TS metrics*
  | STATS SUM(RATE(metrics.system.cpu.time)) BY TBUCKET(10 m)
</code></pre>
<p><img src="https://www.elastic.co/observability-labs/assets/images/esql-grafana-elasticsearch-plugin/ts-command-metrics-graph.png" alt="TS command query in Grafana showing a CPU time rate metric plotted over time" /></p>
<p>You can also use <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/time-series-aggregation-functions/avg_over_time"><code>AVG_OVER_TIME()</code></a> to compute the average value of a metric over a sliding window, then split the results by host and 10-minute buckets:</p>
<pre><code class="language-esql">TS metrics*
  | STATS MAX(AVG_OVER_TIME(metrics.system.memory.utilization)) BY host.name,TBUCKET(10m)
</code></pre>
<p><img src="https://www.elastic.co/observability-labs/assets/images/esql-grafana-elasticsearch-plugin/ts-avg-over-time-by-host.png" alt="TS command query using AVG_OVER_TIME showing memory utilization per host in 10-minute buckets" /></p>
<p><code>TS</code> also runs queries through the ES|QL vectorized compute engine.
Internal benchmarks show performance improvements of an order of magnitude or more compared to equivalent Query DSL queries for TSDS-backed data.</p>
<p>Reference:</p>
<ul>
<li><a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/ts">TS command documentation</a></li>
<li><a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/time-series-aggregation-functions">Time series aggregation functions</a></li>
</ul>
<h2>Inline error messages</h2>
<p>ES|QL queries run against the <a href="https://www.elastic.co/docs/reference/query-languages/esql/esql-rest"><code>/_query</code> HTTP endpoint</a> on Elasticsearch.
If your query has a syntax error or references a non-existent field, Elasticsearch returns a structured error response.
The plugin surfaces this directly in the query editor as an inline message, so you see exactly what went wrong right in the Grafana UI.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/esql-grafana-elasticsearch-plugin/esql-inline-error.png" alt="Grafana Elasticsearch plugin showing an inline ES|QL error message for an unknown column reference" /></p>
<p>In the example above, <code>host.nam</code> is missing the final <code>e</code>.
Elasticsearch catches this as a verification exception and returns the field name that could not be resolved.
That message appears inline, right below the query editor.</p>
<h2>Technical details</h2>
<p>Under the hood, the plugin handles ES|QL and other query types on separate code paths.
ES|QL queries go to the <code>/_query</code> endpoint with <code>Content-Type: application/json</code>.
Lucene and Query DSL queries continue to use <code>/_msearch</code> with <code>Content-Type: application/x-ndjson</code>.</p>
<p>This separation is intentional: <code>/_query</code> returns a different response shape that the plugin parses independently before passing data to Grafana panels.</p>
<h2>Try it out!</h2>
<p>That also means this is a good moment to try it and give feedback.</p>
<p>The <a href="https://github.com/grafana/grafana/pull/117798">upstream PR</a> and the <a href="https://github.com/grafana/grafana/issues/81765">original tracking issue</a> are public.
If you run into problems or have requests, both are open for comments.</p>
<h2>Next steps</h2>
<ul>
<li>Enable the feature in your Grafana 13.0 instance with <code>elasticsearchESQLQuery = true</code></li>
<li>Try the example queries above against your own indices</li>
<li>For metrics data, give the ES|QL <code>TS</code> command a spin, against an Elasticsearch 9.2 or Serverless data source.</li>
<li>Read the full <a href="https://www.elastic.co/docs/reference/query-languages/esql">ES|QL overview</a> to explore what else the language can do</li>
</ul>
<p>If you are not yet on Elasticsearch, you can start a free trial at <a href="https://cloud.elastic.co/registration">Elastic Cloud</a>.</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/esql-grafana-elasticsearch-plugin/header.jpg" length="0" type="image/jpg"/>
        </item>
    </channel>
</rss>