[Python 多線程] logging模組、Logger類 (八)

來源:互聯網
上載者:User

標籤:序列   tar   共用   開啟   模組化   line   配置   lte   格式   

 

 

logging模組:

 

標準庫裡面的logging模組,在前面學習安全執行緒時曾用來解決print被打斷的問題,這裡會介紹logging模組的功能。

logging模組是安全執行緒的,不需要客戶做任何特殊的工作。它通過使用線程鎖實現了這一點; 有一個鎖來序列化訪問模組的共用資料,每個處理常式還建立一個鎖來序列化訪問其底層 I/O。

 

 

日誌記錄層級:

層級 數值
CRITICAL 50
ERROR 40
WARNING 30,預設
INFO 20
DEBUG 10
NOTSET 0

 

 

 

 

 

 

 

定義的記錄層級越低,資訊越多,層級越高,資訊越少。

 

日誌記錄格式化字串:

屬性名稱 格式 描述
asctime %(asctime)s 易讀的時間格式: 預設情況下是‘2003-07-08 16:49:45,896‘的形式(逗號之後的數字是毫秒部分的時間)
filename %(filename)s 路徑名的檔案名稱部分。
funcName %(funcName)s 日誌調用所在的函數名
levelname %(levelname)s 訊息的層級名稱(‘DEBUG‘‘INFO‘‘WARNING‘‘ERROR‘‘CRITICAL‘).
levelno %(levelno)s 對應數字格式的記錄層級 (DEBUGINFOWARNINGERROR,CRITICAL).
lineno %(lineno)d 發出日誌記錄調用的源碼行號 (如果可用)。
module %(module)s 所在的模組名(如test6.py模組則記錄test6)
message %(message)s 記錄的資訊
name %(name)s 調用的logger記錄器的名稱
process %(process)d 進程ID
processName %(processName)s 進程名
thread %(thread)d 線程ID
threadName %(threadName)s 線程名

 

 

使用basicConfig方法配置logging記錄格式:

 

格式 描述
filename 指定使用指定的檔案名稱而不是StreamHandler建立FileHandler。
filemode 指定開啟檔案的模式,如果指定了filename(如果檔案模式未指定,則預設為‘a‘)。
format 為處理常式使用指定的格式字串。
datefmt 使用指定的日期/時間格式。
level 將根記錄器層級設定為指定的層級。
handlers 如果指定,這應該是一個已經建立的處理常式的迭代器添加到根記錄器。任何尚未設定格式化程式的處理常式都將被分配在此函數中建立的預設格式化程式。
  

舉例:

import threadingimport loggingFORMAT = "%(asctime)s %(thread)d %(message)s"logging.basicConfig(level=logging.INFO,format=FORMAT)def add(x,y):    logging.warning("{} {}".format(threading.enumerate(),x+y))t = threading.Timer(1,add,args=(4,5))t.start()運行結果:2017-12-17 15:40:34,226 123145367023616 [<_MainThread(MainThread, stopped 4320629568)>, <Timer(Thread-1, started 123145367023616)>] 9

  

修改日期格式:

DATEFMT ="[%Y-%m-%d %H:%M:%S]"FORMAT = "%(asctime)s %(thread)d %(message)s"logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT)

  [2017-12-17 15:45:18]

輸出到檔案:

logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT,filename=‘class_test.log‘)

  檔案路徑不指定,預設為當前模組路徑。

import threadingimport loggingDATEFMT ="[%Y-%m-%d %H:%M:%S]"FORMAT = "%(asctime)s %(thread)d %(message)s"logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT,filename=‘class_test.log‘)def add(x,y):    logging.warning("{} {}".format(threading.enumerate(),x+y))t = threading.Timer(1,add,args=(4,5))t.start()輸出結果會追加寫入當前模組路徑的class_test.log檔案:[2017-12-17 15:50:13] 123145503244288 [<_MainThread(MainThread, stopped 4320629568)>, <Timer(Thread-1, started 123145503244288)>] 9

  

 

 

 Logger類:

 

