[TOC]
Problem Origin:
? After learning the functional programming of Python, the logging is exposed to such a powerful log module. In order to reduce duplication of code, it should be a lot of classmates and I can not wait to write a log function, such as the following:
# 这里为了便于理解,简单的展示了一个输出到屏幕的日志函数def my_log(): = logging.getLogger(‘mysql.log‘) = logging.StreamHandler() ch.setLevel(logging.ERROR) = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘) ch.setFormatter(fmt) logger.addHandler(ch) return loggermy_log().error(‘run one‘)my_log().error(‘run two‘)my_log().error(‘run three‘)
The function is written, and it seems to be fine, let's run it!
The results are as follows:
2018-06-21 13:06:37,569-mysql.log-error-run One
2018-06-21 13:06:37,569-mysql.log-error-run
2018-06-21 13:06:37,569-mysql.log-error-run
2018-06-21 13:06:37,569-mysql.log-error-run Three
2018-06-21 13:06:37,569-mysql.log-error-run Three
2018-06-21 13:06:37,569-mysql.log-error-run Three
The log is actually repeated output, and the number is increasing.
Problem resolution
In fact, logger = logging.getLogger(‘mysql.log‘)
when executing, not each time a new logger is generated, but first check whether there is a logger object called ' Mysql.log ' in memory, the existence is removed, does not exist the new.
The instantiated logger object has a property such as ' handlers ' to store the Handler, and the code demonstrates the following:
"' Python
Def my_log ():
Logger = Logging.getlogger (' Mysql.log ')
# Print out the handlers list of logger after each call
Print (logger.handlers)
ch = logging.StreamHandler() ch.setLevel(logging.ERROR) fmt = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘) ch.setFormatter(fmt) logger.addHandler(ch) return logger
My_log (). Error (' Run one ')
My_log (). Error (' Run ')
My_log (). Error (' Run three ')
```
Operation Result:
[]
2018-06-21 13:26:14,059-mysql.log-error-run One
[<streamhandler
logger.handlers
Initially an empty list, execute ' logger.addhandler (CH) ' To add a ' streamhandler ', output a log
- In the second call,
logger.handlers
there is already a ' streamhandler ', the execution of ' Logger.addhandler (CH) ' will add a ' streamhandler ' again, at this time the logger has two ' Streamhandler ', output two duplicate logs
- In the third call,
logger.handlers
there are already two ' Streamhandler ', the second execution of ' Logger.addhandler (CH) ' will be added again, at this time the logger has three ' streamhandler ', output three duplicate log
Workaround 1. gaiminghuanxing
# 为日志函数添加一个name,每次调用时传入不同的日志名def my_log(name): = logging.getLogger(name) = logging.StreamHandler() ch.setLevel(logging.ERROR) = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘) ch.setFormatter(fmt) logger.addHandler(ch) return loggermy_log(‘log1‘).error(‘run one‘)my_log(‘log2‘).error(‘run two‘)my_log(‘log3‘).error(‘run three‘)
Operation Result:
2018-06-21 13:40:51,685-log1-error-run One
2018-06-21 13:40:51,685-log2-error-run
2018-06-21 13:40:51,685-log3-error-run Three
2. Timely Cleaning (Logger.handlers.clear)
def my_log(): = logging.getLogger() # 每次被调用后,清空已经存在handler logger.handlers.clear() = logging.StreamHandler() ch.setLevel(logging.ERROR) = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘) ch.setFormatter(fmt) logger.addHandler(ch) return loggermy_log().error(‘run one‘)my_log().error(‘run two‘)my_log().error(‘run three‘)
Ps:removehandler method (Poor compatibility)
# 这种写法下的可以使用removeHandler方法(logger.handlers.clear也可以使用在这种写法的函数内)import loggingdef my_log(msg): logger = logging.getLogger(‘mysql.log‘) ch = logging.StreamHandler() ch.setLevel(logging.ERROR) fmt = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘) ch.setFormatter(fmt) logger.addHandler(ch) logger.error(msg) # 在使用完ch后从移除 logger.removeHandler(ch)my_log(‘run one‘)my_log(‘run two‘)my_log(‘run three‘)
3. Judging before use
ImportLoggingdefMy_log (): Logger=Logging.getlogger (' Mysql.log ')# To determine if logger has added handler, is to return the Logger object directly, otherwise execute handler settings and addhandler (CH) if notLogger.handlers:ch=Logging. Streamhandler () Ch.setlevel (logging. ERROR) FMT=Logging. Formatter ('% (asctime) s - % (name) s - % (levelname) s - % (message) s') Ch.setformatter (FMT) logger.addhandler (CH)returnLoggermy_log (). Error (' Run one ') My_log (). Error (' Run ') My_log (). Error (' Run three ')
Summarize
? The first time I encountered a recurring log output problem, I didn't learn anything about object-oriented programming at the time, and didn't really understand the logging module. After learning object-oriented programming, it's a great feeling to go back and think about these problems.
? For example, at first the logging.getLogger
actual principle is not very understanding, in the object-oriented programming in the Hasattr, GetAttr, SetAttr and so on a few ways after the epiphany. So gentlemen if you still do not understand the logging module, it is advisable not to dwell on these details, continue to learn.
? After the expansion of knowledge, some of the problems will naturally be solved:)
Reference content:
Luffycity:https://www.luffycity.com/home
The Python standard Library
huilan_same:51858817
Analysis of duplicate output of Python log