1- # -*- encoding: utf-8 -*-
21import atexit
32import logging
43import threading
87from typing import Dict , Optional , Tuple , Union
98from pythonLogs .basic_log import BasicLog
109from pythonLogs .constants import LogLevel , RotateWhen
11- from pythonLogs .memory_utils import cleanup_logger_handlers
10+ from pythonLogs .log_utils import cleanup_logger_handlers
11+ from pythonLogs .settings import get_log_settings
1212from pythonLogs .size_rotating import SizeRotatingLog
1313from pythonLogs .timed_rotating import TimedRotatingLog
1414
1515
1616@dataclass
1717class LoggerConfig :
1818 """Configuration class to group logger parameters"""
19+
1920 level : Optional [Union [LogLevel , str ]] = None
2021 name : Optional [str ] = None
2122 directory : Optional [str ] = None
@@ -34,6 +35,7 @@ class LoggerConfig:
3435
3536class LoggerType (str , Enum ):
3637 """Available logger types"""
38+
3739 BASIC = "basic"
3840 SIZE_ROTATING = "size_rotating"
3941 TIMED_ROTATING = "timed_rotating"
@@ -56,12 +58,11 @@ class LoggerFactory:
5658 def _ensure_initialized (cls ) -> None :
5759 """Ensure memory limits are initialized from settings on first use."""
5860 if not cls ._initialized :
59- from pythonLogs .settings import get_log_settings
6061 settings = get_log_settings ()
6162 cls ._max_loggers = settings .max_loggers
6263 cls ._logger_ttl = settings .logger_ttl_seconds
6364 cls ._initialized = True
64-
65+
6566 # Register atexit cleanup on first use
6667 if not cls ._atexit_registered :
6768 atexit .register (cls ._atexit_cleanup )
@@ -71,30 +72,30 @@ def _ensure_initialized(cls) -> None:
7172 def get_or_create_logger (
7273 cls ,
7374 logger_type : Union [LoggerType , str ],
74- name : Optional [str ] = None , ** kwargs ,
75+ name : Optional [str ] = None ,
76+ ** kwargs ,
7577 ) -> logging .Logger :
7678 """
77- Get an existing logger from registry or create new one.
79+ Get an existing logger from registry or create a new one.
7880 Loggers are cached by name for performance.
79-
81+
8082 Args:
8183 logger_type: Type of logger to create
8284 name: Logger name (used as cache key)
8385 **kwargs: Additional logger configuration
84-
86+
8587 Returns:
8688 Cached or newly created logger instance
8789 """
8890 # Use the default name if none provided
8991 if name is None :
90- from pythonLogs .settings import get_log_settings
9192 name = get_log_settings ().appname
9293
9394 # Thread-safe check-and-create operation
9495 with cls ._registry_lock :
9596 # Initialize memory limits from settings on first use
9697 cls ._ensure_initialized ()
97-
98+
9899 # Clean up expired loggers first
99100 cls ._cleanup_expired_loggers ()
100101
@@ -156,7 +157,7 @@ def _enforce_size_limit(cls) -> None:
156157 @classmethod
157158 def set_memory_limits (cls , max_loggers : int = 100 , ttl_seconds : int = 3600 ) -> None :
158159 """Configure memory management limits for the logger registry at runtime.
159-
160+
160161 Args:
161162 max_loggers: Maximum number of cached loggers
162163 ttl_seconds: Time-to-live for cached loggers in seconds
@@ -177,7 +178,7 @@ def _atexit_cleanup(cls) -> None:
177178 except Exception :
178179 # Silently ignore exceptions during shutdown cleanup
179180 pass
180-
181+
181182 @staticmethod
182183 def _cleanup_logger (logger : logging .Logger ) -> None :
183184 """Clean up logger resources by closing all handlers."""
@@ -186,10 +187,10 @@ def _cleanup_logger(logger: logging.Logger) -> None:
186187 @classmethod
187188 def shutdown_logger (cls , name : str ) -> bool :
188189 """Shutdown and remove a specific logger from registry.
189-
190+
190191 Args:
191192 name: Logger name to shut down
192-
193+
193194 Returns:
194195 True if logger was found and shutdown, False otherwise
195196 """
@@ -206,24 +207,34 @@ def get_registered_loggers(cls) -> dict[str, logging.Logger]:
206207 with cls ._registry_lock :
207208 return {name : logger for name , (logger , _ ) in cls ._logger_registry .items ()}
208209
210+ @classmethod
211+ def get_memory_limits (cls ) -> dict [str , int ]:
212+ """Get current memory management limits.
213+
214+ Returns:
215+ Dictionary with current max_loggers and ttl_seconds settings
216+ """
217+ with cls ._registry_lock :
218+ return {
219+ 'max_loggers' : cls ._max_loggers ,
220+ 'ttl_seconds' : cls ._logger_ttl
221+ }
222+
209223 @staticmethod
210224 def create_logger (
211- logger_type : Union [LoggerType , str ],
212- config : Optional [LoggerConfig ] = None ,
213- ** kwargs
225+ logger_type : Union [LoggerType , str ], config : Optional [LoggerConfig ] = None , ** kwargs
214226 ) -> logging .Logger :
215-
216227 """
217228 Factory method to create loggers based on type.
218-
229+
219230 Args:
220231 logger_type: Type of logger to create (LoggerType enum or string)
221232 config: LoggerConfig object with logger parameters
222233 **kwargs: Individual logger parameters (for backward compatibility)
223-
234+
224235 Returns:
225236 Configured logger instance
226-
237+
227238 Raises:
228239 ValueError: If invalid logger_type is provided
229240 """
@@ -237,7 +248,7 @@ def create_logger(
237248 # Merge config and kwargs (kwargs take precedence for backward compatibility)
238249 if config is None :
239250 config = LoggerConfig ()
240-
251+
241252 # Create a new config with kwargs overriding config values
242253 final_config = LoggerConfig (
243254 level = kwargs .get ('level' , config .level ),
@@ -253,7 +264,7 @@ def create_logger(
253264 when = kwargs .get ('when' , config .when ),
254265 sufix = kwargs .get ('sufix' , config .sufix ),
255266 rotateatutc = kwargs .get ('rotateatutc' , config .rotateatutc ),
256- daystokeep = kwargs .get ('daystokeep' , config .daystokeep )
267+ daystokeep = kwargs .get ('daystokeep' , config .daystokeep ),
257268 )
258269
259270 # Convert enum values to strings for logger classes
@@ -269,7 +280,8 @@ def create_logger(
269280 encoding = final_config .encoding ,
270281 datefmt = final_config .datefmt ,
271282 timezone = final_config .timezone ,
272- showlocation = final_config .showlocation , )
283+ showlocation = final_config .showlocation ,
284+ )
273285
274286 case LoggerType .SIZE_ROTATING :
275287 logger_instance = SizeRotatingLog (
@@ -283,7 +295,8 @@ def create_logger(
283295 datefmt = final_config .datefmt ,
284296 timezone = final_config .timezone ,
285297 streamhandler = final_config .streamhandler ,
286- showlocation = final_config .showlocation , )
298+ showlocation = final_config .showlocation ,
299+ )
287300
288301 case LoggerType .TIMED_ROTATING :
289302 logger_instance = TimedRotatingLog (
@@ -299,7 +312,8 @@ def create_logger(
299312 timezone = final_config .timezone ,
300313 streamhandler = final_config .streamhandler ,
301314 showlocation = final_config .showlocation ,
302- rotateatutc = final_config .rotateatutc , )
315+ rotateatutc = final_config .rotateatutc ,
316+ )
303317
304318 case _:
305319 raise ValueError (f"Unsupported logger type: { logger_type } " )
@@ -315,7 +329,6 @@ def create_basic_logger(
315329 timezone : Optional [str ] = None ,
316330 showlocation : Optional [bool ] = None ,
317331 ) -> logging .Logger :
318-
319332 """Convenience method for creating a basic logger"""
320333 return LoggerFactory .create_logger (
321334 LoggerType .BASIC ,
@@ -324,7 +337,8 @@ def create_basic_logger(
324337 encoding = encoding ,
325338 datefmt = datefmt ,
326339 timezone = timezone ,
327- showlocation = showlocation , )
340+ showlocation = showlocation ,
341+ )
328342
329343 @staticmethod
330344 def create_size_rotating_logger (
@@ -340,7 +354,6 @@ def create_size_rotating_logger(
340354 streamhandler : Optional [bool ] = None ,
341355 showlocation : Optional [bool ] = None ,
342356 ) -> logging .Logger :
343-
344357 """Convenience method for creating a size rotating logger"""
345358 return LoggerFactory .create_logger (
346359 LoggerType .SIZE_ROTATING ,
@@ -354,7 +367,8 @@ def create_size_rotating_logger(
354367 datefmt = datefmt ,
355368 timezone = timezone ,
356369 streamhandler = streamhandler ,
357- showlocation = showlocation , )
370+ showlocation = showlocation ,
371+ )
358372
359373 @staticmethod
360374 def create_timed_rotating_logger (
@@ -365,14 +379,13 @@ def create_timed_rotating_logger(
365379 when : Optional [Union [RotateWhen , str ]] = None ,
366380 sufix : Optional [str ] = None ,
367381 daystokeep : Optional [int ] = None ,
368- encoding :Optional [str ] = None ,
382+ encoding : Optional [str ] = None ,
369383 datefmt : Optional [str ] = None ,
370384 timezone : Optional [str ] = None ,
371385 streamhandler : Optional [bool ] = None ,
372386 showlocation : Optional [bool ] = None ,
373387 rotateatutc : Optional [bool ] = None ,
374388 ) -> logging .Logger :
375-
376389 """Convenience method for creating a timed rotating logger"""
377390 return LoggerFactory .create_logger (
378391 LoggerType .TIMED_ROTATING ,
@@ -388,7 +401,8 @@ def create_timed_rotating_logger(
388401 timezone = timezone ,
389402 streamhandler = streamhandler ,
390403 showlocation = showlocation ,
391- rotateatutc = rotateatutc , )
404+ rotateatutc = rotateatutc ,
405+ )
392406
393407
394408# Convenience functions for backward compatibility and easier usage
0 commit comments