構造

使用Factory 方法返回一個Logger執行個體。

logging.getLogger([name=None])

 指定name,返回一個名稱為name的Logger執行個體。如果再次使用相同的名字,是執行個體化一個對象。未指定name,返回Logger執行個體,名稱是root,即根Logger。

Logger是階層的,使用 ‘.‘ 點號分割,如‘a‘、‘a.b‘或‘a.b.c.d‘,‘a‘是‘a.b‘的父parent,a.b是a的子child。對於foo來說,名字為foo.bar、foo.bar.baz、foo.bam都是foo的後代。

 

舉例:

import loggingDATEFMT ="[%Y-%m-%d %H:%M:%S]"FORMAT = "%(asctime)s %(thread)d %(message)s"logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT,filename=‘class_test.log‘)root = logging.getLogger()print(root.name,type(root),root.parent,id(root))logger = logging.getLogger(__name__)print(logger.name, type(logger), id(logger), id((logger.parent)))logger1 = logging.getLogger(__name__ + ".ok")print(logger1.name, type(logger1), id(logger1), id((logger1.parent)))print(logger1.parent,id(logger1.parent))運行結果:root <class ‘logging.RootLogger‘> None 4367575248__main__ <class ‘logging.Logger‘> 4367575864 4367575248__main__.ok <class ‘logging.Logger‘> 4367575920 4367575864<logging.Logger object at 0x10453eb38> 4367575864

  

 

 

子child的層級設定,不影響父parent的層級:

import loggingFORMAT = "%(asctime)s %(thread)d %(message)s"logging.basicConfig(level=logging.WARNING,format=FORMAT,datefmt="[%Y-%m-%d %H:%M:%S]")root = logging.getLogger()print(1,root,id(root)) #RootLogger,根Loggerroot.info(‘my root‘) #低於定義的WARNING層級,所以不會記錄loga = logging.getLogger(__name__) #Logger繼承自RootLoggerprint(2,loga,id(loga),id(loga.parent))print(3,loga.getEffectiveLevel()) #數值形式的有效層級loga.warning(‘before‘)loga.setLevel(28) #順位為28print(4,loga.getEffectiveLevel())loga.info(‘after‘)#loga.warning(‘after1‘)運行結果:[2017-12-17 16:31:20] 4320629568 before1 <logging.RootLogger object at 0x104534f28> 43675359122 <logging.Logger object at 0x1044ef630> 4367250992 43675359123 304 28[2017-12-17 16:31:20] 4320629568 after1

  

 

Handler:

Handler控制日誌資訊的輸出目的地,可以是控制台、檔案。

可以單獨設定level

可以單獨設定格式

可以設定過濾器

 

Handler

  StreamHandler #不指定使用sys.strerr

    FileHandler #檔案

    _StderrHandler #標準輸出

  NullHandler #什麼都不做

 

level的繼承:

import loggingFORMAT = "%(asctime)s %(thread)d %(message)s"logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt="[%Y-%m-%d %H:%M:%S]")root = logging.getLogger() #根Logger層級為INFO 20print(‘root:‘,root.getEffectiveLevel())log1 = logging.getLogger(‘s‘)log1.setLevel(logging.ERROR) #層級為ERROR 40print(‘log1:‘,log1.getEffectiveLevel())log1.error(‘log1 error‘)log2 = logging.getLogger(‘s.s1‘) #繼承自log1 40,無法使用warninglog2.setLevel(logging.WARNING) #設定為WARNING 30,才可以使用warningprint(‘log2:‘,log2.getEffectiveLevel())log2.warning(‘log2 warning‘)運行結果:[2017-12-17 16:52:22] 4320629568 log1 errorroot: 20log1: 40[2017-12-17 16:52:22] 4320629568 log2 warninglog2: 30

  logger執行個體,如果設定了level,就用它和資訊的層級比較,否則,繼承最近的祖先的level。

 

