python模塊logging

在現(xiàn)實(shí)生活中,記錄日志非常重要。銀行轉(zhuǎn)賬時(shí)會(huì)有轉(zhuǎn)賬記錄;飛機(jī)飛行過程中,會(huì)有黑盒子(飛行數(shù)據(jù)記錄器)記錄飛行過程中的一切。如果有出現(xiàn)什么問題,人們可以通過日志數(shù)據(jù)來搞清楚到底發(fā)生了什么。對(duì)于系統(tǒng)開發(fā)、調(diào)試以及運(yùn)行,記錄日志都是同樣的重要。如果沒有日志記錄,程序崩潰時(shí)你幾乎就沒辦法弄明白到底發(fā)生了什么事情。舉個(gè)例子,當(dāng)你在寫一個(gè)服務(wù)器程序時(shí),記錄日志是非常有必要的。下面展示的就是 EZComet.com 服務(wù)器的日志文件截圖。

服務(wù)崩潰后,如果沒有日志,我?guī)缀鯖]辦法知道到底發(fā)生了錯(cuò)誤。日志不僅對(duì)于服務(wù)器很重要,對(duì)于桌面圖形應(yīng)用同樣十分重要。比如,當(dāng)你的客戶的 PC 機(jī)程序崩潰時(shí),你可以讓他們把日志文件發(fā)給你,這樣你就可以找到問題到底出在哪兒。相信我,在不同的 PC 環(huán)境下,你永遠(yuǎn)不會(huì)知道會(huì)有怎樣奇怪的問題。我曾經(jīng)就接收到過這樣的錯(cuò)誤日志。

 2011-08-22 17:52:54,828 - root - ERROR - [Errno 10104] getaddrinfo failed
 Traceback (most recent call last):
 File "<string>", line 124, in main 
 File "<string>", line 20, in __init__
 File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/wx._core", line 7978, in __init__
 File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/wx._core", line 7552, in _BootstrapApp 7   File "<string>", line 84, in OnInit 8   File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/twisted.internet.wxreactor", line 175, in install 9   File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/twisted.internet._threadedselect", line 106, in __init__
 File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/twisted.internet.base", line 488, in __init__
 File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/twisted.internet.posixbase", line 266, in installWaker 12   File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/twisted.internet.posixbase", line 74, in __init__
 File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/socket", line 224, in meth 14 gaierror: [Errno 10104] getaddrinfo failed</pre>

我最終發(fā)現(xiàn),這個(gè)客戶的 PC 機(jī)被一種病毒感染,導(dǎo)致了調(diào)用 gethostname 函數(shù)失敗。看吧,如果沒有日志可以查你怎么可能知道這些。

打印輸出不是個(gè)好辦法

盡管記錄日志非常重要,但是并不是所有的開發(fā)者都能正確地使用它。我曾看到一些開發(fā)者是這樣記錄日志的,在開發(fā)的過程中插入 print 語句,開發(fā)結(jié)束后再將這些語句移除。就像這樣:

print 'Start reading database'
records = model.read_recrods() 3 print '# records', records
print 'Updating record ...'
 model.update_records(records) 6 print 'done'</pre>

這種方式對(duì)于簡(jiǎn)單腳本型程序有用,但是如果是復(fù)雜的系統(tǒng),你最好不要使用這樣的方式。首先,你沒辦法做到在日志文件中只留下極其重要的消息。你會(huì)看到大量的消息日志。但是你卻找不到任何有用的信息。你除了移除這輸出語句這外,沒別的辦法控制代碼,但是極有可能的是你忘記了移出那些沒用的輸出。再者,print 輸出的所有信息都到了標(biāo)準(zhǔn)輸出中,這將嚴(yán)重影響到你從標(biāo)準(zhǔn)輸出中查看其它輸出數(shù)據(jù)。當(dāng)然,你也可以把消息輸出到 stderr ,但是用 print 做日志記錄的方式還是不好。

使用 python 的標(biāo)準(zhǔn)日志模塊

那么,怎么樣記錄日志才是正確的呢?其實(shí)非常簡(jiǎn)單,使用 python 的標(biāo)準(zhǔn)日志模塊。多虧 python 社區(qū)將日志做成了一個(gè)標(biāo)準(zhǔn)模塊。它非常簡(jiǎn)單易用且十分靈活。你可以像這樣使用日志系統(tǒng):

