Solve the problem of repeated printing of pit log encountered by python logging
- 2021-10-11 18:59:14
- OfStack
If logging module in python encounters multi-thread or multi-process or customizes logging in web framework (one request is one independent thread), it is very easy to print logs repeatedly and cause memory crash, so:
The solution is as follows:
Class for overriding log methods:
class Log():
import logging
def __init__(self):
self.logger = logging.getLogger(__name__)
# The following 3 Behavior empties the last file
# Object that empties the current file logging Because logging Will contain all the files logging
logging.Logger.manager.loggerDict.pop(__name__)
# Object of the current file handlers Empty
self.logger.handlers = []
# Then remove the current file again logging Configure
self.logger.removeHandler(self.logger.handlers)
# To judge here, if logger.handlers If the list is empty, add it; Otherwise, write the log directly
if not self.logger.handlers:
# loggger File configuration path
self.handler = logging.FileHandler(os.getcwd() + '/logger/%s_log/%s_score.log' % (str(dt.date.today()), str(dt.date.today())))
# logger Configuration level
self.logger.setLevel(logging.DEBUG)
# logger Output format
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s')
# Add output format to enter handler
self.handler.setFormatter(formatter)
# Add file settings such as handler
self.logger.addHandler(self.handler)
# The following are override methods And clear after each record logger
def info(self,message=None):
self.__init__()
self.logger.info(message)
self.logger.removeHandler(self.logger.handlers)
def debug(self,message=None):
self.__init__()
self.logger.debug(message)
self.logger.removeHandler(self.logger.handlers)
def warning(self,message=None):
self.__init__()
self.logger.warning(message)
self.logger.removeHandler(self.logger.handlers)
def error(self,message=None):
self.__init__()
self.logger.error(message)
self.logger.removeHandler(self.logger.handlers)
def critical(self, message=None):
self.__init__()
self.logger.critical(message)
self.logger.removeHandler(self.logger.handlers)
Pro-test is effective!
In addition, the module pays special attention to the fact that, for example, when web requests, it is called at the interface and then the boot pass parameter must not be a global variable
Supplement: python, multiple files share logger, and the solution to the problem of repeated printing
Problem background & Phenomenon
In a recent project, you need to use the logging library of python to print the log to a file, and then put the python script into crontab for execution. So I wrote a simple package of logger.
As follows:
#!/usr/bin/python
# -*- coding:utf-8 -*-
import logging
import time
import os
class Log(object):
'''
Encapsulated logging
'''
def __init__(self, logger=None, log_cate='search'):
'''
Specify the file path to save the log, the log level, and the call file
Save the log to the specified file
'''
# Create 1 A logger
self.logger = logging.getLogger(logger)
self.logger.setLevel(logging.DEBUG)
# Create 1 A handler For writing to log files
self.log_time = time.strftime("%Y_%m_%d")
file_dir = os.getcwd() + '/../log'
if not os.path.exists(file_dir):
os.mkdir(file_dir)
self.log_path = file_dir
self.log_name = self.log_path + "/" + log_cate + "." + self.log_time + '.log'
# print(self.log_name)
fh = logging.FileHandler(self.log_name, 'a') # Append mode This is python2 Adj.
# fh = logging.FileHandler(self.log_name, 'a', encoding='utf-8') # This is python3 Adj.
fh.setLevel(logging.INFO)
# Re-create 1 A handler For output to the console
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
# Definition handler Output format of
formatter = logging.Formatter(
'[%(asctime)s] %(filename)s->%(funcName)s line:%(lineno)d [%(levelname)s]%(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# To logger Add handler
self.logger.addHandler(fh)
self.logger.addHandler(ch)
# Add the following 1 Sentence to remove the handle after logging
# self.logger.removeHandler(ch)
# self.logger.removeHandler(fh)
# Close an open file
fh.close()
ch.close()
def getlog(self):
return self.logger
The purpose is to make all the places where logger is used, only import is the encapsulation library, and then call it directly. For example, calling logger
a.py
#!/usr/bin/python
# -*- coding:utf-8 -*-
from common.log import Log
log = Log().getlog()
log.info("I am a.py")
b.py
#!/usr/bin/python
# -*- coding:utf-8 -*-
from common.log import Log
log = Log().getlog()
log.info("I am b.py")
c.py
#!/usr/bin/python
# -*- coding:utf-8 -*-
import a
import b
from common.log import Log
log = Log().getlog()
log.info("I am c.py")
The result of executing c. py at this point is as follows:
➜ search git:(master) ✗ python c.py
[2019-01-14 15:58:35,807] a.py- > < module > line:6 [INFO]I am a.py
[2019-01-14 15:58:35,808] b.py- > < module > line:6 [INFO]I am b.py
[2019-01-14 15:58:35,808] b.py- > < module > line:6 [INFO]I am b.py
[2019-01-14 15:58:35,809] c.py- > < module > line:8 [INFO]I am c.py
[2019-01-14 15:58:35,809] c.py- > < module > line:8 [INFO]I am c.py
[2019-01-14 15:58:35,809] c.py- > < module > line:8 [INFO]I am c.py
It can be seen that logger of a. py, b. py and c. py are shared, resulting in repeated printing.
Cause analysis of the problem
From the phenomenon, it can be concluded that log systems between different files influence each other. In a. py, b. py, c. py, our calling mode is log = Log (). getlog (), that is, self. logger = logging. getLogger (logger), and logger parameters are not passed, so the resulting self. logger is RootLogger.
RootLogger is the globally unique ancestor of all Logger objects within an python program. Therefore, our setting of RootLogger will naturally affect all log output. In short, it is the setting of log in the first opened file, and the later opened file will be affected, and the inheritance relationship of logger will be passed through once. In this example, b. py is followed by import after a. py, so b. py executes its own logger once, and then executes RootLogger opened in a. py, and so on..........
Problem solving method
Instead of the default RootLogger, give each Logger a name.
a.py
from common.log import Log
log = Log(__name__).getlog()
log.info("I am a.py")
b.py
from common.log import Log
log = Log(__name__).getlog()
log.info("I am b.py")
c.py
import b
import a
from common.log import Log
log = Log(__name__).getlog()
log.info("I am c.py")
The latest implementation results of c. py:
➜ search git:(master) ✗ python c.py
[2019-01-14 16:24:12,008] b.py- > < module > line:6 [INFO]I am b.py
[2019-01-14 16:24:12,009] a.py- > < module > line:6 [INFO]I am a.py
[2019-01-14 16:24:12,009] c.py- > < module > line:10 [INFO]I am c.py
There is no repetition, which is in line with expectations. The problem was solved.