Skip to content

Commit eca077b

Browse files
authored
Get served logs when remote or executor logs not available for non-running task try (#39177)
1 parent 15c2734 commit eca077b

2 files changed

Lines changed: 18 additions & 8 deletions

File tree

airflow/utils/log/file_task_handler.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -366,10 +366,7 @@ def _read(
366366
executor_messages: list[str] = []
367367
executor_logs: list[str] = []
368368
served_logs: list[str] = []
369-
is_running = ti.try_number == try_number and ti.state in (
370-
TaskInstanceState.RUNNING,
371-
TaskInstanceState.DEFERRED,
372-
)
369+
is_in_running_or_deferred = ti.state in (TaskInstanceState.RUNNING, TaskInstanceState.DEFERRED)
373370
with suppress(NotImplementedError):
374371
remote_messages, remote_logs = self._read_remote_logs(ti, try_number, metadata)
375372
messages_list.extend(remote_messages)
@@ -384,7 +381,9 @@ def _read(
384381
worker_log_full_path = Path(self.local_base, worker_log_rel_path)
385382
local_messages, local_logs = self._read_from_local(worker_log_full_path)
386383
messages_list.extend(local_messages)
387-
if is_running and not executor_messages:
384+
if is_in_running_or_deferred and not executor_messages and not remote_logs:
385+
# While task instance is still running and we don't have either executor nor remote logs, look for served logs
386+
# This is for cases when users have not setup remote logging nor shared drive for logs
388387
served_messages, served_logs = self._read_from_logs_server(ti, worker_log_rel_path)
389388
messages_list.extend(served_messages)
390389
elif ti.state not in State.unfinished and not (local_logs or remote_logs):
@@ -404,11 +403,12 @@ def _read(
404403
)
405404
log_pos = len(logs)
406405
messages = "".join([f"*** {x}\n" for x in messages_list])
406+
end_of_log = ti.try_number != try_number or not is_in_running_or_deferred
407407
if metadata and "log_pos" in metadata:
408408
previous_chars = metadata["log_pos"]
409409
logs = logs[previous_chars:] # Cut off previously passed log test as new tail
410410
out_message = logs if "log_pos" in (metadata or {}) else messages + logs
411-
return out_message, {"end_of_log": not is_running, "log_pos": log_pos}
411+
return out_message, {"end_of_log": end_of_log, "log_pos": log_pos}
412412

413413
@staticmethod
414414
def _get_pod_namespace(ti: TaskInstance):

tests/utils/test_log_handlers.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ def test__read_for_k8s_executor(self, mock_k8s_get_task_log, create_task_instanc
315315

316316
def test__read_for_celery_executor_fallbacks_to_worker(self, create_task_instance):
317317
"""Test for executors which do not have `get_task_log` method, it fallbacks to reading
318-
log from worker. But it happens only for the latest try_number."""
318+
log from worker if and only if remote logs aren't found"""
319319
executor_name = "CeleryExecutor"
320320

321321
ti = create_task_instance(
@@ -336,7 +336,17 @@ def test__read_for_celery_executor_fallbacks_to_worker(self, create_task_instanc
336336
fth._read_from_logs_server.assert_called_once()
337337
assert actual == ("*** this message\nthis\nlog\ncontent", {"end_of_log": False, "log_pos": 16})
338338

339-
# Previous try_number is from remote logs without reaching worker server
339+
# Previous try_number should return served logs when remote logs aren't implemented
340+
fth._read_from_logs_server = mock.Mock()
341+
fth._read_from_logs_server.return_value = ["served logs try_number=1"], ["this\nlog\ncontent"]
342+
actual = fth._read(ti=ti, try_number=1)
343+
fth._read_from_logs_server.assert_called_once()
344+
assert actual == (
345+
"*** served logs try_number=1\nthis\nlog\ncontent",
346+
{"end_of_log": True, "log_pos": 16},
347+
)
348+
349+
# When remote_logs is implemented, previous try_number is from remote logs without reaching worker server
340350
fth._read_from_logs_server.reset_mock()
341351
fth._read_remote_logs = mock.Mock()
342352
fth._read_remote_logs.return_value = ["remote logs"], ["remote\nlog\ncontent"]

0 commit comments

Comments
 (0)