import logging 
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
 
logger.info('Start reading database')
# read database here

records = {'john': 55, 'tom': 66}
logger.debug('Records: %s', records) 10 logger.info('Updating records ...') 
# update records here

logger.info('Finish updating records')</pre>

運(yùn)行的時(shí)候就可看到:

INFO:__main__:Start reading database
INFO:__main__:Updating records ...
INFO:__main__:Finish updating records</pre>

你可能會(huì)問這與使用 print 有什么不同呢。它有以下的優(yōu)勢(shì):

  • 你可以控制消息的級(jí)別,過濾掉那些并不重要的消息。
  • 你可決定輸出到什么地方,以及怎么輸出。

有許多的重要性別級(jí)可供選擇,debug、info、warning、error 以及 critical。通過賦予 logger 或者 handler 不同的級(jí)別,你就可以只輸出錯(cuò)誤消息到特定的記錄文件中,或者在調(diào)試時(shí)只記錄調(diào)試信息。讓我們把 logger 的級(jí)別改成 DEBUG 再看一下輸出結(jié)果:

logging.basicConfig(level=logging.DEBUG)</pre>

輸出變成了:

INFO:__main__:Start reading database
DEBUG:__main__:Records: {'john': 55, 'tom': 66} 
INFO:__main__:Updating records ... 
INFO:__main__:Finish updating records</pre>

正如看到的那樣,我們把 logger 的等級(jí)改為 DEBUG 后,調(diào)試記錄就出現(xiàn)在了輸出當(dāng)中。你也可以選擇怎么處理這些消息。例如,你可以使用 FileHandler 把記錄寫進(jìn)文件中:

import logging 
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

# create a file handler

handler = logging.FileHandler('hello.log')
 handler.setLevel(logging.INFO) 10 
# create a logging format

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 
handler.setFormatter(formatter) 

# add the handlers to the logger
 
logger.addHandler(handler) 19 
logger.info('Hello baby')</pre>

以合適的等級(jí)輸出日志記錄

有了靈活的日志記錄模塊后,你可以按適當(dāng)?shù)牡燃?jí)將日志記錄輸出到任何地方然后配置它們。那么你可能會(huì)問,什么是合適的等級(jí)呢?在這兒我將分享一些我的經(jīng)驗(yàn)。

大多數(shù)的情況下,你都不想閱讀日志中的太多細(xì)節(jié)。因此,只有你在調(diào)試過程中才會(huì)使用 DEBUG 等級(jí)。我只使用 DEBUG 獲取詳細(xì)的調(diào)試信息,特別是當(dāng)數(shù)據(jù)量很大或者頻率很高的時(shí)候,比如算法內(nèi)部每個(gè)循環(huán)的中間狀態(tài)。

def complex_algorithm(items): 
    for i, item in enumerate(items): 
    # do some complex algorithm computation

 logger.debug('%s iteration, item=%s', i, item)

在處理請(qǐng)求或者服務(wù)器狀態(tài)變化等日常事務(wù)中,我會(huì)使用 INFO 等級(jí)。

def handle_request(request): 
logger.info('Handling request %s', request)
# handle request here

result = 'result'
logger.info('Return result: %s', result)

def start_service(): 
logger.info('Starting service at port %s ...', port) 
service.start() 
logger.info('Service is started')

當(dāng)發(fā)生很重要的事件,但是并不是錯(cuò)誤時(shí),我會(huì)使用 WARNING 。比如,當(dāng)用戶登錄密碼錯(cuò)誤時(shí),或者連接變慢時(shí)。

def authenticate(user_name, password, ip_address): 
    if user_name != USER_NAME and password != PASSWORD: 
        logger.warn('Login attempt to %s from IP %s', user_name, ip_address)
        return False 
       # do authentication here</pre>

有錯(cuò)誤發(fā)生時(shí)肯定會(huì)使用 ERROR 等級(jí)了。比如拋出異常,IO 操作失敗或者連接問題等。

