Latest Dynatrace
Dynatrace Workflows use the Jinja templating engine to allow for dynamic configuration in Workflows. Those expressions provide, for example, access to execution parameters, schedule information, event context.
Expressions are supported in any input of any action (unless specified otherwise by the action developer) and the custom task conditions and options. A notable exception is the Run Javascript action, which does not support expression in its input to avoid the possibility of code injection. Instead, SDKs are provided to access the same information directly in JavaScript. For more information, see Run JavaScript action for Workflows.
Expressions enable you to reference results from predecessors in a task configuration and define custom conditions.
There are two kinds of delimiters.
{{ ... }}
for expressions, it's 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 the REST API request returns JSON, an expression will return a native object, which is its string representation.
Access to resources happens in the context of the workflow actor (link to workflow settings).
calendars()
Access business calendars and their attributes. The behavior and result are similar to an API request for the /business_calendars
endpoint.
Arguments:
Keyword arguments: identical to the REST API. For more information, see the note above.
Returns: a list of calendar objects or a single calendar object if id
was specified
Examples:
# access to calendar '854a3452-a6d3-45bd-83e1-e8afa56eabcd'{{ calendars('854a3452-a6d3-45bd-83e1-e8afa56eabcd') }}
{"id": "854a3452-a6d3-45bd-83e1-e8afa56eabcd","created_at": "2022-12-07T12:42:45.732902Z","updated_at": "2022-12-20T09:36:40.303952Z","title": "Sample Calendar","weekstart": 1,"weekdays": [1,2,3,4,5],"holidays": [{"date": "2020-01-01","title": "New Year"},{"date": "2020-01-07","title": "International Programmers Day"}],"valid_from": "2020-01-01","valid_to": "2029-12-31",}
connection()
Get a single connection by schema ID and connection name.
# get the settings object ID by schema ID and name{{ connection('app:dynatrace.slack:connection', 'My Slack Connection') }}# get the settings object ID by schema ID and name from a previous task result{{ connection('app:dynatrace.slack:connection', result('get_my_config')['slack']['connection']) }}
environment()
Information about the environment, for example, id
or url
.
id
and environment url
.{"id": "xyz12345","url": "https://xyz12345.dynatrace.com"}# get the full environment object{{ environment() }}# access current environment id{{ environment().id }} # -> "xyz12345"# access current environment url{{ environment().url }} # -> "https://xyz12345.dynatrace.com"
event()
# Assuming the following sample event as a trigger for a Workflow Execution{"type": "security-problem-event","version": "0.0.2","event.id": "20d01063-14d7-4b99-aef1-77e92962fb7f""event.id": "20d01063-14d7-4b99-aef1-77e92962fb7f","event.kind": "SECURITY_PROBLEM_EVENT","event.name": "Vulnerability resolved","event.type": "THIRD_PARTY","event.status": "Resolved","event.category": "Vulnerability","security-problem.display-id": "S-3750","security-problem.technology": "go","security-problem.vulnerability-type": "third-party"}# get the full event object{{ event() }}# access only the type attribute{{ event('type') }} # -> "security-problem-event"# access the full event object and then select the type attribute{{ event().type }} # -> "security-problem-event"# trying to access the 'technology' attribute of the 'security-problem' object# this will FAIL, as there is actually no 'security-problem' object in the example above{{ event().security-problem.technology }} # -> ERROR# NOTE: events often do not contain structured objects but flattened objects# the 'security-problem.technology' for example is a single attribute, that happens to have a "." in its name# in order to access attributes with "." in its name, use square brackets instead []{{ event()['security-problem.technology'] }} # -> "go"# as an alternative, use the get() function{{ event().get('security-problem.technology') }}# the get function also allows for default values, if the attribute is not defined{{ event().get('does.not.exist', 'my default value') }}
execution()
Access the current execution context.
Arguments: None
Keyword arguments: None
Returns: execution object
Examples:
# access the current execution object{{ execution() }}# access ID of current executionExecution ID {{ execution().id }}# access input of current executionExecution input {{ execution().input | default('no input defined') }}
Sample result
{"id": "b126f1cc-fce1-4d28-adcf-0805b98961b9","state": "RUNNING","started_at": "2022-12-21T18:33:11.084818Z","ended_at": null,"runtime": 12,"user": "716535cb-b992-47e4-90be-7d4b9785a501","title": "Get Security Problem events count","link": "https://xyz12345.apps.dynatrace.com/ui/apps/dynatrace.automations/executions/b126f1cc-fce1-4d28-adcf-0805b98961b9","workflow": {"id": "ef1f1ca4-1d6b-4c7d-b964-5f09096d77cd","title": "Get Security Problem events count","actor": "716535cb-b992-47e4-90be-7d4b9785a501","link": "https://xyz12345.apps.dynatrace.com/ui/apps/dynatrace.automations/workflows/ef1f1ca4-1d6b-4c7d-b964-5f09096d77cd"}}
executions()
Access executions and their attributes. The behavior and result are similar to an API request for the /executions
endpoint.
id
was specified#execution with ID 00c27c88-d066-4424-bc44-f49a75536e37 {{ executions('00c27c88-d066-4424-bc44-f49a75536e37') }}#executions of the workflow with ID '81a7fbb5-7f69-4005-81ec-26a39272bf09' (default limit applies for resultsize){{ executions(workflow='81a7fbb5-7f69-4005-81ec-26a39272bf09') }}#returns up to 5 executions ordered by created_at in descending order{{ executions(limit=5, order='-created_at') }}# returns the most recent execution of workflow '81a7fbb5-7f69-4005-81ec-26a39272bf09'{{ executions(workflow='81a7fbb5-7f69-4005-81ec-26a39272bf09', limit=1, order='-created_at') }}
now()
The current timestamp in UTC or time zone is provided as the input parameter. The expression returns a native Python datetime
object to allow formatting into any desired output. Use strftime
and format codes as described in datetime Python documentation.
Arguments:
Returns: datetime object
Examples:
# current time in UTC{{ now().strftime("%b %d %Y") }}# current time in Europe/Vienna{{ now('Europe/Vienna').strftime("%b %d %Y") }}
Sample result
2022-12-21 18:30:26.518253+00:00
timedelta()
Difference between two datetime values. Expression returns native Python timedelta object to allow time calculations when working with now()
. The JSON representation of this expression is the number of total seconds.
Arguments:
Returns: timedelta object
Examples:
# calculate yesterday by substracting one day{{ now() - timedelta(days=1) }}# offset current date and time by one week{{ now() + timedelta(weeks=1) }}# offset current date and time by one hour, thirty minutes, and fifteen seconds{{ now() - timedelta(hours=1, minutes=30, seconds=15) }}# double the timedelta value and increase it by five minutes{{ timedelta(hours=1)*2 + timedelta(minutes=5) }}
result()
Access the result of a preceding task within the workflow.
# result of 'task_1' in the workflow{{ result('task_1') }}# result attribute 'foo' of 'task_1'# the result function allows to only return part of the object# if the result object does not have an attribute "foo", the function will fail with an "Undefined variables" message{{ result('task_1.foo') }}# alternatively, the whole result object can be returned and afterwards access the attributes of the object# if the result object does not have an attribute "foo", the expression will fail with an "Undefined variables" message{{ result('task_1').foo }}# both options can be combined, for example, with a default filter (see filters){{ result('task_1').foo | default('foo is not defined') }}`# however for the following, at least the "foo" attribute needs to exist otherwise the same error will occour{{ result('task_1').foo.bar | default('foo is not defined') }}`# the get function can also be used to access object attributes{{ 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:
Keyword arguments: identical to the REST API. For more information, see the note above.
Returns: list of scheduling rule objects or a single scheduling rule object if id
was specified
Examples:
# access scheduling rule 'a941f679-a6ee-4f33-9914-b15ea32eb326'{{ scheduling_rules('a941f679-a6ee-4f33-9914-b15ea32eb326') }}
Sample result
{"id": "a941f679-a6ee-4f33-9914-b15ea32eb326","created_at": "2022-12-07T12:42:45.806740Z","updated_at": "2022-12-07T12:42:45.806755Z","title": "First working day of the week","rule_type": "rrule","rrule": {"freq": "WEEKLY","bysetpos": [1],"interval": 1,"datestart": "2020-10-01","byworkday": "WORKING"},"business_calendar": "8b31fda3-3227-431c-aafe-aa849894010b"}
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 one year outlook maximum.
# verify if scheduling rule 'd6882cd1-9af4-41f4-801a-f2999a54aded' includes '2021-06-04'{{ scheduling_rules_includes('d6882cd1-9af4-41f4-801a-f2999a54aded', '2021-06-04') }}# verify if scheduling rule 'd6882cd1-9af4-41f4-801a-f2999a54aded' includes '04.06.2021'{{ 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 also provide a formatting hint on how to interpret the provided start date.
Arguments:
Keyword Arguments:
Returns: preview object with the list of date objects in the "next_executions" attribute
Examples:
# next dates for scheduling rule 'd6882cd1-9af4-41f4-801a-f2999a54aded'{{ scheduling_rules_preview('d6882cd1-9af4-41f4-801a-f2999a54aded') }}# next 10 dates for Schedule 'd6882cd1-9af4-41f4-801a-f2999a54aded' starting from '04.06.2021'{{ scheduling_rules_preview('d6882cd1-9af4-41f4-801a-f2999a54aded', start='04.06.2021', count=10) }}# next 10 dates for Schedule 'd6882cd1-9af4-41f4-801a-f2999a54aded' starting from '04.06.2023' with explicit format hint{{ scheduling_rules_preview('d6882cd1-9af4-41f4-801a-f2999a54aded', start='04.06.2023', format="%d.%m.%Y", count=5) }}# format the first returned date object following pattern %d.%m.%Y{{ scheduling_rules_preview('d6882cd1-9af4-41f4-801a-f2999a54aded', start='04.06.2023')["next_executions"][0].strftime("%d.%m.%Y") }}
Sample result
{"valid": true,"next_executions": ["2023-06-05","2023-06-12","2023-06-19","2023-06-26","2023-07-03"]}
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.
# get the number of seconds between now and 2 pm in New York# this returns 0 if it's already past 2 pm in New York# if it's currently 1 pm, returns 3600{{ 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:
Returns: task object
Examples:
# details of 'task_2' in the workflow{{ task('http_request_1') }}
Example task object
{"id": "http_request_1","name": "http_request_1","input": {"url": "http://www.google.com","method": "GET","headers": "","payload": ""},"state": "SUCCESS","action": "dynatrace.automations:http-function","active": true,"result": {"body": "... ","headers": {"date": "Wed, 21 Dec 2022 17:06:57 GMT","server": "gws","domain=.google.com; HttpOnly","content-type": "text/html; charset=ISO-8859-1","cache-control": "private, max-age=0","x-frame-options": "SAMEORIGIN","x-xss-protection": "0","cross-origin-opener-policy-report-only": "same-origin-allow-popups; report-to=\"gws\""},"status_code": 200},"runtime": 1,"ended_at": "2022-12-21T17:06:58.155478Z","position": {"x": 1,"y": 1},"execution": 'c4ff0688-0100-4618-93bd-e157b9a9280e',"conditions": {},"started_at": "2022-12-21T17:06:56.390869Z","state_info": "","predecessors": [],"triggered_by": [],"condition_results": {}}
workflows()
Access workflows and their attributes. The behavior and result are similar to an API request for the /workflows
endpoint.
id
was specified# return workflow with ID '39e054c0-cfa1-4c67-bdda-497ed20f08f3'{{ workflows('39e054c0-cfa1-4c67-bdda-497ed20f08f3') }}# 5 most recently updated workflows{{ workflows(limit=5, order='-updated_at') }}
Alias for execution()
A control structure is anything that influences the flow of a template. We use it for conditions and loops. Control structures need to be inside {% … %} blocks and typically span multiple lines.
For loops iterate over each item in a list.
Basic example with static listExample assume 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':
We found the following logs:{% for log in result('get_error_logs').records %}- {{ log.status }}: {{ log.content }}{% endfor %}
Inside a loop block, there are additional variables available. For a full list, see Jinja documentation.
The example generating an insert SQL statement from a list of valuesControl structures can also be combined, for example, to iterate a list of lists and create a table-like structure for a notification.
The DB query returned:{% for row in result('get_entries_in_db').rows %}Row {{loop.index}}:{% for element in row %}Value: {{element}}{% endfor %}{% endfor %}
If no iteration occurred because the sequence was empty or the filtering removed all the items from the sequence, you can render a default block using else
.
{% for log in result('get_error_logs').records %}- {{ log.status }}: {{ log.content }}{% else %}no logs found{% endfor %}
The if
statement can be used to test if a variable is defined, not empty, or a comparison is true.
Example to check if there is an event object provided:
{% if 'event' in execution().params %}this execution was triggered by event{% endif %}
or even simpler by using the event() shortcut
{% if event() %}this was triggered by event{% endif %}
The if statements also offer an optional else if elif
and else
block:
{% if result('get_ssl_certificate').expires_in_days <= 14 %}We need to renew our certificate{% elif esult('get_ssl_certificate').expires_in_days <= 30 %}Let's think about renewing our certificate{% else %}All good{% endif %}
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.
Use parentheses to apply arguments to filters, just like a function call. For example, {{ my_list|join(', ') }}
will join a list with commas and whitespace in between.
For the complete list of filters, see Jinja List of Builtin Filters documentation.
first
: Returns the first item of a list.last
: Returns the last item of a list.join
: Returns a string that contains the concatenation of the items in a list. {{ ['a', 'b', 'c']|join('=') }}
returns 'a=b=c'length
: Returns the number of items in a list.unique
: Returns a list of unique items in a list.capitalize
: The first character will be uppercase, and all others lowercase.length
: Returns the number of characters in a string.lower
: Converts a string to lowercase.replace
: Replaces all occurrences of a substring with a new one. {{ 'Hello World'|replace('Hello', 'Greetings') }}
returns 'Greetings World'trim
: Strips leading and trailing characters by default whitespace.truncate
: Returns a truncated copy of the string. The first parameter specifies the length, which defaults to 255
.upper
: Converts a string to uppercase.to_datetime
: Converts an ISO8601-conform string to a datetime-object. An alternative format can be specified with the first parameter. Example: {{ "2019_08_01" | to_datetime('%Y_%m_%d') }}
Advanced searching, filtering, and replacing are supported using regex (regular expressions). Standard keyword parameters existing on any regex filter:
ignorecase
: Performs case insensitive search. Defaults to False
.multiline
: Performs replacement across multiple lines. Defaults to False
.The following regex-specific filters are supported:
regex_search
: Performs a search on the string and extracts the string(or list of strings) that matches the regular expression
Examples: {{ 'a12b34'|regex_search('b\\d\\d') }}
Searches for a regex and extracts a specific group either specified by the name with \\g{groupName}
or specified by the index with \\{groupIndex}
(0 is always the whole match). The result will be a list of matches according to the passed groups
{{ 'a12b34'|regex_search('b(?P<firstDigit>\\d)\\d', '\\gfirstDigit') | first }}
{{ 'Hello World'|regex_search('^(?P<FirstWord>\\w+) (?P<SecondWord>\\w+)$', '\\gSecondWord', '\\1') }}
regex_findall
: Gets all matches in a string.
Example: 'DynaTrace'|regex_findall('[A-Z]')
returns ['D', 'T']
regex_replace
: Replaces a part of a string with another part.
Examples: '1a3'|regex_replace('\d', 'X')
'Hello World'|regex_replace(' \w+$', ' Moon')
Additional keyword parameters for regex_replace
:
count
: Maximum number of pattern occurrences to replace. The default value is zero, which replaces all occurrences.mandatory_count
: Aborts the evaluation if fewer occurrences have been replaced.format_number
: Formats a number in the format "1,234,567.89". You can change the thousand separator and the amount of trailing digits. {{ 3.14159|format_number(trailing_digits=0) }}
results in 3
. {{ 3.1415|format_number(trailing_digits=3, decimal_separator=',') }}
results in 3,142
. {{ 1234|format_number(thousand_separator='_') }}
results in 1_234.00
.base64encode
: Encodes a string or bytes object to a base64 string.base64decode
: Decodes a valid string or bytes object containing a base64 string to a string.to_yaml
: Converts an object to its yaml representation.from_yaml
: Converts a yaml string back to a Python object.to_json
: Converts an object to its JSON representation.from_json
: Converts a json string back to a Python objectdict2items
: Converts a dict to a list of key-value pairs in the form of { 'key': 'keyValue', 'value': 'valueOfPair' }
.
{{ {'a': 1, 'b': 2}|dict2items }}
returns [{ 'key': 'a', 'value': 1 }, { 'key': 'b', 'value': 2 }]
. With the key_name
and value_name
arguments, you can change the key-value key of the return value.items2dict
: Converts a list of key-value pairs to a dict.
{{ [{ 'key': 'a', 'valueA': 1, 'valueB': 7 }, { 'key': 'b', 'valueA': 2, 'valueB': 8 }]|items2dict(value_name='valueA') }}
returns {'a': 1, 'b': 2}
. The arguments key_name
and value_name
can modify which keys are used to construct the dict.validate_regex
: Validate if variable value matches regex. This filter also allows the overriding of the expression value validation definitions defined for the input by the app author. {{ 'example_string' | validate_regex('[a-z_]+') }}
bool
: Returns true if the expression is truthy {{ 'truthy' | bool }}
.json_query
: To select a single value or structure from JSON data. {{ { 'key': 'a', 'value': { 'nestedValue': 'b' }}|json_query('value.nestedValue') }}
returns b
. The filter builds on top of the JMESPATH library. For examples and interactive tryout, see the JMESPATH documentation.ternary
: Returns the first argument value if it is truthy; otherwise the second argument value is returned. The third argument none_val
is optional; if provided, it is returned when the first argument value is None
.
{{ True | ternary("foo", "bar") }}
returns foo
. {{ False | ternary("foo", "bar") }}
returns bar
. {{ None | ternary("foo", "bar", none_val="fizz") }}
returns fizz
.default value
default
: If the value is undefined it will return the provided value, otherwise the value of the variable. {{ my_variable|default('my_variable is not defined') }}