ami*_*pra 14 python logging handler
观察:当我注释掉时,from logging import handlers会观察到以下错误。
Error:
file_handler = logging.handlers.RotatingFileHandler(
AttributeError: module 'logging' has no attribute 'handlers'
Run Code Online (Sandbox Code Playgroud)
问题:如果我已经导入,logging为什么需要这样做from logging import handlers?
import logging
import sys
#from logging import handlers
def LoggerDefination():
#file_handler = logging.FileHandler(filename='..\\logs\\BasicLogger_v0.1.log', mode='a')
file_handler = logging.handlers.RotatingFileHandler(
filename="..\\logs\\BasicLogger_v0.2.log",
mode='a',
maxBytes=20000,
backupCount=7,
encoding=None,
delay=0
)
file_handler.setLevel(logging.DEBUG)
stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setLevel(logging.DEBUG)
handlers = [file_handler, stdout_handler]
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s | %(module)s | %(name)s | LineNo_%(lineno)d | %(levelname)s | %(message)s',
handlers=handlers
)
def fnt_test_log1():
LoggerDefination()
WriteLog1 = logging.getLogger('fnt_test_log1')
#WriteLog1.propagate=False
WriteLog1.info("######## START OF : test_log1 ##########")
WriteLog1.debug("test_log1 | This is debug level")
WriteLog1.debug("test_log1 | This is debug level")
WriteLog1.info("test_log1 | This is info level")
WriteLog1.warning("test_log1 | This is warning level")
WriteLog1.error("test_log1 | This is error level")
WriteLog1.critical("test_log1 |This is critiacl level")
WriteLog1.info("######## END OF : test_log1 ##########")
def fnt_test_log2():
LoggerDefination()
WriteLog2 = logging.getLogger('fnt_test_log2')
WriteLog2.info("######## START OF : test_log2 ##########")
WriteLog2.debug("test_log2 ===> debug")
WriteLog2.debug("test_log2 | This is debug level")
WriteLog2.debug("test_log2 | This is debug level")
WriteLog2.info("test_log2 | This is info level")
WriteLog2.warning("test_log2 | This is warning level")
WriteLog2.error("test_log2 | This is error level")
WriteLog2.critical("test_log2 |This is critiacl level")
WriteLog2.info("######## STOP OF : test_log2 ##########")
if __name__ == '__main__':
LoggerDefination()
MainLog = logging.getLogger('main')
LoggerDefination()
MainLog.info("Executing script: " + __file__)
fnt_test_log1()
fnt_test_log2()
Run Code Online (Sandbox Code Playgroud)
bal*_*alu 20
这是一个由两部分组成的答案:第一部分涉及您眼前的问题。第二部分涉及为什么你的问题可能首先出现的问题(以及,考虑到你的问题已经两个月了,我是如何结束这个帖子的)。
\n第一部分(问题的答案):当导入像 这样的包时import logging,Python 默认情况下从不导入类似的子包(或子模块),logging.handlers而只向您公开包文件中定义的变量__init__.py(在本例中为logging/__init__.py)。不幸的是,很难从外部判断 是logging.handlersin 中的变量logging/__init__.py还是实际的单独 module logging/handlers.py。所以你必须看一下logging/__init__.py,然后你会发现它没有定义handlers变量,而是有一个logging/handlers.py需要通过import logging.handlers或单独导入的模块from logging.handlers import TheHandlerYouWantToUse。所以这应该回答你的问题。
第二部分:我最近注意到我的 IDE (PyCharm) 总是import logging在我真正想要使用logging.handlers.QueueHandler. 由于一些神秘的原因(尽管我在第一部分中说过)它一直在起作用!\xe2\x80\xa6 好吧,大多数时候。
具体来说,在以下代码中,类型注释会导致预期的AttributeError: module 'logging' has no attribute 'handlers'. 然而,在注释掉注释之后(对于 Python < 3.9 在模块执行期间执行),调用该函数可以工作 \xe2\x80\x93 ,前提是我将其称为“足够晚”(更多内容见下文)。
import logging\nfrom multiprocessing.queues import Queue\n\n\ndef redirect_logs_to_queue(\n logging_queue: Queue, level: int = logging.DEBUG\n) -> logging.handlers.QueueHandler: # <-------------------------------- This fails\n\n queue_handler = logging.handlers.QueueHandler(logging_queue) # <--- This works\n root = logging.getLogger()\n root.addHandler(queue_handler)\n root.setLevel(level)\n return queue_handler\nRun Code Online (Sandbox Code Playgroud)\n那么“够晚了”是什么意思呢?不幸的是,我的应用程序有点太复杂,无法进行一些快速的错误查找。尽管如此,我很清楚,logging.handlers必须在启动(即加载/执行我的所有模块)和调用该函数之间的某个时刻“变得可用”。这给了我决定性的提示:事实证明,包层次结构深处的另一个模块正在做from logging.handlers import RotatingFileHandler, QueueListener。该语句加载了整个logging.handlers模块并导致Python将handlers模块“挂载”在其父包中logging,这意味着该logging变量从此以后总是配备一个handlers属性,即使在仅仅之后import logging,这就是为什么我不需要import logging.handlers(并且可能是 PyCharm 注意到的)。
自己尝试一下:
\n这有效:
\nimport logging\nfrom logging.handlers import QueueHandler\nprint(logging.handlers)\nRun Code Online (Sandbox Code Playgroud)\n这不会:
\nimport logging\nprint(logging.handlers)\nRun Code Online (Sandbox Code Playgroud)\n总而言之,这种现象是Python的导入机制使用全局状态来避免重新加载模块的结果。(在这里,我指的“全局状态”是logging您在 时获得的变量import logging。)虽然有时它很危险(如上面的情况),但它确实很有意义:如果您import logging.handlers在多个模块中,则不需要不希望模块中的代码logging.handlers多次加载(并因此执行!)。因此,一旦您导入某处,Python 就会将该handlers属性添加到模块对象中,并且由于共享同一对象的所有模块将突然在任何地方可用。logginglogging.handlersimport logginglogginglogging.handlers
| 归档时间: |
|
| 查看次数: |
43985 次 |
| 最近记录: |