def get_user_by_id(user_id): 
    user = db.read_user(user_id) 
     if user is None: 
           logger.error('Cannot find user with user_id=%s', user_id) 
           return user 
    return user

我很少使用 CRITICAL 。當(dāng)一些特別糟糕的事情發(fā)生時(shí),你可以使用這個(gè)級(jí)別來記錄。比方說,內(nèi)存耗盡,磁盤滿了或者核危機(jī)(希望永遠(yuǎn)別發(fā)生 :S)。

雖然不是非得將 logger 的名稱設(shè)置為 name ,但是這樣做會(huì)給我們帶來諸多益處。在 python 中,變量 name 的名稱就是當(dāng)前模塊的名稱。比如,在模塊 “foo.bar.my_module” 中調(diào)用 logger.getLogger(name) 等價(jià)于調(diào)用logger.getLogger(“foo.bar.my_module”) 。當(dāng)你需要配置 logger 時(shí),你可以配置到 “foo” 中,這樣包 foo 中的所有模塊都會(huì)使用相同的配置。當(dāng)你在讀日志文件的時(shí)候,你就能夠明白消息到底來自于哪一個(gè)模塊。

捕捉異常并使用 traceback 記錄它

出問題的時(shí)候記錄下來是個(gè)好習(xí)慣,但是如果沒有 traceback ,那么它一點(diǎn)兒用也沒有。你應(yīng)該捕獲異常并用 traceback 把它們記錄下來。比如下面這個(gè)例子:

try: 
    open('/path/to/does/not/exist', 'rb')
    except (SystemExit, KeyboardInterrupt):
    raise
except Exception, e: 
logger.error('Failed to open file', exc_info=True)

使用參數(shù) exc_info=true 調(diào)用 logger 方法, traceback 會(huì)輸出到 logger 中。你可以看到下面的結(jié)果

ERROR:__main__:Failed to open file 
Traceback (most recent call last): 
File "example.py", line 6, in <module>
open('/path/to/does/not/exist', 'rb') 
IOError: [Errno 2] No such file or directory: '/path/to/does/not/exist'

Python 使用logging模塊記錄日志涉及四個(gè)主要類,使用官方文檔中的概括最為合適:

logger提供了應(yīng)用程序可以直接使用的接口;

handler將(logger創(chuàng)建的)日志記錄發(fā)送到合適的目的輸出;

filter提供了細(xì)度設(shè)備來決定輸出哪條日志記錄;

formatter決定日志記錄的最終輸出格式。

logging模塊是在2.3新引進(jìn)的功能,下面是一些常用的類和模塊級(jí)函數(shù)

模塊級(jí)函數(shù)
logging.getLogger([name]):返回一個(gè)logger對(duì)象,如果沒有指定名字將返回root logger
logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical():設(shè)定root logger的日志級(jí)別
logging.basicConfig():用默認(rèn)Formatter為日志系統(tǒng)建立一個(gè)StreamHandler,設(shè)置基礎(chǔ)配置并加到root logger中

image

每個(gè)程序在輸出信息之前都要獲得一個(gè)Logger。Logger通常對(duì)應(yīng)了程序的模塊名,比如聊天工具的圖形界面模塊可以這樣獲得它的Logger:

LOG=logging.getLogger(”chat.gui”)

而核心模塊可以這樣:

LOG=logging.getLogger(”chat.kernel”)

Logger.setLevel(lel):指定最低的日志級(jí)別,低于lel的級(jí)別將被忽略。debug是最低的內(nèi)置級(jí)別,critical為最高
Logger.addFilter(filt)、Logger.removeFilter(filt):添加或刪除指定的filter
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或刪除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以設(shè)置的日志級(jí)別
設(shè)置logger的level, level有以下幾個(gè)級(jí)別:

image
NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL

如果把looger的級(jí)別設(shè)置為INFO, 那么小于INFO級(jí)別的日志都不輸出, 大于等于INFO級(jí)別的日志都輸出

Handlers

