Blog

How one ES|QL query builds a metric chart for every metric in Elasticsearch

METRICS_INFO reports what metrics are in your data and how to aggregate each one, so Kibana Discover can chart counters, gauges and histograms correctly with no configuration and no field names to look up.

Store high-cardinality metrics efficiently with time series data streams, and keep your Prometheus and PromQL workflows along for the ride. 

Dig into infrastructure and metrics monitoring. Start a free cloud trial or try Elastic on your local machine now.

Type TS metrics-* in Kibana Discover and you get a chart for every metric in your data, already using the right aggregation and unit. No field names, no per-metric setup.

METRICS_INFO, an ES|QL command, reports which metrics and time series exist in the scope of your query, one row each. Discover appends it to your query behind the scenes, builds every metric chart from that single response, and can split those charts by any dimension your data exposes. Gauges are averaged, counters use SUM(RATE()), histograms take a percentile. You never need to know which aggregation a metric requires.

For the design and internals, including the per-series sibling command TS_INFO, see the METRICS_INFO and TS_INFO deep dive.

What METRICS_INFO returns

METRICS_INFO retrieves information about the metrics available in your time series data streams, together with applicable dimensions and other metadata, all scoped to the current TS query.

TS metrics-* | METRICS_INFO

You get one row describing each metric in the query scope:

metric_namedata_streamunitmetric_typefield_typedimension_fields
system.cpu.user.pctmetrics-system.cpu-defaultpercentgaugedouble[host.name, cloud.region]
activemq.broker.connections.countmetrics-activemq.broker-defaultnullcounterlong[activemq.broker.mbean,agent.id]

For syntax, see the METRICS_INFO command. For the design and internals, including the per-series sibling command TS_INFO, see the METRICS_INFO and TS_INFO deep dive.

How Discover turns a TS query into metric charts

Discover provides a dedicated experience for exploring metrics data. When it detects a TS query, it automatically builds an inventory of charts for the metrics available in your data.

Your original query remains unchanged and continues to run as usual. Behind the scenes, Discover derives a second request from it by appending | METRICS_INFO.

For example, if you run:

TS metrics-*
| WHERE `cloud.provider` == "gcp" AND `cloud.region` == "us-central1"

Discover derives a second request behind the scenes:

TS metrics-*
| WHERE `cloud.provider` == "gcp" AND `cloud.region` == "us-central1"
| METRICS_INFO

The METRICS_INFO response is parsed once and becomes the source for the dedicated metrics experience in Discover. From that inventory, Discover can generate charts and provide capabilities such as searching and filtering metrics, breaking them down by dimensions, inspecting the ES|QL query behind each chart, and adding metrics to dashboards.

What each METRICS_INFO column controls

Discover uses one METRICS_INFO response to generate every chart in the inventory. The response tells Discover which metrics to render, where to find their data, how to aggregate their values and how to display them.

Each column in the response plays a specific role:

Column nameWhat it controls in the inventory
metric_nameWhich metric panels are rendered
data_streamWhere each panel gets its data
metric_typeHow each metric is aggregated
field_typeThe type of the field, e.g., double, long
unitHow values are formatted
dimension_fieldsWhich dimensions can be used to filter and split charts

Which metric charts get rendered: metric_name

Each entry in the METRICS_INFO response represents a metric that Discover can visualize.

Discover iterates over the parsed response and creates a chart panel for each metric. The inventory therefore reflects the contents of the response directly.

Where each chart gets its data: data_stream

Each chart queries its data independently, even though all metric metadata comes from the same METRICS_INFO request.

The data_stream value determines the source used to construct the chart's ES|QL query.

For example:

TS metrics-system.cpu-default
| STATS AVG(system.cpu.user.pct) BY TBUCKET(100)

Querying each data stream separately matters most for searches that span multiple projects.

When the same metric_name appears in multiple data_stream values, Discover creates a separate panel for each stream. For example, in a serverless environment with cross-project search, each panel queries its own backing data and identifies the stream it represents.

This metric exists in multiple data streams. This chart shows data from metrics-system.cpu-default only.

Discover separates the panels intentionally. Combining results across streams could hide differences between them, which may be important when investigating metrics across projects or environments.

How counter, gauge, and histogram metrics are aggregated: metric_type, field_type

The metric_type tells Lens charts how to aggregate the metric, while the field_type describes the field.

Three metric types are currently supported:

metric_typeWhat the chart computesExample
gaugeAVG(field), representing a point-in-time levelCPU usage
counterSUM(RATE(field)), representing a rate of changeBytes sent per second
histogramPERCENTILE(field, p), summarizing a distributionp99 latency

How values are displayed: unit

The unit column controls how values are formatted on the Y axis. Lens, the charting library behind each panel, applies the formatting.

For example:

  • bytes: 1,024 is displayed as 1 KB.
  • percent: 0.75 is displayed as 75%.
  • No unit: the raw value is displayed without unit-specific formatting.

How charts are filtered and split by dimension: dimension_fields

The dimension_fields column identifies the dimensions associated with each metric, such as host.name, cloud.region, or service.name.

Discover combines these values across the METRICS_INFO response to populate the dimensions dropdown in the inventory toolbar.

Selecting a dimension affects the inventory in two ways:

  1. It filters the inventory. Discover re-runs METRICS_INFO with a condition such as WHERE MV_CONTAINS(dimension_fields, "host.name"), removing metrics that do not support the selected dimension.

  2. It splits each chart. Discover adds the selected dimension to the BY clause of each chart's ES|QL query, producing one series for each dimension value.

For example:

TS metrics-system.cpu-default
| STATS AVG(system.cpu.user.pct)
  BY TBUCKET(100), host.name

The result is a chart with a separate series for each host.name, while the inventory ensures that only metrics supporting that dimension are included in the inventory.

When you query a different data stream, any previously selected dimensions that the new stream does not expose are automatically cleared, so the per-chart queries never reference fields that do not exist there.

Try it in Kibana Discover

Visualizing your metrics requires no configuration, no dashboard setup, and no per-metric query to write. One TS query is enough.

Step 1: Ingest metrics data

If you are starting from scratch, you can send Prometheus metrics to Elasticsearch using Prometheus Remote Write. Any Elastic integration that collects system or application metrics works the same way. Once data lands in a TSDB-backed metrics-* data stream, Discover picks it up without any extra setup.

Step 2: Open Discover and run a TS query

  1. Open Kibana -> Discover.
  2. Switch to ES|QL mode.
  3. Type TS metrics-* and run the query.

Step 3: Explore your metric charts

Discover builds the inventory automatically. From there, you can:

  • Search for a metric by name to narrow the inventory.
  • Select a dimension from the toolbar to split every chart by host.name, cloud.region, or any dimension your data exposes.
  • Click a chart panel to open the full ES|QL query behind it.
  • Add individual panels to a dashboard.

Your metrics are ready to explore immediately, so you can start investigating your data as soon as you run the query.

See the documentation for how to Explore metrics data with Discover in Kibana.

Related Content

From a 582ms latency spike to the team that owns it, using Kibana Discover

Jeffrey Rengifo

Kubernetes observability: SLO templates that turn alerts into error budgets

Agi K Thomas

Correlate logs, metrics, and traces in one ES|QL query

Vinay Chandrasekhar

vLLM Prometheus metrics for self-hosted LLM tuning: TTFT, KV Cache, and GPU Utilization

Bahubali Shetti

From CrashLoopBackOff to OOMKilled with PromQL in Elasticsearch and Kibana

Miguel Sánchez Gómez