python入門教程:logging 熱文推薦:

一、 基礎使用

1.1 logging使用場景

日誌是什麼?這個不用多解釋。百分之九十的程序都需要提供日誌功能。Python內置的logging模塊,爲我們提供了現成的高效好用的日誌解決方案。但是,不是所有的場景都需要使用logging模塊,下面是Python官方推薦的使用方法:

logging模塊定義了下表所示的日誌級別,按事件嚴重程度由低到高排列(注意是全部大寫!因爲它們是常量。):

默認級別是WARNING,表示只有WARING和比WARNING更嚴重的事件纔會被記錄到日誌內,低級別的信息會被忽略。因此,默認情況下,DEBUG和INFO會被忽略,WARING、ERROR和CRITICAL會被記錄。

有多種方法用來處理被跟蹤的事件。最簡單的方法就是把它們打印到終端控制檯上。或者將它們寫入一個磁盤文件內。

1.2 簡單範例

在什麼都不配置和設定的情況下,logging會簡單地將日誌打印在顯示器上,如下例所示:

import logging
logging.warning('Watch out!')  # 消息會被打印到控制檯上
logging.info('I told you so')  # 這行不會被打印,因爲級別低於默認級別

如果,將上面的代碼放在一個腳本里並運行,結果是:

WARNING:root:Watch out!

默認情況下,打印出來的內容包括日誌級別、調用者和具體的日誌信息。所有的這些內容都是可以自定義的,在後面我們會細說。

1.3 記錄到文件內

要把日誌輸出到文件內,就不能使用上面的方法了,但是logging模塊同樣給我們提供了一個相對便捷的手段,那就是logging.basicConfig()方法。

重新進入解釋器環境,執行下面的代碼:

import logging
logging.basicConfig(filename='example.log',level=logging.DEBUG)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')

然後打開本地的example.log文件,可以看到下面的日誌消息:

DEBUG:root:This message should go to the log file
INFO:root:So should this
WARNING:root:And this, too

我們通過level=logging.DEBUG參數,設定了日誌記錄的門檻。如果想在命令行調用時設置日誌級別,可以使用下面的選項:

--log=INFO

可以通過下面的方法來獲取用戶輸入的日誌級別參數:

numeric_level = getattr(logging, loglevel.upper(), None)
if not isinstance(numeric_level, int):
    raise ValueError('Invalid log level: %s' % loglevel)
logging.basicConfig(level=numeric_level, ...)

默認情況下,日誌會不斷的追加到文件的後面。如果你不想保存之前的日誌,每次都清空文件,然後寫入當前日誌,則可以如下設置:

logging.basicConfig(filename='example.log', filemode='w', level=logging.DEBUG)

關鍵是將filemode設置爲‘w’。

1.4 多模塊中同時使用日誌功能

如果你的程序包含多個文件(模塊),下面是個如何在其中組織日誌的例子:

# myapp.py
import logging
import mylib

def main():
    logging.basicConfig(filename='myapp.log', level=logging.INFO)
    logging.info('Started')
    mylib.do_something()
    logging.info('Finished')

if __name__ == '__main__':
    main()
# mylib.py
import logging

def do_something():
    logging.info('Doing something')

運行myapp.py模塊,你可以在myapp.log日誌文件中看到下面的內容:

INFO:root:Started
INFO:root:Doing something
INFO:root:Finished

1.5 日誌的變量數據

在logging模塊中通過百分符%方式的格式化控制,生成消息字符串,類同於字符串數據類型的格式化輸出,但也有不同之處。

import logging
logging.warning('%s before you %s', 'Look', 'leap!')

結果:

WARNING:root:Look before you leap!

可以看到兩個%s分別被‘Look’和‘leap!’替代了。

1.6 消息格式

要控制消息格式,獲得更多的花樣,可以提供format參數:

import logging
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logging.debug('This message should appear on the console')
logging.info('So should this')
logging.warning('And this, too')

輸出結果:

DEBUG:This message should appear on the console
INFO:So should this
WARNING:And this, too

對於%(levelname)s這種東西,是logging模塊內置的,可以被輸出到日誌中的對象,更多的內容在下面將會列舉。

1.7 附加時間信息

要在日誌內容中附加時間信息,可以在format字符串中添加%(asctime)s。

import logging
logging.basicConfig(format='%(asctime)s %(message)s')
logging.warning('is when this event was logged.')

輸出結果:

2010-12-12 11:41:42,612 is when this event was logged.

默認情況下,時間的顯示使用ISO8601格式。如果想做更深入的定製,可以提供datefmt參數,如下所示:

import logging
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logging.warning('is when this event was logged.')

輸出結果:

12/12/2010 11:46:36 AM is when this event was logged.

datefmt參數的定製和time模塊的time.strftime()一樣!

