一般情況下,一些程序的調試過程中我們會讓它輸出一些信息,特別是一些大型的程序,我們通過這些信息可以了解程序的運行情況,python提供了一個日志模塊logging,它可以把我們想要的信息全部保存到一個日志文件中,方面我們查看。最近做的項目,有一些業務處理邏輯是先將數據寫入隊列,然后通過python讀取隊列中的內容,繼續處理后續的邏輯。因為隊列消費一次就沒了,所以做好日志記錄格外重要;
test_log1.py
#! /usr/bin/python import logging LOG_FILENAME="log_test.txt" logging.basicConfig(filename=LOG_FILENAME,level=logging.NOTSET) logging.debug("This message should go to the log file") LOG_FILENAME_22="log_test22.txt" logging.basicConfig(filename=LOG_FILENAME_22,level=logging.DEBUG) logging.debug("This message 222should go to the log file")
執行結果:
只生成了一個log_test.txt文件,文件內容是:
DEBUG:root:This message should go to the log file
DEBUG:root:This message 222should go to the log file
而沒有生成log_test22.txt文件.
原因:查看logging的文檔:
FUNCTIONS addLevelName(level, levelName) Associate 'levelName' with 'level'. This is used when converting levels to text during message formatting. basicConfig(**kwargs) Do basic configuration for the logging system. This function does nothing if the root logger already has handlers configured. It is a convenience method intended for use by simple scripts to do one-shot configuration of the logging package. The default behaviour is to create a StreamHandler which writes to sys.stderr, set a formatter using the BASIC_FORMAT format string, and add the handler to the root logger. A number of optional keyword arguments may be specified, which can alter the default behaviour. filename Specifies that a FileHandler be created, using the specified filename, rather than a StreamHandler. filemode Specifies the mode to open the file, if filename is specified (if filemode is unspecified, it defaults to 'a'). format Use the specified format string for the handler. datefmt Use the specified date/time format. level Set the root logger level to the specified level. stream Use the specified stream to initialize the StreamHandler. Note that this argument is incompatible with 'filename' - if both are present, 'stream' is ignored.
test_log2.py
>>> import logging >>> logger=logging.getLogger() >>> handler=logging.FileHandler("Log_test.txt") >>> logger.addHandler(handler) >>> logger.setLevel(logging.NOTSET) >>> logger.error("This is an error message") >>> logger.info("This is an info message") >>> logger.critical("This is a critical message")
日志文件中會出現三行內容:
This is an error message
This is an info message
This is a critical message
上面程序的第2行是生成一個日志對象,里面的參數時日志的名字,可以帶,也可以不帶。
第3行是生成了一個handler,logging支持很多種Handler,像FileHandler,SocketHandler等待,這里由於我們要寫文件,所以用了FileHandler,它的參數就是filename,默認當前路徑,當然我們可以自己指定路徑。
第5行設置日志信息輸出的級別。Logging提供了多種日志級別,如NOTSET,DEBUG,INFO,WARNING,ERROR,CRITICAL等,每個級別都對應一個數值,如果我們不自己設置輸出級別,那么系統會執行缺省級別,值為30,就warning。Logging也提供了一個方法來查看缺省日志級別,getLevelName(logger,getEffectiveLevel())。
如果想將寫入日志的這個功能抽象出一個方法出來,並且能夠制定不同的日志寫入不同的文件里,如,
test_log3.py
#! /usr/bin/python import logging def setLog(log_filename,log_message): logger=logging.getLogger() handler=logging.FileHandler(log_filename) logger.addHandler(handler) logger.setLevel(logging.NOTSET) logger.debug(log_message) # 如果沒有此句話,則會將同一個message追加到不同的log中 logger.removeHandler(handler) if __name__ =='__main__': setLog('Log_test','it all right') setLog('Log_test88','it all righ8888t') setLog('Log_test99','it all righ999t')
上面最重要的是:logger.removeHandler(handler),沒有了這行code,'it all righ8888t'會寫入到Log_test文件中;
日志對象對於不同的級別信息提供不同的函數進行輸出,如:info(), error(), debug()等。當寫入日志時,小於指定級別的信息將被忽略。因此為了輸出想要的日志級別一定要設置好此參數。這里我設為NOTSET(值為0),也就是想輸出所有信息。系統默認的日志級別排序為,CRITICAL,ERROR,WARNING,INFO,DEBUG,NOTSET。比如說我們要輸出的信息為CRITICAL,但是我們的日志級別為DEBUG,那么這個信息將被忽略掉。我們看下面的例子:
test_log4.py
#! /usr/bin/python # -*- coding: utf-8 -*- import logging import sys LEVELS={'debug':logging.DEBUG, 'info':logging.INFO, 'warning':logging.WARNING, 'error':logging.ERROR, 'critical':logging.CRITICAL} if len(sys.argv)>1: level_name=sys.argv[1] level=LEVELS.get(level_name,logging.NOTSET) logging.basicConfig(level=level) logging.debug("This is a debug message") logging.info("This is an info message") logging.warning("This is a warning message") logging.error("This is an error message") logging.critical("This is a critical error message")
執行結果:
可以看到過濾進行的很明顯。當我們設置級別最低位debug時,所有的信息都輸出了,當我們設為最高位critical時候,只有critical輸出了,低於critical的被過濾了。
Logging是非常有用的,一個程序的健壯性也這個有關,當一個程序包含很多的調試信息時,可以方便我們發現問題,發現錯誤。