diff --git a/docs/sources/configure/jinja2-templating/index.md b/docs/sources/configure/jinja2-templating/index.md index 4eb2b0a412..ff97020687 100644 --- a/docs/sources/configure/jinja2-templating/index.md +++ b/docs/sources/configure/jinja2-templating/index.md @@ -219,9 +219,10 @@ Built-in functions: - `tojson` - dumps a structure to JSON - `tojson_pretty` - same as tojson, but prettified - `iso8601_to_time` - converts time from iso8601 (`2015-02-17T18:30:20.000Z`) to datetime -- `datetimeformat` - converts time from datetime to the given format (`%H:%M / %d-%m-%Y` by default) +- `datetimeformat` - converts datetime to string according to strftime format codes (`%H:%M / %d-%m-%Y` by default) - `datetimeformat_as_timezone` - same as `datetimeformat`, with the inclusion of timezone conversion (`UTC` by default) - Usage example: `{{ payload.alerts.startsAt | iso8601_to_time | datetimeformat_as_timezone('%Y-%m-%dT%H:%M:%S%z', 'America/Chicago') }}` +- `datetimeparse` - converts string to datetime according to strftime format codes (`%H:%M / %d-%m-%Y` by default) - `regex_replace` - performs a regex find and replace - `regex_match` - performs a regex match, returns `True` or `False` - Usage example: `{{ payload.ruleName | regex_match(".*") }}` diff --git a/engine/common/jinja_templater/filters.py b/engine/common/jinja_templater/filters.py index 3eb98442c5..c8ffc12af0 100644 --- a/engine/common/jinja_templater/filters.py +++ b/engine/common/jinja_templater/filters.py @@ -1,11 +1,19 @@ import base64 import json import re +from datetime import datetime from django.utils.dateparse import parse_datetime from pytz import timezone +def datetimeparse(value, format="%H:%M / %d-%m-%Y"): + try: + return datetime.strptime(value, format) + except (ValueError, AttributeError, TypeError): + return None + + def datetimeformat(value, format="%H:%M / %d-%m-%Y"): try: return value.strftime(format) diff --git a/engine/common/jinja_templater/jinja_template_env.py b/engine/common/jinja_templater/jinja_template_env.py index d9204928ec..f24a0c5517 100644 --- a/engine/common/jinja_templater/jinja_template_env.py +++ b/engine/common/jinja_templater/jinja_template_env.py @@ -7,6 +7,7 @@ b64decode, datetimeformat, datetimeformat_as_timezone, + datetimeparse, iso8601_to_time, json_dumps, parse_json, @@ -25,6 +26,7 @@ def raise_security_exception(name): jinja_template_env.filters["datetimeformat"] = datetimeformat jinja_template_env.filters["datetimeformat_as_timezone"] = datetimeformat_as_timezone +jinja_template_env.filters["datetimeparse"] = datetimeparse jinja_template_env.filters["iso8601_to_time"] = iso8601_to_time jinja_template_env.filters["tojson_pretty"] = to_pretty_json jinja_template_env.globals["time"] = timezone.now diff --git a/engine/common/tests/test_apply_jinja_template.py b/engine/common/tests/test_apply_jinja_template.py index e127fb7d96..ca947236bb 100644 --- a/engine/common/tests/test_apply_jinja_template.py +++ b/engine/common/tests/test_apply_jinja_template.py @@ -1,5 +1,6 @@ import base64 import json +from datetime import datetime from unittest.mock import patch import pytest @@ -44,6 +45,14 @@ def test_apply_jinja_template_datetimeformat(): "{{ payload.naive | iso8601_to_time | datetimeformat('%Y-%m-%dT%H:%M:%S%z') }}", payload, ) == parse_datetime(payload["naive"]).strftime("%Y-%m-%dT%H:%M:%S%z") + assert apply_jinja_template( + "{{ payload.aware | datetimeparse('%Y-%m-%d %H:%M:%S%z') | datetimeformat('%Y-%m-%dT%H:%M:%S%z') }}", + payload, + ) == datetime.strptime(payload["aware"], "%Y-%m-%d %H:%M:%S%z").strftime("%Y-%m-%dT%H:%M:%S%z") + assert apply_jinja_template( + "{{ payload.naive | datetimeparse('%Y-%m-%d %H:%M:%S') | datetimeformat('%Y-%m-%dT%H:%M:%S%z') }}", + payload, + ) == datetime.strptime(payload["naive"], "%Y-%m-%d %H:%M:%S").strftime("%Y-%m-%dT%H:%M:%S%z") def test_apply_jinja_template_datetimeformat_as_timezone(): @@ -57,12 +66,46 @@ def test_apply_jinja_template_datetimeformat_as_timezone(): "{{ payload.naive | iso8601_to_time | datetimeformat_as_timezone('%Y-%m-%dT%H:%M:%S%z', 'America/Chicago') }}", payload, ) == parse_datetime(payload["naive"]).astimezone(timezone("America/Chicago")).strftime("%Y-%m-%dT%H:%M:%S%z") + assert ( + apply_jinja_template( + """{{ payload.aware | datetimeparse('%Y-%m-%d %H:%M:%S%z') | datetimeformat_as_timezone('%Y-%m-%dT%H:%M:%S%z', + 'America/Chicago') }}""", + payload, + ) + == parse_datetime(payload["aware"]).astimezone(timezone("America/Chicago")).strftime("%Y-%m-%dT%H:%M:%S%z") + ) + assert ( + apply_jinja_template( + """{{ payload.naive | datetimeparse('%Y-%m-%d %H:%M:%S') | datetimeformat_as_timezone('%Y-%m-%dT%H:%M:%S%z', + 'America/Chicago') }}""", + payload, + ) + == parse_datetime(payload["naive"]).astimezone(timezone("America/Chicago")).strftime("%Y-%m-%dT%H:%M:%S%z") + ) with pytest.raises(JinjaTemplateWarning): apply_jinja_template( "{{ payload.aware | iso8601_to_time | datetimeformat_as_timezone('%Y-%m-%dT%H:%M:%S%z', 'potato') }}", payload, ) + apply_jinja_template( + """{{ payload.aware | datetimeparse('%Y-%m-%d %H:%M:%S%z') | + datetimeformat_as_timezone('%Y-%m-%dT%H:%M:%S%z', 'potato') }}""", + payload, + ) + + +def test_apply_jinja_template_datetimeparse(): + payload = {"aware": "15 05 2024 07:52:11 -0600", "naive": "2024-05-15T07:52:11"} + + assert apply_jinja_template( + "{{ payload.aware | datetimeparse('%d %m %Y %H:%M:%S %z') }}", + payload, + ) == str(datetime.strptime(payload["aware"], "%d %m %Y %H:%M:%S %z")) + assert apply_jinja_template( + "{{ payload.naive | datetimeparse('%Y-%m-%dT%H:%M:%S') }}", + payload, + ) == str(datetime.strptime(payload["naive"], "%Y-%m-%dT%H:%M:%S")) def test_apply_jinja_template_b64decode(): diff --git a/grafana-plugin/src/components/CheatSheet/CheatSheet.config.ts b/grafana-plugin/src/components/CheatSheet/CheatSheet.config.ts index 197453aee6..523b1dadac 100644 --- a/grafana-plugin/src/components/CheatSheet/CheatSheet.config.ts +++ b/grafana-plugin/src/components/CheatSheet/CheatSheet.config.ts @@ -84,7 +84,7 @@ export const genericTemplateCheatSheet: CheatSheetInterface = { { listItemName: 'labels - labels assigned to the last alert in the group' }, { listItemName: 'web_title, web_mesage, web_image_url - templates from Web' }, { listItemName: 'payload, grafana_oncall_link, grafana_oncall_incident_id, integration_name, source_link' }, - { listItemName: 'time(), datetimeformat, datetimeformat_as_timezone, iso8601_to_time' }, + { listItemName: 'time(), datetimeformat, datetimeformat_as_timezone, datetimeparse, iso8601_to_time' }, { listItemName: 'to_pretty_json' }, { listItemName: 'regex_replace, regex_match' }, { listItemName: 'b64decode' },