python3 logging

https://docs.python.org/3.5/library/logging.html,先3.5是由於我當前的python 版本是3.5html

之因此要來詳細的寫是由於以前學django時也有這個,不是很理解,因此這裏就多瞭解下。python

寫到後面發現整個文章一點條理都沒有,但因爲內容比較多,就不從新整理了django

logging框架中主要由四個部分組成:app

    Loggers expose the interface that application code directly uses.
    Handlers send the log records (created by loggers) to the appropriate destination.
    Filters provide a finer grained facility for determining which log records to output.
    Formatters specify the layout of log records in the final output.

 

  • Loggers: 提供應用直接調用的接口
  • Handlers: 決定將日誌記錄發送至正確的目的地
  • Filters: 提供更精細的決定哪些日誌輸出的能力,簡單點說就是決定哪些輸出哪些不輸出
  • Formatters: 制定最終輸出的格式。

logger對象

事實上logger是不直接實例化的,可是咱們能夠經過模塊級別的函數logging.getLogger(name)來調用。若是屢次經過同一個名字調用getLogger()將只能獲得對同一個對象的引用。
框架

注意: logging.getLogger(name) 中的name是一個支持經過「.」(點號)分層級的值。ide

例如: 你定義一個logger: foo,那麼foo.bar, foo.baz,就都算做它的子代,就是繼承,有父子關係。函數

logger名字的層級與python中包的層級是一致的。因此爲了區分它,若是你基於模塊來組織logger,spa

那麼建議你使用:logging.getLogger(__name__)這種形式,由於對於模塊而言,在pythondebug

包的命名空間中__name__的值就是模塊的名字。日誌

 

經常使用方法:

Logger.setLevel(lvl):

將logger的門限設置爲lvl,低於此等級的信息將被忽略,當一個Logger被創造出來時,它的等級被設置爲:

NOTSET(未設置) 這樣的結果就是: 若是它是一個root logger,它將處理全部的信息,若是沒有root logger

它將繼承父級的logger等級。Note: root logger可經過level waring來建立,注意這裏是個坑,

事實上默認root logger等級爲warning,不要搞錯了

 

 級別設定:前面是名字,後面是對應的數字值

 

Logger.exception(msg, *args, **kwargs)

以error級別來記錄信息,異常信息也會被添加到信息(message),須要exception handler調用才行

Logger.addFilter(filt)

添加指定的過濾器

Logger.removeFilter(filt)

移除指定的過濾器

這裏的方法多得讓人想撞死在屏幕上,之後慢慢更新吧。

Handler

  • Handler.setLevel(lel):指定被處理的信息級別,低於lel級別的信息將被忽略
  • Handler.setFormatter():給這個handler選擇一個格式
  • Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個filter對象

handler有多達15種,這裏只說下常見的幾種:

1.logging.StreamHandler 

發送信息到流,類文件對象便可,如終端,文件等

2.logging.FileHandler

發送信息到硬盤文件

3.logging.RotatingFileHandler
這個Handler相似於上面的FileHandler,可是它能夠管理文件大小,輪詢日誌文件(不知道是否是檢測日誌文件大小)。

當文件達到必定大小以後,它會自動將當前日誌文件更名,而後建立一個新的同名日誌文件繼續輸出。

4.logging.handlers.TimedRotatingFileHandler

這個Handler和RotatingFileHandler相似,不過,它沒有經過判斷文件大小來決定什麼時候從新建立日誌文件,

而是間隔必定時間就 自動建立新的日誌文件。

Formatter

Formatters 決定了記錄格式。Formatter會將傳遞來的信息拼接成一條具體的字符串,

默認狀況下Format只會將信息%(message)s直接打印出來。Format中有一些自帶的LogRecord屬性可使用,以下表格:

其中lineno,pathname,通過實測了,並非有些博客裏說的什麼當前日誌記錄的行號。後面會有實例。

這裏有一個簡單的應用 的例子,記錄出錯信息:

#!/usr/bin/env python
#coding:utf-8
# Created by Andy @ 2017/6/22


import logging


logging.basicConfig(level=logging.DEBUG,
        format='%(asctime)s %(pathname)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s ',
        datefmt='%a, %d %b %Y %H:%M:%S',
        filename=r'D:\Coding\oldboy\day13 module\test.log',
        filemode='w')