handler處理:

import loggingFORMAT = "%(asctime)s %(thread)d %(message)s"logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt="[%Y-%m-%d %H:%M:%S]")root = logging.getLogger()print(1,root.getEffectiveLevel()) #RootLogger,根Loggerlog1 = logging.getLogger(‘s‘)print(2,log1.getEffectiveLevel())h1 = logging.FileHandler(‘test.log‘)h1.setLevel(logging.WARNING)log1.addHandler(h1)print(3,log1.getEffectiveLevel())log2 = logging.getLogger(‘s.s2‘)print(4,log2.getEffectiveLevel())h2 = logging.FileHandler(‘test1.log‘)h2.setLevel(logging.WARNING)log1.addHandler(h2)print(3,log1.getEffectiveLevel())log2.warning(‘log2 info---‘)運行結果:1 20[2017-12-17 19:02:53] 7956 log2 info---2 203 204 203 20

  test.log和test1.log最終都會記錄一份"log2 info---"

 

 同樣,handler也可以設定使用logging.Formatter()設定格式和Logging.Filter()設定過濾器:

import loggingFORMAT = "%(asctime)s %(thread)d %(message)s"logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt="[%Y-%m-%d %H:%M:%S]")root = logging.getLogger()print(1,root.getEffectiveLevel()) #RootLogger,根Loggerlog1 = logging.getLogger(‘s‘)#模組化用__module__,函數化用__name__作為Logger名,Logger同名記憶體中也只有一個print(2,log1.getEffectiveLevel())h1 = logging.FileHandler(‘test.log‘)h1.setLevel(logging.WARNING)fmt1 = logging.Formatter(‘[%(asctime)s] %(thread)s %(threadName)s log1-handler1 %(message)s‘)h1.setFormatter(fmt1) #重新個人化定義記錄的格式化字串log1.addHandler(h1)filter1 = logging.Filter(‘s‘) #過濾器 會記錄s, s.s2的資訊log1.addFilter(filter1)print(3,log1.getEffectiveLevel())log2 = logging.getLogger(‘s.s2‘)print(4,log2.getEffectiveLevel())h2 = logging.FileHandler(‘test1.log‘)h2.setLevel(logging.WARNING)log1.addHandler(h2)filter1 = logging.Filter(‘s.s2‘) #過濾器不會記錄s.s2的訊息,只會記錄自己的訊息log1.addFilter(filter1)print(3,log1.getEffectiveLevel())log1.warning(‘log1 warning===‘)log2.warning(‘log2 warning---‘)運行結果:test.log: #handler1記錄了到了log1和log2的資訊[2017-12-17 19:43:12,654] 5872 MainThread log1-handler1 log1 warning===[2017-12-17 19:43:12,654] 5872 MainThread log1-handler1 log2 warning---test1.log:    #handler2隻記錄了它自己的資訊log2 warning---

 

 

 

渣圖:

 

總結:

1. 每一個Logger執行個體的level如同入口,讓水流進來,如果這個門檻太高,資訊就進不來

2. 如果level沒有設定,就用父logger的,如果父logger的level也沒有設定,繼續找父的父的,最終找到root上,如果root設定了就用它的,如果root沒有設定,root的預設值是WARNING

3. 在某個logger上產生某種層級的資訊,首先和logger的level檢查,如果訊息level低於logger的EffectiveLevl有效層級,訊息丟棄,不會再向父logger傳遞該訊息。如果通過(大於等於)檢查後,訊息交給logger所有的handler處理,每一個handler需要和自己level比較來決定是否處理。如果沒有一個handler,或者訊息已經被handler處理過了,這個訊息會繼續發送給父logger處理。

4. 父logger拿到訊息,會重複第三條的過程,直至根logger

 

[Python 多線程] logging模組、Logger類 (八)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.