Python 日志功能詳解

Python 日志功能詳解

本文首發(fā)于Gevin的博客

原文鏈接:Python 日志功能詳解

未經 Gevin 授權低淡,禁止轉載

軟件開發(fā)中通過日志記錄程序的運行情況是一個開發(fā)的好習慣椅邓,對于錯誤排查和系統(tǒng)運維都有很大幫助炎咖。Python標準庫自帶日志模塊厕吉,已經足夠強大受扳,大部分情況下序无,python程序的日志功能直接調用標準庫的日志模塊即可验毡『獯矗《The Hitchhiker’s Guide to Python》已對“日志”進行了詳細闡述,python的官方文檔也對日志做了說明晶通,但Gevin依然感覺璃氢,通過這些英文資料,還不能讓初學者在短時間迅速掌握python日志模塊的使用狮辽,因此按照自己的思路一也,把相關內容做了如下整理,并附加一些Gevin認為文檔中沒有說明清楚的內容喉脖。

1. 基本用法

如果開發(fā)輕量級的應用椰苟,對日志的需求也比較簡單,直接參考如下示例树叽,在相關代碼邏輯中加入日志功能即可:

#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import logging

logging.debug('debug message')
logging.info('info message')
logging.warn('warn message')
logging.error('error message')
logging.critical('critical message')

output:

WARNING:root:warn message
ERROR:root:error message
CRITICAL:root:critical message

默認情況下舆蝴,logging模塊將日志打印到屏幕上,日志級別為WARNING(即只有日志級別等于或高于WARNING的日志信息才會輸出)题诵,日志格式為 warning level:instance name:warning message

1.1 將日志記錄到文件中

將日志記錄到文件中洁仗,只需在調用logging模塊記錄日志前,做個簡單的配置即可:

#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import logging

# 配置日志文件和日志級別
logging.basicConfig(filename='logger.log', level=logging.INFO)

logging.debug('debug message')
logging.info('info message')
logging.warn('warn message')
logging.error('error message')
logging.critical('critical message')

本樣例在記錄日志前性锭,通過logging.basicConfig做簡單配置赠潦,將日志記錄到日志文件logger.log中,也修改了默認的日志等級草冈,高于或等于INFO級別的日志信息她奥,都會記錄到日志文件中。

2. 更加完善的日志功能

2.1 幾個關鍵概念

如果要更加靈活的使用日志模塊疲陕,首先要了解日志模塊是怎樣工作的方淤。 LoggerHandler蹄殃,FormatterFilter是日志模塊的幾個基本概念携茂,日志模塊的工作原理要從這四個基本概念說起。

  • Logger 即記錄器诅岩,Logger提供了日志相關功能的調用接口讳苦。
  • Handler 即處理器,將(記錄器產生的)日志記錄發(fā)送至合適的目的地吩谦。
  • Filter 即過濾器鸳谜,提供了更好的粒度控制,它可以決定輸出哪些日志記錄式廷。
  • Formatter 即格式化器咐扭,指明了最終輸出中日志記錄的格式。

2.1.1 Logger

Logger 即“記錄器”,Logger對象實例是日志記錄功能的載體蝗肪,如:

#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import logging

logger = logging.getLogger('simple_example')

logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

值得一提的是袜爪,Logger對象從不直接實例化,而是通過模塊級的功能logging.getLogger(name)創(chuàng)建Logger實例薛闪。調用 logging.getLogger(name) 功能時辛馆,如果傳入的name參數(shù)值相同,則總是返回同一個Logger對象實例的引用豁延。

如果沒有顯式的進行創(chuàng)建昙篙,則默認創(chuàng)建一個root logger,并應用默認的日志級別(WARN)诱咏、默認的處理器Handler(StreamHandler苔可,即將日志信息打印輸出在標準輸出上),和默認的格式化器Formatter(默認的格式即為第一個簡單使用程序中輸出的格式)袋狞。

Logger類包含的成員和方法可以查看官方文檔硕蛹。

2.1.2 Handler

Handler 將日志信息發(fā)送到設置的位置,可以通過Logger對象的addHandler()方法為Logger對象添加0個或多個handler硕并。一種日志的典型應用場景為蛮艰,系統(tǒng)希望將所有的日志信息保存到log文件中棋傍,其中日志等級等于或高于ERROR的消息還要在屏幕標準輸出上顯示,日志等級為CRITICAL的還需要發(fā)送郵件通知评肆;這種場景就需要3個獨立的handler來實現(xiàn)需求乙濒,這三個handler分別與指定的日志等級或日志位置做響應