handler對(duì)象負(fù)責(zé)發(fā)送相關(guān)的信息到指定目的地。Python的日志系統(tǒng)有多種Handler可以使用。有些Handler可以把信息輸出到控制臺(tái),有些Logger可以把信息輸出到文件,還有些 Handler可以把信息發(fā)送到網(wǎng)絡(luò)上。如果覺得不夠用,還可以編寫自己的Handler。可以通過addHandler()方法添加多個(gè)多 handler
Handler.setLevel(lel):指定被處理的信息級(jí)別,低于lel級(jí)別的信息將被忽略
Handler.setFormatter():給這個(gè)handler選擇一個(gè)格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個(gè)filter對(duì)象

Formatters

Formatter對(duì)象設(shè)置日志信息最后的規(guī)則、結(jié)構(gòu)和內(nèi)容,默認(rèn)的時(shí)間格式為%Y-%m-%d %H:%M:%S,下面是Formatter常用的一些信息
%(name)s
Logger的名字
%(levelno)s
數(shù)字形式的日志級(jí)別
%(levelname)s
文本形式的日志級(jí)別
%(pathname)s
調(diào)用日志輸出函數(shù)的模塊的完整路徑名,可能沒有
%(filename)s
調(diào)用日志輸出函數(shù)的模塊的文件名
%(module)s
調(diào)用日志輸出函數(shù)的模塊名
%(funcName)s
調(diào)用日志輸出函數(shù)的函數(shù)名
%(lineno)d
調(diào)用日志輸出函數(shù)的語句所在的代碼行
%(created)f
當(dāng)前時(shí)間,用UNIX標(biāo)準(zhǔn)的表示時(shí)間的浮 點(diǎn)數(shù)表示
%(relativeCreated)d
輸出日志信息時(shí)的,自Logger創(chuàng)建以 來的毫秒數(shù)
%(asctime)s
字符串形式的當(dāng)前時(shí)間。默認(rèn)格式是 “2003-07-08 16:49:45,896”。逗號(hào)后面的是毫秒
%(thread)d
線程ID??赡軟]有
%(threadName)s
線程名??赡軟]有
%(process)d
進(jìn)程ID??赡軟]有
%(message)s
用戶輸出的消息
設(shè)置過濾器

細(xì)心的朋友一定會(huì)發(fā)現(xiàn)前文調(diào)用logging.getLogger()時(shí)參數(shù)的格式類似于“A.B.C”。采取這樣的格式其實(shí)就是為了可以配置過濾器??匆幌逻@段代碼:
LOG=logging.getLogger(”chat.gui.statistic”)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter(’%(asctime)s %(levelname)s %(message)s’)
console.setFormatter(formatter)
filter=logging.Filter(”chat.gui”)
console.addFilter(filter)
LOG.addHandler(console)
和前面不同的是我們?cè)贖andler上添加了一個(gè)過濾器?,F(xiàn)在我們輸出日志信息的時(shí)候就會(huì)經(jīng)過過濾器的處理。名為“A.B”的過濾器只讓名字帶有 “A.B”前綴的Logger輸出信息??梢蕴砑佣鄠€(gè)過濾器,只要有一個(gè)過濾器拒絕,日志信息就不會(huì)被輸出。當(dāng)然名為“A”前綴的Logger會(huì)輸出信息。另外,在Logger中也可以添加過濾器。

