I'm running into some sort of looping issue attempting to implement logging in my project using a custom handler so I'm seeking for help. I do have some programming experience but I'm pretty new to python so maybe I get this all wrong.
As shown below, I get a "RecursionError". I've also attached a truncated copy of the error as well as the code at the end of this post.
Thanks in advance !
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))
UPDATE (2020-04-03):
By using this snippet I was able to identify all the loggers I had to disable to avoid the loop:
for key in logging.Logger.manager.loggerDict:
print(key)
I then use this to disable them:
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
Not super pretty but it works. Please feel free to comment if you think there's a major drawback to this method.