需要一提的是陕赃,為Logger配置的handler不能是Handler基類對象,而是Handler的子類對象颁股,常用的Handler為StreamHandler, FileHandler么库, 和NullHandler,Handler的全部子類及詳細介紹可以查看官方文檔相應頁面如果需要了解更多關于Handler的信息甘有,直接查看官方文檔即可诉儒。

2.1.3 Formatter

Formatter 用于設置日志輸出的格式,與前兩個基本概念不同的是亏掀,該類可以直接初始化對象忱反,即 formatter=logging.Formatter(fmt=None, datefmt=None),創(chuàng)建formatter時滤愕,傳入分別fmtdatefmt參數(shù)來修改日志格式和時間格式温算,默認的日志格式為%(asctime)s - %(levelname)s - %(message)s,默認的時間格式為%Y-%m-%d %H:%M:%S

2.1.4 Filter

Filter 可用于Logger對象或Handler對象间影,用于提供比日志等級更加復雜的日志過濾方式注竿。默認的filter只允許在指定logger層級下的日志消息通過過濾。例如,如果把filter設置為filter=logging.Filter('A.B')巩割,則logger ‘A.B’, ‘A.B.C’, ‘A.B.C.D’, ‘A.B.D’ 產生的日志信息可以通過過濾裙顽,但'A.BB', 'B.A.B'均不行。如果以空字符串初始化filter喂分,則所有的日志消息都可以通過過濾锦庸。

Filter在日志功能配置中是非必須的,只在對日志消息過濾需求比較復雜時配置使用即可蒲祈。

2.2 日志產生流程

日志產生的流程邏輯參考下圖即可:

2.3 日志模塊的使用

日志模塊使用的關鍵是“日志的配置”甘萧,日志配置好后,只要調用logger.INFO(), logger.ERROR()等方法即可創(chuàng)建日志內容梆掸。

開發(fā)者可以通過三種方法配置日志模塊:

  1. 在Python代碼中顯示創(chuàng)建loggers, handlers, formatters甚至filters扬卷,并調用這幾個對象中的各個配置函數(shù)來完成日志配置
  2. 將配置信息寫到配置文件中,然后讀取配置文件信息來完成日志配置
  3. 將配置信息寫到一個Dict中酸钦,然后讀取這個配置字典來完成日志配置

2.3.1 通過代碼配置并使用日志模塊

通過代碼配置日志模塊簡單方便怪得,但如果需要修改配置時,需要改代碼卑硫,因此不建議在大型項目中使用這種方法徒恋。

通過代碼配置日志模塊可以很好的理解日志模塊的工作原理,用于學習欢伏,是一個很好的案例入挣,因此Gevin也在下文中對此詳細介紹。

1. 創(chuàng)建Logger

import logging

# create logger
logger = logging.getLogger('simple_example')

# Set default log level
logger.setLevel(logging.DEBUG)

2. 創(chuàng)建Handler


# create console handler and set level to warn

ch = logging.StreamHandler()
ch.setLevel(logging.WARN)

3. 創(chuàng)建Fomatter

# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

4. 配置Logger

# add formatter to ch
ch.setFormatter(formatter)

# add ch to logger
# The final log level is the higher one between the default and the one in handler
logger.addHandler(ch)

5. 使用日志模塊

logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

6. 完整的例子


#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import logging

# create logger
logger = logging.getLogger('simple_example')

# Set default log level
logger.setLevel(logging.DEBUG)


ch = logging.StreamHandler()
ch.setLevel(logging.WARN)

ch2 = logging.FileHandler('logging.log')
ch2.setLevel(logging.INFO)

# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# add formatter to ch
ch.setFormatter(formatter)
ch2.setFormatter(formatter)

# add ch to logger
# The final log level is the higher one between the default and the one in handler
logger.addHandler(ch)
logger.addHandler(ch2)

# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

2.3.2 通過配置文件配置并使用日志模塊

通過配置文件配置日志模塊時硝拧,配置文件通常使用.ini格式径筏,日志模塊需要調用fileConfig,即logging.config.fileConfig('logging_config.ini')障陶,然后logger的使用方法與上面相同:


#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import logging
import logging.config

logging.config.fileConfig('logging_config.ini')

# create logger
logger = logging.getLogger('root')

# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

其中滋恬,logging_config.ini文件內容如下:

[loggers]
keys=root,simpleExample

[handlers]
keys=consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_simpleExample]
level=INFO
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

通過配置文件配置日志模塊,邏輯與代碼中配置一樣抱究,也是把logger, handlerformatter定義好恢氯,然后組裝到一起即可,無非ini配置和代碼配置時的語法不通而已媳维,開發(fā)者在基于ini文件配置日志模塊時酿雪,只要參考上面例子做相應修改即可。

2.3.3 通過Dict對象配置并使用日志模塊

