This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new ac7a9f7483d Add log_timestamp_format config option for component log
timestamps (#63321)
ac7a9f7483d is described below
commit ac7a9f7483d32fa3506f77967a7c359ae4ce5765
Author: Shubham Gondane <[email protected]>
AuthorDate: Wed Mar 11 05:42:03 2026 -0700
Add log_timestamp_format config option for component log timestamps (#63321)
* Add log_timestamp_format config option for component log timestamps
* Add strftime to spelling wordlist
---
airflow-core/src/airflow/config_templates/config.yml | 15 ++++++++++++++-
airflow-core/src/airflow/logging_config.py | 1 +
docs/spelling_wordlist.txt | 1 +
shared/logging/src/airflow_shared/logging/structlog.py | 8 +++++++-
shared/logging/tests/logging/test_structlog.py | 10 ++++++++++
5 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/airflow-core/src/airflow/config_templates/config.yml
b/airflow-core/src/airflow/config_templates/config.yml
index 2d70e625c15..d398f54ddfd 100644
--- a/airflow-core/src/airflow/config_templates/config.yml
+++ b/airflow-core/src/airflow/config_templates/config.yml
@@ -917,11 +917,24 @@ logging:
description: |
Determines the formatter class used by Airflow for structuring its log
messages
The default formatter class is timezone-aware, which means that
timestamps attached to log entries
- will be adjusted to reflect the local timezone of the Airflow instance
+ will be adjusted to reflect the local timezone of the Airflow instance.
+ Note: This setting does NOT affect component logs (scheduler,
api-server, triggerer, etc.) since
+ those use structlog directly. Use ``log_timestamp_format`` to control
timestamps for those logs.
version_added: 2.3.4
type: string
example: ~
default: "airflow.utils.log.timezone_aware.TimezoneAware"
+ log_timestamp_format:
+ description: |
+ Timestamp format for component logs (scheduler, api-server, triggerer,
etc.).
+ Use ``iso`` for ISO 8601 format (default), or a Python strftime format
string
+ such as ``%Y-%m-%d %H:%M:%S``.
+ Note: This setting only applies to component logs rendered via
structlog.
+ Task/DAG logs use ``log_format`` instead.
+ version_added: 3.0.4
+ type: string
+ example: "%Y-%m-%d %H:%M:%S"
+ default: "iso"
secret_mask_adapter:
description: |
An import path to a function to add adaptations of each secret added
with
diff --git a/airflow-core/src/airflow/logging_config.py
b/airflow-core/src/airflow/logging_config.py
index b0aa945e6b4..da15d0c246a 100644
--- a/airflow-core/src/airflow/logging_config.py
+++ b/airflow-core/src/airflow/logging_config.py
@@ -120,6 +120,7 @@ def configure_logging():
namespace_log_levels=conf.get("logging", "namespace_levels",
fallback=None),
stdlib_config=logging_config,
log_format=log_fmt,
+ log_timestamp_format=conf.get("logging", "log_timestamp_format",
fallback="iso"),
callsite_parameters=callsite_params,
colors=colors,
)
diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt
index 8dc6d26e91e..fab58efe027 100644
--- a/docs/spelling_wordlist.txt
+++ b/docs/spelling_wordlist.txt
@@ -1510,6 +1510,7 @@ StoredInfoType
storedInfoType
str
Streamable
+strftime
Stringified
stringified
Struct
diff --git a/shared/logging/src/airflow_shared/logging/structlog.py
b/shared/logging/src/airflow_shared/logging/structlog.py
index a4fe4ec384c..5464d578a10 100644
--- a/shared/logging/src/airflow_shared/logging/structlog.py
+++ b/shared/logging/src/airflow_shared/logging/structlog.py
@@ -230,6 +230,7 @@ def structlog_processors(
log_format: str = "",
colors: bool = True,
callsite_parameters: tuple[CallsiteParameter, ...] = (),
+ log_timestamp_format: str = "iso",
):
"""
Create the correct list of structlog processors for the given config.
@@ -245,7 +246,7 @@ def structlog_processors(
:meta private:
"""
- timestamper = structlog.processors.MaybeTimeStamper(fmt="iso")
+ timestamper =
structlog.processors.MaybeTimeStamper(fmt=log_timestamp_format)
# Processors shared between stdlib handlers and structlog processors
shared_processors: list[structlog.typing.Processor] = [
@@ -387,6 +388,7 @@ def configure_logging(
json_output: bool = False,
log_level: str = "DEBUG",
log_format: str = "",
+ log_timestamp_format: str = "iso",
stdlib_config: dict | None = None,
extra_processors: Sequence[Processor] | None = None,
callsite_parameters: Iterable[CallsiteParameter] | None = None,
@@ -404,6 +406,9 @@ def configure_logging(
:param json_output: Set to true to write all logs as JSON (one per line)
:param log_level: The default log level to use for most logs
:param log_format: A percent-style log format to write non JSON logs with.
+ :param log_timestamp_format: Timestamp format for component logs. Use
``"iso"`` for ISO 8601 format
+ (the default), or a strftime format string such as ``"%Y-%m-%d
%H:%M:%S"``. Note: this only
+ applies to component logs rendered via structlog (scheduler,
api-server, triggerer, etc.).
:param output: Where to write the logs to. If ``json_output`` is true this
must be a binary stream
:param colors: Whether to use colors for non-JSON logs. This only works if
standard out is a TTY (that is,
an interactive session), unless overridden by environment variables
described below.
@@ -465,6 +470,7 @@ def configure_logging(
log_format=log_format,
colors=colors,
callsite_parameters=tuple(callsite_parameters or ()),
+ log_timestamp_format=log_timestamp_format,
)
shared_pre_chain += list(extra_processors)
pre_chain: list[structlog.typing.Processor] =
[structlog.stdlib.add_logger_name] + shared_pre_chain
diff --git a/shared/logging/tests/logging/test_structlog.py
b/shared/logging/tests/logging/test_structlog.py
index 5637ad4333d..42d1e715aef 100644
--- a/shared/logging/tests/logging/test_structlog.py
+++ b/shared/logging/tests/logging/test_structlog.py
@@ -206,6 +206,16 @@ def test_precent_fmt_force_no_colors(
)
+def test_log_timestamp_format(structlog_config):
+ """Test that log_timestamp_format controls the timestamp format in
component logs."""
+ with structlog_config(colors=False, log_timestamp_format="%Y-%m-%d
%H:%M:%S") as sio:
+ logger = structlog.get_logger("my.logger")
+ logger.info("Hello")
+
+ written = sio.getvalue()
+ assert "1985-10-26 00:00:00" in written
+
+
@pytest.mark.parametrize(
("get_logger", "config_kwargs", "log_kwargs", "expected_kwargs"),
[