1919
2020import os
2121import pathlib
22+ import shutil
23+
24+ from packaging .version import Version
2225
2326from airflow .compat .functools import cached_property
2427from airflow .configuration import conf
2730from airflow .utils .log .logging_mixin import LoggingMixin
2831
2932
33+ def get_default_delete_local_copy ():
34+ """Load delete_local_logs conf if Airflow version > 2.6 and return False if not
35+ TODO: delete this function when min airflow version >= 2.6
36+ """
37+ from airflow .version import version
38+
39+ if Version (version ) < Version ("2.6" ):
40+ return False
41+ return conf .getboolean ("logging" , "delete_local_logs" )
42+
43+
3044class S3TaskHandler (FileTaskHandler , LoggingMixin ):
3145 """
3246 S3TaskHandler is a python log handler that handles and reads
@@ -36,13 +50,18 @@ class S3TaskHandler(FileTaskHandler, LoggingMixin):
3650
3751 trigger_should_wrap = True
3852
39- def __init__ (self , base_log_folder : str , s3_log_folder : str , filename_template : str | None = None ):
53+ def __init__ (
54+ self , base_log_folder : str , s3_log_folder : str , filename_template : str | None = None , ** kwargs
55+ ):
4056 super ().__init__ (base_log_folder , filename_template )
4157 self .remote_base = s3_log_folder
4258 self .log_relative_path = ""
4359 self ._hook = None
4460 self .closed = False
4561 self .upload_on_close = True
62+ self .delete_local_copy = (
63+ kwargs ["delete_local_copy" ] if "delete_local_copy" in kwargs else get_default_delete_local_copy ()
64+ )
4665
4766 @cached_property
4867 def hook (self ):
@@ -84,7 +103,9 @@ def close(self):
84103 if os .path .exists (local_loc ):
85104 # read log and remove old logs to get just the latest additions
86105 log = pathlib .Path (local_loc ).read_text ()
87- self .s3_write (log , remote_loc )
106+ write_to_s3 = self .s3_write (log , remote_loc )
107+ if write_to_s3 and self .delete_local_copy :
108+ shutil .rmtree (os .path .dirname (local_loc ))
88109
89110 # Mark closed so we don't double write if close is called twice
90111 self .closed = True
@@ -164,23 +185,25 @@ def s3_read(self, remote_log_location: str, return_error: bool = False) -> str:
164185 return msg
165186 return ""
166187
167- def s3_write (self , log : str , remote_log_location : str , append : bool = True , max_retry : int = 1 ):
188+ def s3_write (self , log : str , remote_log_location : str , append : bool = True , max_retry : int = 1 ) -> bool :
168189 """
169- Writes the log to the remote_log_location. Fails silently if no hook
170- was created.
190+ Writes the log to the remote_log_location and return `True` when done. Fails silently
191+ and return `False` if no log was created.
171192
172193 :param log: the log to write to the remote_log_location
173194 :param remote_log_location: the log's location in remote storage
174195 :param append: if False, any existing log file is overwritten. If True,
175196 the new log is appended to any existing logs.
176197 :param max_retry: Maximum number of times to retry on upload failure
198+ :return: whether the log is successfully written to remote location or not.
177199 """
178200 try :
179201 if append and self .s3_log_exists (remote_log_location ):
180202 old_log = self .s3_read (remote_log_location )
181203 log = "\n " .join ([old_log , log ]) if old_log else log
182204 except Exception :
183205 self .log .exception ("Could not verify previous log to append" )
206+ return False
184207
185208 # Default to a single retry attempt because s3 upload failures are
186209 # rare but occasionally occur. Multiple retry attempts are unlikely
@@ -199,3 +222,5 @@ def s3_write(self, log: str, remote_log_location: str, append: bool = True, max_
199222 self .log .warning ("Failed attempt to write logs to %s, will retry" , remote_log_location )
200223 else :
201224 self .log .exception ("Could not write logs to %s" , remote_log_location )
225+ return False
226+ return True
0 commit comments