基本介紹
- logging提供的模塊級(jí)別的函數(shù)記錄日志
- 日志級(jí)別: DEBUG < INFO < WARNING < ERROR < CRITICAL
- 可以通過(guò)logging模塊定義的模塊級(jí)別的方法去完成簡(jiǎn)單的日志記錄
- 只有級(jí)別大于或等于日志記錄器指定級(jí)別的日志記錄才會(huì)被輸出,小于該級(jí)別的日志記錄將會(huì)被丟棄蚓让。
- 最簡(jiǎn)單的日志輸出
先來(lái)試著分別輸出一條不同日志級(jí)別的日志記錄:
import logging
logging.debug("This is a debug log.")
logging.info("This is a info log.")
logging.warning("This is a warning log.")
logging.error("This is a error log.")
logging.critical("This is a critical log.")
也可以這樣寫:
logging.log(logging.DEBUG, "This is a debug log.")
logging.log(logging.INFO, "This is a info log.")
logging.log(logging.WARNING, "This is a warning log.")
logging.log(logging.ERROR, "This is a error log.")
logging.log(logging.CRITICAL, "This is a critical log.")
輸出結(jié)果:
WARNING:root:This is a warning log.
ERROR:root:This is a error log.
CRITICAL:root:This is a critical log.
-
那么問(wèn)題來(lái)了
問(wèn)題1:為什么前面兩條日志沒(méi)有被打印出來(lái)项棠?
這是因?yàn)閘ogging模塊提供的日志記錄函數(shù)所使用的日志器設(shè)置的日志級(jí)別是WARNING昌跌,因此只有WARNING級(jí)別的日志記錄以及大于它的ERROR和CRITICAL級(jí)別的日志記錄被輸出了去件,而小于它的DEBUG和INFO級(jí)別的日志記錄被丟棄了。問(wèn)題2:打印出來(lái)的日志信息中各字段表示什么意思必孤?為什么會(huì)這樣輸出蓖救?
上面輸出結(jié)果中每行日志記錄的各個(gè)字段含義分別是:日志級(jí)別:日志器名稱:日志內(nèi)容
之所以會(huì)這樣輸出,是因?yàn)閘ogging模塊提供的日志記錄函數(shù)所使用的日志器設(shè)置的日志格式默認(rèn)是BASIC_FORMAT旧困,其值為:"%(levelname)s:%(name)s:%(message)s"問(wèn)題3:如果將日志記錄輸出到文件中醇份,而不是打印到控制臺(tái)稼锅?
因?yàn)樵趌ogging模塊提供的日志記錄函數(shù)所使用的日志器設(shè)置的處理器所指定的日志輸出位置默認(rèn)為:
sys.stderr。問(wèn)題4:我是怎么知道這些的僚纷?
查看這些日志記錄函數(shù)的實(shí)現(xiàn)代碼矩距,可以發(fā)現(xiàn):當(dāng)我們沒(méi)有提供任何配置信息的時(shí)候,這些函數(shù)都會(huì)去調(diào)用logging.basicConfig(**kwargs)方法怖竭,且不會(huì)向該方法傳遞任何參數(shù)锥债。繼續(xù)查看basicConfig()方法的代碼就可以找到上面這些問(wèn)題的答案了。問(wèn)題5:怎么修改這些默認(rèn)設(shè)置呢痊臭?
其實(shí)很簡(jiǎn)單哮肚,在我們調(diào)用上面這些日志記錄函數(shù)之前,手動(dòng)調(diào)用一下basicConfig()方法广匙,把我們想設(shè)置的內(nèi)容以參數(shù)的形式傳遞進(jìn)去就可以了允趟。 logging.basicConfig()函數(shù)說(shuō)明
該方法用于為logging日志系統(tǒng)做一些基本配置,方法定義如下:
logging.basicConfig(**kwargs)
該函數(shù)可接收的關(guān)鍵字參數(shù)如下:
參數(shù)名稱 | 描述
| -
filename | 指定日志輸出目標(biāo)文件的文件名鸦致,指定該設(shè)置項(xiàng)后日志信心就不會(huì)被輸出到控制臺(tái)了
filemode | 指定日志文件的打開(kāi)模式潮剪,默認(rèn)為'a'。需要注意的是分唾,該選項(xiàng)要在filename指定時(shí)才有效
format | 指定日志格式字符串抗碰,即指定日志輸出時(shí)所包含的字段信息以及它們的順序。logging模塊定義的格式字段下面會(huì)列出鳍寂。
datefmt | 指定日期/時(shí)間格式改含。需要注意的是,該選項(xiàng)要在format中包含時(shí)間字段%(asctime)s時(shí)才有效
level | 指定日志器的日志級(jí)別
stream | 指定日志輸出目標(biāo)stream迄汛,如sys.stdout捍壤、sys.stderr以及網(wǎng)絡(luò)stream。需要說(shuō)明的是鞍爱,stream和filename不能同時(shí)提供鹃觉,否則會(huì)引發(fā) ValueError異常
style | Python 3.2中新添加的配置項(xiàng)。指定format格式字符串的風(fēng)格睹逃,可取值為'%'盗扇、'{'和'$',默認(rèn)為'%'
handlers | Python 3.3中新添加的配置項(xiàng)沉填。該選項(xiàng)如果被指定疗隶,它應(yīng)該是一個(gè)創(chuàng)建了多個(gè)Handler的可迭代對(duì)象,這些handler將會(huì)被添加到root logger翼闹。需要說(shuō)明的是:filename斑鼻、stream和handlers這三個(gè)配置項(xiàng)只能有一個(gè)存在,不能同時(shí)出現(xiàn)2個(gè)或3個(gè)猎荠,否則會(huì)引發(fā)ValueError異常坚弱。
- logging模塊定義的格式字符串字段
我們來(lái)列舉一下logging模塊中定義好的可以用于format格式字符串中字段有哪些:
字段/屬性名稱 | 使用格式 | 描述
| - | -
asctime | %(asctime)s | 日志事件發(fā)生的時(shí)間--人類可讀時(shí)間蜀备,如:2003-07-08 16:49:45,896
created | %(created)f | 日志事件發(fā)生的時(shí)間--時(shí)間戳,就是當(dāng)時(shí)調(diào)用time.time()函數(shù)返回的值
relativeCreated | %(relativeCreated)d | 日志事件發(fā)生的時(shí)間相對(duì)于logging模塊加載時(shí)間的相對(duì)毫秒數(shù)(目前還不知道干嘛用的)
msecs | %(msecs)d | 日志事件發(fā)生事件的毫秒部分
levelname | %(levelname)s | 該日志記錄的文字形式的日志級(jí)別('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')
levelno | %(levelno)s | 該日志記錄的數(shù)字形式的日志級(jí)別(10, 20, 30, 40, 50)
name | %(name)s | 所使用的日志器名稱荒叶,默認(rèn)是'root'碾阁,因?yàn)槟J(rèn)使用的是 rootLogger
message | %(message)s | 日志記錄的文本內(nèi)容,通過(guò) msg % args計(jì)算得到的
pathname | %(pathname)s | 調(diào)用日志記錄函數(shù)的源碼文件的全路徑
filename | %(filename)s | pathname的文件名部分些楣,包含文件后綴
module | %(module)s | filename的名稱部分脂凶,不包含后綴
lineno | %(lineno)d | 調(diào)用日志記錄函數(shù)的源代碼所在的行號(hào)
funcName | %(funcName)s | 調(diào)用日志記錄函數(shù)的函數(shù)名
process | %(process)d | 進(jìn)程ID
processName | %(processName)s | 進(jìn)程名稱,Python 3.1新增
thread | %(thread)d | 線程ID
threadName | %(thread)s | 線程名稱
5.經(jīng)過(guò)配置的日志輸出
先簡(jiǎn)單配置下日志器的日志級(jí)別
logging.basicConfig(level=logging.DEBUG)
logging.debug("This is a debug log.")
logging.info("This is a info log.")
logging.warning("This is a warning log.")
logging.error("This is a error log.")
logging.critical("This is a critical log.")
輸出結(jié)果:
DEBUG:root:This is a debug log.
INFO:root:This is a info log.
WARNING:root:This is a warning log.
ERROR:root:This is a error log.
CRITICAL:root:This is a critical log.
所有等級(jí)的日志信息都被輸出了戈毒,說(shuō)明配置生效了艰猬。
在配置日志器日志級(jí)別的基礎(chǔ)上,在配置下日志輸出目標(biāo)文件和日志格式
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
logging.basicConfig(filename='my.log', level=logging.DEBUG, format=LOG_FORMAT)
logging.debug("This is a debug log.")
logging.info("This is a info log.")
logging.warning("This is a warning log.")
logging.error("This is a error log.")
logging.critical("This is a critical log.")
此時(shí)會(huì)發(fā)現(xiàn)控制臺(tái)中已經(jīng)沒(méi)有輸出日志內(nèi)容了埋市,但是在python代碼文件的相同目錄下會(huì)生成一個(gè)名為'my.log'的日志文件冠桃,該文件中的內(nèi)容為:
2017-05-08 14:29:53,783 - DEBUG - This is a debug log.
2017-05-08 14:29:53,784 - INFO - This is a info log.
2017-05-08 14:29:53,784 - WARNING - This is a warning log.
2017-05-08 14:29:53,784 - ERROR - This is a error log.
2017-05-08 14:29:53,784 - CRITICAL - This is a critical log.
在上面的基礎(chǔ)上,我們?cè)賮?lái)設(shè)置下日期/時(shí)間格式
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
DATE_FORMAT = "%m/%d/%Y %H:%M:%S %p"
logging.basicConfig(filename='my.log', level=logging.DEBUG, format=LOG_FORMAT, datefmt=DATE_FORMAT)
logging.debug("This is a debug log.")
logging.info("This is a info log.")
logging.warning("This is a warning log.")
logging.error("This is a error log.")
logging.critical("This is a critical log.")
此時(shí)會(huì)在my.log日志文件中看到如下輸出內(nèi)容:
05/08/2017 14:29:04 PM - DEBUG - This is a debug log.
05/08/2017 14:29:04 PM - INFO - This is a info log.
05/08/2017 14:29:04 PM - WARNING - This is a warning log.
05/08/2017 14:29:04 PM - ERROR - This is a error log.
05/08/2017 14:29:04 PM - CRITICAL - This is a critical log.
掌握了上面的內(nèi)容之后道宅,已經(jīng)能夠滿足我們平時(shí)開(kāi)發(fā)中需要的日志記錄功能食听。
封裝一下
import os
import logging
# debug -> info -> warn -> error -> critical
def getLogger(name, saveDir="./log/", maxBytes=20 * 1024 * 1024, backupCount=20, hasInit=False):
if not os.path.exists(saveDir):
os.system("mkdir -p %s" % saveDir)
logger = logging.getLogger(name)
if not hasInit:
logger.setLevel(logging.DEBUG)
# 處理文件輸出,輸出所有級(jí)別
logFile = "%s/%s.log" % (saveDir, name)
formatter = logging.Formatter("[%(asctime)s] [%(levelname)s] [%(funcName)s:%(lineno)s] %(message)s")
fileHandler = RotatingFileHandler(logFile, maxBytes=maxBytes, backupCount=backupCount)
fileHandler.setLevel(logging.DEBUG)
fileHandler.setFormatter(formatter)
logger.addHandler(fileHandler)
# 標(biāo)準(zhǔn)輸出(屏幕)
stdoutFormatter = logging.Formatter("\033[1;32;40m[%(asctime)s] [%(levelname)s] [%(funcName)s:%(lineno)s] %(message)s\033[0m")
stdoutHandler = logging.StreamHandler(sys.stdout)
stdoutHandler.setLevel(logging.INFO)
stdoutHandler.setFormatter(stdoutFormatter)
stdoutHandler.addFilter(InfoFilter(logging.INFO))
logger.addHandler(stdoutHandler)
# 錯(cuò)誤輸出(屏幕)
stderrFormatter = logging.Formatter("\033[1;31;40m[%(asctime)s] [%(levelname)s] [%(funcName)s:%(lineno)s] %(message)s\033[0m")
stderrHandler = logging.StreamHandler(sys.stderr)
stderrHandler.setLevel(logging.WARNING)
stderrHandler.setFormatter(stderrFormatter)
logger.addHandler(stderrHandler)
# propagate 屬性為 True(默認(rèn)值)污茵,則它的記錄也會(huì)傳到父 logger樱报。因此,logger 在記錄到文件的同時(shí)泞当,也會(huì)在 stdout 輸出日志迹蛤。
logger.propagate = False # duplicate log
return logger
# 調(diào)用
getLogger(test)
調(diào)用結(jié)果:在當(dāng)前路徑的log下生成文件名為test.log的文件,里面會(huì)有各類日志襟士。
logging.Formatter 的常用格式字符串
格式字符串 | 作用 |
---|---|
%(name)s | 日志記錄器的名稱(記錄通道) |
%(levelno)s | 日志記錄級(jí)別的數(shù)字 DEBUG=10盗飒、INFO=20、WARNING=30陋桂、ERROR=40逆趣、CRITICAL=50 |
%(levelname)s | 日志記錄級(jí)別的文本 “DEBUG”、“INFO”嗜历、“WARNING”宣渗、“ERROR”、“CRITICAL” |
%(pathname)s | 日志調(diào)用的源文件的完整路徑名 |
%(filename)s | 日志調(diào)用的源文件的文件名部分 |
%(module)s | 日志調(diào)用的源文件的文件名的名稱部分 |
%(lineno)d | 日志調(diào)用的源行號(hào) |
%(funcName)s | 日志調(diào)用的函數(shù)名 |
%(created)f | 打印日志的時(shí)間 time.time() 的返回值 |
%(asctime)s | 打印日志的時(shí)間 datetime.datetime.now() 的返回值 |
%(msecs)d | 打印日志的毫秒部分 |
%(relativeCreated)d | 打印日志的時(shí)間梨州,毫秒為單位 是相對(duì)于加載 logging 模塊的時(shí)間(通常在應(yīng)用程序啟動(dòng)時(shí)) |
%(thread)d | 線程ID |
%(threadName)s | 線程名痕囱,一般是主線程 MainThread |
%(process)d | 進(jìn)程ID |
%(message)s | 日志信息 |