每個(gè)Logger可以附加多個(gè)Handler。接下來我們就來介紹一些常用的Handler:

  1. logging.StreamHandler
    使用這個(gè)Handler可以向類似與sys.stdout或者sys.stderr的任何文件對(duì)象(file object)輸出信息。它的構(gòu)造函數(shù)是:
    StreamHandler([strm])
    其中strm參數(shù)是一個(gè)文件對(duì)象。默認(rèn)是sys.stderr
  2. logging.FileHandler
    和StreamHandler類似,用于向一個(gè)文件輸出日志信息。不過FileHandler會(huì)幫你打開這個(gè)文件。它的構(gòu)造函數(shù)是:
    FileHandler(filename[,mode])
    filename是文件名,必須指定一個(gè)文件名。
    mode是文件的打開方式。參見Python內(nèi)置函數(shù)open()的用法。默認(rèn)是’a',即添加到文件末尾。
  3. logging.handlers.RotatingFileHandler
    這個(gè)Handler類似于上面的FileHandler,但是它可以管理文件大小。當(dāng)文件達(dá)到一定大小之后,它會(huì)自動(dòng)將當(dāng)前日志文件改名,然后創(chuàng)建 一個(gè)新的同名日志文件繼續(xù)輸出。比如日志文件是chat.log。當(dāng)chat.log達(dá)到指定的大小之后,RotatingFileHandler自動(dòng)把 文件改名為chat.log.1。不過,如果chat.log.1已經(jīng)存在,會(huì)先把chat.log.1重命名為chat.log.2。。。最后重新創(chuàng)建 chat.log,繼續(xù)輸出日志信息。它的構(gòu)造函數(shù)是:
    RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
    其中filename和mode兩個(gè)參數(shù)和FileHandler一樣。
    maxBytes用于指定日志文件的最大文件大小。如果maxBytes為0,意味著日志文件可以無限大,這時(shí)上面描述的重命名過程就不會(huì)發(fā)生。
    backupCount用于指定保留的備份文件的個(gè)數(shù)。比如,如果指定為2,當(dāng)上面描述的重命名過程發(fā)生時(shí),原有的chat.log.2并不會(huì)被更名,而是被刪除。
  4. logging.handlers.TimedRotatingFileHandler
    這個(gè)Handler和RotatingFileHandler類似,不過,它沒有通過判斷文件大小來決定何時(shí)重新創(chuàng)建日志文件,而是間隔一定時(shí)間就 自動(dòng)創(chuàng)建新的日志文件。重命名的過程與RotatingFileHandler類似,不過新的文件不是附加數(shù)字,而是當(dāng)前時(shí)間。它的構(gòu)造函數(shù)是:
    TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
    其中filename參數(shù)和backupCount參數(shù)和RotatingFileHandler具有相同的意義。
    interval是時(shí)間間隔。
    when參數(shù)是一個(gè)字符串。表示時(shí)間間隔的單位,不區(qū)分大小寫。它有以下取值:
    S 秒
    M 分
    H 小時(shí)
    D 天
    W 每星期(interval==0時(shí)代表星期一)
    midnight 每天凌晨
  5. logging.handlers.SocketHandler
  6. logging.handlers.DatagramHandler
    以上兩個(gè)Handler類似,都是將日志信息發(fā)送到網(wǎng)絡(luò)。不同的是前者使用TCP協(xié)議,后者使用UDP協(xié)議。它們的構(gòu)造函數(shù)是:
    Handler(host, port)
    其中host是主機(jī)名,port是端口名
  7. logging.handlers.SysLogHandler
  8. logging.handlers.NTEventLogHandler
  9. logging.handlers.SMTPHandler
  10. logging.handlers.MemoryHandler
  11. logging.handlers.HTTPHandler
# encoding:utf-8
#import logging
#FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s'
#logging.basicConfig(format=FORMAT)
#d = {'clientip': '192.168.0.1', 'user': 'fbloggs'}
#logger = logging.getLogger('tcpserver')
#logger.warning('Protocol problem: %s', 'connection reset', extra=d)

#FORMAT = '%(asctime)-15s %(message)s'
#logging.basicConfig(filename = "C:\\Users\\june\\Desktop\\1.txt", level = logging.DEBUG, filemode = "a", format=FORMAT) 
#logging.debug('this is a message') 
#logging.debug('test') 

#import logging
#import datetime
# 18 #curDate = datetime.date.today() - datetime.timedelta(days=0)
#logName =  'C:\\Users\\june\\Desktop\\error_%s.log' %curDate
#logging.basicConfig(level=logging.INFO,
# format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
# #datefmt='%a, %d %b %Y %H:%M:%S',
# filename=logName,
# filemode='a')
##2013-10-21 03:25:51,509 writeLog.py[line:14] INFO This is info message
##2013-10-21 03:25:51,510 writeLog.py[line:15] WARNING This is warning message
#logging.debug('This is debug message')
#logging.info('This is info message')
#logging.warning('This is warning message')import logging
import logging.config 33 
logging.config.fileConfig("logging.conf")   
#create logger
loggerInfo = logging.getLogger("infoLogger")  
#"application" code
loggerInfo.debug("debug message") 
loggerInfo.info("info message")   
loggerInfo.warn("warn message") 
loggerInfo.error("error message") 
loggerInfo.critical("critical message")   

