自定义python日志记录处理程序不断循环

时间:2020-03-23 14:16:23

标签: python python-3.x logging

我遇到了某种循环问题,试图使用自定义处理程序在我的项目中实现日志记录,因此我正在寻求帮助。我确实有一定的编程经验,但是我对python还是很陌生,所以也许我完全错了。

如下所示,我收到一个“ RecursionError”。我还在这篇文章的结尾处附加了错误的截断副本以及代码。

提前谢谢!

Error:

Traceback (most recent call last):
  File "app.py", line 18, in <module>
    logger.debug('debug message!')
  File "/usr/lib/python3.8/logging/__init__.py", line 1422, in debug
    self._log(DEBUG, msg, args, **kwargs)
  File "/usr/lib/python3.8/logging/__init__.py", line 1577, in _log
    self.handle(record)
  File "/usr/lib/python3.8/logging/__init__.py", line 1587, in handle
    self.callHandlers(record)
  File "/usr/lib/python3.8/logging/__init__.py", line 1649, in callHandlers
    hdlr.handle(record)
  File "/usr/lib/python3.8/logging/__init__.py", line 950, in handle
    self.emit(record)
  File "/app/python/logger_handlers.py", line 27, in emit
    requests.post(self.url, headers = header, data = json.dumps(payload))
[...truncated...]
RecursionError: maximum recursion depth exceeded in comparison
# app.py
import logging
import my_module
from logger_handlers import CustomHandler

logging.getLogger("requests").disabled = True

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# Custom handler
custom_handler = CustomHandler(url = 'http://some_url.com/api/1/log')
custom_handler.setLevel(logging.DEBUG)
custom_handler.setFormatter(formatter)
logger.addHandler(custom_handler)

# Log to root handler
logger.debug('debug message!')

# Run a function in a different module that also has a logger defined 
my_module.run()
# my_module.py
import logging

log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler())

def run():
    log.debug('A message from A Module')
# logger_handlers.py
import logging
import requests
import json

from socket import gethostname, gethostbyname

class CustomHandler(logging.Handler):

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.url = kwargs['url']

    def emit(self, record):
        message = self.format(record)
        header = {"content-type": "application/json"}
        payload = {
            "token":None,
            "client_version":"",
            "parameters": {
                "source": "Host: {} ({}), Module: {}, {}".format(gethostname(), gethostbyname(gethostname()), record.filename, record.funcName),
                "severity": record.levelname,
                "message": message
            }
        }
        requests.post(self.url, headers = header, data = json.dumps(payload))

更新(2020-04-03):

通过使用此代码段,我能够识别出为避免循环而必须禁用的所有记录器:

for key in logging.Logger.manager.loggerDict:
    print(key)

然后我用它来禁用它们:

logging.getLogger("urllib3.util.retry").disabled = True
logging.getLogger("urllib3.util").disabled = True
logging.getLogger("urllib3").disabled = True
logging.getLogger("urllib3.connection").disabled = True
logging.getLogger("urllib3.response").disabled = True
logging.getLogger("urllib3.connectionpool").disabled = True
logging.getLogger("urllib3.poolmanager").disabled = True
logging.getLogger("requests").disabled = True

不是很漂亮,但是可以。如果您认为此方法存在主要缺点,请随时发表评论。

2 个答案:

答案 0 :(得分:0)

在您的app.py脚本中,只需将 name 作为name参数传递给getLogger()。所以,

logger = logging.getLogger(__name__)

答案 1 :(得分:0)

使用请求模块执行请求时,将创建日志。有些来自requests记录器,也有些来自其他使用的库。例如,urllib模块还具有一个创建日志的记录器。这些日志在日志层次结构中传播并最终到达根记录器。根记录器也有您的处理程序,因此将再次执行q请求,从而创建更多日志,并最终存储在根记录器中。

仅将处理程序添加到请求日志不传播到的记录器中。