基于Dict對象配置日志模塊在python中應用廣泛侄刽,很多Django或Flask項目都采用這種方式指黎,但很多官方文檔對這種方法介紹并不多,因此州丹,本文提供一個使用樣例醋安,以后開發(fā)中參考該樣例修改一下即可杂彭。


#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import logging
import logging.config

config = {
    'version': 1,
    'formatters': {
        'simple': {
            'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'formatter': 'simple'
        },
        'file': {
            'class': 'logging.FileHandler',
            'filename': 'logging.log',
            'level': 'DEBUG',
            'formatter': 'simple'
        },
    },
    'loggers':{
        'root': {
            'handlers': ['console'],
            'level': 'DEBUG',
            # 'propagate': True,
        },
        'simple': {
            'handlers': ['console', 'file'],
            'level': 'WARN',
        }
    }
}

logging.config.dictConfig(config)


print 'logger:'
logger = logging.getLogger('root')

logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')


print 'logger2:'
logger2 = logging.getLogger('simple')

logger2.debug('debug message')
logger2.info('info message')
logger2.warn('warn message')
logger2.error('error message')
logger2.critical('critical message')


注:

日志的嚴重等級

Log Level如下,嚴重等級為NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL, 嚴重程度依次遞增

CRITICAL: 50
ERROR: 40
WARNING: 30
INFO: 20
DEBUG: 10
NOTSET: 0

修改日志消息的格式

日志的默認顯示格式為:%(asctime)s - %(name)s - %(levelname)s - %(message)s吓揪,如果只想顯示日志等級和日志信息亲怠,可以把格式改為:%(levelname)s:%(message)s,想了解全部Formatter中的可用變量柠辞,請查閱LogRecord attributes

日期時間的默認格式是ISO8601团秽,修改日期時間格式請參考 time.strftime()

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市叭首,隨后出現(xiàn)的幾起案子习勤,更是在濱河造成了極大的恐慌,老刑警劉巖焙格,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件图毕,死亡現(xiàn)場離奇詭異,居然都是意外死亡眷唉,警方通過查閱死者的電腦和手機予颤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冬阳,“玉大人蛤虐,你說我怎么就攤上這事「闻悖” “怎么了笆焰?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長见坑。 經常有香客問我,道長捏检,這世上最難降的妖魔是什么荞驴? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮贯城,結果婚禮上熊楼,老公的妹妹穿的比我還像新娘。我一直安慰自己能犯,他們只是感情好鲫骗,可當我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著踩晶,像睡著了一般执泰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上渡蜻,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天术吝,我揣著相機與錄音计济,去河邊找鬼。 笑死排苍,一個胖子當著我的面吹牛沦寂,可吹牛的內容都是我干的。 我是一名探鬼主播淘衙,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼传藏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了彤守?” 一聲冷哼從身側響起毯侦,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎遗增,沒想到半個月后叫惊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡做修,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年霍狰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饰及。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡蔗坯,死狀恐怖,靈堂內的尸體忽然破棺而出燎含,到底是詐尸還是另有隱情宾濒,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布屏箍,位于F島的核電站绘梦,受9級特大地震影響,放射性物質發(fā)生泄漏赴魁。R本人自食惡果不足惜卸奉,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望颖御。 院中可真熱鬧榄棵,春花似錦、人聲如沸潘拱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芦岂。三九已至瘪弓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間禽最,已是汗流浹背杠茬。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工月褥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瓢喉。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓宁赤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親栓票。 傳聞我的和親對象是個殘疾皇子决左,可洞房花燭夜當晚...
    茶點故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內容

  • 本文章是我大概三年前,在上家單位使用 Python 工作時結合官方文檔做的整理∽咛埃現(xiàn)在 Python 官方文檔聽說已...
    好吃的野菜閱讀 216,069評論 14 232
  • 本文翻譯自logging howto 基礎教程 日志是跟蹤軟件運行時發(fā)生事件的一種手段佛猛。Python開發(fā)者在代碼中...
    大蟒傳奇閱讀 4,246評論 0 17
  • 前言 在自動化測試實踐過程中,必不可少的就是進行日志管理坠狡,方便調試和生產問題追蹤继找,python提供了logg...
    苦葉子閱讀 806評論 0 0
  • 本篇文章主要對 python logging 的介紹加深理解。更主要是 討論在多進程環(huán)境下如何使用logging ...
    doudou0o閱讀 40,958評論 52 42
  • 這篇文章其實我真的構思很久了逃沿,雖然現(xiàn)在已經戒了屁股癮婴渡,但是游戲里我所學到的東西真的不只是一星半點。所以現(xiàn)...
    虛妄青嵐閱讀 469評論 11 4