def login():
	while True:
		try:
			name = input('Input user name:')
			password = int(input('Input password:')) # 這裏故意轉成整型,觸發異常
			if name == 'andy' and password == 'nopasswd':
				print('logging succeed!')
		except ValueError as e:
			logging.debug(e)
			break

if __name__ == '__main__':
	login()

 

 終端驗證

Input user name:andy
Input password:nopasswd

Process finished with exit code 0

 打開test.log:

Fri, 23 Jun 2017 09:56:40 D:/Coding/oldboy/day13 module/log.py log.py[line:24] DEBUG invalid literal for int() with base 10: 'nopasswd' 

 注意看,lineno 並非在日誌裏面的行號,而是你代碼的行號,在24行調用了logging.debug(e)

 這裏現定義一個一simple_logger:

#!/usr/bin/env python
#coding:utf-8
# Created by Andy @ 2017/6/22


import logging
import os

log_path = os.path.join(os.getcwd(),'test.log')

logging.basicConfig(level=logging.DEBUG,
        format='%(asctime)s %(pathname)s line:%(lineno)d %(message)s ',
        datefmt='%Y-%m-%d %H:%M:%S', # 將日期格式化成正常模式
        filename=log_path,
        filemode='a') # 指定成追加模式,默認就是追加,因此這句非必須

simple_logger = logging.getLogger('simple')
fh = logging.StreamHandler() #輸出到終端
fh.setLevel(level = logging.WARNING) #等級比默認的高,但調用時必須一致
formatter = logging.Formatter("%(asctime)s %(message)s %(levelname)s")
fh.setFormatter(formatter)
simple_logger.addHandler(fh)


def login():
	while True:
		try:
			name = input('Input user name:')
			password = int(input('Input password:')) # 這裏故意轉成整型,觸發異常
			if name == 'andy' and password == 'nopasswd':
				print('logging succeed!')
		except ValueError as e:
			simple_logger.warning(e)
			break

if __name__ == '__main__':
	login()

 

 運行:

終端輸出:

Input user name:andy
Input password:andy
2017-06-24 09:55:57,395 invalid literal for int() with base 10: 'andy' WARNING

 test.log文件:

2017-06-24 09:55:57 D:/Coding/oldboy/day13 module/log.py line:33 invalid literal for int() with base 10: 'andy' 

 這晨須要 注意的是:由於默認的logger等級是debug,因此它什麼消息都會輸出,而simple_logger則只輸出比自身高等級的信息,

而且:調用simple_logger時必須比定義的等級高於或者等於定義的等級,這句話什麼意思呢?看上面的例子,simple_logger

定義時的等級爲warning,那麼你調用時最少得warning等級,或者比它高的critical才能正常打印消息(它規定就是這樣),不然你是看不到任何效果的

(這裏坑了很久,一直沒消息打印而找不到緣由,root logger默認等級是warning,而非Noset),可是若是你調用的等級比較低,

並不影響root 這個logger打印日誌信息。

填坑來了:

若是沒指定默認的logger的等級,那麼默認的等級warning就會生效,因此纔出現上面的狀況,若是須要將debug等級的信息也輸入,那麼,這裏須要加一條:

simple_logger.setLevel(logging.DEBUG)
# 若是不設置此logger的級別,那麼handler的記錄是從logger傳過來的,也就是默認從logger的warning來的

 

 

 

 

下面是一個使用配置文件 的例子:

#!/usr/bin/env python
#coding:utf-8
# Created by Andy @ 2017/6/25


import logging
import logging.config

logging.config.fileConfig('logging.conf')

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

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

 

 

 配置文件:

[loggers]
keys=root,simpleExample

[handlers]
keys=consoleHandler,simpleHandler

[formatters]
keys=consoleFormatter,simpleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_simpleExample]
level=INFO
handlers=simpleHandler
qualname=simpleExample
propagate=1

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

[handler_simpleHandler]
class=FileHandler
level=INFO
formatter=simpleFormatter
args=('simple.log','w')


[formatter_consoleFormatter]
format=%(levelname)s :%(message)s

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

 以前的例子沒已經刪除了,找到緣由:propagate=1 ,只有當propagate 爲True時,logger的信息才能傳到上一級logger,或者說父logger,若是你設置爲0

那麼,就只有文件中有寫入,而終端不會有信息打印出來。

相關文章
相關標籤/搜索