30
30
31
31
License: MIT
32
32
"""
33
- import time
34
33
import logging
34
+ import os
35
+ import time
35
36
from pathlib import Path
36
37
from uuid import uuid4
37
38
@@ -204,7 +205,7 @@ def emit(self, record):
204
205
205
206
if intercept_standard_logging :
206
207
# Add interceptor handler to all existing loggers
207
- for name in logging .root .manager .loggerDict :
208
+ for name in logging .Logger .manager .loggerDict :
208
209
logging .getLogger (name ).addHandler (InterceptHandler ())
209
210
210
211
# Add interceptor handler to the root logger
@@ -215,72 +216,42 @@ def emit(self, record):
215
216
216
217
217
218
class ResilientFileSink :
218
- """
219
- A file sink designed for resilience, capable of retrying write operations.
220
-
221
- This class implements a resilient file writing mechanism that attempts to write messages to a file, retrying the operation a specified number of times if it fails. This is particularly useful in scenarios where write operations might intermittently fail due to temporary issues such as file system locks or networked file system delays.
222
-
223
- Attributes:
224
- path (str): The path to the file where messages will be written.
225
- max_retries (int): The maximum number of retry attempts for a failed write operation.
226
- retry_delay (float): The delay between retry attempts, in seconds.
227
-
228
- Methods:
229
- write(message): Attempts to write a message to the file, retrying on failure up to `max_retries` times.
230
- """
231
- def __init__ (self , path , max_retries = 3 , retry_delay = 1.0 , formatter = None , level = logging .INFO ):
219
+ def __init__ (self , path , retry_count = 5 , retry_delay = 1 ):
232
220
self .path = path
233
- self .max_retries = max_retries
221
+ self .retry_count = retry_count
234
222
self .retry_delay = retry_delay
235
- self ._formatter = formatter or logging .Formatter ('%(asctime)s - %(name)s - %(levelname)s - %(message)s' )
236
- self ._level = level # Set the default logging level
237
-
238
- @property
239
- def formatter (self ):
240
- return self ._formatter
241
-
242
- @formatter .setter
243
- def formatter (self , value ):
244
- self ._formatter = value
223
+ # Ensure the directory exists
224
+ os .makedirs (os .path .dirname (path ), exist_ok = True )
245
225
246
- @property
247
- def level (self ):
248
- return self ._level
249
-
250
- @level .setter
251
- def level (self , value ):
252
- self ._level = value
253
-
254
- def _should_log (self , message_level ):
255
- return message_level >= self ._level
256
-
257
- def _format_message (self , message ):
258
- return self ._formatter .format (message )
259
-
260
- def write (self , message ):
261
- if not self ._should_log (message .level ):
262
- return # Skip messages below the sink's level
263
-
264
- for attempt in range (self .max_retries ):
226
+ def __call__ (self , message ):
227
+ attempt = 0
228
+ while attempt < self .retry_count :
265
229
try :
266
- # Consider locking mechanism here for thread safety
230
+ # Open the file in append mode and write the message
267
231
with open (self .path , 'a' ) as file :
268
- file .write (self ._format_message (message ) + '\n ' )
269
- break # Exit loop on success
270
- except (IOError , PermissionError ) as e :
271
- if attempt >= self .max_retries - 1 :
272
- raise e # Reraise last exception after all retries
273
- time .sleep (self .retry_delay ) # Wait before retrying
232
+ file .write (message )
233
+ break # Exit the loop if write succeeds
234
+ except Exception as e :
235
+ attempt += 1
236
+ time .sleep (self .retry_delay )
237
+ if attempt == self .retry_count :
238
+ print (f"Failed to log message after { self .retry_count } attempts: { e } " )
239
+
274
240
275
241
if file_sink :
276
- # Create an instance of ResilientFileSink
242
+ # Create an instance of ResilientFileSink if file_sink is True
277
243
resilient_sink = ResilientFileSink (str (log_path ))
278
244
279
- # Configure the logger to use the ResilientFileSink
245
+ # Append the ResilientFileSink instance to the handlers list
280
246
basic_config_handlers .append (resilient_sink )
281
247
282
248
if intercept_standard_logging :
249
+ # Append an InterceptHandler instance to the handlers list if intercept_standard_logging is True
283
250
basic_config_handlers .append (InterceptHandler ())
284
251
252
+ if len (basic_config_handlers ) > 0 :
253
+ # Configure the root logger if there are any handlers specified
254
+ logging .basicConfig (handlers = basic_config_handlers , level = logging_level .upper ())
255
+
285
256
if len (basic_config_handlers ) > 0 :
286
257
logging .basicConfig (handlers = basic_config_handlers , level = logging_level .upper ())
0 commit comments