@@ -144,6 +144,8 @@ class RuntimeTaskInstance(TaskInstance):
144
144
145
145
rendered_map_index : str | None = None
146
146
147
+ log_url : str | None = None
148
+
147
149
def __rich_repr__ (self ):
148
150
yield "id" , self .id
149
151
yield "task_id" , self .task_id
@@ -549,6 +551,23 @@ def _xcom_push_to_db(ti: RuntimeTaskInstance, key: str, value: Any) -> None:
549
551
)
550
552
551
553
554
+ def get_log_url_from_ti (ti : RuntimeTaskInstance ) -> str :
555
+ from urllib .parse import quote
556
+
557
+ from airflow .configuration import conf
558
+
559
+ run_id = quote (ti .run_id )
560
+ base_url = conf .get ("api" , "base_url" , fallback = "http://localhost:8080/" )
561
+ map_index_value = getattr (ti , "map_index" , - 1 )
562
+ map_index = f"/mapped/{ map_index_value } " if map_index_value is not None and map_index_value >= 0 else ""
563
+ try_number_value = getattr (ti , "try_number" , 0 )
564
+ try_number = (
565
+ f"?try_number={ try_number_value } " if try_number_value is not None and try_number_value > 0 else ""
566
+ )
567
+ _log_uri = f"{ base_url } dags/{ ti .dag_id } /runs/{ run_id } /tasks/{ ti .task_id } { map_index } { try_number } "
568
+ return _log_uri
569
+
570
+
552
571
def parse (what : StartupDetails , log : Logger ) -> RuntimeTaskInstance :
553
572
# TODO: Task-SDK:
554
573
# Using DagBag here is about 98% wrong, but it'll do for now
@@ -677,6 +696,7 @@ def startup() -> tuple[RuntimeTaskInstance, Context, Logger]:
677
696
678
697
with _airflow_parsing_context_manager (dag_id = msg .ti .dag_id , task_id = msg .ti .task_id ):
679
698
ti = parse (msg , log )
699
+ ti .log_url = get_log_url_from_ti (ti )
680
700
log .debug ("DAG file parsed" , file = msg .dag_rel_path )
681
701
682
702
run_as_user = getattr (ti .task , "run_as_user" , None ) or conf .get (
0 commit comments