二、 高級用法

如果只是簡單地使用logging,那麼使用上面介紹的方法就可以了,如果要深度定製logging,那麼就需要對它有更深入的瞭解。下面的內容纔是基本的logging模塊的使用方法。

logging模塊採用了模塊化設計,主要包含四種組件:

Loggers:記錄器,提供應用程序代碼能直接使用的接口;

Handlers:處理器,將記錄器產生的日誌發送至目的地;

Filters:過濾器,提供更好的粒度控制,決定哪些日誌會被輸出;

Formatters:格式化器,設置日誌內容的組成結構和消息字段。

2.1 日誌流程圖

日誌事件信息在loggers和handlers中的邏輯流程如下圖所示:

下面是同時向屏幕和文件進行日誌輸出的流程:

2.2 Loggers記錄器

logging模塊的日誌功能是基於Logger類實現的。我們可以通過下面的方法獲取一個Logger類的實例(建議以模塊名命名logger實例)。

logger = logging.getLogger(__name__)

Logger是一個樹形層級結構,在使用debug(),info(),warn(),error(),critical()等方法之前必須先創建一個Logger的實例,即創建一個記錄器,如果沒有顯式的進行創建,則默認創建一個root logger,並應用默認的日誌級別(WARN),默認的處理器Handler(StreamHandler,即將日誌信息打印在標準輸出上),和默認的格式化器Formatter,就像我們在前面舉的那些例子一樣。

logger對象有三重功能。首先,提供應用程序調用的接口;其次,決定日誌記錄的級別;最後,將日誌內容傳遞到相關聯的handlers中。

總結logger對象的用法,可以分成兩類:配置和消息發送。

下面是最常用的配置方法:

Logger.setLevel():設置日誌記錄級別

Logger.addHandler()和Logger.removeHandler():爲logger對象添加或刪除handler處理器對象。

Logger.addFilter()和Logger.removeFilter():爲爲logger對象添加或刪除filter過濾器對象。

配置好logger對象後,就可以使用下面的方法創建日誌消息了:

Logger.debug(), Logger.info(), Logger.warning(), Logger.error(), and Logger.critical():創建對應級別的日誌,但不一定會被記錄。

Logger.exception():創建一個類似Logger.error()的日誌消息。不同的是Logger.exception()保存有一個追蹤棧。該方法只能在異常handler中調用。

Logger.log():顯式的創建一條日誌,是前面幾種方法的通用方法。

注意,getLogger()方法返回一個logger對象的引用,並以你提供的name參數命名,如果未提供名字,那麼默認爲‘root’。使用同樣的name參數,多次調用getLogger(),將返回同樣的logger對象。

2.3 Handlers處理器

Handlers對象是日誌信息的處理器、分發器。它們將日誌分發到不同的目的地。比如有時候我們希望將所有的日誌都記錄在本地文件內,將error及其以上級別的日誌發送到標準輸出stdout,將critical級別的日誌以郵件的方法發送給管理員。這就需要同時有三個獨立的handler,分別負責一個方向的日誌處理。

logging模塊使用較多的handlers有兩個,StreamHandler和FileHandler。

StreamHandler

標準輸出stdout(如顯示器)分發器。

創建方法: sh = logging.StreamHandler(stream=None)

FileHandler

將日誌保存到磁盤文件的處理器。

創建方法: fh = logging.FileHandler(filename, mode='a', encoding=None, delay=False)

handlers對象有下面的方法:

setLevel():和logger對象的一樣,設置日誌記錄級別。那爲什麼要設置兩層日誌級別呢?logger對象的日誌級別是全局性的,對所有handler都有效,相當於默認等級。而handlers的日誌級別只對自己接收到的logger傳來的日誌有效,進行了更深一層的過濾。

setFormatter():設置當前handler對象使用的消息格式。

addFilter() 和 removeFilter():配置或刪除一個filter過濾對象

logging模塊內置了下面的handler處理器,從字面上你就能看出它們的大概用途:

  • StreamHandler
  • FileHandler
  • BaseRotatingHandler
  • RotatingFileHandler
  • TimedRotatingFileHandler
  • SocketHandler
  • DatagramHandler
  • SMTPHandler
  • SysLogHandler
  • NTEventLogHandler
  • HTTPHandler
  • WatchedFileHandler
  • QueueHandler
  • NullHandler
    2.4 Formatters
    Formatter對象用來最終設置日誌信息的順序、結構和內容。其構造方法爲:
ft = logging.Formatter.__init__(fmt=None, datefmt=None, style=’%’)

如果不指定datefmt,那麼它默認是%Y-%m-%d %H:%M:%S樣式的。

style參數默認爲百分符%,這表示前面的fmt參數應該是一個%(<dictionary key>)s格式的字符串,而可以使用的logging內置的keys,如下表所示:

2.5 Filter過濾器

Handlers和Loggers可以使用Filters來完成比日誌級別更復雜的過濾。比如我們定義了filter = logging.Filter('a.b.c'),並將這個Filter添加到了一個Handler上,則使用該Handler的Logger中只有名字帶a.b.c前綴的Logger才能輸出其日誌。

創建方法: filter = logging.Filter(name='')

例如:

filter = logging.Filter('mylogger.child1.child2')  
fh.addFilter(filter)

則只會輸出下面格式的日誌,注意其用戶名:

2017-09-27 16:27:46,227 - mylogger.child1.child2 - DEBUG - logger1 debug message
2017-09-27 16:27:46,227 - mylogger.child1.child2 - DEBUG - logger1 debug message
2017-09-27 16:27:46,227 - mylogger.child1.child2 - DEBUG - logger1 debug message
2017-09-27 16:27:46,227 - mylogger.child1.child2 - DEBUG - logger1 debug message

2.6 配置日誌模塊
有三種配置logging的方法:

  • 創建loggers、handlers和formatters,然後使用Python的代碼調用上面介紹過的配置函數。
  • 創建一個logging配置文件,然後使用fileConfig()方法讀取它。
  • 創建一個配置信息字典然後將它傳遞給dictConfig()方法。
    下面的例子採用了第一種方法:
#simple_logging_module.py

import logging

# 創建logger記錄器
 logger = logging.getLogger('simple_example')
 logger.setLevel(logging.DEBUG)

# 創建一個控制檯處理器,並將日誌級別設置爲debug。
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)

# 創建formatter格式化器
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# 將formatter添加到ch處理器
ch.setFormatter(formatter)

# 將ch添加到logger
logger.addHandler(ch)

# 然後就可以開始使用了!
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

在命令行中運行上面的代碼,輸出結果如下:

$ python simple_logging_module.py
2005-03-19 15:10:26,618 - simple_example - DEBUG - debug message
2005-03-19 15:10:26,620 - simple_example - INFO - info message
2005-03-19 15:10:26,695 - simple_example - WARNING - warn message
2005-03-19 15:10:26,697 - simple_example - ERROR - error message
2005-03-19 15:10:26,773 - simple_example - CRITICAL - critical message

下面是使用第二種方法,logging配置文件的方式:

# simple_logging_config.py

import logging
import logging.config

logging.config.fileConfig('logging.conf') # 讀取config文件

# 創建logger記錄器
logger = logging.getLogger('simpleExample')

# 使用日誌功能
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

其中的logging.conf配置文件內容如下:

[loggers]
keys=root,simpleExample

[handlers]
keys=consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=

在命令行中執行代碼,結果如下:

$ python simple_logging_config.py
2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message
2005-03-19 15:38:55,979 - simpleExample - INFO - info message
2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message
2005-03-19 15:38:56,055 - simpleExample - ERROR - error message
2005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message

Python官方更推薦第三種新的配置方法,類字典形式的配置信息,因爲Python的字典運用形式多樣,操作靈活。比如,你可以通過JSON格式保存字典,或者YAML格式保存信息,然後讀取成字典。當然,你也可以直接在Python代碼裏編寫傳統的帶有配置信息的字典。一切都是基於鍵值對形式的就OK。

下面的例子就是基於YAML配置文件的日誌。logging.conf.yaml配置文件內容如下:

version: 1
formatters:
  simple:
    format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
handlers:
  console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: simple
    stream: ext://sys.stdout
loggers:
  simpleExample:
    level: DEBUG
    handlers: [console]
    propagate: no
root:
  level: DEBUG
  handlers: [console]

這裏要先通過pip安裝yaml模塊:

pip install pyyaml

yaml模塊的使用很簡單,使用open()方法打開一個yaml文件對象,然後使用yaml的load()方法將文件內容讀成一個Python的字典對象。最後我們根據這個字典對象,使用logging.conf的dictConfig()方法,獲取配置信息。如下代碼所示:

import logging
import logging.config
import yaml

# 通過yaml文件配置logging
f = open("logging.conf.yaml")
dic = yaml.load(f)
f.close()
logging.config.dictConfig(dic)

# 創建logger
logger = logging.getLogger('simpleExample')

# 輸出日誌
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

輸出結果:

2017-09-27 17:41:09,241 - simpleExample - DEBUG - debug message
2017-09-27 17:41:09,242 - simpleExample - INFO - info message
2017-09-27 17:41:09,242 - simpleExample - WARNING - warn message
2017-09-27 17:41:09,242 - simpleExample - ERROR - error message
2017-09-27 17:41:09,242 - simpleExample - CRITICAL - critical message

熱文推薦:

全網首發!最新最全的python學習資料路線整合

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章