问题描述
这不是关于logging
替代方案的建议的问题。
但是,我想尝试一些替代记录器,例如Twiggy或Loguru。或者是其他东西。问题在于,尽管logging
的配置是集中式的,但记录器的获取遍及整个代码库。
获取代码
import logging #? I'd like to import an alternative here.
logger = logging.getLogger(__name__)
以及有多少实例
ack -l --python logging.getLogger | wc -l
193
有什么好的方法可以绕过stdlib在后台进行日志记录,而在调用logging.getLogger
时返回Loguru或Twiggy记录器呢?
我可以想到几个:
-
在Python路径条目中早于stdlib版本放入自定义
logging.py
-
使用导入模拟装饰器返回与stdlib不同的模块
通过早期导入 -
monkeypatching
logging
并将logging.getLogger
设置为自定义工厂函数,将返回Loguru或其他替代方法。
是否有人尝试换出logging
而没有修改每个logging.getLogging
的电话吗?你是怎么做到的?
此外,这是在Django Web应用程序的上下文中。但是,我宁愿不要与settings.LOGGING
混在一起。
作为参考,这是对Loguru记录器的收购,我绝对要避免在发现Loguru不适合我的需要之前分发超过200个文件的代码类型。
from loguru import logger #❌ I don't want to have to this 200 times!!!
logger.debug("That's it,beautiful and simple logging!")
一天结束时,理想的情况是我找到一段时间进行登录的好方法,如果我得到了它的配置,也许以后再恢复到stdlib logging
固定。但这不需要触摸所有这些文件。我可以先尝试Loguru,然后尝试Twiggy,然后再尝试其他操作。
基本上,如何将日志记录功能的实际提供者与所有应用程序文件分离?
还要清楚一点,我使用的任何日志记录提供程序都必须支持或可以调整以支持logger API,例如logger.info(),logger.debug()
等。因此,这个问题是不是关注以下应用程序代码:
logger.info("this is your info")
解决方法
由于您打算更改记录器,因此首先集中代码是有道理的,以便以后可以轻松对其进行更改。
因此,您可以创建一个新的日志记录模块,该模块的行为类似于内置的logging
,并将所有导入替换为
import my.logging.module
然后在需要实施其他记录器时修改my.logging.module
。
在那里,在my.logging.module
中,您可以选择使用一些特殊的逻辑来实现自己的功能(在不同的记录器之间进行切换等),也可以对默认行为进行修改from logging import *
我用usercustomize.py
代替了记录仪。那行得通,但没用的是芹菜和Django都因为看不到完整的stdlib logging
API而非常害怕。
但是只要不涉及芹菜和Django,修补日志记录就可以很好地工作。
usercustomize.py:
位置 /Users/myuser/Library/Python/3.8/lib/python/site-packages/usercustomize.py 。 Python对于该位置非常讲究,就像您在其中看到的一样
$ python -m site
USER_SITE: '/Users/myuser/Library/Python/3.8/lib/python/site-packages'
您只需在该位置将符号链接拖放到usercustomize.py
。但是,这也意味着所有 Python代码都会受到日志记录的影响(尽管您可以使用环境变量来调用原始的logging.getLogger)。
这基本上满足了我的要求(实际代码稍微复杂一些,但这只是因为loguru不喜欢过早初始化),所以我不得不使用一个属性。
import logging
from loguru import logger
stdlib_getLogger = logging.getLogger
# configuration goes into an endless loop if done "too early"
# and `asyincio needs to be imported first for some reason
# I ended up using a class and @property
# but that has more to do with loguru than the core idea of replacement
# logger.configure(
# handlers=[
# dict(sink=sys.stderr,format="[{time}] {message}"),# dict(sink="mylog.log",enqueue=True,serialize=True),# ])
def custom_getLogger(name,*args,**kwargs):
#loguru's
return logger
#if you want to revert to stdlib conditionally
return stdlib_getLogger(name,**kwargs)
logging.getLogger = custom_getLogger