{"id":1014,"date":"2026-05-29T12:19:58","date_gmt":"2026-05-29T12:19:58","guid":{"rendered":"https:\/\/www.devopsschool.com\/tutorials\/?p=1014"},"modified":"2026-05-29T12:20:00","modified_gmt":"2026-05-29T12:20:00","slug":"dynatrace-query-language-tutorial-complete-step-by-step-dql-guide-from-basics-to-advanced-observability-queries","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/tutorials\/dynatrace-query-language-tutorial-complete-step-by-step-dql-guide-from-basics-to-advanced-observability-queries\/","title":{"rendered":"Dynatrace Query Language Tutorial: Complete Step-by-Step DQL Guide from Basics to Advanced Observability Queries"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Dynatrace Query Language, or <strong>DQL<\/strong>, is the query language used to explore, filter, aggregate, correlate, and visualize data stored in <strong>Dynatrace Grail<\/strong>. Dynatrace describes DQL as a language for exploring data, discovering patterns, identifying anomalies\/outliers, and building analysis on top of Grail data. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This guide is designed for hands-on learning in the <strong>Dynatrace Playground<\/strong>, especially from:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Dynatrace Playground \u2192 Notebooks \u2192 Add \u2192 DQL\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You can copy\/paste most examples directly.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">1. Where to run DQL in Dynatrace<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">You can run DQL in multiple Dynatrace places.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Option 1: Notebooks \u2014 best place for learning<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use this for practice, training, investigation, and experiments.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Steps:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1. Open Dynatrace Playground\n2. Go to Apps\n3. Open Notebooks\n4. Click Notebook or Create new notebook\n5. Open Add menu\n6. Select DQL\n7. Paste query\n8. Click Run\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace\u2019s own tutorial recommends <strong>Notebooks<\/strong> for running DQL examples: go to <strong>Notebooks<\/strong>, create a notebook, open <strong>Add<\/strong>, select <strong>DQL<\/strong>, enter your query, and click <strong>Run<\/strong>. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/observe\/application-observability\/distributed-tracing\/use-traces-and-dql-to-spot-patterns\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Option 2: Dashboards \u2014 best place for reusable charts<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use this when you want to convert your DQL into a dashboard tile.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Steps:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1. Open Dynatrace Playground\n2. Go to Dashboards\n3. Open or create a dashboard\n4. Click Add &gt; DQL\n5. On Data tab, paste query\n6. Click Run\n7. Go to Visual tab\n8. Choose Table, Line chart, Bar chart, Single value, etc.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace dashboards support <strong>Add &gt; DQL<\/strong>, where the <strong>Data<\/strong> tab is used to define the query, <strong>Run<\/strong> executes it, and the <strong>Visual<\/strong> tab controls the result format. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/analyze-explore-automate\/dashboards-and-notebooks\/dashboards-new\/components\/dashboard-component-data\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Option 3: Logs app \u2014 best for log investigation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use this when your main target is logs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Typical flow:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1. Go to Logs\n2. Use filter\/search\n3. Switch to advanced DQL\/edit DQL query mode if available\n4. Run query\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace documentation describes testing DQL matchers from Logs by going to Logs, opening the actions menu next to the filter field, selecting <strong>Edit DQL query<\/strong>, entering the DQL query, and running it. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/analyze-explore-automate\/logs\/lma-classic-log-processing\/lma-log-processing-examples?utm_source=chatgpt.com\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Option 4: Documentation \u201cRun in Playground\u201d<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Many Dynatrace documentation examples include <strong>Run in Playground<\/strong>. That is very useful because it opens a ready-made query in the Playground.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">2. DQL mental model<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">DQL is a <strong>read-only<\/strong>, pipeline-based query language. A DQL query contains one or more commands, and each command passes records to the next command using the pipe operator <code>|<\/code>. Dynatrace explains that each command returns tabular output: records are rows, fields are columns, and command order matters for both results and performance. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/dql-guide\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Think like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Load data \u2192 filter data \u2192 select fields \u2192 transform \u2192 aggregate \u2192 visualize\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Mermaid view of DQL pipeline<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart LR\n    A&#91;fetch \/ data \/ timeseries] --&gt; B&#91;filter \/ search]\n    B --&gt; C&#91;fields \/ fieldsAdd \/ fieldsRemove]\n    C --&gt; D&#91;parse \/ fieldsFlatten]\n    D --&gt; E&#91;summarize \/ makeTimeseries]\n    E --&gt; F&#91;sort \/ limit]\n    F --&gt; G&#91;Table \/ Line chart \/ Bar chart \/ Single value]\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Basic DQL example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs\n| filter loglevel == \"ERROR\"\n| summarize error_count = count()\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>One-row table with error_count.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">3. DQL command categories<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace groups DQL commands into categories such as data source commands, metric commands, filter\/search commands, selection\/modification commands, parsing commands, ordering commands, structuring commands, aggregation commands, correlation\/join commands, and Smartscape commands. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Category<\/th><th>Important commands<\/th><th>Purpose<\/th><\/tr><\/thead><tbody><tr><td>Data source<\/td><td><code>fetch<\/code>, <code>data<\/code>, <code>describe<\/code>, <code>fieldsSnapshot<\/code><\/td><td>Load or inspect data<\/td><\/tr><tr><td>Metrics<\/td><td><code>timeseries<\/code>, <code>metrics<\/code><\/td><td>Query metric data<\/td><\/tr><tr><td>Filter\/search<\/td><td><code>filter<\/code>, <code>filterOut<\/code>, <code>search<\/code>, <code>dedup<\/code><\/td><td>Reduce records<\/td><\/tr><tr><td>Selection<\/td><td><code>fields<\/code>, <code>fieldsAdd<\/code>, <code>fieldsRemove<\/code>, <code>fieldsRename<\/code><\/td><td>Control columns<\/td><\/tr><tr><td>Parsing<\/td><td><code>parse<\/code><\/td><td>Extract structured data<\/td><\/tr><tr><td>Ordering<\/td><td><code>sort<\/code>, <code>limit<\/code><\/td><td>Order\/restrict output<\/td><\/tr><tr><td>Structuring<\/td><td><code>fieldsFlatten<\/code>, <code>expand<\/code><\/td><td>Work with nested records\/arrays<\/td><\/tr><tr><td>Aggregation<\/td><td><code>summarize<\/code>, <code>makeTimeseries<\/code>, <code>fieldsSummary<\/code><\/td><td>Group and calculate<\/td><\/tr><tr><td>Correlation<\/td><td><code>join<\/code>, <code>lookup<\/code>, <code>append<\/code><\/td><td>Combine datasets<\/td><\/tr><tr><td>Smartscape<\/td><td><code>smartscapeNodes<\/code>, <code>smartscapeEdges<\/code>, <code>traverse<\/code><\/td><td>Entity topology<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">4. First safe command: <code>data<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Before using real Dynatrace logs, learn with <code>data<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>data<\/code> command creates sample records during query runtime. It is useful for testing and documentation because it does not depend on whether your Playground has logs\/spans\/events at that exact time. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/data-source-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Run this in Notebooks<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200, duration_ms = 120),\n     record(service = \"checkout\", status = 500, duration_ms = 900),\n     record(service = \"payment\", status = 200, duration_ms = 300),\n     record(service = \"payment\", status = 503, duration_ms = 1500)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>A table with four rows:\nservice | status | duration_ms\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is your safest learning playground inside the Dynatrace Playground.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">5. Load real data with <code>fetch<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>fetch<\/code> command loads data from a Dynatrace\/Grail data object. The simplest example is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace documents <code>fetch logs<\/code> as the simplest form of the <code>fetch<\/code> command, and <code>fetch<\/code> supports parameters such as <code>from<\/code>, <code>to<\/code>, <code>timeframe<\/code>, <code>bucket<\/code>, <code>samplingRatio<\/code>, and <code>scanLimitGBytes<\/code>. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/data-source-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Common data objects<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Data object<\/th><th>Query<\/th><th>Use case<\/th><\/tr><\/thead><tbody><tr><td>Logs<\/td><td><code>fetch logs<\/code><\/td><td>Application, infrastructure, Kubernetes, process logs<\/td><\/tr><tr><td>Events<\/td><td><code>fetch events<\/code><\/td><td>System\/security\/custom events<\/td><\/tr><tr><td>Business events<\/td><td><code>fetch bizevents<\/code><\/td><td>Business transactions and custom business data<\/td><\/tr><tr><td>Spans<\/td><td><code>fetch spans<\/code><\/td><td>Distributed tracing\/span-level analysis<\/td><\/tr><tr><td>Problems<\/td><td><code>fetch dt.davis.problems<\/code><\/td><td>Davis problem analysis<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Run: recent logs<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Up to 20 log records.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If you see no result, change the Notebook timeframe to a wider window, such as <strong>Last 24 hours<\/strong>, or use an explicit timeframe:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| limit 20\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Run: recent spans<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch spans, from:-24h\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Up to 20 distributed trace span records.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If no result appears, the Playground dataset\/timeframe may not contain spans in that window.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">6. Understand timeframe<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">There are two ways to control time.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Method 1: UI timeframe<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use the time selector in the top-right of Notebook\/Dashboard.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Good for beginners.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Method 2: DQL timeframe<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>from<\/code>, <code>to<\/code>, or <code>timeframe<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace recommends using the UI timeframe controls, but DQL can override them using <code>from<\/code>, <code>to<\/code>, or <code>timeframe<\/code>. If no timeframe is specified in the app\/API, Dynatrace notes a default timeframe behavior; the documentation example also shows relative and absolute timeframes. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/dql-guide\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Last 2 hours<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:now() - 2h\n| limit 20\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Last 24 hours, excluding last 2 hours<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:now() - 24h, to:now() - 2h\n| limit 20\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Shorter syntax<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| limit 20\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Absolute timeframe<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, timeframe:\"2026-05-28T00:00:00Z\/2026-05-29T00:00:00Z\"\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Records only from the specified time window.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">7. Select fields with <code>fields<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Raw records can contain many fields. Use <code>fields<\/code> to keep only the fields you want.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace lists <code>fields<\/code> under selection\/modification commands and describes it as keeping only specified fields. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Run<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| fields timestamp, loglevel, log.source, content\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>A cleaner table with only timestamp, loglevel, log.source, and content.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">With sample data<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200, duration_ms = 120),\n     record(service = \"checkout\", status = 500, duration_ms = 900),\n     record(service = \"payment\", status = 503, duration_ms = 1500)\n| fields service, status\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Only service and status columns.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">8. Add calculated fields with <code>fieldsAdd<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\"><code>fieldsAdd<\/code> evaluates an expression and appends or replaces a field. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Run<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200, duration_ms = 120),\n     record(service = \"checkout\", status = 500, duration_ms = 900),\n     record(service = \"payment\", status = 503, duration_ms = 1500)\n| fieldsAdd is_error = status &gt;= 500\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>New column is_error:\nfalse\ntrue\ntrue\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Add severity category<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200, duration_ms = 120),\n     record(service = \"checkout\", status = 500, duration_ms = 900),\n     record(service = \"payment\", status = 503, duration_ms = 1500)\n| fieldsAdd severity = if(status &gt;= 500, \"error\", else:\"ok\")\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>New severity column:\nok\nerror\nerror\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">9. Sort and limit<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>sort<\/code> to order results and <code>limit<\/code> to reduce result size.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace documents <code>sort<\/code> as sorting records and <code>limit<\/code> as limiting the number of returned records. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Sort sample records<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200, duration_ms = 120),\n     record(service = \"checkout\", status = 500, duration_ms = 900),\n     record(service = \"payment\", status = 503, duration_ms = 1500),\n     record(service = \"catalog\", status = 200, duration_ms = 80)\n| sort duration_ms desc\n| limit 2\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Top 2 slowest records.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Logs sorted latest first<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| fields timestamp, loglevel, content\n| sort timestamp desc\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>20 latest log records.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Performance note: Dynatrace recommends putting <code>sort<\/code> near the end of the query rather than sorting immediately after <code>fetch<\/code>, because sorting early can reduce performance. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/dql-best-practices?utm_source=chatgpt.com\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">10. Filter data with <code>filter<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\"><code>filter<\/code> keeps only records matching a condition. Dynatrace describes <code>filter<\/code> as reducing the number of records by keeping only records that match the specified condition. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/filtering-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Equality filter<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200),\n     record(service = \"checkout\", status = 500),\n     record(service = \"payment\", status = 503)\n| filter service == \"checkout\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Only records where service is checkout.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Not equal<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200),\n     record(service = \"checkout\", status = 500),\n     record(service = \"payment\", status = 503)\n| filter service != \"payment\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Everything except payment.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Greater than \/ less than<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", duration_ms = 120),\n     record(service = \"payment\", duration_ms = 1500),\n     record(service = \"catalog\", duration_ms = 80)\n| filter duration_ms &gt; 500\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Only slow records above 500 ms.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Multiple conditions<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200, duration_ms = 120),\n     record(service = \"checkout\", status = 500, duration_ms = 900),\n     record(service = \"payment\", status = 503, duration_ms = 1500)\n| filter status &gt;= 500 and duration_ms &gt; 1000\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Only payment 503 with duration 1500.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">OR condition<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200),\n     record(service = \"checkout\", status = 500),\n     record(service = \"payment\", status = 503)\n| filter status == 500 or status == 503\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Only 500 and 503 records.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">11. String filtering: <code>contains<\/code>, <code>startsWith<\/code>, <code>endsWith<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">DQL functions like <code>contains<\/code>, <code>startsWith<\/code>, and <code>endsWith<\/code> are useful for string filtering. Dynatrace lists string functions including <code>contains<\/code>, <code>endsWith<\/code>, <code>matchesPhrase<\/code>, <code>parse<\/code>, <code>startsWith<\/code>, <code>substring<\/code>, and others. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/functions\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">contains<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(message = \"Payment failed due to timeout\"),\n     record(message = \"Checkout completed\"),\n     record(message = \"Database connection failed\")\n| filter contains(message, \"failed\")\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Rows where message contains failed.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">startsWith<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(path = \"\/api\/orders\"),\n     record(path = \"\/admin\/login\"),\n     record(path = \"\/api\/payments\")\n| filter startsWith(path, \"\/api\")\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/api\/orders\n\/api\/payments\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">endsWith<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(file = \"app.log\"),\n     record(file = \"audit.log\"),\n     record(file = \"error.txt\")\n| filter endsWith(file, \".log\")\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>app.log\naudit.log\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Real log example<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| filter loglevel == \"ERROR\" and contains(content, \"Exception\")\n| fields timestamp, loglevel, content\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ERROR logs where content contains Exception.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">12. Search with <code>search<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>search<\/code> when you want a simple search-bar style query.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace says the <code>search<\/code> command works like a search bar in DQL, can search across all fields or specific fields, and performs case-insensitive string matching. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/filtering-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Search all fields<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| search \"timeout\"\n| fields timestamp, loglevel, content\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Logs containing timeout in any searchable field.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Search specific field<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| search content ~ \"timeout\"\n| fields timestamp, loglevel, content\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Logs where content matches timeout.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Search with wildcard<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| search content ~ \"time*\"\n| fields timestamp, loglevel, content\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Logs where content has token beginning with time.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Difference between <code>filter<\/code> and <code>search<\/code><\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Feature<\/th><th><code>filter<\/code><\/th><th><code>search<\/code><\/th><\/tr><\/thead><tbody><tr><td>Best for<\/td><td>Precise conditions<\/td><td>Text search<\/td><\/tr><tr><td>Case behavior<\/td><td>Depends on operator\/function<\/td><td>Case-insensitive search behavior<\/td><\/tr><tr><td>Example<\/td><td><code>filter loglevel == \"ERROR\"<\/code><\/td><td><code>search \"error\"<\/code><\/td><\/tr><tr><td>Field-specific<\/td><td>Yes<\/td><td>Yes, with <code>field ~ \"term\"<\/code><\/td><\/tr><tr><td>Good for<\/td><td>Status, duration, service, entity<\/td><td>Keyword investigation<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>filter<\/code> when you know the field and exact condition. Use <code>search<\/code> when you are exploring.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">13. Exclude data with <code>filterOut<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\"><code>filterOut<\/code> removes records that match a condition. Dynatrace notes one important difference: <code>filterOut x<\/code> keeps records where <code>x<\/code> is null, while <code>filter not x<\/code> removes records where <code>x<\/code> is null. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/filtering-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Run<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", loglevel = \"INFO\"),\n     record(service = \"checkout\", loglevel = \"ERROR\"),\n     record(service = \"payment\", loglevel = \"WARN\")\n| filterOut loglevel == \"INFO\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ERROR and WARN records only.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Real log example<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| filterOut loglevel == \"INFO\" or loglevel == \"NONE\"\n| fields timestamp, loglevel, content\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Logs except INFO\/NONE.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">14. Remove duplicates with <code>dedup<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\"><code>dedup<\/code> removes duplicate records based on one or more fields. Dynatrace explains that <code>dedup<\/code> removes duplicate values, while <code>summarize<\/code> groups records and aggregates them. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/filtering-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Run<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200),\n     record(service = \"checkout\", status = 500),\n     record(service = \"payment\", status = 503),\n     record(service = \"payment\", status = 200)\n| dedup service\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>One row per service.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Keep latest per service<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(timestamp = 1, service = \"checkout\", status = 200),\n     record(timestamp = 2, service = \"checkout\", status = 500),\n     record(timestamp = 3, service = \"payment\", status = 503),\n     record(timestamp = 4, service = \"payment\", status = 200)\n| dedup service, sort:{timestamp desc}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Latest record per service.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">15. Understand DQL data types<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">DQL is strongly typed. Functions and operators expect specific declared data types, and types are assigned during parsing or casting. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/data-types\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Important types:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Type<\/th><th>Example<\/th><th>Use<\/th><\/tr><\/thead><tbody><tr><td><code>string<\/code><\/td><td><code>\"checkout\"<\/code><\/td><td>Text<\/td><\/tr><tr><td><code>long<\/code><\/td><td><code>500<\/code><\/td><td>Integer<\/td><\/tr><tr><td><code>double<\/code><\/td><td><code>99.95<\/code><\/td><td>Decimal<\/td><\/tr><tr><td><code>boolean<\/code><\/td><td><code>true<\/code>, <code>false<\/code><\/td><td>Conditions<\/td><\/tr><tr><td><code>timestamp<\/code><\/td><td><code>now()<\/code><\/td><td>Point in time<\/td><\/tr><tr><td><code>duration<\/code><\/td><td><code>2h<\/code>, <code>500ms<\/code><\/td><td>Time duration<\/td><\/tr><tr><td><code>timeframe<\/code><\/td><td><code>timeframe(from:..., to:...)<\/code><\/td><td>Start\/end window<\/td><\/tr><tr><td><code>array<\/code><\/td><td><code>array(1,2,3)<\/code><\/td><td>List<\/td><\/tr><tr><td><code>record<\/code><\/td><td><code>record(name=\"app\")<\/code><\/td><td>Nested object<\/td><\/tr><tr><td><code>ip<\/code><\/td><td>IP address<\/td><td>Network fields<\/td><\/tr><tr><td><code>uid<\/code><\/td><td>Entity\/problem IDs<\/td><td>Unique identifiers<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace documents primitive types such as Boolean, Long, Double, Timestamp, Timeframe, Duration, String, IP address, UID, and complex types like Array and Record. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/data-types\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Check type using <code>type()<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace lists <code>type<\/code> as a conversion\/type function that returns the type of a value as a string. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/functions\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 500, duration_ms = 900)\n| fields service_type = type(service),\n         status_type = type(status),\n         duration_type = type(duration_ms)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>service_type  = string\nstatus_type   = long\nduration_type = long\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Casting examples<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(status_text = \"500\", duration_text = \"120.5\", enabled_text = \"true\")\n| fields status_num = toLong(status_text),\n         duration_num = toDouble(duration_text),\n         enabled_bool = toBoolean(enabled_text)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>status_num as long\nduration_num as double\nenabled_bool as boolean\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">16. Functions in DQL<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Functions transform, test, calculate, or format values.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace groups DQL functions into categories such as aggregation, string, conversion\/type, conditional, boolean, time, array, mathematical, join, and general functions. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/functions\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Important function categories<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>mindmap\n  root((DQL Functions))\n    Aggregation\n      count\n      avg\n      sum\n      min\n      max\n      percentile\n      countIf\n    String\n      contains\n      startsWith\n      endsWith\n      lower\n      concat\n      matchesPhrase\n      parse\n    Type conversion\n      toLong\n      toDouble\n      toString\n      toTimestamp\n      type\n    Conditional\n      if\n      coalesce\n    Boolean\n      isNull\n      isNotNull\n      exists\n    Time\n      now\n      formatTimestamp\n      getHour\n      getDayOfWeek\n    Array\n      arrayAvg\n      arrayMax\n      arraySize\n      arrayFirst\n    Entity\n      entityName\n      entityAttr\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Conditional function: <code>if<\/code><\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200),\n     record(service = \"payment\", status = 503)\n| fieldsAdd result = if(status &gt;= 500, \"failed\", else:\"success\")\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>checkout \u2192 success\npayment  \u2192 failed\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Null handling: <code>coalesce<\/code><\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", owner = \"team-a\"),\n     record(service = \"payment\")\n| fieldsAdd owner_safe = coalesce(owner, \"unknown\")\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>checkout \u2192 team-a\npayment  \u2192 unknown\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Time function<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", timestamp = now())\n| fields timestamp,\n         hour = formatTimestamp(timestamp, format:\"HH\"),\n         day = formatTimestamp(timestamp, format:\"EE\")\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>timestamp plus formatted hour\/day columns.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">17. Aggregation with <code>summarize<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\"><code>summarize<\/code> groups records and calculates values.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace describes <code>summarize<\/code> as grouping records that have the same field values and aggregating them. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Count all records<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200),\n     record(service = \"checkout\", status = 500),\n     record(service = \"payment\", status = 503)\n| summarize total = count()\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>total = 3\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Count by service<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200),\n     record(service = \"checkout\", status = 500),\n     record(service = \"payment\", status = 503)\n| summarize total = count(), by:{service}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>checkout = 2\npayment  = 1\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Count failures by service<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200),\n     record(service = \"checkout\", status = 500),\n     record(service = \"payment\", status = 503),\n     record(service = \"payment\", status = 200)\n| summarize failures = countIf(status &gt;= 500), total = count(), by:{service}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>checkout \u2192 failures 1, total 2\npayment  \u2192 failures 1, total 2\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Average and percentile<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", duration_ms = 120),\n     record(service = \"checkout\", duration_ms = 900),\n     record(service = \"checkout\", duration_ms = 1500),\n     record(service = \"payment\", duration_ms = 300),\n     record(service = \"payment\", duration_ms = 2000)\n| summarize avg_duration = avg(duration_ms),\n            p95_duration = percentile(duration_ms, 95),\n            max_duration = max(duration_ms),\n            requests = count(),\n  by:{service}\n| sort p95_duration desc\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>One row per service with average, p95, max, and request count.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Aggregation functions include <code>avg<\/code>, <code>count<\/code>, <code>countIf<\/code>, <code>max<\/code>, <code>median<\/code>, <code>min<\/code>, <code>percentile<\/code>, <code>sum<\/code>, and several more. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/functions\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">18. Create time charts with <code>makeTimeseries<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>makeTimeseries<\/code> when you start from raw records such as logs, events, or spans and want to aggregate them over time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace says DQL provides commands like <code>makeTimeseries<\/code> to aggregate raw event records into chartable time series. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/dql-guide\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Error logs over time<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| filter loglevel == \"ERROR\" or loglevel == \"SEVERE\"\n| makeTimeseries errors = count(), by:{loglevel}, interval:5m\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>A time series grouped by loglevel.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In Notebooks or Dashboards, choose:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Visualization \u2192 Line chart\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Sample data with timestamps<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(timestamp = now() - 20m, service = \"checkout\", status = 500),\n     record(timestamp = now() - 15m, service = \"checkout\", status = 200),\n     record(timestamp = now() - 10m, service = \"payment\", status = 503),\n     record(timestamp = now() - 5m, service = \"payment\", status = 200)\n| filter status &gt;= 500\n| makeTimeseries failures = count(), by:{service}, interval:5m\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Time series of failures by service.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">19. Query metrics with <code>timeseries<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>timeseries<\/code> for metric data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace describes <code>timeseries<\/code> as a starting DQL command that combines loading, filtering, and aggregating metric data into a time series output. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/metric-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Average CPU usage<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries usage = avg(dt.host.cpu.usage)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Time series showing average CPU usage.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Visualization:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Line chart\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">CPU by host<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries usage = avg(dt.host.cpu.usage), by:{dt.entity.host}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>One CPU usage series per host.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">p99 service response time<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries p99 = percentile(dt.service.request.response_time, 99),\nby:{dt.entity.service}\n| limit 5\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>p99 response time series for up to 5 services.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace documents metric aggregation functions for <code>timeseries<\/code>, including <code>sum<\/code>, <code>avg<\/code>, <code>min<\/code>, <code>max<\/code>, <code>count<\/code>, <code>percentile<\/code>, and <code>countDistinct<\/code>. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/metric-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">20. Explore available metrics with <code>metrics<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>metrics<\/code> to discover metric keys and dimensions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace explains that <code>metrics<\/code> retrieves metric series for exploring metric keys, dimension keys, and values, but recommends <code>timeseries<\/code> for charting\/calculations because <code>metrics<\/code> does not return timestamps or time-series values. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/metric-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Run<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>metrics\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Metric metadata rows.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Find CPU metrics<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>metrics\n| filter contains(metric.key, \"cpu\")\n| dedup metric.key\n| sort metric.key asc\n| limit 50\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>List of metric keys containing cpu.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">21. Parse logs with <code>parse<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>parse<\/code> when your log content is text\/JSON and you need to extract fields.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace describes <code>parse<\/code> as parsing a record field into one or more fields using a pattern, and notes that it works with Dynatrace Pattern Language. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/extraction-and-parsing-commands?utm_source=chatgpt.com\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Parse JSON from sample data<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(content = \"{\\\"service\\\":\\\"checkout\\\",\\\"status\\\":500,\\\"duration_ms\\\":900}\"),\n     record(content = \"{\\\"service\\\":\\\"payment\\\",\\\"status\\\":200,\\\"duration_ms\\\":300}\")\n| parse content, \"JSON:json\"\n| fields json&#91;service], json&#91;status], json&#91;duration_ms]\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Extracted service, status, and duration_ms from JSON.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Flatten parsed JSON<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(content = \"{\\\"service\\\":\\\"checkout\\\",\\\"status\\\":500,\\\"duration_ms\\\":900}\"),\n     record(content = \"{\\\"service\\\":\\\"payment\\\",\\\"status\\\":200,\\\"duration_ms\\\":300}\")\n| parse content, \"JSON:json\"\n| fieldsFlatten json\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Fields from JSON become normal table columns.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace documents <code>fieldsFlatten<\/code> as extracting\/flattening fields from a nested record. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Real log JSON parsing<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| filter contains(content, \"{\")\n| parse content, \"JSON:json\"\n| fields timestamp, loglevel, json\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Parsed JSON records, if your logs contain JSON.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If parsing fails, the log may not be valid JSON or may have prefix\/suffix text.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">22. Flatten nested records with <code>fieldsFlatten<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Use this after parsing JSON or when records contain nested structures.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(payload = record(service = \"checkout\", status = 500, duration_ms = 900)),\n     record(payload = record(service = \"payment\", status = 200, duration_ms = 300))\n| fieldsFlatten payload, prefix:\"app.\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>app.service\napp.status\napp.duration_ms\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">23. Work with arrays<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Arrays appear in timeseries results, JSON arrays, or custom records.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace documents arrays as complex types containing a sequence of values identified by index. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/data-types\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Create and inspect array<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", durations = array(100, 200, 500, 900))\n| fields service,\n         first_value = durations&#91;0],\n         avg_value = arrayAvg(durations),\n         max_value = arrayMax(durations)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>first_value = 100\navg_value   = 425\nmax_value   = 900\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace lists array functions such as <code>arrayAvg<\/code>, <code>arrayMax<\/code>, <code>arrayMin<\/code>, <code>arrayFirst<\/code>, <code>arrayLast<\/code>, <code>arrayDistinct<\/code>, and others. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/functions\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">24. Add entity names with <code>entityName<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace entity IDs are often not human-friendly. Use <code>entityName()<\/code> when available.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace lists <code>entityName<\/code> as a general DQL function that returns the name of an entity. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/functions\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Host CPU with host name<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries usage = avg(dt.host.cpu.usage), by:{dt.entity.host}\n| fieldsAdd host_name = entityName(dt.entity.host)\n| fields host_name, usage, timeframe, interval\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CPU series with readable host_name.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">25. Join and lookup basics<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Use joins when you need to combine results from two datasets.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace lists <code>join<\/code>, <code>joinNested<\/code>, <code>lookup<\/code>, and <code>append<\/code> as correlation\/join commands. <code>join<\/code> joins records when source and subquery fulfill a join condition, while <code>lookup<\/code> adds fields from a subquery by matching source and lookup fields. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Simple lookup with sample data<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", owner_id = 1, errors = 10),\n     record(service = \"payment\", owner_id = 2, errors = 5)\n| lookup &#91;\n    data record(owner_id = 1, owner = \"Team A\"),\n         record(owner_id = 2, owner = \"Team B\")\n  ],\n  sourceField:owner_id,\n  lookupField:owner_id\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Original records enriched with owner data.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Join sample data<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", errors = 10),\n     record(service = \"payment\", errors = 5)\n| join &#91;\n    data record(service = \"checkout\", requests = 1000),\n         record(service = \"payment\", requests = 500)\n  ],\n  on:{service}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Errors joined with request counts by service.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">26. Visualization views in Dynatrace<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">After running DQL in Notebooks or Dashboards, choose the right visualization.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace lets you choose visualization types for dashboard tiles and notebook sections after adding a query. In Notebooks, the Visualization section displays visualization types; in Dashboards, the Visual tab is available after running the query. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/analyze-explore-automate\/dashboards-and-notebooks\/edit-visualizations\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Common views<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>View<\/th><th>Best for<\/th><th>Example query<\/th><\/tr><\/thead><tbody><tr><td>Table<\/td><td>Raw rows, grouped summary<\/td><td>`fetch logs<\/td><\/tr><tr><td>Line chart<\/td><td>Time trend<\/td><td><code>timeseries avg(dt.host.cpu.usage)<\/code><\/td><\/tr><tr><td>Bar chart<\/td><td>Top N comparison<\/td><td><code>summarize count(), by:{service}<\/code><\/td><\/tr><tr><td>Pie chart<\/td><td>Share\/distribution<\/td><td>Count by status\/loglevel<\/td><\/tr><tr><td>Single value<\/td><td>KPI\/SLO number<\/td><td>Error count, p95, CPU average<\/td><\/tr><tr><td>Markdown\/Text<\/td><td>Notes\/documentation<\/td><td>Notebook explanation<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Line chart<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use a line chart for measurements and trends over time, comparing multiple series, or finding correlations between variables. Dynatrace\u2019s line chart example uses <code>timeseries avg(dt.host.cpu.usage)<\/code>. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/analyze-explore-automate\/dashboards-and-notebooks\/edit-visualizations\/visualization-chart-line\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries avg_cpu = avg(dt.host.cpu.usage)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected visual:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Line chart of CPU over time.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Single value<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use single value for one important KPI, business metric, or SLO-type measurement. Dynatrace documents single value visualizations for aggregated measurements, KPIs, and infrastructure-related SLOs. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/analyze-explore-automate\/dashboards-and-notebooks\/edit-visualizations\/visualization-chart-single-value\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries sparkline = avg(dt.host.cpu.usage)\n| fieldsAdd value = arrayAvg(sparkline)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected visual:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Single value with optional sparkline.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">27. Discover fields before writing queries<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">A very important beginner skill: first discover what fields exist.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Use <code>fieldsSnapshot<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>fieldsSnapshot<\/code> returns a snapshot of fields present in records for supported data objects such as <code>logs<\/code>, <code>spans<\/code>, <code>smartscape.nodes<\/code>, and <code>metrics<\/code>, and Dynatrace notes it does not scan raw data and does not produce consumption. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/data-source-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fieldsSnapshot logs\n| sort relative_count desc\n| limit 50\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Top fields found in logs.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Fields by bucket and type<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fieldsSnapshot logs, by:{dt.system.bucket, data_type}\n| sort relative_count desc\n| limit 100\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Fields with bucket and data type information.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Find sparse fields<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fieldsSnapshot logs, by:{dt.system.bucket}\n| filter relative_count &lt; 10\n| sort relative_count asc\n| limit 50\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Fields present in fewer than 10% of log records.\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Use <code>describe<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>describe<\/code> returns known fields and their data types for a data object. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/data-source-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>describe bizevents\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Known fields and data types for business events.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">28. Beginner practice labs<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 1: Load logs<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Where to run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Notebooks \u2192 Add \u2192 DQL\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Query:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>20 logs or fewer.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If no result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| limit 20\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 2: Show important log columns<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| fields timestamp, loglevel, log.source, content\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Clean log table.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 3: Error logs only<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| filter loglevel == \"ERROR\" or loglevel == \"SEVERE\"\n| fields timestamp, loglevel, content\n| sort timestamp desc\n| limit 50\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Latest ERROR\/SEVERE logs.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 4: Search timeout logs<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| search content ~ \"timeout\"\n| fields timestamp, loglevel, content\n| sort timestamp desc\n| limit 50\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Logs containing timeout.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 5: Count logs by log level<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| summarize logs = count(), by:{loglevel}\n| sort logs desc\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Table: loglevel | logs\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Best visualization:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Bar chart or Pie chart\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 6: Errors over time<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| filter loglevel == \"ERROR\" or loglevel == \"SEVERE\"\n| makeTimeseries errors = count(), by:{loglevel}, interval:15m\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Time series of error count.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Best visualization:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Line chart\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">29. Intermediate practice labs<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 7: Top sources producing errors<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| filter loglevel == \"ERROR\" or loglevel == \"SEVERE\"\n| summarize errors = count(), by:{log.source}\n| sort errors desc\n| limit 10\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Top 10 log sources by error count.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 8: Find repeated messages<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| filter loglevel == \"ERROR\" or loglevel == \"SEVERE\"\n| summarize occurrences = count(), by:{content}\n| sort occurrences desc\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Most repeated error messages.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Warning:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>content can be high-cardinality. Use carefully on large datasets.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 9: Parse JSON logs<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| filter contains(content, \"{\")\n| parse content, \"JSON:json\"\n| fields timestamp, loglevel, json\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Parsed JSON object if log content is JSON.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 10: Flatten JSON logs<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| filter contains(content, \"{\")\n| parse content, \"JSON:json\"\n| fieldsFlatten json\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>JSON keys become fields.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">30. Metrics practice labs<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 11: Average CPU usage<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries cpu = avg(dt.host.cpu.usage), from:-2h\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CPU usage time series.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Best visualization:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Line chart\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 12: CPU usage by host<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries cpu = avg(dt.host.cpu.usage), by:{dt.entity.host}, from:-2h\n| fieldsAdd host = entityName(dt.entity.host)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CPU series grouped by host.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 13: Top hosts by average CPU<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries cpu = avg(dt.host.cpu.usage), by:{dt.entity.host}, from:-2h\n| fieldsAdd host = entityName(dt.entity.host)\n| fieldsAdd avg_cpu = arrayAvg(cpu)\n| sort avg_cpu desc\n| limit 10\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Top 10 hosts by average CPU.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Best visualization:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Table or Single value grid\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 14: Service response time p99<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries p99 = percentile(dt.service.request.response_time, 99),\nby:{dt.entity.service},\nfrom:-2h\n| fieldsAdd service = entityName(dt.entity.service)\n| limit 10\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>p99 response time for services.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Note: Dynatrace documents that <code>dt.service.request.response_time<\/code> is reported in microseconds in its percentile examples, so be careful when interpreting units. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/metric-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">31. Distributed tracing\/spans practice labs<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace\u2019s trace\/DQL tutorial says DQL can help identify inefficient database queries, workload patterns, abnormalities, and performance-analysis signals using traces and logs. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/observe\/application-observability\/distributed-tracing\/use-traces-and-dql-to-spot-patterns\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 15: Show recent spans<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch spans, from:-2h\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Recent span records.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 16: Inspect span fields<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fieldsSnapshot spans\n| sort relative_count desc\n| limit 50\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Common fields available in spans.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 17: Slow spans<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch spans, from:-2h\n| filter duration &gt; 1s\n| fields timestamp, duration, span.name, dt.entity.service\n| sort duration desc\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Slow span operations.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If <code>span.name<\/code> is not present in your environment, inspect fields first:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fieldsSnapshot spans\n| filter contains(field, \"span\")\n| limit 50\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lab 18: Failed spans<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch spans, from:-2h\n| filter request.is_failed == true\n| summarize failed_spans = count(), by:{dt.entity.service}\n| sort failed_spans desc\n| limit 10\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Services with failed spans.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If <code>request.is_failed<\/code> is unavailable, use <code>fieldsSnapshot spans<\/code> and search for failure\/error fields.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">32. Davis problem analysis<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Count problems in last 24 hours<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch dt.davis.problems, from:now()-24h, to:now()\n| summarize problemCount = countDistinct(event.id)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace\u2019s own DQL example for Dynatrace Intelligence uses <code>fetch dt.davis.problems<\/code> and <code>countDistinct(event.id)<\/code> to count distinct problems in the last 24 hours. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/dynatrace-intelligence\/use-cases\/dynatrace-intelligence-dql-examples?utm_source=chatgpt.com\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>One number: problemCount.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">33. Advanced: compare current period with past period<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace documents the <code>shift<\/code> parameter for <code>timeseries<\/code>, which lets you compare a metric series with another timeframe, such as the same period 7 days earlier. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/metric-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">CPU now vs 7 days ago<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries cpu_now = avg(dt.host.cpu.usage), by:{dt.entity.host}, from:-24h\n| append &#91;\n    timeseries cpu_7d_ago = avg(dt.host.cpu.usage), by:{dt.entity.host}, shift:-7d, from:-24h\n  ]\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Current CPU series plus shifted CPU series from 7 days ago.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Best visualization:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Line chart\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">34. Advanced: calculate failure rate from logs<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| fieldsAdd is_error = loglevel == \"ERROR\" or loglevel == \"SEVERE\"\n| summarize total_logs = count(),\n            error_logs = countIf(is_error)\n| fieldsAdd error_rate_percent = toDouble(error_logs) \/ toDouble(total_logs) * 100\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>total_logs\nerror_logs\nerror_rate_percent\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Best visualization:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Single value\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">35. Advanced: service health summary from sample data<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This query is fully runnable because it uses <code>data<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200, duration_ms = 120),\n     record(service = \"checkout\", status = 500, duration_ms = 900),\n     record(service = \"checkout\", status = 503, duration_ms = 1500),\n     record(service = \"payment\", status = 200, duration_ms = 300),\n     record(service = \"payment\", status = 200, duration_ms = 400),\n     record(service = \"catalog\", status = 500, duration_ms = 2000)\n| summarize total_requests = count(),\n            failed_requests = countIf(status &gt;= 500),\n            avg_duration = avg(duration_ms),\n            p95_duration = percentile(duration_ms, 95),\n  by:{service}\n| fieldsAdd failure_rate_percent = toDouble(failed_requests) \/ toDouble(total_requests) * 100\n| sort failure_rate_percent desc\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Health summary per service.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is a very good pattern for real service observability.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">36. Advanced: log message classification<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| fieldsAdd category = if(contains(content, \"timeout\"), \"timeout\",\n                    else:if(contains(content, \"connection\"), \"connection\",\n                    else:if(contains(content, \"permission\"), \"permission\",\n                    else:\"other\")))\n| summarize logs = count(), by:{category}\n| sort logs desc\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected result:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Logs grouped by message category.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Best visualization:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Bar chart or Pie chart\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">37. DQL query structure cheat sheet<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart TD\n    A&#91;Start Command] --&gt; B{What kind of data?}\n    B --&gt;|Logs\/Events\/Spans| C&#91;fetch logs\/events\/spans]\n    B --&gt;|Metrics| D&#91;timeseries]\n    B --&gt;|Practice data| E&#91;data record...]\n    C --&gt; F&#91;filter\/search\/filterOut]\n    D --&gt; G&#91;by\/filter\/from\/to]\n    E --&gt; F\n    F --&gt; H&#91;fields\/fieldsAdd\/parse]\n    H --&gt; I&#91;summarize\/makeTimeseries]\n    I --&gt; J&#91;sort\/limit]\n    J --&gt; K&#91;Visualization]\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">38. Best practices for writing DQL<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">1. Start small<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Bad for beginners:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Better:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-30m\n| limit 20\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">2. Filter early<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Good:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| filter loglevel == \"ERROR\"\n| fields timestamp, loglevel, content\n| limit 50\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">3. Sort late<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace recommends sorting near the end rather than immediately after <code>fetch<\/code>. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/dql-best-practices?utm_source=chatgpt.com\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Better:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| filter loglevel == \"ERROR\"\n| fields timestamp, loglevel, content\n| sort timestamp desc\n| limit 50\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">4. Use <code>fields<\/code> to reduce noisy output<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| filter loglevel == \"ERROR\"\n| fields timestamp, loglevel, content\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">5. Do not <code>limit<\/code> before aggregation unless intentional<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Dynatrace\u2019s best-practice guidance says to use <code>summarize<\/code> for tabular aggregation and <code>makeTimeseries<\/code> for time charts, and not to use <code>limit<\/code> before aggregation unless that is intentional because it can produce wrong aggregates. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/dql-best-practices?utm_source=chatgpt.com\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wrong:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| limit 100\n| summarize count(), by:{loglevel}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Better:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| summarize logs = count(), by:{loglevel}\n| sort logs desc\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">6. Discover fields before assuming names<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fieldsSnapshot logs\n| limit 100\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">7. Use <code>data<\/code> to learn syntax<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(a = \"DQL\", b = 1)\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">8. Use <code>timeseries<\/code> for metrics, not <code>fetch<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For metrics, use:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries avg(dt.host.cpu.usage)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>metrics<\/code> only to discover metric keys\/dimensions. Dynatrace recommends <code>timeseries<\/code> for actual time-series analysis. (<a href=\"https:\/\/docs.dynatrace.com\/docs\/platform\/grail\/dynatrace-query-language\/commands\/metric-commands\">docs.dynatrace.com<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">39. Common DQL mistakes and fixes<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Mistake 1: No data returned<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Possible causes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Wrong timeframe\nWrong field name\nNo matching data in Playground\nNo permission for bucket\/table\nWrong data object\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Fix:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| limit 20\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then inspect fields:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fieldsSnapshot logs\n| limit 100\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Mistake 2: Field does not exist<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Fix:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fieldsSnapshot logs\n| filter contains(field, \"service\")\n| limit 50\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Mistake 3: Comparing string and number<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Wrong:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(status = \"500\")\n| filter status &gt;= 500\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Better:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(status = \"500\")\n| fieldsAdd status_num = toLong(status)\n| filter status_num &gt;= 500\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Mistake 4: Expecting <code>search<\/code> and <code>filter<\/code> to behave the same<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>search<\/code> for text exploration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs\n| search \"timeout\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>filter<\/code> for exact logic:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs\n| filter loglevel == \"ERROR\"\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Mistake 5: Trying to chart non-time data as line chart<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This is table\/bar-style data:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| summarize logs = count(), by:{loglevel}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is line-chart data:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| makeTimeseries logs = count(), by:{loglevel}, interval:15m\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">40. Copy-ready command reference<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Load<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch events, from:-24h\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch spans, from:-24h\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch bizevents, from:-24h\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Inspect<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fieldsSnapshot logs\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>fieldsSnapshot spans\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>describe bizevents\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Filter<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| filter loglevel == \"ERROR\"\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| filter loglevel != \"INFO\"\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| filter contains(content, \"Exception\")\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Search<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| search \"timeout\"\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| search content ~ \"timeout\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Select fields<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-2h\n| fields timestamp, loglevel, content\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Aggregate<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| summarize logs = count(), by:{loglevel}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Time chart from logs<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| makeTimeseries logs = count(), by:{loglevel}, interval:15m\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Metrics<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries cpu = avg(dt.host.cpu.usage)\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries cpu = avg(dt.host.cpu.usage), by:{dt.entity.host}\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>metrics\n| filter contains(metric.key, \"cpu\")\n| dedup metric.key\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Parse JSON<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| filter contains(content, \"{\")\n| parse content, \"JSON:json\"\n| fields timestamp, json\n| limit 20\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Flatten JSON<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| filter contains(content, \"{\")\n| parse content, \"JSON:json\"\n| fieldsFlatten json\n| limit 20\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">41. Recommended learning path<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Day 1: DQL basics<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Practice:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>data\nfetch\npipe |\nfields\nlimit\nsort\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(service = \"checkout\", status = 200),\n     record(service = \"payment\", status = 500)\n| fields service, status\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Day 2: Filtering and searching<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Practice:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>filter\nfilterOut\nsearch\ncontains\nstartsWith\nendsWith\nand\/or\/not\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(message = \"payment timeout\", status = 500),\n     record(message = \"checkout success\", status = 200)\n| filter status &gt;= 500 and contains(message, \"timeout\")\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Day 3: Logs<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Practice:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs\nloglevel\ncontent\nlog.source\ntimestamp\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| filter loglevel == \"ERROR\"\n| fields timestamp, loglevel, content\n| sort timestamp desc\n| limit 50\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Day 4: Aggregation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Practice:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>summarize\ncount\ncountIf\navg\npercentile\nby:{}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| summarize logs = count(), by:{loglevel}\n| sort logs desc\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Day 5: Time series<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Practice:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>makeTimeseries\ntimeseries\ninterval\nby\nline chart\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch logs, from:-24h\n| makeTimeseries logs = count(), by:{loglevel}, interval:15m\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Day 6: Metrics<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Practice:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries\nmetrics\nmetric.key\nentityName\narrayAvg\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>timeseries cpu = avg(dt.host.cpu.usage), by:{dt.entity.host}\n| fieldsAdd host = entityName(dt.entity.host)\n| fieldsAdd avg_cpu = arrayAvg(cpu)\n| sort avg_cpu desc\n| limit 10\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Day 7: Parsing<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Practice:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>parse\nJSON\nfieldsFlatten\nrecord\narray\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>data record(content = \"{\\\"service\\\":\\\"checkout\\\",\\\"status\\\":500,\\\"duration_ms\\\":900}\")\n| parse content, \"JSON:json\"\n| fieldsFlatten json\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Day 8: Spans and distributed tracing<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Practice:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch spans\nduration\nservice\nfailed requests\nslow operations\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fetch spans, from:-24h\n| filter duration &gt; 1s\n| fields timestamp, duration, dt.entity.service\n| sort duration desc\n| limit 20\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Day 9: Dashboards<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Practice:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Add &gt; DQL\nData tab\nVisual tab\nTable\nLine chart\nSingle value\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Create these dashboard tiles:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1. Error count by loglevel\n2. Errors over time\n3. CPU usage by host\n4. Top slow spans\n5. Problem count\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Day 10: Real troubleshooting notebook<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Build one notebook with sections:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1. Recent errors\n2. Top error sources\n3. Error trend\n4. CPU trend\n5. Slow spans\n6. Failed spans\n7. Problem count\n8. Notes\/analysis\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That is how you start using DQL like a real Dynatrace observability engineer.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dynatrace Query Language, or DQL, is the query language used to explore, filter, aggregate, correlate, and visualize data stored in Dynatrace Grail. Dynatrace describes DQL as a&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1014","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1014","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/comments?post=1014"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1014\/revisions"}],"predecessor-version":[{"id":1015,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1014\/revisions\/1015"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/media?parent=1014"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/categories?post=1014"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/tags?post=1014"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}