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`; });