Homeโ€บ๐Ÿ” Track 2: Query & Exploreโ€บModule 42 min read ยท 5/21

DQL Fundamentals

Hands-on

DQL Fundamentals

DQL (Dynatrace Query Language) is the single query language for all data in Grail. Every dashboard tile, every alert, every notebook section uses DQL.

The Pipeline Pattern

Every DQL query is a pipeline โ€” data flows through commands connected by | (pipe):

fetch logs                          // 1. Load data
| filter loglevel == "ERROR"        // 2. Keep only errors
| fields timestamp, content         // 3. Select columns
| sort timestamp desc               // 4. Order results
| limit 10                          // 5. Limit output

Essential Commands

Command         What It Does                              Example
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
fetch           Load data from Grail                      fetch logs
timeseries      Load metrics as time series                timeseries avg(dt.host.cpu.usage)
filter          Keep rows matching condition               filter loglevel == "ERROR"
filterOut       Remove rows matching condition             filterOut loglevel == "NONE"
fields          Select specific columns                    fields timestamp, content
fieldsAdd       Add computed columns                       fieldsAdd duration_ms = duration / 1000
sort            Order results                              sort timestamp desc
limit           Limit number of results                    limit 20
summarize       Group and aggregate                        summarize count(), by:{loglevel}
dedup           Remove duplicates                          dedup entity.name
parse           Extract fields from text                   parse content, "JSON:log"
expand          Flatten arrays into rows                   expand tags
describe        Show schema of a data object               describe dt.entity.host

Aggregation Functions

Function        What It Calculates                        Example
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
count()         Number of records                         summarize cnt=count()
avg()           Average value                             summarize avg(duration)
sum()           Total                                     summarize sum(bytes)
min() / max()   Minimum / maximum                         summarize max(cpu)
percentile()    Percentile value                          summarize p95=percentile(rt, 95)
countIf()       Conditional count                         summarize errors=countIf(status >= 400)

โš ๏ธ You MUST alias aggregations before sorting: summarize cnt=count() | sort cnt desc. Writing sort count() desc directly will fail.

Hands-On: Try These Queries

// Count logs by level
fetch logs
| summarize cnt=count(), by:{loglevel}
| sort cnt desc

// Host CPU over time
timeseries avg(dt.host.cpu.usage), by:{dt.entity.host}

// Services with their type
fetch dt.entity.service
| fields entity.name, serviceType

// Errors in the last hour
fetch logs, from:now()-1h
| filter loglevel == "ERROR"
| summarize cnt=count()

๐Ÿ›  Try it: Open a Notebook โ†’ paste each query in a separate DQL section โ†’ run them. timeseries queries render as charts, fetch queries render as tables.

Key Rules

  • Strings use double quotes โ€” "ERROR" not 'ERROR' (single quotes are not supported)
  • Sort BEFORE fields โ€” sort needs the column to exist, fields drops columns
  • timeseries is a starting command โ€” for metrics only, not for logs/events
  • makeTimeseries is a pipe command โ€” creates time series from fetched data (logs, events)
  • describe shows all available fields for any data object
  • Named parameters required โ€” substring(content, from:0, to:100) not substring(content, 0, 100). Same for if(x > 10, then:"high", else:"low")
  • Backticks for special field names โ€” `error-code` for fields with hyphens or special characters
  • array() for multi-value filters โ€” filter in(loglevel, array("ERROR", "WARN", "SEVERE"))
  • Expand uses brackets โ€” after expand arr, access fields via arr[field] NOT arr.field