首頁  >  文章  >  後端開發  >  Python中內建的日誌模組logging用法詳解

Python中內建的日誌模組logging用法詳解

WBOY
WBOY原創
2016-08-04 08:55:501024瀏覽

logging模組簡介

Python的logging模組提供了通用的日誌系統,可以方便第三方模組或是應用使用。這個模組提供不同的日誌級別,並且可以採用不同的方式記錄日誌,例如文件,HTTP GET/POST,SMTP,Socket等,甚至可以自己實現具體的日誌記錄方式。
logging模組與log4j的機制是一樣的,只是具體的實作細節不同。模組提供logger,handler,filter,formatter。

  • logger:提供日誌接口,供應用程式碼使用。 logger最長用的操作有兩類:設定和發送日誌訊息。可以透過logging.getLogger(name)取得logger對象,如果不指定name則傳回root對象,多次使用相同的name呼叫getLogger方法傳回同一個logger對象。
  • handler:將日誌記錄(log record)傳送到適當的目的地(destination),例如文件,socket等。一個logger物件可以透過addHandler方法添加0到多個handler,每個handler又可以定義不同日誌級別,以實現日誌分級過濾顯示。
  •  filter:提供一種優雅的方式決定一個日誌記錄是否要傳送到handler。
  •  formatter:指定日誌記錄輸出的具體格式。 formatter的建構方法需要兩個參數:訊息的格式字串和日期字串,這兩個參數都是可選的。

與log4j類似,logger,handler和日誌訊息的呼叫可以有具體的日誌等級(Level),只有在日誌訊息的層級大於logger和handler的等級。

logging用法解析

1. 初始化 logger = logging.getLogger("endlesscode"),getLogger()方法後面最好加上所要日誌記錄的模組名字,後面的日誌格式中的%(name)s 對應的是這裡的模組名字
2. 設定等級 logger.setLevel(logging.DEBUG),Logging中有NOTSET 3. Handler,常用的是StreamHandler和FileHandler,windows下你可以簡單理解為一個是console和文件日誌,一個打印在CMD視窗上,一個記錄在一個文件上
4. formatter,定義了最終log資訊的順序,結構和內容,我喜歡用這樣的格式'[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m -%d %H:%M:%S',
%(name)s Logger的名字
%(levelname)s 文字形式的日誌等級
%(message)s 用戶輸出的訊息
%(asctime)s 字串形式的當前時間。預設格式是 “2003-07-08 16:49:45,896”。逗號後面的是毫秒
%(levelno)s 數位形式的日誌等級
%(pathname)s 呼叫日誌輸出函數的模組的完整路徑名,可能沒有
%(filename)s 呼叫日誌輸出函數的模組的檔案名稱
%(module)s  呼叫日誌輸出函數的模組名稱
%(funcName)s 呼叫日誌輸出函數的函數名稱
%(lineno)d 呼叫日誌輸出函數的語句所在的程式碼行
%(created)f 當前時間,以UNIX標準的表示時間的浮 點數表示
%(relativeCreated)d 輸出日誌訊息時的,自Logger創建以 來的毫秒數
%(thread)d 線程ID。可能沒有
%(threadName)s 執行緒名。可能沒有
%(process)d 進程ID。可能沒有
5. 記錄 使用object.debug(message)來記錄日誌
下面來寫一個實例,在CMD視窗上只打出error以上等級的日誌,但在日誌中打出debug以上的資訊

import logging
logger = logging.getLogger("simple_example")
logger.setLevel(logging.DEBUG)
# 建立一个filehandler来把日志记录在文件里,级别为debug以上
fh = logging.FileHandler("spam.log")
fh.setLevel(logging.DEBUG)
# 建立一个streamhandler来把日志打在CMD窗口上,级别为error以上
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
# 设置日志格式
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
ch.setFormatter(formatter)
fh.setFormatter(formatter)
#将相应的handler添加在logger对象中
logger.addHandler(ch)
logger.addHandler(fh)
# 开始打日志
logger.debug("debug message")
logger.info("info message")
logger.warn("warn message")
logger.error("error message")
logger.critical("critical message")

運行一下將會看到CMD視窗只記錄兩條,spam.log中記錄了五條日誌

2016712145241018.jpg (773×353)

當一個專案比較大的時候,不同的文件中都要用到Log,可以考慮將其封裝為一個類別來使用

#! /usr/bin/env python
#coding=gbk
import logging,os

class Logger:
 def __init__(self, path,clevel = logging.DEBUG,Flevel = logging.DEBUG):
  self.logger = logging.getLogger(path)
  self.logger.setLevel(logging.DEBUG)
  fmt = logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S')
  #设置CMD日志
  sh = logging.StreamHandler()
  sh.setFormatter(fmt)
  sh.setLevel(clevel)
  #设置文件日志
  fh = logging.FileHandler(path)
  fh.setFormatter(fmt)
  fh.setLevel(Flevel)
  self.logger.addHandler(sh)
  self.logger.addHandler(fh)

 def debug(self,message):
  self.logger.debug(message)

 def info(self,message):
  self.logger.info(message)

 def war(self,message):
  self.logger.warn(message)

 def error(self,message):
  self.logger.error(message)

 def cri(self,message):
  self.logger.critical(message)

if __name__ =='__main__':
 logyyx = Logger('yyx.log',logging.ERROR,logging.DEBUG)
 logyyx.debug('一个debug信息')
 logyyx.info('一个info信息')
 logyyx.war('一个warning信息')
 logyyx.error('一个error信息')
 logyyx.cri('一个致命critical信息')

這樣每次使用的時候只要實例化一個物件就可以了

