配置輸出日誌到文件
導入模塊 import logging,os FILE = os.getcwd() 設置文件路徑,默認是追加到文件中,不過可以設置filemode="w",爲重寫進去。 logging.basicConfig(filename=os.path.join(FILE,"dosubprocess.log"),filemode="w", format="%(levelname)s:%(message)s",level=logging.INFO)
可以在外面設置級別
import logging logging.basicConfig(level="laowang") #必須調用getLOgger獲得一個loggging對象後,纔可以爲他設置級別。 log=logging.getLogger(__name__) #logging的屬性,propagate,意思是是否消息是否層層上傳。 print(log.propagate) #設置logging對象的級別 log.setLevel(logging.WARN)
logging創建流handler,將信息顯示到控制檯,
import logging,os logging.basicConfig(filename=os.path.join(os.getcwd(),"my_property.log"), format="%(levelname)-10s %(asctime)-20s %(message)s", datefmt="%m/%d/%Y %I:%M:%S", level=logging.DEBUG, filemode="w") console=logging.StreamHandler() console.setLevel(logging.INFO) formatter=logging.Formatter("%(levelname)-10s %(asctime)-20s %(message)s") console.setFormatter(formatter) logging.getLogger("").addHandler(console)
''' 快速入門 基礎知識 日誌的作用是跟蹤,django項目中不可缺少。 派出: 控制檯輸出:print() 報告事件,發生在一個程序的正常運行:logging.info() 或 logging.debug() 發出警告關於一個特定的運行時事件:warnings.warn() 或 logging.warning() 報告一個錯誤對於一個特定的運行時事件:異常處理 報告一個錯誤當沒有引發一個異常:logging.error()、logging.exception() 或 logging.critical() DEBUG:詳細的信息,通常只出現在診斷問題上 INFO:確認一切按預期運行 WARNING:一個跡象表明,一些意想不到的事情發生了,或表明一些問題在不久的將來(例如。磁盤空間低”)。這個軟件還能按預期工作 ERROR:個更嚴重的問題,軟件沒能執行一些功能 CRITICAL:一個嚴重的錯誤,這表明程序本身可能無法繼續運行 日誌一共分成5個等級,從低到高分別是:DEBUG INFO WARNING ERROR CRITICAL。這5個等級,也分別對應5種打日誌的方法: debug 、info 、warning 、error 、critical。 默認的是WARNING,當在WARNING或之上時才被跟蹤。 有兩種方式記錄跟蹤,一種輸出控制檯,另一種是記錄到文件中,如日誌文件。 日誌一共分成5個等級,從低到高分別是:DEBUG INFO WARNING ERROR CRITICAL。這5個等級,也分別對應5種打日誌的方法: debug 、info 、warning 、error 、critical。 默認的是WARNING,當在WARNING或之上時才被跟蹤。 有兩種方式記錄跟蹤,一種輸出控制檯,另一種是記錄到文件中,如日誌文件 ''' ''' 簡單日誌操作 寫入一個文件裏面: ''' #logging to file # import os # import logging # # # with open("log.txt","w",encoding="utf-8") as f: # # f.write("") # # FILE =os.getcwd() # logging.basicConfig(filename=os.path.join(FILE,"log.txt"),level=logging.DEBUG) # logging.debug("寫進去") # logging.info("滾進去") # logging.warning("也滾進去") ''' 來學習一些日誌組件以及一些高級部分。 日誌組件包括:loggers、handlers、filters、formatters。 Logger 對象扮演了三重角色。 首先,它暴露給應用幾個方法以便應用可以在運行時寫log; 其次,Logger對象按照log信息的嚴重程度或者 根據filter對象來決定如何處理log信息(默認的過濾功能); 最後,logger還負責把log信息傳送給相關的loghandlers。 Handler對象負責分配合適的log信息(基於log信息的嚴重 程度)到handler指定的目的地。 Logger對象可以用addHandler()方法添加零個或多個handler對象到它自身。 一個常見的場景是,一個應用可能希望把所有的log信息都發送到一個log文件中去, 所有的error級別以上的log信息都發送到stdout, 所有critical 的log信息通過email發送。 這個場景裏要求三個不同handler處理,每個handler負責把特定的log信息發送到特定的地方。 filter:細緻化,選擇哪些日誌輸出 format:設置顯示格式 ''' ''' ogging.basicConfig ( [ * * kwargs ] ) 該語句是日誌模塊配置基本信息。kwargs 支持如下幾個關鍵字參數: filename :日誌文件的保存路徑。如果配置了些參數,將自動創建一個FileHandler作爲Handler; filemode :日誌文件的打開模式。 默認值爲’a’,表示日誌消息以追加的形式添加到日誌文件中。如果設爲’w’, 那麼每次程序啓動的時候都會創建一個新的日誌文件; format :設置日誌輸出格式; datefmt :定義日期格式; level :設置日誌的級別.對低於該級別的日誌消息將被忽略; stream :設置特定的流用於初始化StreamHandler。 ''' ''' logging.getLogger ( [ name ] ) 創建Logger對象。日誌記錄的工作主要由Logger對象來完成。 在調用getLogger時要提供Logger的名稱(注:多次使用相同名稱 來調用getLogger, 返回的是同一個對象的引用。),Logger實例之間有層次關係,這些關係通過Logger名稱來體現,如 ''' # import logging '''命名''' # log2=logging.getLogger("BeginMan") #生成一個日誌對象 # print(log2)#<logging.Logger object at 0x00000000026D1710> '''無名''' # log3=logging.getLogger() # print(log3) '''最好的方式''' # log = logging.getLogger(__name__)#_name__ is the module’s name in the Python package namespace. # print(log) # print(__name__) ''' Logger對象, 有如下屬性和方法: Logger.propagate 具體參考:http://docs.python.org/2.7/library/logging.html Logger.setLevel(lvl) ——————– 設置日誌的級別。對於低於該級別的日誌消息將被忽略。 ''' # import logging # import os # logging.basicConfig(format="%(levelname)s,%(message)s",filename=os.path.join(os.getcwd(),"log.txt"),level=logging.DEBUG) # log=logging.getLogger("root.set") #Logger 對象 # print(log.propagate) # # log.setLevel(logging.WARN) #日誌記錄級別爲WARNNING # log.info("msg") # log.debug("msg") # log.warning("msg") # log.error("msg") # ''' Handler對象、Formatter對象、Filter對象、Filter對象 ''' # import logging # import os # '''logger''' # l=logging.Logger("root") #創建logger對象 # log=logging.getLogger("root") #通過logging.getlogger創建對象 # # print(l) # print(log) # # '''Handler''' # handler=logging.Handler() #創建Handler對象 # handler.__init__(logging.DEBUG) #通過設置levell勞初始刷handler實例 # handler.createLock()#初始化一個縣城索,可以用來序列化,訪問底層i/ogongneng,這可鞥不是縣城安全的 # handler.acquire() #獲取線程鎖,通過handler.createLock() # handler.release() #釋放獲得的縣城索 # handler.setLevel(logging.DEBUG) #設置臨界值,如果logging信息級別小於他的責被忽視 # handler.setFormatter("%(levelname)s,%(message)s") #設置格式 # handler.addFilter(filter)# ''' 3.將日誌同時輸出到文件和屏幕 ''' # import logging # logging.basicConfig(level=logging.DEBUG, # format="%(asctime)s %(filename)s [line:%(lineno)d %(levelname)s %(message)s", # datefmt="%a %d %b %Y %H:%M:%S", # filename="myapp.log", # filemode="w") # 定義一個StreamHandler,將INFO級別或更高的日誌信息打印到標準錯誤, # 並將其添加到當前的日誌處理對象 # console=logging.StreamHandler() # console.setLevel(logging.INFO) # formatter=logging.Formatter("%(name)-12s:%(levelname)-8s %(message)s") # console.setFormatter(formatter) # logging.getLogger("").addHandler(console) # # logging.debug("This is debug message") # logging.info("This is info message ") # logging.warning("Thsi is warning message") # level: 設置日誌級別,默認爲logging.WARNING # stream: 指定將日誌的輸出流, # 可以指定輸出到sys.stderr,sys.stdout或者文件,默認輸出到sys.stderr, # 當stream和filename同時指定時,stream被忽略 ''' . 每一個Logger實例的level如同入口,讓水流進來,如果這個門檻太高,信息就進不來。例如log2.info('log3 info'),如果log2定義的級別高於info級別,就不會又信息通過log2 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的propagate屬性是否爲True,Ture則把這個消息會繼續發給父Logger,當前Logger的父Logger稱爲當前Logger,新的Logger的所有Handler繼續處理消息。 4. logger實例初始的propagate屬性爲True,即允許想父logger傳遞消息 5. logger.basicConfig 如果root沒有handler,就默認創建一個StreamHandler,如果設置了filename,就創建一個FileHandler。如果設置了format參數,就會用它生成一個formatter對象,並把這個formatter加入到剛纔創建的handler上,然後把這些handler加入到root.handlers列表上。level 是設置給root.logger的。 如果root.handlers列表不爲空,logging.basicConfig的調用什麼都不做。 標準庫裏面的logging模塊,在前面學習線程安全時曾用來解決print被打斷的問題,這裏會介紹logging模塊的功能。 logging模塊是線程安全的,不需要客戶做任何特殊的工作。它通過使用線程鎖實現了這一點; 有一個鎖來序列化訪問模塊的共享數據, 每個處理程序還創建一個鎖來序列化訪問其底層 I/O。 使用工廠方法返回一個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 logging # DATEFMT="[%Y-%m-%d %H:%M:%s]" # FORMAT="%(asctime)s %(thread)d %(message)s" # logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT,filename="log.txt") # # 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(logger.parent)) ''' 子child的級別設置,不影響父parent的級別: ''' # import logging # # FORMAT="%(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)) # root.info("my root") # # loga=logging.getLogger(__name__) # print(2,id(loga),id(loga.parent)) # print(3,loga.getEffectiveLevel()) # # loga.warning("before") # loga.setLevel(28) # print(4,loga.getEffectiveLevel) # loga.info("after") # loga.warning("after") ''' Handler StreamHandler #不指定使用sys.strerr FileHandler #文件 _StderrHandler #標準輸出 NullHandler #什麼都不做 logger實例,如果設置了level,就用它和信息的級別比較,否則,繼承最近的祖先的level。 ''' # import logging # FORMAT ="%(asctime)s %(thread)d %(message)s" # logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt="[%Y-%m-%d %H:%M:%S]") # # root=logging.getLogger() # print("root",root.getEffectiveLevel()) # # log1=logging.getLogger("s") # log1.setLevel(logging.ERROR) # print("log1:",log1.getEffectiveLevel()) # log1.error("log1 error") # # log2=logging.getLogger("s.s1") # log2.setLevel(logging.WARNING) # print("log2",log2.getEffectiveLevel()) # log2.warning("log2 warning") # # ''' Handler: Handler控制日誌信息的輸出目的地,可以是控制檯、文件。 可以單獨設置level 可以單獨設置格式 可以設置過濾器 Handler StreamHandler #不指定使用sys.strerr FileHandler #文件 _StderrHandler #標準輸出 NullHandler #什麼都不做 ''' # import logging # # FORMAT ="%(asctime)s %(thread)d %(message)s" # logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt="[%Y-%m-%d %H:%M:%S]") # # root=logging.getLogger() # print("root:",root.getEffectiveLevel()) # # log1=logging.getLogger("s") # log1.setLevel(logging.ERROR) # print("log1:",log1.getEffectiveLevel()) # log1.error("log1.error") # # log2=logging.getLogger("s.s1") # log2.setLevel(logging.WARNING) # print("log2:",log2.getEffectiveLevel()) # log2.warning("log2.warning") ''' loggerLevel --> FilterConditions --> HandlerLevel --> 父LoggerFilter --> 父LoggerHandler --> RootHandler --> 標準輸出或記錄到日誌: ''' import logging,datetime FORMAT="%(asctime)s %(thread)s %(message)s" logging.basicConfig(level=logging.WARNING,format=FORMAT,datefmt="[%Y-%m-%d %H:%M:%S]") "--------------root----------------------" root=logging.getLogger() print(1,root.getEffectiveLevel()) "---------------------log1---------------------" log1=logging.getLogger("s") log1.setLevel(logging.ERROR) print(2,log1.getEffectiveLevel()) h1=logging.FileHandler("h1.log") h1.setLevel(logging.INFO) log1.addHandler(h1) "----------------log2-----------" log2=logging.getLogger("s.s2") log2.setLevel(logging.WARNING) print(3,log2.getEffectiveLevel()) h2=logging.FileHandler("h2.log") h2.setLevel(logging.WARNING) f2=logging.Filter("s.s3") h2.addFilter(f2) log2.addHandler(h2) log2.warning("4,log2 warning---{}".format(datetime.datetime.now()))
如果要實現多個模塊用一個定義好的logging模式,可以定義一個模板, 然後各個模塊在導入的時候,調用一下,就好啦。 文件一 log1 import logging from string import Template def lo(): logging.info("log1--------------") logging.warning("name:%s msg:%s","BeginMan","Hi") logging.warning("name:%s msg:%s"%("BeginMan","Hi")) logging.warning("name:{0} mag:{1}".format("b而過inMan","HI")) msg=Template("name:$who msg:$what") logging.warning(msg.substitute(who="BeginMan",what="Hi")) 文件log2 import logging import os FIFE =os.getcwd() import log1 def main(): logging.basicConfig(filename=os.path.join(FIFE,"log1.txt"),level=logging.INFO) logging.info("start-------------") log1.lo() logging.info("end---------") if __name__=="__main__": main()