https://docs.python.org/3.5/library/logging.html,先3.5是由於我當前的python 版本是3.5html
之因此要來詳細的寫是由於以前學django時也有這個,不是很理解,因此這裏就多瞭解下。python
寫到後面發現整個文章一點條理都沒有,但因爲內容比較多,就不從新整理了django
logging框架中主要由四個部分組成:app
Loggers expose the interface that application code directly uses. Handlers send the log records (created by loggers) to the appropriate destination. Filters provide a finer grained facility for determining which log records to output. Formatters specify the layout of log records in the final output.
事實上logger是不直接實例化的,可是咱們能夠經過模塊級別的函數logging.getLogger(name)
來調用。若是屢次經過同一個名字調用getLogger()將只能獲得對同一個對象的引用。
框架
注意: logging.getLogger(name) 中的name是一個支持經過「.」(點號)分層級的值。ide
例如: 你定義一個logger: foo,那麼foo.bar, foo.baz,就都算做它的子代,就是繼承,有父子關係。函數
logger名字的層級與python中包的層級是一致的。因此爲了區分它,若是你基於模塊來組織logger,spa
那麼建議你使用:logging.getLogger(__name__)
這種形式,由於對於模塊而言,在pythondebug
包的命名空間中__name__的值就是模塊的名字。日誌
經常使用方法:
Logger.
setLevel
(lvl):
將logger的門限設置爲lvl,低於此等級的信息將被忽略,當一個Logger被創造出來時,它的等級被設置爲:
NOTSET(未設置) 這樣的結果就是: 若是它是一個root logger,它將處理全部的信息,若是沒有root logger
它將繼承父級的logger等級。Note: root logger可經過level waring來建立,注意這裏是個坑,
事實上默認root logger等級爲warning,不要搞錯了
級別設定:前面是名字,後面是對應的數字值
Logger.
exception
(msg, *args, **kwargs)
以error級別來記錄信息,異常信息也會被添加到信息(message),須要exception handler調用才行
Logger.
addFilter
(filt)
添加指定的過濾器
Logger.
removeFilter
(filt)
移除指定的過濾器
這裏的方法多得讓人想撞死在屏幕上,之後慢慢更新吧。
handler有多達15種,這裏只說下常見的幾種:
1.logging.StreamHandler
發送信息到流,類文件對象便可,如終端,文件等
2.logging.FileHandler
發送信息到硬盤文件
3.logging.RotatingFileHandler
這個Handler相似於上面的FileHandler,可是它能夠管理文件大小,輪詢日誌文件(不知道是否是檢測日誌文件大小)。
當文件達到必定大小以後,它會自動將當前日誌文件更名,而後建立一個新的同名日誌文件繼續輸出。
4.logging.handlers.TimedRotatingFileHandler
這個Handler和RotatingFileHandler相似,不過,它沒有經過判斷文件大小來決定什麼時候從新建立日誌文件,
而是間隔必定時間就 自動建立新的日誌文件。
Formatters 決定了記錄格式。Formatter會將傳遞來的信息拼接成一條具體的字符串,
默認狀況下Format只會將信息%(message)s
直接打印出來。Format中有一些自帶的LogRecord屬性可使用,以下表格:
其中lineno,pathname,通過實測了,並非有些博客裏說的什麼當前日誌記錄的行號。後面會有實例。
這裏有一個簡單的應用 的例子,記錄出錯信息:
#!/usr/bin/env python #coding:utf-8 # Created by Andy @ 2017/6/22 import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(pathname)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s ', datefmt='%a, %d %b %Y %H:%M:%S', filename=r'D:\Coding\oldboy\day13 module\test.log', filemode='w') def login(): while True: try: name = input('Input user name:') password = int(input('Input password:')) # 這裏故意轉成整型,觸發異常 if name == 'andy' and password == 'nopasswd': print('logging succeed!') except ValueError as e: logging.debug(e) break if __name__ == '__main__': login()
終端驗證
Input user name:andy Input password:nopasswd Process finished with exit code 0
打開test.log:
Fri, 23 Jun 2017 09:56:40 D:/Coding/oldboy/day13 module/log.py log.py[line:24] DEBUG invalid literal for int() with base 10: 'nopasswd'
注意看,lineno 並非在日誌裏面的行號,而是你代碼的行號,在24行調用了logging.debug(e)
#!/usr/bin/env python #coding:utf-8 # Created by Andy @ 2017/6/22 import logging import os log_path = os.path.join(os.getcwd(),'test.log') logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(pathname)s line:%(lineno)d %(message)s ', datefmt='%Y-%m-%d %H:%M:%S', # 將日期格式化成正常模式 filename=log_path, filemode='a') # 指定成追加模式,默認就是追加,因此這句非必須 simple_logger = logging.getLogger('simple') fh = logging.StreamHandler() #輸出到終端 fh.setLevel(level = logging.WARNING) #等級比默認的高,但調用時必須一致 formatter = logging.Formatter("%(asctime)s %(message)s %(levelname)s") fh.setFormatter(formatter) simple_logger.addHandler(fh) def login(): while True: try: name = input('Input user name:') password = int(input('Input password:')) # 這裏故意轉成整型,觸發異常 if name == 'andy' and password == 'nopasswd': print('logging succeed!') except ValueError as e: simple_logger.warning(e) break if __name__ == '__main__': login()
運行:
終端輸出:
Input user name:andy Input password:andy 2017-06-24 09:55:57,395 invalid literal for int() with base 10: 'andy' WARNING
test.log文件:
2017-06-24 09:55:57 D:/Coding/oldboy/day13 module/log.py line:33 invalid literal for int() with base 10: 'andy'
這晨須要 注意的是:由於默認的logger等級是debug,因此它什麼消息都會輸出,而simple_logger則只輸出比自身高等級的信息,
而且:調用simple_logger時必須比定義的等級高於或者等於定義的等級,這句話什麼意思呢?看上面的例子,simple_logger
定義時的等級爲warning,那麼你調用時最少得warning等級,或者比它高的critical才能正常打印消息(它規定就是這樣),不然你是看不到任何效果的
(這裏坑了很久,一直沒消息打印而找不到緣由,root logger默認等級是warning,而非Noset),可是若是你調用的等級比較低,
並不影響root 這個logger打印日誌信息。
填坑來了:
若是沒指定默認的logger的等級,那麼默認的等級warning就會生效,因此纔出現上面的狀況,若是須要將debug等級的信息也輸入,那麼,這裏須要加一條:
simple_logger.setLevel(logging.DEBUG) # 若是不設置此logger的級別,那麼handler的記錄是從logger傳過來的,也就是默認從logger的warning來的
下面是一個使用配置文件 的例子:
#!/usr/bin/env python #coding:utf-8 # Created by Andy @ 2017/6/25 import logging import logging.config logging.config.fileConfig('logging.conf') # create logger logger = logging.getLogger('simpleExample') # 'application' code logger.debug('debug message') logger.info('info message') logger.warn('warn message') logger.error('error message') logger.critical('critical message')
配置文件:
[loggers] keys=root,simpleExample [handlers] keys=consoleHandler,simpleHandler [formatters] keys=consoleFormatter,simpleFormatter [logger_root] level=DEBUG handlers=consoleHandler [logger_simpleExample] level=INFO handlers=simpleHandler qualname=simpleExample propagate=1 [handler_consoleHandler] class=StreamHandler level=DEBUG formatter=consoleFormatter args=(sys.stdout,) [handler_simpleHandler] class=FileHandler level=INFO formatter=simpleFormatter args=('simple.log','w') [formatter_consoleFormatter] format=%(levelname)s :%(message)s [formatter_simpleFormatter] format=%(asctime)s - %(name)s - %(levelname)s - %(message)s datefmt=
以前的例子沒已經刪除了,找到緣由:propagate=1 ,只有當propagate 爲True時,logger的信息才能傳到上一級logger,或者說父logger,若是你設置爲0
那麼,就只有文件中有寫入,而終端不會有信息打印出來。