3030
3131# LogWrap Implementation
3232from logwrap import class_decorator
33+ from logwrap import constants
3334from logwrap import repr_utils
3435
3536LOGGER : logging .Logger = logging .getLogger ("logwrap" )
@@ -154,7 +155,7 @@ def __init__(
154155 self ,
155156 func : typing .Optional [typing .Callable [..., FuncResultType ]] = None ,
156157 * ,
157- log : logging .Logger = LOGGER ,
158+ log : typing . Optional [ logging .Logger ] = None ,
158159 log_level : int = logging .DEBUG ,
159160 exc_level : int = logging .ERROR ,
160161 max_indent : int = 20 ,
@@ -170,8 +171,8 @@ def __init__(
170171
171172 :param func: function to wrap
172173 :type func: typing.Optional[typing.Callable]
173- :param log: logger object for decorator, by default used 'logwrap'
174- :type log: logging.Logger
174+ :param log: logger object for decorator, by default trying to use logger from target module. Fallback: 'logwrap'
175+ :type log: typing.Optional[ logging.Logger]
175176 :param log_level: log level for successful calls
176177 :type log_level: int
177178 :param exc_level: log level for exception cases
@@ -202,6 +203,7 @@ def __init__(
202203
203204 .. versionchanged:: 3.3.0 Extract func from log and do not use Union.
204205 .. versionchanged:: 5.1.0 log_traceback parameter
206+ .. versionchanged:: 8.0.0 pick up logger from target module if possible
205207 """
206208 super ().__init__ (func = func )
207209
@@ -215,7 +217,13 @@ def __init__(
215217 else :
216218 self .__blacklisted_exceptions = list (blacklisted_exceptions )
217219
218- self .__logger : logging .Logger = log
220+ if isinstance (log , logging .Logger ):
221+ self .__logger : typing .Optional [logging .Logger ] = log
222+ else :
223+ self .__logger = None
224+
225+ if func is not None : # Special case: we can prefetch logger
226+ self .__logger = self ._get_logger_for_func (func )
219227
220228 self .__log_level : int = log_level
221229 self .__exc_level : int = exc_level
@@ -228,6 +236,18 @@ def __init__(
228236
229237 # We are not interested to pass any arguments to object
230238
239+ def _get_logger_for_func (self , func : FuncResultType ) -> logging .Logger :
240+ """Get logger for function from function module if possible."""
241+ if self .__logger is not None :
242+ return self .__logger
243+
244+ func_module = inspect .getmodule (func )
245+ for logger_name in constants .VALID_LOGGER_NAMES :
246+ logger_candidate = getattr (func_module , logger_name , None )
247+ if isinstance (logger_candidate , logging .Logger ):
248+ return logger_candidate
249+ return LOGGER
250+
231251 @property
232252 def log_level (self ) -> int :
233253 """Log level for normal behavior.
@@ -385,10 +405,10 @@ def log_result_obj(self, val: bool) -> None:
385405 self .__log_result_obj = val
386406
387407 @property
388- def _logger (self ) -> logging .Logger :
408+ def _logger (self ) -> typing . Optional [ logging .Logger ] :
389409 """Logger instance.
390410
391- :rtype: logging.Logger
411+ :rtype: typing.Optional[ logging.Logger]
392412 """
393413 return self .__logger
394414
@@ -515,30 +535,33 @@ def _get_func_args_repr(
515535 param_str += "\n "
516536 return param_str
517537
518- def _make_done_record (self , func_name : str , result : typing .Any ) -> None :
538+ def _make_done_record (self , logger : logging . Logger , func_name : str , result : typing .Any ) -> None :
519539 """Construct success record.
520540
541+ :type logger: logging.Logger
521542 :type func_name: str
522543 :type result: typing.Any
523544 """
524545 msg : str = f"Done: { func_name !r} "
525546
526547 if self .log_result_obj :
527548 msg += f" with result:\n { repr_utils .pretty_repr (result , max_indent = self .max_indent )} "
528- self . _logger .log (level = self .log_level , msg = msg )
549+ logger .log (level = self .log_level , msg = msg )
529550
530- def _make_calling_record (self , name : str , arguments : str , method : str = "Calling" ) -> None :
551+ def _make_calling_record (self , logger : logging . Logger , name : str , arguments : str , method : str = "Calling" ) -> None :
531552 """Make log record before execution.
532553
554+ :type logger: logging.Logger
533555 :type name: str
534556 :type arguments: str
535557 :type method: str
536558 """
537- self . _logger .log (level = self .log_level , msg = f"{ method } : \n { name } ({ arguments if self .log_call_args else '' } )" )
559+ logger .log (level = self .log_level , msg = f"{ method } : \n { name } ({ arguments if self .log_call_args else '' } )" )
538560
539- def _make_exc_record (self , name : str , arguments : str , exception : Exception ) -> None :
561+ def _make_exc_record (self , logger : logging . Logger , name : str , arguments : str , exception : Exception ) -> None :
540562 """Make log record if exception raised.
541563
564+ :type logger: logging.Logger
542565 :type name: str
543566 :type arguments: str
544567 :type exception: Exception
@@ -554,7 +577,7 @@ def _make_exc_record(self, name: str, arguments: str, exception: Exception) -> N
554577 else exception .__class__ .__name__
555578 )
556579
557- self . _logger .log (
580+ logger .log (
558581 level = self .exc_level ,
559582 msg = f"Failed: \n { name } ({ arguments if self .log_call_args_on_exc else '' } )\n { tb_text } " ,
560583 exc_info = False ,
@@ -569,18 +592,20 @@ def _get_function_wrapper(self, func: typing.Callable[..., FuncResultType]) -> t
569592 :rtype: typing.Callable
570593 """
571594
595+ logger : logging .Logger = self ._get_logger_for_func (func )
596+
572597 # noinspection PyCompatibility,PyMissingOrEmptyDocstring
573598 @functools .wraps (func )
574599 async def async_wrapper (* args : typing .Any , ** kwargs : typing .Any ) -> typing .Any :
575600 sig : inspect .Signature = inspect .signature (self ._spec or func )
576601 args_repr : str = self ._get_func_args_repr (sig = sig , args = args , kwargs = kwargs )
577602
578603 try :
579- self ._make_calling_record (name = func .__name__ , arguments = args_repr , method = "Awaiting" )
604+ self ._make_calling_record (logger = logger , name = func .__name__ , arguments = args_repr , method = "Awaiting" )
580605 result = await func (* args , ** kwargs )
581- self ._make_done_record (func .__name__ , result )
606+ self ._make_done_record (logger = logger , func_name = func .__name__ , result = result )
582607 except Exception as e :
583- self ._make_exc_record (name = func .__name__ , arguments = args_repr , exception = e )
608+ self ._make_exc_record (logger = logger , name = func .__name__ , arguments = args_repr , exception = e )
584609 raise
585610 return result # type: ignore
586611
@@ -591,11 +616,11 @@ def wrapper(*args: typing.Any, **kwargs: typing.Any) -> typing.Any:
591616 args_repr : str = self ._get_func_args_repr (sig = sig , args = args , kwargs = kwargs )
592617
593618 try :
594- self ._make_calling_record (name = func .__name__ , arguments = args_repr )
619+ self ._make_calling_record (logger = logger , name = func .__name__ , arguments = args_repr )
595620 result = func (* args , ** kwargs )
596- self ._make_done_record (func .__name__ , result )
621+ self ._make_done_record (logger = logger , func_name = func .__name__ , result = result )
597622 except Exception as e :
598- self ._make_exc_record (name = func .__name__ , arguments = args_repr , exception = e )
623+ self ._make_exc_record (logger = logger , name = func .__name__ , arguments = args_repr , exception = e )
599624 raise
600625 return result
601626
@@ -622,7 +647,7 @@ def __call__( # pylint: disable=useless-super-delegation
622647def logwrap (
623648 func : None = None ,
624649 * ,
625- log : logging .Logger = LOGGER ,
650+ log : typing . Optional [ logging .Logger ] = None ,
626651 log_level : int = logging .DEBUG ,
627652 exc_level : int = logging .ERROR ,
628653 max_indent : int = 20 ,
@@ -641,7 +666,7 @@ def logwrap(
641666def logwrap (
642667 func : typing .Callable [..., typing .Awaitable [FuncFinalResult ]],
643668 * ,
644- log : logging .Logger = LOGGER ,
669+ log : typing . Optional [ logging .Logger ] = None ,
645670 log_level : int = logging .DEBUG ,
646671 exc_level : int = logging .ERROR ,
647672 max_indent : int = 20 ,
@@ -660,7 +685,7 @@ def logwrap(
660685def logwrap (
661686 func : typing .Callable [..., FuncFinalResult ],
662687 * ,
663- log : logging .Logger = LOGGER ,
688+ log : typing . Optional [ logging .Logger ] = None ,
664689 log_level : int = logging .DEBUG ,
665690 exc_level : int = logging .ERROR ,
666691 max_indent : int = 20 ,
@@ -678,7 +703,7 @@ def logwrap(
678703def logwrap ( # noqa: F811
679704 func : typing .Optional [typing .Callable [..., FuncResultType ]] = None ,
680705 * ,
681- log : logging .Logger = LOGGER ,
706+ log : typing . Optional [ logging .Logger ] = None ,
682707 log_level : int = logging .DEBUG ,
683708 exc_level : int = logging .ERROR ,
684709 max_indent : int = 20 ,
@@ -694,8 +719,8 @@ def logwrap( # noqa: F811
694719
695720 :param func: function to wrap
696721 :type func: typing.Optional[typing.Callable]
697- :param log: logger object for decorator, by default used 'logwrap'
698- :type log: logging.Logger
722+ :param log: logger object for decorator, by default trying to use logger from target module. Fallback: 'logwrap'
723+ :type log: typing.Optional[ logging.Logger]
699724 :param log_level: log level for successful calls
700725 :type log_level: int
701726 :param exc_level: log level for exception cases
@@ -723,12 +748,13 @@ def logwrap( # noqa: F811
723748 :param log_result_obj: log result of function call.
724749 :type log_result_obj: bool
725750 :return: built real decorator.
726- :rtype: _log_wrap_shared.BaseLogWrap
751+ :rtype: typing.Union[LogWrap, typing.Callable[..., FuncResultType]]
727752
728753 .. versionchanged:: 3.3.0 Extract func from log and do not use Union.
729754 .. versionchanged:: 3.3.0 Deprecation of *args
730755 .. versionchanged:: 4.0.0 Drop of *args
731756 .. versionchanged:: 5.1.0 log_traceback parameter
757+ .. versionchanged:: 8.0.0 pick up logger from target module if possible
732758 """
733759 wrapper = LogWrap (
734760 log = log ,
0 commit comments