logobj = Logger(‘filename',clevel,Flevel)

如果想在CMD視窗中對於error的日誌標紅,warning的日誌標黃,那麼可以使用ctypes模組

2016712145318276.jpg (732×225)

#! /usr/bin/env python
#coding=gbk
import logging,os
import ctypes

FOREGROUND_WHITE = 0x0007
FOREGROUND_BLUE = 0x01 # text color contains blue.
FOREGROUND_GREEN= 0x02 # text color contains green.
FOREGROUND_RED = 0x04 # text color contains red.
FOREGROUND_YELLOW = FOREGROUND_RED | FOREGROUND_GREEN

STD_OUTPUT_HANDLE= -11
std_out_handle = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
def set_color(color, handle=std_out_handle):
 bool = ctypes.windll.kernel32.SetConsoleTextAttribute(handle, color)
 return bool

class Logger:
 def __init__(self, path,clevel = logging.DEBUG,Flevel = logging.DEBUG):
  self.logger = logging.getLogger(path)
  self.logger.setLevel(logging.DEBUG)
  fmt = logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S')
  #设置CMD日志
  sh = logging.StreamHandler()
  sh.setFormatter(fmt)
  sh.setLevel(clevel)
  #设置文件日志
  fh = logging.FileHandler(path)
  fh.setFormatter(fmt)
  fh.setLevel(Flevel)
  self.logger.addHandler(sh)
  self.logger.addHandler(fh)

 def debug(self,message):
  self.logger.debug(message)

 def info(self,message):
  self.logger.info(message)

 def war(self,message,color=FOREGROUND_YELLOW):
  set_color(color)
  self.logger.warn(message)
  set_color(FOREGROUND_WHITE)

 def error(self,message,color=FOREGROUND_RED):
  set_color(color)
  self.logger.error(message)
  set_color(FOREGROUND_WHITE)

 def cri(self,message):
  self.logger.critical(message)

if __name__ =='__main__':
 logyyx = Logger('yyx.log',logging.WARNING,logging.DEBUG)
 logyyx.debug('一个debug信息')
 logyyx.info('一个info信息')
 logyyx.war('一个warning信息')
 logyyx.error('一个error信息')
 logyyx.cri('一个致命critical信息')

多模組使用logging
logging模組保證在同一個python解釋器內,多次調用logging.getLogger('log_name')都會傳回同一個logger實例,即使是在多個模組的情況下。所以典型的多模組場景下使用logging的方式是在main模組中配置logging,這個配置會作用於多個的子模組,然後在其他模組中直接透過getLogger取得Logger物件。
設定檔:

[loggers] 
keys=root,main 
 
[handlers] 
keys=consoleHandler,fileHandler 
 
[formatters] 
keys=fmt 
 
[logger_root] 
level=DEBUG 
handlers=consoleHandler 
 
[logger_main] 
level=DEBUG 
qualname=main 
handlers=fileHandler 
 
[handler_consoleHandler] 
class=StreamHandler 
level=DEBUG 
formatter=fmt 
args=(sys.stdout,) 
 
[handler_fileHandler] 
class=logging.handlers.RotatingFileHandler 
level=DEBUG 
formatter=fmt 
args=('tst.log','a',20000,5,) 
 
[formatter_fmt] 
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s 
datefmt= 

主模組main.py:

import logging 
import logging.config 
 
logging.config.fileConfig('logging.conf') 
root_logger = logging.getLogger('root') 
root_logger.debug('test root logger...') 
 
logger = logging.getLogger('main') 
logger.info('test main logger') 
logger.info('start import module \'mod\'...') 
import mod 
 
logger.debug('let\'s test mod.testLogger()') 
mod.testLogger() 
 
root_logger.info('finish test...') 

子模組mod.py:

import logging 
import submod 
 
logger = logging.getLogger('main.mod') 
logger.info('logger of mod say something...') 
 
def testLogger(): 
  logger.debug('this is mod.testLogger...') 
  submod.tst() 

子子模組submod.py:

import logging 
 
logger = logging.getLogger('main.mod.submod') 
logger.info('logger of submod say something...') 
 
def tst(): 
  logger.info('this is submod.tst()...') 

然后运行python main.py,控制台输出:

2012-03-09 18:22:22,793 - root - DEBUG - test root logger... 
2012-03-09 18:22:22,793 - main - INFO - test main logger 
2012-03-09 18:22:22,809 - main - INFO - start import module 'mod'... 
2012-03-09 18:22:22,809 - main.mod.submod - INFO - logger of submod say something... 
2012-03-09 18:22:22,809 - main.mod - INFO - logger say something... 
2012-03-09 18:22:22,809 - main - DEBUG - let's test mod.testLogger() 
2012-03-09 18:22:22,825 - main.mod - DEBUG - this is mod.testLogger... 
2012-03-09 18:22:22,825 - main.mod.submod - INFO - this is submod.tst()... 
2012-03-09 18:22:22,841 - root - INFO - finish test... 

可以看出,和预想的一样,然后在看一下tst.log,logger配置中的输出的目的地:

2012-03-09 18:22:22,793 - main - INFO - test main logger 
2012-03-09 18:22:22,809 - main - INFO - start import module 'mod'... 
2012-03-09 18:22:22,809 - main.mod.submod - INFO - logger of submod say something... 
2012-03-09 18:22:22,809 - main.mod - INFO - logger say something... 
2012-03-09 18:22:22,809 - main - DEBUG - let's test mod.testLogger() 
2012-03-09 18:22:22,825 - main.mod - DEBUG - this is mod.testLogger... 
2012-03-09 18:22:22,825 - main.mod.submod - INFO - this is submod.tst()... 

tst.log中没有root logger输出的信息,因为logging.conf中配置了只有main logger及其子logger使用RotatingFileHandler,而root logger是输出到标准输出。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn