This is an automated email from the ASF dual-hosted git repository.

vatsrahul1001 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 ebe6c58d42e Fix triggerer CrashLoopBackOff when json_logs is enabled 
(#68584)
ebe6c58d42e is described below

commit ebe6c58d42e6b6799a61b98312f0e38671204de1
Author: safaehar <[email protected]>
AuthorDate: Wed Jul 29 10:44:17 2026 +0200

    Fix triggerer CrashLoopBackOff when json_logs is enabled (#68584)
    
    * Fix triggerer CrashLoopBackOff when json_logs is enabled
    
    TriggerRunnerSupervisor._process_log_messages_from_subprocess primes itself
    by calling airflow.sdk.log.configure_logging() with no arguments. 
json_output
    defaults to False, so this reconfigures structlog globally and installs the
    text WriteLogger factory -- overwriting the bytes BytesLogger factory that
    startup set up from json_logs=True.
    
    The stdout/stderr forwarders (_create_log_forwarder -> forward_to_log) were
    already wrapped with the JSON (bytes) processor chain but bind their 
underlying
    logger lazily. As soon as a trigger subprocess writes to stdout/stderr -- 
for
    example an import-time warning from a provider trigger that pulls in a heavy
    client (kubernetes, boto3) -- the lazy bind resolves against the now-text
    factory and WriteLogger.msg does `message + "\n"` on bytes from the JSON
    renderer, raising `TypeError: can't concat str to bytes` and crash-looping 
the
    triggerer.
    
    Pass json_output from the logging.json_logs config so the global structlog
    factory stays consistent with the rest of the process.
    
    * Add newsfragment
    
    * Refactor docstring for test_process_log_messages_configures_logging
    
    Updated the docstring to clarify the behavior of 
`_process_log_messages_from_subprocess()` regarding JSON logging configuration.
    
    * Delete airflow-core/newsfragments/68584.bugfix.rst
    
    * Remove comments about logging configuration
    
    Removed comments explaining the configure_logging function's behavior with 
json_logs setting.
---
 .../src/airflow/jobs/triggerer_job_runner.py        |  2 +-
 airflow-core/tests/unit/jobs/test_triggerer_job.py  | 21 +++++++++++++++++++++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/airflow-core/src/airflow/jobs/triggerer_job_runner.py 
b/airflow-core/src/airflow/jobs/triggerer_job_runner.py
index f851e491a69..8f8e930b07f 100644
--- a/airflow-core/src/airflow/jobs/triggerer_job_runner.py
+++ b/airflow-core/src/airflow/jobs/triggerer_job_runner.py
@@ -1018,7 +1018,7 @@ class TriggerRunnerSupervisor(WatchedSubprocess):
 
         from airflow.sdk.log import configure_logging
 
-        configure_logging()
+        configure_logging(json_output=conf.getboolean("logging", "json_logs", 
fallback=False))
 
         fallback_log = structlog.get_logger(logger_name=__name__)
 
diff --git a/airflow-core/tests/unit/jobs/test_triggerer_job.py 
b/airflow-core/tests/unit/jobs/test_triggerer_job.py
index 31a77b50b65..dcaaf7b3951 100644
--- a/airflow-core/tests/unit/jobs/test_triggerer_job.py
+++ b/airflow-core/tests/unit/jobs/test_triggerer_job.py
@@ -362,6 +362,27 @@ def test_run_invokes_seams_in_order(supervisor_builder, 
mocker):
     assert events == ["enter", "tick-1", "tick-2", "tick-3", "exit"]
 
 
[email protected]("json_logs", [True, False])
+def 
test_process_log_messages_configures_logging_matching_json_logs(supervisor_builder,
 mocker, json_logs):
+    """_process_log_messages_from_subprocess() must reconfigure logging using 
the
+    configured ``logging.json_logs`` value rather than the default
+    ``json_output=False``.
+    This generator reconfigures structlog globally when first primed. Failing 
to
+    propagate the configured JSON logging mode can leave the triggerer with an
+    inconsistent logging configuration and break subprocess log forwarding.
+    """
+    supervisor = supervisor_builder()
+
+    configure_logging = mocker.patch("airflow.sdk.log.configure_logging")
+    mocker.patch("airflow.sdk.log.logging_processors")
+
+    with conf_vars({("logging", "json_logs"): str(json_logs)}):
+        gen = supervisor._process_log_messages_from_subprocess()
+        next(gen)  # prime the generator -- this is what calls 
configure_logging()
+
+    configure_logging.assert_called_once_with(json_output=json_logs)
+
+
 def test_client_delegates_to_make_client_and_caches_result(supervisor_builder, 
mocker):
     """``supervisor.client`` delegates to ``make_client`` (the 
subclass-override hook)
     and caches the result across accesses."""

Reply via email to