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

kaxilnaik pushed a commit to branch v3-0-test
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit 4be0475ce4f05b2d1528f906b5ab59d24c844c51
Author: ayush3singh <[email protected]>
AuthorDate: Fri May 16 14:13:06 2025 +0530

    Fixes issue RuntimeTaskInstance does not contain log_url | added during 
taskrunner startup (#50376)
    
    (cherry picked from commit 330789ecd8bd3df4c5760f5b6172a10c77b6b0ef)
---
 .../src/airflow/sdk/execution_time/task_runner.py    | 20 ++++++++++++++++++++
 .../task_sdk/execution_time/test_task_runner.py      |  3 +++
 2 files changed, 23 insertions(+)

diff --git a/task-sdk/src/airflow/sdk/execution_time/task_runner.py 
b/task-sdk/src/airflow/sdk/execution_time/task_runner.py
index 5fa868b9b88..6c6e597f65e 100644
--- a/task-sdk/src/airflow/sdk/execution_time/task_runner.py
+++ b/task-sdk/src/airflow/sdk/execution_time/task_runner.py
@@ -144,6 +144,8 @@ class RuntimeTaskInstance(TaskInstance):
 
     rendered_map_index: str | None = None
 
+    log_url: str | None = None
+
     def __rich_repr__(self):
         yield "id", self.id
         yield "task_id", self.task_id
@@ -549,6 +551,23 @@ def _xcom_push_to_db(ti: RuntimeTaskInstance, key: str, 
value: Any) -> None:
     )
 
 
+def get_log_url_from_ti(ti: RuntimeTaskInstance) -> str:
+    from urllib.parse import quote
+
+    from airflow.configuration import conf
+
+    run_id = quote(ti.run_id)
+    base_url = conf.get("api", "base_url", fallback="http://localhost:8080/";)
+    map_index_value = getattr(ti, "map_index", -1)
+    map_index = f"/mapped/{map_index_value}" if map_index_value is not None 
and map_index_value >= 0 else ""
+    try_number_value = getattr(ti, "try_number", 0)
+    try_number = (
+        f"?try_number={try_number_value}" if try_number_value is not None and 
try_number_value > 0 else ""
+    )
+    _log_uri = 
f"{base_url}dags/{ti.dag_id}/runs/{run_id}/tasks/{ti.task_id}{map_index}{try_number}"
+    return _log_uri
+
+
 def parse(what: StartupDetails, log: Logger) -> RuntimeTaskInstance:
     # TODO: Task-SDK:
     # Using DagBag here is about 98% wrong, but it'll do for now
@@ -677,6 +696,7 @@ def startup() -> tuple[RuntimeTaskInstance, Context, 
Logger]:
 
     with _airflow_parsing_context_manager(dag_id=msg.ti.dag_id, 
task_id=msg.ti.task_id):
         ti = parse(msg, log)
+        ti.log_url = get_log_url_from_ti(ti)
     log.debug("DAG file parsed", file=msg.dag_rel_path)
 
     run_as_user = getattr(ti.task, "run_as_user", None) or conf.get(
diff --git a/task-sdk/tests/task_sdk/execution_time/test_task_runner.py 
b/task-sdk/tests/task_sdk/execution_time/test_task_runner.py
index 180068f801b..f2ff8967081 100644
--- a/task-sdk/tests/task_sdk/execution_time/test_task_runner.py
+++ b/task-sdk/tests/task_sdk/execution_time/test_task_runner.py
@@ -106,6 +106,7 @@ from airflow.sdk.execution_time.task_runner import (
     _push_xcom_if_needed,
     _xcom_push,
     finalize,
+    get_log_url_from_ti,
     parse,
     run,
     startup,
@@ -2206,6 +2207,8 @@ class TestTaskRunnerCallsListeners:
         mocked_parse(what, "basic_dag", task)
 
         runtime_ti, context, log = startup()
+        assert runtime_ti is not None
+        assert runtime_ti.log_url == get_log_url_from_ti(runtime_ti)
         assert isinstance(listener.component, TaskRunnerMarker)
         del listener.component
 

Reply via email to