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 語(yǔ)句吼驶,開發(fā)結(jié)束后再將這些語(yǔ)句移除。就像這樣:

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ì)看到大量的消息日志骡技。但是你卻找不到任何有用的信息。你除了移除這輸出語(yǔ)句這外羞反,沒別的辦法控制代碼布朦,但是極有可能的是你忘記了移出那些沒用的輸出。再者苟弛,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ù)的語(yǔ)句所在的代碼行
%(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è)過濾器「攀現(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ù)的語(yǔ)句所在的代碼行
#  
# %(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)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市卵沉,隨后出現(xiàn)的幾起案子颠锉,更是在濱河造成了極大的恐慌,老刑警劉巖史汗,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件琼掠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡停撞,警方通過查閱死者的電腦和手機(jī)瓷蛙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來戈毒,“玉大人艰猬,你說我怎么就攤上這事÷袷校” “怎么了冠桃?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)恐疲。 經(jīng)常有香客問我腊满,道長(zhǎng),這世上最難降的妖魔是什么培己? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮胚泌,結(jié)果婚禮上省咨,老公的妹妹穿的比我還像新娘。我一直安慰自己玷室,他們只是感情好零蓉,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布笤受。 她就那樣靜靜地躺著,像睡著了一般敌蜂。 火紅的嫁衣襯著肌膚如雪箩兽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天章喉,我揣著相機(jī)與錄音汗贫,去河邊找鬼。 笑死秸脱,一個(gè)胖子當(dāng)著我的面吹牛落包,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播摊唇,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了晶丘?” 一聲冷哼從身側(cè)響起握巢,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎岛请,沒想到半個(gè)月后笔呀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡髓需,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年许师,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片僚匆。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡微渠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出咧擂,到底是詐尸還是另有隱情逞盆,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布松申,位于F島的核電站云芦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏贸桶。R本人自食惡果不足惜舅逸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望皇筛。 院中可真熱鬧琉历,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蝇恶,卻和暖如春拳魁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背撮弧。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工潘懊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人想虎。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓卦尊,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親舌厨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子岂却,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容