diff --git a/airflow/config_templates/airflow_local_settings.py b/airflow/config_templates/airflow_local_settings.py
index 6684fd18e51a0..3beafbd2b2da6 100644
--- a/airflow/config_templates/airflow_local_settings.py
+++ b/airflow/config_templates/airflow_local_settings.py
@@ -31,7 +31,6 @@
# settings.py and cli.py. Please see AIRFLOW-1455.
LOG_LEVEL: str = conf.get_mandatory_value('logging', 'LOGGING_LEVEL').upper()
-
# Flask appbuilder's info level log is very verbose,
# so it's set to 'WARN' by default.
FAB_LOG_LEVEL: str = conf.get_mandatory_value('logging', 'FAB_LOGGING_LEVEL').upper()
@@ -60,10 +59,13 @@
'version': 1,
'disable_existing_loggers': False,
'formatters': {
- 'airflow': {'format': LOG_FORMAT},
+ 'airflow': {
+ 'format': LOG_FORMAT,
+ 'class': 'airflow.utils.log.timezone_aware.TimezoneAware',
+ },
'airflow_coloured': {
'format': COLORED_LOG_FORMAT if COLORED_LOG else LOG_FORMAT,
- 'class': COLORED_FORMATTER_CLASS if COLORED_LOG else 'logging.Formatter',
+ 'class': COLORED_FORMATTER_CLASS if COLORED_LOG else 'airflow.utils.log.timezone_aware.TimezoneAware',
},
},
'filters': {
diff --git a/airflow/utils/log/colored_log.py b/airflow/utils/log/colored_log.py
index d1adb0859b3a7..d93f5726fe9b2 100644
--- a/airflow/utils/log/colored_log.py
+++ b/airflow/utils/log/colored_log.py
@@ -42,6 +42,8 @@ class CustomTTYColoredFormatter(TTYColoredFormatter):
by adding attributes to message arguments and coloring error
traceback.
"""
+ default_time_format = '%Y-%m-%d %H:%M:%S%z'
+ default_msec_format = None
def __init__(self, *args, **kwargs):
kwargs["stream"] = sys.stdout or kwargs.get("stream")
diff --git a/airflow/utils/log/timezone_aware.py b/airflow/utils/log/timezone_aware.py
new file mode 100644
index 0000000000000..28cc6d836a8dc
--- /dev/null
+++ b/airflow/utils/log/timezone_aware.py
@@ -0,0 +1,23 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import logging
+
+
+class TimezoneAware(logging.Formatter):
+ default_time_format = '%Y-%m-%d %H:%M:%S%z'
+ default_msec_format = None
diff --git a/airflow/www/static/js/ti_log.js b/airflow/www/static/js/ti_log.js
index 1bf6b501a659c..942704b308f22 100644
--- a/airflow/www/static/js/ti_log.js
+++ b/airflow/www/static/js/ti_log.js
@@ -102,7 +102,7 @@ function autoTailingLog(tryNumber, metadata = null, autoTailing = false) {
// Detect urls and log timestamps
const urlRegex = /http(s)?:\/\/[\w.-]+(\.?:[\w.-]+)*([/?#][\w\-._~:/?#[\]@!$&'()*+,;=.%]+)?/g;
- const dateRegex = /\d{4}[./-]\d{2}[./-]\d{2} \d{2}:\d{2}:\d{2},\d{3}/g;
+ const dateRegex = /\d{4}[./-]\d{2}[./-]\d{2} \d{2}:\d{2}:\d{2}[+-]\d{4}/g;
res.message.forEach((item) => {
const logBlockElementId = `try-${tryNumber}-${item[0]}`;
@@ -120,7 +120,7 @@ function autoTailingLog(tryNumber, metadata = null, autoTailing = false) {
const escapedMessage = escapeHtml(item[1]);
const linkifiedMessage = escapedMessage
.replace(urlRegex, (url) => `${url}`)
- .replaceAll(dateRegex, (date) => ``);
+ .replaceAll(dateRegex, (date) => ``);
logBlock.innerHTML += `${linkifiedMessage}\n`;
});