Latest Dynatrace
Grail metrics are queried with DQL, while classic metrics are queried using metric selectors. This guide shows how to convert classic metric selector expressions to DQL so you can smoothly and efficiently transition to Grail.
To make converting queries easier, Data Explorer and Dashboards Classic can now help you transform your existing metric selector queries into DQL.
Because there isn't an exact, one-to-one mapping between Classic metric selectors and DQL, some queries will require manual adjustments during the conversion. The troubleshooting section on this page can help you in these scenarios.
In this section, you'll learn how to use Dynatrace's conversion tool to product DQL from existing Classic metric selectors.
To automatically convert the metric selector to a DQL query in Notebooks or Dashboards
Go to Data Explorer to create and run your query.
The metric selector for this query in the advanced mode reads as:
builtin:host.cpu.usage:splitBy("dt.entity.host"):sort(value(auto,descending)):limit(20)
Select Open with… in the upper-right corner of the Data Explorer Result section.
Follow the on-screen instructions to:
When the destination document is displayed, verify the resulting query.
In our example, the resulting query is
timeseries usage = avg(dt.host.cpu.usage), by: { dt.entity.host }| sort arrayAvg(usage) desc| fieldsAdd entityName(dt.entity.host)| limit 20
If you have questions, see the troubleshooting section.
If your metric selector is not automatically convertable, in this section you'll learn how to manually convert your metric selector to DQL.
filter
and splitBy
, can be included in this initial command.timeseries
command can be added by additional commands as illustrated below.A list of Classic metrics and their equivalents in Grail can be found in the Built-in Metrics on Grail. Bear in mind that not all Classic metrics have Grail equivalents migration guides, and some metrics are not yet supported on Grail.
You should use Grail metrics when querying DQL. A list of Classic metrics and their equivalents in Grail can be found in Built-in Metrics on Grail.
Some metrics, such as those prefixed with builtin:apps
, are not supported on Grail and cannot be queried with DQL. The full list is available on Built-in Metrics on Grail.
In the process of transitioning from classic queries to Grail in Dynatrace, you might notice some differences in your query results. This is expected, as not all classic metrics have direct equivalents in Grail. However, if you encounter differences where you expect the queries to match, the following scenarios might help explain why.
It's possible that none of the following scenarios describe your query if you converted your Metrics Classic selector yourself. Try creating the DQL using the transpiler and comparing the results.
Scenario
Guide
The automatically converted DQL query returns no data on Grail.
Not all classic metrics have equivalents in Grail, and some metrics are not yet supported on Grail. For a list classic metrics and their equivalents in Grail, see Built-in Metrics on Grail.
The charts look similar but the numbers are slightly different.
To reduce complexity, several metrics have been refactored and have no direct equivalents in Grail. The runtime metrics migration guide will help you migrate these queries to Grail.
The percentile
function returns a different result than in Metrics Classic.
Grail uses a more accurate algorithm to calculate percentiles. Learn more in Metric commands.
The count
function returns a different result than in Metrics Classic.
DQL uses the count
function to calculate metric cardinality. You may need to use sum(..., rollup:total)
. To learn more, see the count aggregation section.
The chart looks similar, but the numbers are on a different scale.
Scale factor changes may indicate a bug in the metric calculation. In this case, please report the issue to the Dynatrace support team.
In DQL, there are equivalent aggregations for avg
, sum
, min
, max
, count
, and percentile
.
builtin:host.cpu.usage:splitby():avg
For example, the Classic metric selector query above can be converted to DQL as follows:
timeseries avg(dt.host.cpu.usage)
Specifying a time aggregation is possible with both the Metrics Classic metric selector and DQL.
builtin:host.cpu.usage:max:splitby():avg
The example above calculates the average maximum CPU usage across all hosts. It can be converted to DQL with the rollup
parameter as follows:
timeseries avg(dt.host.cpu.usage, rollup:max)
You can reproduce the Metrics Classic median
aggregation with the parametrized function percentile(..., 50)
.
builtin:host.cpu.usage:avg:splitby():median
For example, the Metrics Classic metric selector query above can be converted to DQL as follows:
timeseries median=percentile(dt.host.cpu.usage, 50, rollup:avg)
The Metrics Classic value
aggregation performs a sum for count metrics, and is therefore equivalent to the timeseries sum
aggregation.
builtin:service.requestCount.total:splitBy():value
For example, the Metrics Classic metric selector query above can be converted to DQL as follows:
timeseries sum(dt.service.request.count)
The Metrics Classic metric selector includes a pseudo-aggregation called auto
. Based on the metric's metadata, auto
selects the default aggregation for that metric. DQL doesn't have an equivalent pseudo-aggregation, however, so you need to explicitly specify the aggregation.
builtin:host.cpu.usage:splitby():auto
For example, the Metrics Classic metric builtin:host.cpu.usage
defaults to the avg
aggregation. Therefore, the Metrics Classic metric selector above can be converted to DQL as follows:
timeseries avg(dt.host.cpu.usage)
Custom metrics can be determined from the metric key directly. A Metrics Classic metric.key
with the .count
suffix uses the value
aggregation by default (and therefore will use a sum
in the converted DQL). All other custom metrics use the avg
aggregation by default.
For non-custom metrics (generally metric keys that contain a colon :
), there are two options:
Use the automatic converter to convert a simple metric selector such as
builtin:host.cpu.usage:splitby():auto
Look up the defaultAggregation
property of your metric's metadata via the Metrics Classic Metrics browser or the metric metadata API.
Because Metrics Classic metric selectors don't require an explicit aggregation, it's possible to omit the aggregation entirely. The auto
transformation is used implicitly in these cases.
builtin:host.cpu.usage:splitby()
Consequently, this metric selector is equivalent to the examples above.
The vast majority of Metrics Classic count
aggregations return cardinality–the number of series represented by a metric. The DQL count
function returns cardinality as well.
builtin:host.cpu.usage:splitBy():count
For example, many Dynatrace users want to count the number of hosts. This selector is converted to DQL as follows:
timeseries num_hosts = count(dt.host.cpu.usage)
The Metrics Classic count
transformation does ultimately depend on the metric metadata. In some scenarios, count
returns the number of observations reported to a metric. This behavior is uncommon but nevertheless useful in these scenarios.
record_processing_time:splitBy("host.name"):count
The above metric selector queries a hypothetical custom metric. As a custom metric without the .count
suffix (see below), the count
transformation here calculates the count of records processed. The converted DQL uses sum(..., rollup:total)
:
timeseries records_processed = sum(record_processing_time, rollup:total)
The final behavior of count
ultimately depends on a number of conditions. The automatic converter performs all these checks for you. You can provide a simple metric selector and determine from the resulting DQL which count is performed. For example:
builtin:host.cpu.usage:splitBy():count
The Metrics Classic splitBy
transformation is replaced by the timeseries by
parameter.
builtin:host.cpu.usage:splitby():avgbuiltin:service.requestCount.total:splitBy("dt.entity.service"):sum
For example, the Metrics Classic metric selector queries above can be converted to DQL as follows:
timeseries avg(dt.host.cpu.usage)timeseries sum(dt.service.request.count), by:{dt.entity.service}
The Metrics Classic merge
transformation is a counterpart to the splitBy
transformation. There is no equivalent to merge
in DQL, as it can be expressed equivalently with splitBy
.
builtin:host.net.nic.bytesRx:merge("dt.entity.network_interface"):avg
Because the Metrics Classic metric builtin:host.net.nic.bytesRx has two dimensions, dt.entity.host
and dt.entity.network_interface
, the above merge on dt.entity.network_interface
is equivalent to a split on dt.entity.host
:
builtin:host.net.nic.bytesRx:splitBy("dt.entity.host"):avg
Consequently, the metric selector can be converted to DQL as described in the split by transformation section:
timeseries bytes_rx=avg(dt.host.net.nic.bytes_rx), by:{dt.entity.host}
The Metrics Classic filter
transformation is equivalent to the timeseries filter
parameter.
builtin:cloud.aws.dynamo.tables:filter(in("dt.entity.aws_availability_zone",entitySelector("type(aws_availability_zone),entityName.equals(~"us-east-1a~")"))):splitBy():sort(value(auto,descending)):limit(20)
As Metrics Classic filter
transformations rely on entity selectors, the same syntax is readily supported in DQL with the classicEntitySelector
function.
timeseries tables=avg(dt.cloud.aws.dynamo.tables),by:{dt.entity.aws_availability_zone},filter:{in(dt.entity.aws_availability_zone,classicEntitySelector("type(aws_availability_zone),entityName.equals(\"us-east-1a\")"))}
The following table shows Metrics Classic filter conditions and their equivalent DQL.
Entity selector existsKey
and remainder
have no equivalent in DQL and are ignored at conversion.
The Metrics Classic series condition consists of an aggregation and a comparison operator, which can be reconstructed from array functions and comparison operators respectively.
builtin:host.disk.usedPct:splitBy("dt.entity.host"):filter(series(avg,gt(20)))
For example, the Metrics Classic metric selector query above can be converted to DQL as follows:
timeseries percent = avg(dt.host.disk.used.percent),by:{dt.entity.host}| filter arrayAvg(percent) > 20
In this example, avg
is replaced by arrayAvg
, and gt
is replaced by the >
(greater than) operator.
DQL uses variable assignment and sequential commands to improve on the arithmetic in Metrics Classic metric queries. You can learn more in DQL operators.
(100 * builtin:kubernetes.resourcequota.limits_memory_used/ builtin:kubernetes.resourcequota.limits_memory):splitBy("dt.entity.cloud_application_namespace","k8s.resourcequota.name")
The above metric selector query is formatted to highlight difference with the following converted DQL.
timeserieslimits_memory_used=avg(dt.kubernetes.resourcequota.limits_memory_used),limits_memory=avg(dt.kubernetes.resourcequota.limits_memory),by:{dt.entity.cloud_application_namespace, k8s.resourcequota.name}| fieldsAdd// use square brackets [] to perform timeseries arithmeticlimits_memory_usage = 100 * limits_memory_used[] / limits_memory[]
There is a clear difference in the approach taken with DQL. Metrics Classic metric selectors mix arithmetic with queries, whereas DQL separates these steps: first you assign the inputs, and then you perform the calculation within a fieldsadd
command.
This approach is both easier to read and easier to write:
fetch logs
or the makeTimeseries
command, for example.The Metrics Classic transformations in this section can be converted to DQL.
The Metrics Classic default
transformation is equivalent to the timeseries default
parameter.
builtin:host.availability.state:splitBy("dt.entity.host"):sum():default(0)
For example, the Metrics Classic metric selector query above can be converted to DQL as follows:
timeseries availability = sum(dt.host.availability, default:0),by:dt.entity.host
The Metrics Classic default(x, always)
transformation is a special case. The behavior of always
is mapped to the timeseries nonempty
parameter.
builtin:host.availability.state:splitBy("dt.entity.host"):sum():default(0,always)
For example, the Metrics Classic metric selector query above can be converted to DQL as follows:
timeseries availability = sum(dt.host.availability, default:0),by:{dt.entity.host},nonempty:true
The Metrics Classic delta
transformation is equivalent to the arrayDelta
function in DQL.
builtin:service.errors.fivexx.rate:splitBy():sum:delta
For example, the Metrics Classic metric selector query above can be converted to DQL as follows:
timeseries rate=sum(dt.service.errors.fivexx.rate)| fieldsAdd rate=arrayDelta(rate)
The following Metrics Classic fold
transformations have equivalent array functions in DQL:
fold(avg)
fold(max)
fold(min)
fold(sum)
fold(value)
fold(count)
fold(median)
fold(percentile(X))
For example, this Metrics Classic metric selector query:
builtin:host.cpu.usage:avg:fold(avg)
can be converted to DQL as follows:
timeseries usage=avg(dt.host.cpu.usage), by:{dt.entity.host}| fieldsAdd usage=arrayAvg(usage)
There are two ways to determine the equivalent DQL:
fold
transformation.fold
with fold(sum)
or fold(avg)
and compare the new query results to the original.An empty fold
transformation resolves to either the arraySum
or arrayAvg
function in DQL, depending on a combination of metric metadata and the sequence of operations before the fold
.
The fold
transformation has some implicit uses to be aware of in Data Explorer and Dashboards Classic. The Single value visualization, shown below, converts a line chart to a single value.
DQL does not allow implicit single value charts. Instead, the same result can be achieved by adding a fold
transformation, which can be converted to DQL as documented above.
builtin:kubernetes.container.restarts:splitby():sum
Using the above example, you can reproduce the Data Explorer's Single value by appending a fold
transformation.
builtin:kubernetes.container.restarts:splitby():sum:fold
In turn, the new selector can be converted to DQL.
timeseries restarts = sum(kubernetes.container.restarts)| fieldsAdd restarts = arraySum(restarts)
The Metrics Classic last
transformation is equivalent to the arrayLast
function in DQL.
For example, this Metrics Classic metric selector query:
builtin:service.response.time:splitBy("dt.entity.service"):percentile(99):last
Can be converted to DQL as follows:
timeseries time=percentile(dt.service.response.time, 99),by:{dt.entity.service}| fieldsAdd time=arrayLast(time)
The Metrics Classic lastReal
transformation has no equivalent in DQL. It also uses arrayLast
at conversion.
The Metrics Classic limit
transformation is equivalent to the limit
command in DQL.
For example, this Metrics Classic metric selector query (formatted for clarity):
builtin:host.cpu.usage:splitBy("dt.entity.host"):avg:sort(value(avg,descending)):limit(3)
can be converted to DQL as follows:
timeseries usage=avg(dt.host.cpu.usage), by:{dt.entity.host}| sort arrayAvg(usage) desc| limit 3
The Metrics Classic names
transformation is equivalent to the entityName
DQL function.
For example, this Metrics Classic metric selector query:
builtin:dt.host.disk.avail:splitBy("dt.entity.host", "dt.entity.disk"):max:names
can be converted to DQL as follows:
timeseries avail = max(dt.host.cpu.usage),by:{dt.entity.host, dt.entity.disk}| fieldsadd entityName(dt.entity.host), entityName(dt.entity.disk)
The Metrics Classic parents
transformation is not directly supported in DQL, but in many cases it can be reproduced.
For example, this Classic metric selector query (formatted for clarity):
builtin:tech.jvm.threads.count:avg:splitBy("dt.entity.process_group_instance"):parents:splitBy("dt.entity.host"):avg
uses the parents
transformation, so it can split on the parent dt.entity.host
dimension. Because data is already enriched in Grail, you can instead split by the host dimension directly.
timeseries avg(dt.runtime.jvm.threads.count),by:{dt.entity.host}
Missing enriched dimensions may indicate a bug in the metric calculation. In this case, please report the issue to the Dynatrace support team.
The Metrics Classic partition
transformation is unique in that it creates new series from existing ones. The equivalent DQL makes use of iterative expressions.
For example, this Metrics Classic metric selector query (formatted for clarity):
builtin:host.disk.avail:fold(avg):limit(3):partition("disk_usage",value("underused",gt(450000000000)),value("optimal",otherwise))
can be converted to DQL as follows:
timeseries avail=avg(dt.host.disk.avail), by: { dt.entity.disk, dt.entity.host }| fieldsAdd avail=arrayAvg(avail)| fieldsAdd disk_usage=if(avail>450000000000, "underused", else: "optimal")| limit 3
This example Metrics Classic metric selector query (formatted for clarity):
builtin:host.disk.avail:auto:limit(3):partition("disk_usage",value("underused",gt(450000000000)),value("optimal",otherwise))
can be converted to DQL as follows:
timeseries avail=avg(dt.host.disk.avail), by: { dt.entity.disk, dt.entity.host }| expand disk_usage=array("underused", "optimal")| fieldsAdd avail=if(disk_usage=="underused",if(avail[]>450000000000, avail[]),else:if(disk_usage=="optimal", if(NOT(avail[]>450000000000), avail[])))| filterOut isNull(arrayMin(avail))| limit 3| filterOut isNull(arrayMin(avail)) // arrayMin returns null if all elements are null
The Metrics Classic rate
transformation is equivalent to the timeseries rate
parameter.
For example, this Metrics Classic metric selector query:
builtin:service.requestCount.total:splitBy("dt.entity.service"):value:rate(1s)
can be converted to DQL as follows:
timeseries total=sum(dt.service.request.count, rate:1s),by:{dt.entity.service}
The Metrics Classic rollup
transformations have equivalent array functions in DQL:
rollup(avg)
rollup(max)
rollup(min)
rollup(sum)
rollup(value)
rollup(count)
rollup(median)
rollup(percentile(X))
For example, this Metrics Classic metric selector query:
builtin:host.cpu.usage:splitBy():avg:rollup(avg,5m)
can be converted to DQL as follows:
timeseries usage=avg(dt.host.cpu.usage), interval:1m| fieldsadd usage=arrayMovingAvg(usage, 5)
The moving window is time-agnostic and so the interval
parameter has been fixed to 1m
to ensure a 5-minute moving average. While the Metrics Classic rollup
transformation adjusts the query timeframe to include past data points, the DQL function does not adapt the query timeframe automatically, which means the first n
data points are null
(if n
is the window size). To get the same results, modify the query timeframe on the timeseries
command using the from:
parameter.
DQL array functions are not a direct replacement for rollup
when migrating Metric Events configurations.
The Metrics Classic smooth
transformation has no equivalent DQL.
The Metrics Classic sort
transformation is equivalent to the sort
command in DQL.
For example, this Metrics Classic metric selector query (formatted for clarity):
builtin:host.cpu.usage:splitBy("dt.entity.host"):avg:sort(value(avg,descending)):limit(3)
can be converted to DQL as follows:
timeseries usage=avg(dt.host.cpu.usage), by:{dt.entity.host}| sort arrayAvg(usage) desc| limit 3
The Metrics Classic timeshift
transformation is equivalent to the timeseries shift:
parameter.
For example, this MetricsClassic metric selector query:
builtin:host.cpu.usage:splitBy():avg:timeshift(-7d)
can be converted to DQL as follows:
timeseries usage=avg(dt.host.cpu.usage), shift:-7d
The Metrics Classic setUnit
and toUnit
transformations are not supported directly in DQL.
Instead, you can use the "Units and formats" section of any chart.