Expression reference
Latest Dynatrace
Dynatrace Workflows use the Jinja templating engine to allow for dynamic configurations in workflows. Those expressions provide access to execution parameters, schedule information, event context, and much more.
Expressions are supported in any input of any action (unless specified otherwise by the action developer) as well as the custom task conditions and options. A noteable exception is the Run Javascript action, which does not support expression in its input to avoid the possibility of code injection.
Run JavaScript
The Dynatrace Platform provides a JavaScript runtime that can be used for custom scripts in apps such as Notebooks and Dashboards, as well as in custom script tasks in Workflows.
Custom JavaScript tasks in workflows are provided with an execution_id
and action_execution_id
that, in conjunction with the automation SDKs, give you access to task results, workflow execution parameters, and so on, directly as JavaScript objects without using Jinja expressions.
To use the Automation SDKs, they need to be imported in the custom script task. Then they can be initialized with the execution context.
We offer both a client automation SDK, which gives full access to the Automation API, and a convenience-focused automation utils SDK.
Task result
Example using the automation-utils SDK to access result
1// import of sdk modules2import { execution } from '@dynatrace-sdk/automation-utils';34export default async function ({ execution_id }) {5 // load the execution object using the current execution_id6 var ex = await execution(execution_id)78 // get the result of task 'my_task'. 'my_task' must be a predecessor.9 var myResult = await ex.result('my_task');1011 // log the result object12 console.log('The whole result object: ', myResult);13 console.log('only one variable: ', myResult.myVariable)14}
Example using the client-automation SDK to access result
1// import of sdk modules2import { executionsClient } from '@dynatrace-sdk/client-automation';34export default async function ({ execution_id }) {5 // load the execution object using the current execution_id6 var config = {executionId: execution_id, id: 'my_task'}7 var myResult = await executionsClient.getTaskExecutionResult(config)89 // log the result object10 console.log('My task result: ', myResult)11 console.log('only one variable: ', myResult.myVariable)12}
Task loop
When using the option to loop a task, you might want to access the value of the current loop item. For this, the action_execution_id
is needed.
Example using the automation-utils SDK to access loop item
1// import of sdk modules2import { actionExecution } from "@dynatrace-sdk/automation-utils";34export default async function ({ execution_id, action_execution_id }) {5 // get the loop item for the action execution6 const actionEx = await actionExecution(action_execution_id);78 // log the current value of the loop item9 console.log(actionEx.loopItem)10}
Example using the client-automation SDK to access loop item
1// import of sdk modules2import { executionsClient, actionExecutionsClient } from '@dynatrace-sdk/client-automation';34export default async function ({ execution_id, action_execution_id }) {5 // get the loop item for the action execution6 const actionEx = await actionExecutionsClient.getActionExecution({ id: action_execution_id });78 // log the current value of the loop item9 console.log(actionEx.loopItem)10}
Expressions
Expressions enable you to reference results from predecessors in a task configuration and define custom conditions.
There are two kinds of delimiters.
{{ ... }}
for expressions, used to access data from other tasks, executions and functions.{% ... %}
for statements and control structures like loops and if conditions.
The list below is a reference list of the expressions available.
Beyond that you can use any templating functionality Jinja provides!
Whether you use the REST API or expressions to access workflows, executions, scheduling rules, or calendars, the same arguments are available to control paging, filtering, ordering, search, and expansion.
/executions?name=foo&limit=50&offset=0
behaves the same as {{ executions(name='foo', limit=50, offset=0)
in the same user context. Mind that while REST API request returns JSON, an expression will return a native object, respectively its string representation.
Access to resources happens in context of the workflow actor (link to workflow settings).
calendars()
Access business calendars and their attributes. The behavior and result is similar to an API request for the /business_calendars
endpoint.
-
Arguments:
identifier: Calendar ID
-
Keyword arguments: identical to the REST API please see note on top.
-
Returns: list of calendar objects or a single calendar object if ID was specified
-
Examples:
1# access to calendar '854a3452-a6d3-45bd-83e1-e8afa56eabcd'2{{ calendars('854a3452-a6d3-45bd-83e1-e8afa56eabcd') }}1{2 "id": "854a3452-a6d3-45bd-83e1-e8afa56eabcd",3 "created_at": "2022-12-07T12:42:45.732902Z",4 "updated_at": "2022-12-20T09:36:40.303952Z",5 "title": "Sample Calendar",6 "weekstart": 1,7 "weekdays": [8 1,9 2,10 3,11 4,12 513 ],14 "holidays": [15 {16 "date": "2020-01-01",17 "title": "New Year"18 },19 {20 "date": "2020-01-07",21 "title": "International Programmers Day"22 }23 ],24 "valid_from": "2020-01-01",25 "valid_to": "2029-12-31",26}
event()
- Arguments:
event attribute (optional): Access only a specific attribute of the event object
Keyword arguments: None
Returns: event object which was passed via exeuction params or None if no event was given
- Examples:
1# Assuming the following sample event as a trigger for a Workflow Execution2{3 "type": "security-problem-event",4 "version": "0.0.2",5 "event.id": "20d01063-14d7-4b99-aef1-77e92962fb7f"6 "event.id": "20d01063-14d7-4b99-aef1-77e92962fb7f",7 "event.kind": "SECURITY_PROBLEM_EVENT",8 "event.name": "Vulnerability resolved",9 "event.type": "THIRD_PARTY",10 "event.status": "Resolved",11 "event.category": "Vulnerability",12 "security-problem.display-id": "S-3750",13 "security-problem.technology": "go",14 "security-problem.vulnerability-type": "third-party"15}1617# get the full event object18{{ event() }}1920# access only the type attribute21{{ event('type') }} # -> "security-problem-event"2223# access the full event object and then select the type attribute24{{ event().type }} # -> "security-problem-event"2526# trying to access the 'technology' attribute of the 'security-problem' object27# this will FAIL, as there is actually no 'security-problem' object in the example above28{{ event().security-problem.technology }} # -> ERROR2930# NOTE: events often do not contain structured objects but flattened objects31# the 'security-problem.technology' for example is a single attribute, that happens to have a "." in its name32# in order to access attributes with "." in its name, use square brackets instead []33{{ event()['security-problem.technology'] }} # -> "go"3435# as an alternative, use the get() function36{{ event().get('security-problem.technology') }}3738# the get function also allows for default values, if the attribute is not defined39{{ event().get('does.not.exist', 'my default value') }}
execution()
Access the current execution context.
-
Arguments: None
-
Keyword arguments: None
-
Returns: execution object
-
Examples:
1# access the current execution object2{{ execution() }}34# access ID of current execution5Execution ID {{ execution().id }}67# access input of current execution8Execution input {{ execution().input | default('no input defined') }}Sample result
1{2 "id": "b126f1cc-fce1-4d28-adcf-0805b98961b9",3 "state": "RUNNING",4 "started_at": "2022-12-21T18:33:11.084818Z",5 "ended_at": null,6 "runtime": 12,7 "user": "716535cb-b992-47e4-90be-7d4b9785a501",8 "title": "Get Security Problem events count"9}
executions()
Access executions and their attributes. The behavior and result is similar to an API request for the /executions
endpoint.
- Arguments:
identifier: workflow execution ID
Keyword arguments: identical to the REST API please see note on top.
Returns: list of execution objects or a single execution object if ID was specified
- Examples:
1#execution with ID 00c27c88-d066-4424-bc44-f49a75536e37 {{ executions('00c27c88-d066-4424-bc44-f49a75536e37') }}23#executions of the workflow with ID '81a7fbb5-7f69-4005-81ec-26a39272bf09' (default limit applies for resultsize)4{{ executions(workflow='81a7fbb5-7f69-4005-81ec-26a39272bf09') }}56#returns up to 5 executions ordered by created_at in descending order7{{ executions(limit=5, order='-created_at') }}89# returns the most recent execution of workflow '81a7fbb5-7f69-4005-81ec-26a39272bf09'10{{ executions(workflow='81a7fbb5-7f69-4005-81ec-26a39272bf09', limit=1, order='-created_at') }}
now()
Current timestamp in UTC or timezone as provided as input parameter. Expression returns native Python datetime object to allow formatting into any desired output. Use strftime
and format codes as described in Python documentation.
-
Arguments:
- timezone (optional): Timezones as available in pytz. If no timezone is provided, UTC is used.
-
Returns: datetime object
-
Examples:
1# current time in UTC2{{ now().strftime("%b %d %Y") }}34# current time in Europe/Vienna5{{ now('Europe/Vienna').strftime("%b %d %Y") }}Sample result
12022-12-21 18:30:26.518253+00:00
result()
Access the result of a preceeding task within the workflow.
- Arguments:
task name: Name to identify the task you try to access the result from
Returns: Task result object
- Examples:
1# result of 'task_1' in the workflow2{{ result('task_1') }}34# result attribute 'foo' of 'task_1'5# the result function allows to only return part of the object6# if the result object does not have an attribute "foo", the function will fail with an "Undefined variables" message7{{ result('task_1.foo') }}89# alternatively, the whole result object can be returned and afterwards access the attributes of the object10# if the result object does not have an attribute "foo", the expression will fail with an "Undefined variables" message11{{ result('task_1').foo }}1213# both options can be combined, for example, with a default filter (see filters)14{{ result('task_1').foo | default('foo is not defined') }}`1516# however for the following, at least the "foo" attribute needs to exist otherwise the same error will occour17{{ result('task_1').foo.bar | default('foo is not defined') }}`1819# the get function can also be used to access object attributes20{{ result('task_1').get('foo', 'foo is not defined') }}
scheduling_rules()
Access Scheduling rules and their attributes. The behavior and result is similar to an API request for the scheduling_rules
endpoint.
-
Arguments:
identifier: scheduling rule ID
-
Keyword arguments: identical to the REST API please see note on top.
-
Returns: list of scheduling rule objects or a single scheduling rule object if ID was specified
-
Examples:
1# access scheduling rule 'a941f679-a6ee-4f33-9914-b15ea32eb326'2{{ scheduling_rules('a941f679-a6ee-4f33-9914-b15ea32eb326') }}Sample result
1{2 "id": "a941f679-a6ee-4f33-9914-b15ea32eb326",3 "created_at": "2022-12-07T12:42:45.806740Z",4 "updated_at": "2022-12-07T12:42:45.806755Z",5 "title": "First working day of the week",6 "rule_type": "rrule",7 "rrule": {8 "freq": "WEEKLY",9 "bysetpos": [10 111 ],12 "interval": 1,13 "datestart": "2020-10-01",14 "byworkday": "WORKING"15 },16 "business_calendar": "8b31fda3-3227-431c-aafe-aa849894010b"17}
scheduling_rules_includes()
Verify if a date is part of the selected dates of a scheduling rule.
You provide a scheduling rule identifier and a date as input, and the expression will evaluate to a boolean (True
or False
). This can be used to implement logic in a task condition to control the workflow. The verification is done for a 1 year outlook maximum.
- Arguments:
identifier: Scheduling rule ID
date: date to verify
- Keyword Arguments:
- format (optional): format of start date using strptime format codes
count (optional): number of preview dates to retrieve
Returns: boolean
- Examples:
1# verify if scheduling rule 'd6882cd1-9af4-41f4-801a-f2999a54aded' includes '2021-06-04'2{{ scheduling_rules_includes('d6882cd1-9af4-41f4-801a-f2999a54aded', '2021-06-04') }}34# verify if scheduling rule 'd6882cd1-9af4-41f4-801a-f2999a54aded' includes '04.06.2021'5{{ scheduling_rules_includes('d6882cd1-9af4-41f4-801a-f2999a54aded', '04.06.2021', format='%d.%m.%Y') }}
scheduling_rules_preview()
Preview the next n dates for a scheduling rule. You can configure a start timestamp and count of dates you would like to retrieve. Optionally you can provide also a formatting hint, on how to interprete the provided start date.
-
Arguments:
Identifier: scheduling rule ID
-
Keyword Arguments:
start (optional): start date as string
- format (optional): format of start date using strptime format codes
count (optional): number of preview dates to retrieve
-
Returns: preview object with the list of date srings in the "next_executions" attribute
-
Examples:
1#next dates for scheduling rule 'd6882cd1-9af4-41f4-801a-f2999a54aded'2{{ scheduling_rules_preview('d6882cd1-9af4-41f4-801a-f2999a54aded') }}34#next 10 dates for Schedule 'd6882cd1-9af4-41f4-801a-f2999a54aded' starting from '04.06.2021'5{{ scheduling_rules_preview('d6882cd1-9af4-41f4-801a-f2999a54aded', start='04.06.2021', count=10) }}67#next 10 dates for Schedule 'd6882cd1-9af4-41f4-801a-f2999a54aded' starting from '04.06.2023' with explicit format hint8{{ scheduling_rules_preview('d6882cd1-9af4-41f4-801a-f2999a54aded', start='04.06.2023', format="%d.%m.%Y", count=5 }}Sample result
1{2"valid": true,3"next_executions": [4 "2023-06-05",5 "2023-06-12",6 "2023-06-19",7 "2023-06-26",8 "2023-07-03"9 ]10}
seconds_before()
Returns the number of seconds until clock_time in timezone_name. If the time in timezone_name is < clock_time, and 0 otherwise.
Arguments: None
- Keyword Arguments:
clock_time: The time of day to compare to as string in the format of 'hh:mm:ss'
- timezone_name: Timezones as available in pytz
Returns: integer
- Examples:
1# get the number of seconds between now and 2 pm in New York2# this returns 0 if it's already past 2 pm in New York3# if it's currently 1 pm, returns 36004{{ seconds_before('14:00:00', 'America/New_York') }}
task()
Access to a task and its attributes within an execution. This allows you to access information about any other task within the same workflow.
-
Arguments:
task name: Name to identify the task you try to access. If no task name is given, the current task will be returned.
-
Returns: task object
-
Examples:
1# details of 'task_2' in the workflow2{{ task('http_request_1') }}Example task object
1{2 "id": "http_request_1",3 "name": "http_request_1",4 "input": {5 "url": "http://www.google.com",6 "method": "GET",7 "headers": "",8 "payload": ""9 },10 "state": "SUCCESS",11 "action": "dynatrace.automations:http-function",12 "active": true,13 "result": {14 "body": "... ",15 "headers": {16 "date": "Wed, 21 Dec 2022 17:06:57 GMT",17 "server": "gws",18 "domain=.google.com; HttpOnly",19 "content-type": "text/html; charset=ISO-8859-1",20 "cache-control": "private, max-age=0",21 "x-frame-options": "SAMEORIGIN",22 "x-xss-protection": "0",23 "cross-origin-opener-policy-report-only": "same-origin-allow-popups; report-to=\"gws\""24 },25 "status_code": 20026 },27 "runtime": 1,28 "ended_at": "2022-12-21T17:06:58.155478Z",29 "position": {30 "x": 1,31 "y": 132 },33 "execution": 'c4ff0688-0100-4618-93bd-e157b9a9280e',34 "conditions": {},35 "started_at": "2022-12-21T17:06:56.390869Z",36 "state_info": "",37 "predecessors": [],38 "triggered_by": [],39 "condition_results": {}40}
workflows()
Access workflows and their attributes. The behavior and result is similar to an API request for the /workflows
endpoint.
- Arguments:
identifier: workflow ID
Keyword arguments: identical to the REST API please see note on top.
Returns: list of workflow objects or a single workflow object if ID was specified
- Examples:
1# return workflow with ID '39e054c0-cfa1-4c67-bdda-497ed20f08f3'2{{ workflows('39e054c0-cfa1-4c67-bdda-497ed20f08f3') }}34# 5 most recently updated workflows5{{ workflows(limit=5, order='-updated_at') }}
workflow_execution()
Alias for execution()
Control structures
A control structure is anything that influences the flow of a template. We use it for conditions and loops. Control structures need be inside {% … %} blocks and typically span across multiple lines.
For loop
For loops iterate over each item in a list.
Basic example with static list
1{% for my_item in ["item 1", "item 2", "item 3"] %}2 item : {{ my_item }}3{% endfor %}
Example assuming you have a previous task called 'get_error_logs' which has a list of logs in its 'records', and each item is an object with multiple attributes, among which 'status' and 'content':
1We found the following logs:2{% for log in result('get_error_logs').records %}3 - {{ log.status }}: {{ log.content }}4{% endfor %}
Inside a loop block, there are additional variables available. For a full list, see Jinja documentation.
loop.index: The current iteration of the loop (1 indexed)
loop.first: True if first iteration
loop.last: True if last iteration
loop.length: The number of items in the sequence
Example generating an insert SQL statement from a list of values
1INSERT into dummy_table(name, address, priority)2VALUES3{% for sub in result('get_').subscribers %}4 ('My Item {{ sub.name }}', 'Sample Address {{ sub.address }}', 42)5 {% if not loop.last %},{% endif %}6{% endfor %}
Control strcutures can also be combined, for example, to iterate of a list of lists and create a table like structure for a notifcation.
1The DB query returned:23{% for row in result('get_entries_in_db').rows %}4Row {{loop.index}}:5 {% for element in row %}6 Value: {{element}}7 {% endfor %}8{% endfor %}
If no iteration took place because the sequence was empty or the filtering removed all the items from the sequence, you can render a default block by using else
.
1{% for log in result('get_error_logs').records %}2 - {{ log.status }}: {{ log.content }}3{% else %}4 no logs found5{% endfor %}
If statement
The if
statement can be used to test if a varaible is defined, not empty, or a comparison is true.
Example to check if there is an event object provided:
1{% if 'event' in execution().params %}2this execution was triggered by event3{% endif %}
or even simpler by using the event() shortcut
1{% if event() %}2this was triggered by event3{% endif %}
The if statements also offers an optional else if elif
and else
block:
1{% if result('get_ssl_certificate').expires_in_days <= 14 %}2 We need to renew our certificate3{% elif esult('get_ssl_certificate').expires_in_days <= 30 %}4 Let's think about renewing our certificate5{% else %}6 All good7{% endif %}
Filters
Variables can be modified by filters using a pipe symbol (|) and may have optional arguments.
For example, {{ my_name|capitalize }}
the first character will be uppercase, all others lowercase.
To apply arguments to filters, use paranthesis, just like a function call. For example, {{ my_list|join(', ') }}
will join a list with commas and whitespace in between.
For the full list of filters, see Jinja documentation.
Common filters:
for lists
first
: Return the first item of a list.last
: Return the last item of a list.join
: Return a string which is the concatenation of the items in a list.{{ ['a', 'b', 'c']|join('=') }}
returns 'a=b=c'length
: Return the number of items in a list.unique
: Returns a list of unique items in a list.
for strings
capitalize
: The first character will be uppercase, all others lowercase.length
: Return the number of characters in a string.lower
: Convert a string to lowercase.replace
: Replace all occurrences of a substring with a new one.{{ 'Hello World'|replace('Hello', 'Greetings') }}
returns 'Greetings World'trim
: Strip leading and trailing characters, by default whitespace.truncate
: Return a truncated copy of the string. The length is specified with the first parameter which defaults to 255.upper
: Convert a string to uppercase.
default value
default
: If the value is undefined it will return provided value, otherwise the value of the variable.{{ my_variable|default('my_variable is not defined') }}