loggerError = logging.getLogger("errorLogger") 
loggerError.error("Error: Hello world!")</pre>


#coding=utf-8
import logging 3 import datetime  
format='%(asctime)s - %(filename)s - [line:%(lineno)d] - %(levelname)s - %(message)s'
curDate = datetime.date.today() - datetime.timedelta(days=0)
infoLogName =  r'C:/Users/june/Desktop/info_%s.log' %curDate
errorLogName =  r'C:/Users/june/Desktop/error_%s.log' %curDate

formatter = logging.Formatter(format)  
infoLogger = logging.getLogger("infoLog") 
errorLogger = logging.getLogger("errorLog") 

infoLogger.setLevel(logging.INFO)   
errorLogger.setLevel(logging.ERROR)   
infoHandler = logging.FileHandler(infoLogName, 'a') 
infoHandler.setLevel(logging.INFO) 
infoHandler.setFormatter(formatter)   
errorHandler = logging.FileHandler(errorLogName, 'a')      
errorHandler.setLevel(logging.ERROR)  
errorHandler.setFormatter(formatter) 
testHandler = logging.StreamHandler()
testHandler.setFormatter(formatter)
testHandler.setLevel(logging.ERROR)
infoLogger.addHandler(infoHandler)
infoLogger.addHandler(testHandler) 
errorLogger.addHandler(errorHandler)    
#infoLogger.debug("debug message")
#infoLogger.info("info message")
#infoLogger.warn("warn message")
# # 下面這行會(huì)同時(shí)打印在文件和終端上
#infoLogger.error("error message")
# 40 #errorLogger.error("error message")
#errorLogger.critical("critical message")  


"""
Created on 2016年8月18日
@author: apple
"""
#-*- coding:utf-8 -*-
 
#開發(fā)出一個(gè)日志系統(tǒng),既要把日志輸出到控制臺(tái),還要寫入日志文件

import logging 11 import time
import os 
import os.path 

class Logger(): 
    def __init__(self, log_name, logger_name):

     '''
            指定保存日志的文件路徑,日志級(jí)別以及調(diào)用文件
             將日志    存入到指定的文件中

     '''
     #設(shè)置日志文件名稱:time.time()取得當(dāng)前時(shí)間;time.localtime()取得本地時(shí)間;time.strftime()格式化日期;
           time_str = time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime(time.time()))
           logname = time_str + '_' + log_name + '.log'
 
            #設(shè)置日志文件所在的路徑
           log_filedir = 'Log'
           if not os.path.isdir(log_filedir):
                print("日志文件夾 %s 不存在,開始創(chuàng)建此文件夾" %log_filedir)
                os.mkdir('Log')
           else:
                print("日志文件夾 %s 存在" %log_filedir)
                os.chdir('Log')
 
            #創(chuàng)建一個(gè)logger以及設(shè)置日志級(jí)別
            #logging有6個(gè)日志級(jí)別:NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL對(duì)應(yīng)的值分別為:0,10,20,30,40,50
            #例如:logging.DEBUG和10是等價(jià)的表示方法
            #可以給日志對(duì)象(Logger Instance)設(shè)置日志級(jí)別,低于該級(jí)別的日志消息將會(huì)被忽略,也可以給Hanlder設(shè)置日志級(jí)別
            #對(duì)于低于該級(jí)別的日志消息, Handler也會(huì)忽略。
          self.logger = logging.getLogger(logger_name) 
          self.logger.setLevel(logging.DEBUG)
     
         #創(chuàng)建文件handler,用于寫入日志文件并設(shè)置文件日志級(jí)別
          file_handler = logging.FileHandler(logname) 
          file_handler.setLevel(logging.DEBUG)
    
         #創(chuàng)建控制端輸出handler,用于輸出到控制端并設(shè)置輸出日志級(jí)別
           console_handler = logging.StreamHandler() 
           console_handler.setLevel(logging.DEBUG)
  
           #在控制端handler添加過濾器,將含有chat或者gui的handler信息輸出
           filter = logging.Filter("chat.gui")
           console_handler.addFilter(filter)
      
           #定義handler的輸出格式并將格式應(yīng)用到handler
           formatter = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s')
        file_handler.setFormatter(formatter)
       console_handler.setFormatter(formatter)
          
          #將handler加入到logger
         self.logger.addHandler(file_handler)
         self.logger.addHandler(console_handler)
         
         self.logger.debug("這個(gè)是debug日志信息")
         self.logger.info("歡迎大家來到 Python的世界")
         
        
          #將handler從logger中移除
        self.logger.removeHandler(file_handler)
          self.logger.removeHandler(console_handler)
 
 if __name__ == '__main__':       
    print(os.getcwd())
    Log = Logger('create_log', "chat.gui.statistic")
         
 
 
# 模塊級(jí)函數(shù)
 # 
 # logging.getLogger([name]):返回一個(gè)logger對(duì)象,如果沒有指定名字將返回root logger
 # logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical():設(shè)定root logger的日志級(jí)別
 # logging.basicConfig():用默認(rèn)Formatter為日志系統(tǒng)建立一個(gè)StreamHandler,設(shè)置基礎(chǔ)配置并加到root logger中
  # 
 # Loggers
 # 
 # Logger.setLevel(lel):指定最低的日志級(jí)別,低于lel的級(jí)別將被忽略。debug是最低的內(nèi)置級(jí)別,critical為最高
  # Logger.addFilter(filt)、Logger.removeFilter(filt):添加或刪除指定的filter
 # Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或刪除指定的handler
 # Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以設(shè)置的日志級(jí)別
 
 # Handlers
 # 
 # handler對(duì)象負(fù)責(zé)發(fā)送相關(guān)的信息到指定目的地??梢酝ㄟ^addHandler()方法添加多個(gè)多handler
 # Handler.setLevel(lel):指定被處理的信息級(jí)別,低于lel級(jí)別的信息將被忽略
 # Handler.setFormatter():給這個(gè)handler選擇一個(gè)格式
 # Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個(gè)filter對(duì)象
 
 # Formatters
 # 
 # Formatter對(duì)象設(shè)置日志信息最后的規(guī)則、結(jié)構(gòu)和內(nèi)容,默認(rèn)的時(shí)間格式為%Y-%m-%d %H:%M:%S,下面是Formatter常用的一些信息


 # %(name)s                       Logger的名字
 #  
# %(levelno)s                    數(shù)字形式的日志級(jí)別
#  
# %(levelname)s                文本形式的日志級(jí)別

%(pathname)s 調(diào)用日志輸出函數(shù)的模塊的完整路徑名,可能沒有

# 
# %(filename)s                  調(diào)用日志輸出函數(shù)的模塊的文件名
 #  
# %(module)s                    調(diào)用日志輸出函數(shù)的模塊名
#  
# %(funcName)s                調(diào)用日志輸出函數(shù)的函數(shù)名
#  
# %(lineno)d                     調(diào)用日志輸出函數(shù)的語句所在的代碼行
#  
# %(created)f                    當(dāng)前時(shí)間,用UNIX標(biāo)準(zhǔn)的表示時(shí)間的浮 點(diǎn)數(shù)表示
#  
# %(relativeCreated)d        輸出日志信息時(shí)的,自Logger創(chuàng)建以 來的毫秒數(shù)
#  
# %(asctime)s                  字符串形式的當(dāng)前時(shí)間。默認(rèn)格式是 “2003-07-08 16:49:45,896”。逗號(hào)后面的是毫秒
# 
# %(thread)d                   線程ID。可能沒有
# 
# %(threadName)s           線程名??赡軟]有
# 
# %(process)d                 進(jìn)程ID??赡軟]有
#  
# %(message)s               用戶輸出的消息  


 '''
  Created on 2016年8月25日
 
@author: apple
 '''
import logging 7 
 logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(name)s %(levelname)s %(message)s', 
                     datefmt='%m-%d %H:%M',
                     filename='./AutoUpdate.log',
                     filemode='w') 
  
 console = logging.StreamHandler() 
 console.setLevel(logging.INFO)     formatter = logging.Formatter('%(name)s: %(levelname)-8s %(message)s') 
console.setFormatter(formatter) 

 logging.getLogger('').addHandler(console) 

logging.info("hello world!")</pre>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容