python3 logging


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

之所以要來詳細的寫是因為之前學django時也有這個,不是很理解,所以這里就多了解下。

寫到后面發現整個文章一點條理都沒有,但由於內容比較多,就不重新整理了

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

    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是一個支持通過“.”(點號)分層級的值。

例如: 你定義一個logger: foo,那么foo.bar, foo.baz,就都算作它的子代,就是繼承,有父子關系。

logger名字的層級與python中包的層級是一致的。所以為了區分它,如果你基於模塊來組織logger,

那么建議你使用:logging.getLogger(__name__)這種形式,因為對於模塊而言,在python

包的命名空間中__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

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM