feat: enhanced logging to file support, redirecting all stdout and stderr to log file.

This feature woulb be useful for troubleshooting daemonized bots since now all exceptions are also wrote to log file.
This commit is contained in:
Terry Geng 2020-05-09 10:44:01 +08:00
parent aba9eea336
commit a58af46f15
2 changed files with 19 additions and 0 deletions

View File

@ -700,6 +700,7 @@ if __name__ == '__main__':
var.db = SettingsDatabase(var.dbfile) var.db = SettingsDatabase(var.dbfile)
# Setup logger # Setup logger
bot_logger = logging.getLogger("bot") bot_logger = logging.getLogger("bot")
formatter = logging.Formatter('[%(asctime)s %(levelname)s %(threadName)s] %(message)s', "%b %d %H:%M:%S") formatter = logging.Formatter('[%(asctime)s %(levelname)s %(threadName)s] %(message)s', "%b %d %H:%M:%S")
bot_logger.setLevel(logging.INFO) bot_logger.setLevel(logging.INFO)
@ -714,7 +715,10 @@ if __name__ == '__main__':
logfile = util.solve_filepath(var.config.get('bot', 'logfile')) logfile = util.solve_filepath(var.config.get('bot', 'logfile'))
handler = None handler = None
if logfile: if logfile:
print(f"Redirecting stdout and stderr to log file: {logfile}")
handler = logging.handlers.RotatingFileHandler(logfile, mode='a', maxBytes=10240) # Rotate after 10KB handler = logging.handlers.RotatingFileHandler(logfile, mode='a', maxBytes=10240) # Rotate after 10KB
sys.stdout = util.LoggerIOWrapper(bot_logger, logging.INFO, fallback_io_buffer=sys.stdout.buffer)
sys.stderr = util.LoggerIOWrapper(bot_logger, logging.ERROR, fallback_io_buffer=sys.stderr.buffer)
else: else:
handler = logging.StreamHandler() handler = logging.StreamHandler()
@ -755,3 +759,4 @@ if __name__ == '__main__':
# Start the main loop. # Start the main loop.
var.bot.loop() var.bot.loop()

14
util.py
View File

@ -4,6 +4,7 @@
import hashlib import hashlib
import magic import magic
import os import os
import io
import sys import sys
import variables as var import variables as var
import zipfile import zipfile
@ -335,3 +336,16 @@ def youtube_search(query):
error_traceback = traceback.format_exc().split("During")[0] error_traceback = traceback.format_exc().split("During")[0]
log.error("util: youtube query failed with error:\n %s" % error_traceback) log.error("util: youtube query failed with error:\n %s" % error_traceback)
return False return False
class LoggerIOWrapper(io.TextIOWrapper):
def __init__(self, logger: logging.Logger, logging_level, fallback_io_buffer):
super().__init__(fallback_io_buffer, write_through=True)
self.logger = logger
self.logging_level = logging_level
def write(self, text):
if isinstance(text, bytes):
self.logger.log(self.logging_level, text.decode('utf-8').rstrip())
else:
self.logger.log(self.logging_level, text.rstrip())