diff --git a/content/en/synthetics/notifications/template_variables.md b/content/en/synthetics/notifications/template_variables.md index dde18cb4d6a..0a37d38d965 100644 --- a/content/en/synthetics/notifications/template_variables.md +++ b/content/en/synthetics/notifications/template_variables.md @@ -13,41 +13,17 @@ further_reading: ## Overview -Template variables allow you to insert dynamic values from your test results and configuration into Synthetic Monitoring notification messages. Access these variables using the `synthetics.attributes` prefix. For example: +Template variables allow you to insert dynamic values from your test results and configuration into Synthetic Monitoring notification messages. These variables are accessed using the `synthetics.attributes` prefix. -```text -Test failed at step {{synthetics.failed_step.name}} with error: {{synthetics.failed_step.failure.message}}. -``` +**Note:** Not all variables are available for every test type. You may need to test different outputs to verify the data returned. You can export the result as a JSON file from the **Actions** tab of a test run in the [Results Explorer][1], then reference the path directly within your monitor configuration. -**Note**: For information about accessing local (config) variables, see the [Variables](#variables) section. +{{< img src="synthetics/notifications/action_tab.png" alt="Actions tab from the Synthetics Result Explorer with Export Result JSON highlighted" style="width:90%;" >}} -### Common variable shortcuts +## Available variables -`{{synthetics.failed_step.name}}` -: The name of the failing step (for example, `Test div #title content`). +### Test execution variables -`{{synthetics.failed_step.failure.message}}` -: The error message (for example, `Element's content should match the given regex`). - -`{{synthetics.failed_step.url}}` -: The URL of the failed step (for example, `https://www.datadoghq.com/blog/`). - -`{{synthetics.attributes.result.response.statusCode}}` -: The HTTP status code (for example, `403`). - -`{{synthetics.result.step_count}}` -: Number of steps (for example, `4`). - -`{{synthetics.result.duration}}` -: Duration of the test run (in milliseconds) (for example, `9096`). - -`{{tags.env}}` -: The environment tag value (for example, `prod`). - -**Note:** Not all variables are available for every test type. You may need to test different outputs to verify the data returned. You can export the result as a JSON file from the **Actions** tab, then reference the path directly within your monitor configuration. - - -### Result attributes +Use these variables to include details about the test, execution location, device, counts, and result status in your notification messages. {{< tabs >}} {{% tab "Test Info" %}} @@ -108,20 +84,6 @@ Applies to browser and mobile tests. `{{synthetics.attributes.device.platform.name}}`, `{{synthetics.attributes.device.platform.version}}` : Platform information (mobile tests only) -**Example values:** -```json -{ - "device": { - "id": "chrome.laptop_large", - "name": "Laptop Large", - "type": "laptop", - "resolution": {"width": 1440, "height": 1100}, - "browser": {"type": "Chrome"}, - "platform": {"name": "Android", "version": "14"} - } -} -``` - {{% /tab %}} {{% tab "Result" %}} @@ -149,24 +111,6 @@ Applies to browser and mobile tests. `{{synthetics.attributes.result.failure.code}}` : The failure code -**Example values:** -```json -{ - "result": { - "id": "3015485096247415772", - "status": "failed", - "duration": 9096, - "testStartedAt": 1743760758904, - "testFinishedAt": 1743760772025, - "testTriggeredAt": 1743760758593, - "failure": { - "message": "Error: Element's content should match the given regex", - "code": "ASSERTION_FAILURE" - } - } -} -``` - {{% /tab %}} {{% tab "Count" %}} @@ -190,7 +134,9 @@ Applies to Multistep, Browser, and Mobile tests. {{% /tab %}} {{< /tabs >}} -## Variables +### Result variables + +These variables provide access to local and global variable values used during test execution. Use them to include variable names, types, and values in your notifications. These variables are accessed with the `{{synthetics.attributes.result}}` prefix. {{< tabs >}} {{% tab "Local config variables" %}} @@ -211,16 +157,6 @@ Located at `{{synthetics.attributes.result.variables.config}}`: `{{synthetics.attributes.result.variables.config.value}}` : Variable value (non-obfuscated only) -**Examples:** -```json -{ - "name": "RANDOM_NUMBER", - "type": "text", - "secure": false, - "value": "133245995" -} -``` - {{% /tab %}} {{% tab "Global variables" %}} @@ -242,116 +178,67 @@ Located at `{{synthetics.attributes.result.variables.extracted}}`: `{{synthetics.attributes.result.variables.extracted.val}}` : Variable value (note: uses `.val`, not `.value`) -**Examples:** -```json -{ - "id": "ec734823-536e-4aba-8b5f-55733189d936", - "name": "EXTRACTED_NUMBER", - "secure": false, - "val": "250661" -} -``` - {{% /tab %}} {{% tab "Step extracted variables" %}} -For tests with steps, step data is contained in `{{synthetics.attributes.result.steps}}`. +For tests with steps, step data is contained in `{{synthetics.attributes.result.steps..extractedValue}}`. For information on how to access the `` see the [step summary](#step-summary) section below. -`.extractedValue.name` +`synthetics.attributes.result.steps..extractedValue.name` : Variable name -`.extractedValue.secure` +`synthetics.attributes.result.steps..extractedValue.secure` : Whether the variable value is obfuscated -`.extractedValue.value` +`synthetics.attributes.result.steps..extractedValue.value` : Variable value (if step was successful) -**Examples:** -```json -{ - "extractedValue": { - "name": "EXTRACTED_COUNT", - "secure": false, - "value": "12" - } -} -``` - {{% /tab %}} {{< /tabs >}} ### Variables extracted by steps -Similar to standard API tests, the variables are listed in the `variables.extracted` property, but inside steps themselves. These values are available as long as the step is successful. +For multistep API, browser, and mobile tests, extracted variables are available at the step level within the `synthetics.attributes.variables.extracted` property. These values are only available when the step completes successfully. {{< tabs >}} {{% tab "General steps" %}} **For multistep/browser/mobile tests**: -`.steps.allowFailure` +`synthetics.attributes.variables.extracted.steps.allowFailure` : Whether the step is allowed to fail without failing the entire test -`.steps.duration` +`synthetics.attributes.variables.extracted.steps.duration` : Step execution duration in milliseconds -`.steps.failure` +`synthetics.attributes.variables.extracted.steps.failure` : Failure information object containing `.code` and `.message` -`.steps.id` +`synthetics.attributes.variables.extracted.steps.id` : Unique step identifier -`.steps.isCritical` +`synthetics.attributes.variables.extracted.steps.isCritical` : Whether the step is critical to the test -`.steps.status` +`synthetics.attributes.variables.extracted.steps.status` : Step execution status -`.steps.type` +`synthetics.attributes.variables.extracted.steps.type` : Type of step being executed **Subtest information:** -`.steps.subTest.id` +`synthetics.attributes.variables.extracted.steps.subTest.id` : Subtest identifier -`.steps.subStep.parentStep.id` +`synthetics.attributes.variables.extracted.steps.subStep.parentStep.id` : Parent step identifier -`.steps.subStep.parentTest.id` +`synthetics.attributes.variables.extracted.steps.subStep.parentTest.id` : Parent test identifier -`.steps.subStep.level` +`synthetics.attributes.variables.extracted.steps.subStep.level` : Nesting level (1 for subtests, 2 for subtests of subtests) -**Examples:** -```json -{ - "steps": [ - { - "allowFailure": false, - "duration": 10955, - "failure": { - "code": "ASSERTION_FAILURE", - "message": "Element's content should not equal given value." - }, - "id": "g8e-q4a-fix", - "isCritical": true, - "status": "failed", - "type": "assertElementContent", - "subTest": { - "id": "m2i-fcy-eva" - }, - "subStep": { - "parentStep": {"id": "ikj-juk-z2u"}, - "parentTest": {"id": "th5-wic-5mj"}, - "level": 1 - } - } - ] -} -``` - {{% /tab %}} {{% tab "Browser Tests" %}} @@ -362,450 +249,160 @@ Similar to standard API tests, the variables are listed in the `variables.extrac **Steps:** -`.apiTest.request` +`synthetics.attributes.variables.extracted.apiTest.request` : API test request configuration (only for "Run API Test" steps where `type` is `runApiTest`) -`.apiTest.result` +`synthetics.attributes.variables.extracted.apiTest.result` : API test result data (similar to `attributes.result` for API tests) -`.assertionResult.expected` +`synthetics.attributes.variables.extracted.assertionResult.expected` : Expected value for assertions -`.assertionResults.checkType` +`synthetics.attributes.variables.extracted.assertionResults.checkType` : Type of assertion check -`.assertionResults.actual` +`synthetics.attributes.variables.extracted.assertionResults.actual` : Actual value found during assertion -`.browserErrors` +`synthetics.attributes.variables.extracted.browserErrors` : List of browser errors encountered -`.timings.firstByte` +`synthetics.attributes.variables.extracted.timings.firstByte` : Time to first byte -`.timings.tcp` +`synthetics.attributes.variables.extracted.timings.tcp` : TCP connection timing -`.description` +`synthetics.attributes.variables.extracted.description` : Step description -**Examples:** -```json -{ - "startUrl": "https://datadoghq.com", - "apiTest": { - "request": { - "subType": "http", - "method": "GET", - "url": "https://datadoghq.com" - }, - "result": { - "statusCode": 200 - } - }, - "assertionResults": { - "expected": "100", - "checkType": "equals", - "actual": "200" - }, - "timings": { - "firstByte": 7.1, - "tcp": 5.2 - } -} -``` - -Examples for `.browserErrors`: - -```json -{ - "name": "Console error", - "description": "Failed to load resource: the server responded with a status of 403 ()", - "type": "js" -}, -{ - "name": "[GET] 403 - https://accounts.google.com/v3/signin/identifier?dsh=S688774280%3A1687962864348747&conti", - "description": "https://accounts.google.com/v3/signin/identifier?dsh=S688774280%3A1687962864348747&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Faction_handle_signin%3Dtrue%26app%3Ddesktop%26hl%3Den%26next%3D%252Fsignin_passive%26feature%3Dpassive&hl=en&ifkv=AeDOFXjMKzxp0wt-b9IzWKz6RS9Kk-VmW5z_fzLP_cjbSWd4hWeP5g53fvdrhX6b2cDVQrNtJ5B7vA&passive=true&service=youtube&uilel=3&flowName=GlifWebSignIn&flowEntry=ServiceLogin\n}} {{% collapse-content title= "gRPC" level="h4" expanded=false %}} -`.callType` +`synthetics.attributes.variables.extracted.callType` : Call type (`unary` or `healthcheck`) -`.timings.rpc` +`synthetics.attributes.variables.extracted.timings.rpc` : RPC call timing -`.response.healthcheck.status` +`synthetics.attributes.variables.extracted.response.healthcheck.status` : Health check status -`.request.message` +`synthetics.attributes.variables.extracted.request.message` : gRPC request message -`.response.message` +`synthetics.attributes.variables.extracted.response.message` : gRPC response message -**Examples:** -```json -{ - "callType": "healthcheck", - "timings": { - "total": 55.3, - "rpc": 9.2, - "dns": 46.1 - }, - "response": { - "healthcheck": { - "status": 1 - } - }, - "request": { - "message": "Ping" - }, - "response": { - "message": "Pong" // Responses can be truncated if too big (only the start is available) - } -} -``` - {{< /collapse-content >}} {{% collapse-content title= "UDP" level="h4" expanded=false %}} -`.request.message` +`synthetics.attributes.variables.extracted.request.message` : UDP request message -`.response.message` +`synthetics.attributes.variables.extracted.response.message` : UDP response message -`.timings.message` +`synthetics.attributes.variables.extracted.timings.message` : Message timing -**Examples:** -```json -{ - "timings": { - "total": 135.3, - "dns": 14.4, - "message": 120.9 - }, - "request": { - "message": "Ping" - }, - "response": { - "message": "Pong" - } -} -``` - {{< /collapse-content >}} {{% collapse-content title= "TCP" level="h4" expanded=false %}} -`.connectionOutcome` +`synthetics.attributes.variables.extracted.connectionOutcome` : Connection result -`.netpath.routers.ip` +`synthetics.attributes.variables.extracted.netpath.routers.ip` : Router IP addresses -`.traceroute.latency.min` +`synthetics.attributes.variables.extracted.traceroute.latency.min` : Minimum latency -`.traceroute.latency.max` +`synthetics.attributes.variables.extracted.traceroute.latency.max` : Maximum latency -`.traceroute.latency.avg` +`synthetics.attributes.variables.extracted.traceroute.latency.avg` : Average latency -`.traceroute.latency.stddev` +`synthetics.attributes.variables.extracted.traceroute.latency.stddev` : Standard deviation -`.traceroute.latency.values` +`synthetics.attributes.variables.extracted.traceroute.latency.values` : Latency values array -**Examples:** -```json -[ - { - "packetLossPercentage": 1, - "packetsReceived": 0, - "packetsSent": 2, - "routers": [ - { - "ip": "???" - } - ] - }, - { - "packetLossPercentage": 0, - "packetsReceived": 2, - "latency": { - "avg": 0.2375, - "min": 0.189, - "max": 0.286, - "values": [ - 0.189, - 0.286 - ], - "stddev": 0.04849999999999999 - }, - "packetsSent": 2, - "routers": [ - { - "ip": "10.241.134.75" - } - ] - } -] -``` - {{< /collapse-content >}} {{% collapse-content title= "ICMP" level="h4" expanded=false %}} -`.traceroute` +`synthetics.attributes.variables.extracted.traceroute` : Same structure as TCP traceroute -`.request.host` +`synthetics.attributes.variables.extracted.request.host` : Target host -`.ping` +`synthetics.attributes.variables.extracted.ping` : Ping results -`.latency.min`, `.latency.max`, `.latency.avg`, `.latency.stddev`, `.latency.values` +`synthetics.attributes.variables.extracted.latency.min`, `synthetics.attributes.variables.extracted.latency.max`, `synthetics.attributes.variables.extracted.latency.avg`, `synthetics.attributes.variables.extracted.latency.stddev`, `synthetics.attributes.variables.extracted.latency.values` : Latency measurements (same as TCP) -**Examples:** -```json -{ - "ping": { - "packetLossPercentage": 0, - "packetsReceived": 4, - "latency": { - "avg": 1.47375, - "min": 1.442, - "max": 1.516, - "values": [ - 1.467, - 1.442, - 1.47, - 1.516 - ], - "stddev": 0.02670557057993708 - }, - "resolvedIp": "18.245.199.70", - "packetsSent": 4, - "packetSize": 56 - } -} -``` - {{< /collapse-content >}} {{% /tab %}} @@ -813,125 +410,168 @@ Examples for `.browserErrors`: {{% collapse-content title= "SSL" level="h4" expanded=false %}} -`.cert` +`synthetics.attributes.variables.extracted.cert` : SSL certificate information -`.cipher` +`synthetics.attributes.variables.extracted.cipher` : Cipher suite used -`.issuer` +`synthetics.attributes.variables.extracted.issuer` : Certificate issuer -`.subject` +`synthetics.attributes.variables.extracted.subject` : Certificate subject -`.valid.from` +`synthetics.attributes.variables.extracted.valid.from` : Certificate valid from date -`.valid.to` +`synthetics.attributes.variables.extracted.valid.to` : Certificate valid to date -`.ocsp` +`synthetics.attributes.variables.extracted.ocsp` : OCSP (Online Certificate Status Protocol) information -`.timings.handshake` +`synthetics.attributes.variables.extracted.timings.handshake` : SSL handshake timing -**Examples:** -```json - "cipher": TLS_AES_128_GCM_SHA256, - "issuer": { - "C": "US", - "CN": "DigiCert Global G2 TLS RSA SHA256 2020 CA1", - "O": "DigiCert Inc" - }, -``` -```json -{ - "issuer": { - "C": "US", - "CN": "DigiCert Global G2 TLS RSA SHA256 2020 CA1", - "O": "DigiCert Inc" - }, - "valid.from": 1751414400000, //milliseconds - "valid.to": 1783036799000 //milliseconds -} -``` - {{< /collapse-content >}} {{% collapse-content title= "DNS" level="h4" expanded=false %}} -`.response.records.type` +`synthetics.attributes.variables.extracted.response.records.type` : DNS record type -`.response.records.values` +`synthetics.attributes.variables.extracted.response.records.values` : DNS record values -**Examples:** -```json -{ - "dns": { - "response": { - "records": { - "type": "A", - "values": ["192.0.2.1", "192.0.2.2"] - } - } - } -} -``` - {{< /collapse-content >}} -{{% /tab %}} -{{% tab "Step summary" %}} +{{% collapse-content title= "HTTP" level="h4" expanded=false %}} + +**Request:** + +`synthetics.attributes.variables.extracted.request` +: Information about the request + +`synthetics.attributes.variables.extracted.request.method` +: The HTTP method + +`synthetics.attributes.variables.extracted.request.body` +: The request body if set + +`synthetics.attributes.variables.extracted.request.headers` +: The request headers + +**Response:** -**Step Summary:** -- `.result.steps.` - - `.id`, `.status`, `.type`, `.duration`, `.description`, `.failure.message`, `.code`, `.url` +`synthetics.attributes.variables.extracted.response` +: Information about the response -The step summary contains the same data as described in [steps](#variables-extracted-by-steps), but you can access it in several ways: +`synthetics.attributes.variables.extracted.response.body` +: The response body as string (truncated if too big) -By step index (0-based): -- `.steps.0` - first step -- `.steps.1` - second step -- `.steps.-1` - last step -- `.steps.-2` - step before last +`synthetics.attributes.variables.extracted.response.bodySize` +: The size of the full response body -By step name: -- `.steps[Click button]` +`synthetics.attributes.variables.extracted.response.cacheHeaders` +: A dictionary of caching-related headers -By step id: -- `.steps.abc-def-ghi` +`synthetics.attributes.variables.extracted.response.cdn` +: The response CDN info if any -Then you access the data as usual, for example: -- `.steps.-1.status` -- `.steps[Click button].status` -- `.steps.abc-def-ghi.status` +`synthetics.attributes.variables.extracted.response.cdn.provider` +: The CDN provider name (for example, `akamai`, `cloudflare`) -**Summary Data:** -- `.count.steps.{total,completed}`, `.count.errors`, `.count.hops` (for example, `4`) +`synthetics.attributes.variables.extracted.response.cdn.cache` +: The cache info -**Service Tag:** -If `service` tag is set: -- `{{service.name}}` -- `{{service.team}}` -- `{{service.docs}}`, `{{service.links}}` +`synthetics.attributes.variables.extracted.response.cdn.cache.cached` +: If the data was cached -**Examples**: -```json -{ - "service.name": "API Server", - "service.team": "Backend team", - "service.docs": "https://docs.datadoghq.com/api/" -} -``` +`synthetics.attributes.variables.extracted.response.cdn.cache.status` +: The cache status as provided in associated cache header + +`synthetics.attributes.variables.extracted.response.headers` +: The response headers + +`synthetics.attributes.variables.extracted.response.httpVersion` +: The HTTP version + +`synthetics.attributes.variables.extracted.response.redirects` +: A list of redirections if any + +`synthetics.attributes.variables.extracted.response.redirects.statusCode` +: The HTTP status code for the redirect + +`synthetics.attributes.variables.extracted.response.redirects.location` +: The returned location to redirect to + +`synthetics.attributes.variables.extracted.response.statusCode` +: The response HTTP status code + +**Timings:** + +`synthetics.attributes.variables.extracted.timings.authentication` +: The time spent for the authentication challenge (for example, NTLM) + +`synthetics.attributes.variables.extracted.timings.download` +: The time spent downloading the response + +`synthetics.attributes.variables.extracted.timings.firstByte` +: The time spent waiting for the first byte of response to be received + +`synthetics.attributes.variables.extracted.timings.redirect` +: The time spent in HTTP redirections + +`synthetics.attributes.variables.extracted.timings.ssl` +: The duration of the TLS handshake (only when testing an HTTPS endpoint) + +{{< /collapse-content >}} {{% /tab %}} {{< /tabs >}} +### Step summary + +Access step data by index, name, or ID to reference specific steps in your notification messages. This section also includes summary counts for total steps, completed steps, and errors. + +Each step exposes the following properties: `.id`, `.status`, `.type`, `.duration`, `.description`, `.failure.message`, `.code`, and `.url`. + +You can reference steps in three ways: + +#### By index (0-based) + +Use positive numbers to count from the beginning, or negative numbers to count from the end: + +| Syntax | Description | +|--------|-------------| +| `synthetics.attributes.result.steps.0` | First step | +| `synthetics.attributes.result.steps.1` | Second step | +| `synthetics.attributes.result.steps.-1` | Last step | +| `synthetics.attributes.result.steps.-2` | Second to last step | + +#### By step name + +Use the step name in brackets: + +`.steps[Click button]` + +#### By step ID + +Use the step's unique identifier: + +`.steps.abc-def-ghi` + +#### Accessing step properties + +Combine any reference method with a property: + +- `{{synthetics.attributes.result.steps.-1.status}}` - Status of the last step +- `{{synthetics.attributes.result.steps[Click button].status}}` - Status of the step named "Click button" +- `{{synthetics.attributes.result.steps.abc-def-ghi.status}}` - Status of the step with step ID "abc-def-ghi" ## Further Reading {{< partial name="whats-next/whats-next.html" >}} + +[1]: /synthetics/explore/results_explorer \ No newline at end of file diff --git a/static/images/synthetics/notifications/action_tab.png b/static/images/synthetics/notifications/action_tab.png new file mode 100644 index 00000000000..17d48e9f733 Binary files /dev/null and b/static/images/synthetics/notifications/action_tab.png differ