在現(xiàn)實生活中,記錄日志非常重要。銀行轉(zhuǎn)賬時會有轉(zhuǎn)賬記錄;飛機飛行過程中,會有黑盒子(飛行數(shù)據(jù)記錄器)記錄飛行過程中的一切。如果有出現(xiàn)什么問題,人們可以通過日志數(shù)據(jù)來搞清楚到底發(fā)生了什么。對于系統(tǒng)開發(fā)、調(diào)試以及運行,記錄日志都是同樣的重要。如果沒有日志記錄,程序崩潰時你幾乎就沒辦法弄明白到底發(fā)生了什么事情。舉個例子,當你在寫一個服務器程序時,記錄日志是非常有必要的。下面展示的就是 EZComet.com 服務器的日志文件截圖。
服務崩潰后,如果沒有日志,我?guī)缀鯖]辦法知道到底發(fā)生了錯誤。日志不僅對于服務器很重要,對于桌面圖形應用同樣十分重要。比如,當你的客戶的 PC 機程序崩潰時,你可以讓他們把日志文件發(fā)給你,這樣你就可以找到問題到底出在哪兒。相信我,在不同的 PC 環(huán)境下,你永遠不會知道會有怎樣奇怪的問題。我曾經(jīng)就接收到過這樣的錯誤日志。
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),這個客戶的 PC 機被一種病毒感染,導致了調(diào)用 gethostname 函數(shù)失敗。看吧,如果沒有日志可以查你怎么可能知道這些。
打印輸出不是個好辦法
盡管記錄日志非常重要,但是并不是所有的開發(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>
這種方式對于簡單腳本型程序有用,但是如果是復雜的系統(tǒng),你最好不要使用這樣的方式。首先,你沒辦法做到在日志文件中只留下極其重要的消息。你會看到大量的消息日志。但是你卻找不到任何有用的信息。你除了移除這輸出語句這外,沒別的辦法控制代碼,但是極有可能的是你忘記了移出那些沒用的輸出。再者,print 輸出的所有信息都到了標準輸出中,這將嚴重影響到你從標準輸出中查看其它輸出數(shù)據(jù)。當然,你也可以把消息輸出到 stderr ,但是用 print 做日志記錄的方式還是不好。
使用 python 的標準日志模塊
那么,怎么樣記錄日志才是正確的呢?其實非常簡單,使用 python 的標準日志模塊。多虧 python 社區(qū)將日志做成了一個標準模塊。它非常簡單易用且十分靈活。你可以像這樣使用日志系統(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>
運行的時候就可看到:
INFO:__main__:Start reading database
INFO:__main__:Updating records ...
INFO:__main__:Finish updating records</pre>
你可能會問這與使用 print 有什么不同呢。它有以下的優(yōu)勢:
- 你可以控制消息的級別,過濾掉那些并不重要的消息。
- 你可決定輸出到什么地方,以及怎么輸出。
有許多的重要性別級可供選擇,debug、info、warning、error 以及 critical。通過賦予 logger 或者 handler 不同的級別,你就可以只輸出錯誤消息到特定的記錄文件中,或者在調(diào)試時只記錄調(diào)試信息。讓我們把 logger 的級別改成 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 的等級改為 DEBUG 后,調(diào)試記錄就出現(xiàn)在了輸出當中。你也可以選擇怎么處理這些消息。例如,你可以使用 FileHandler 把記錄寫進文件中:
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>
以合適的等級輸出日志記錄
有了靈活的日志記錄模塊后,你可以按適當?shù)牡燃墝⑷罩居涗涊敵龅饺魏蔚胤饺缓笈渲盟鼈儭D敲茨憧赡軙枺裁词呛线m的等級呢?在這兒我將分享一些我的經(jīng)驗。
大多數(shù)的情況下,你都不想閱讀日志中的太多細節(jié)。因此,只有你在調(diào)試過程中才會使用 DEBUG 等級。我只使用 DEBUG 獲取詳細的調(diào)試信息,特別是當數(shù)據(jù)量很大或者頻率很高的時候,比如算法內(nèi)部每個循環(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)
在處理請求或者服務器狀態(tài)變化等日常事務中,我會使用 INFO 等級。
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')
當發(fā)生很重要的事件,但是并不是錯誤時,我會使用 WARNING 。比如,當用戶登錄密碼錯誤時,或者連接變慢時。
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>
有錯誤發(fā)生時肯定會使用 ERROR 等級了。比如拋出異常,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 。當一些特別糟糕的事情發(fā)生時,你可以使用這個級別來記錄。比方說,內(nèi)存耗盡,磁盤滿了或者核危機(希望永遠別發(fā)生 :S)。
雖然不是非得將 logger 的名稱設置為 name ,但是這樣做會給我們帶來諸多益處。在 python 中,變量 name 的名稱就是當前模塊的名稱。比如,在模塊 “foo.bar.my_module” 中調(diào)用 logger.getLogger(name) 等價于調(diào)用logger.getLogger(“foo.bar.my_module”) 。當你需要配置 logger 時,你可以配置到 “foo” 中,這樣包 foo 中的所有模塊都會使用相同的配置。當你在讀日志文件的時候,你就能夠明白消息到底來自于哪一個模塊。
捕捉異常并使用 traceback 記錄它
出問題的時候記錄下來是個好習慣,但是如果沒有 traceback ,那么它一點兒用也沒有。你應該捕獲異常并用 traceback 把它們記錄下來。比如下面這個例子:
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 會輸出到 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模塊記錄日志涉及四個主要類,使用官方文檔中的概括最為合適:
logger提供了應用程序可以直接使用的接口;
handler將(logger創(chuàng)建的)日志記錄發(fā)送到合適的目的輸出;
filter提供了細度設備來決定輸出哪條日志記錄;
formatter決定日志記錄的最終輸出格式。
logging模塊是在2.3新引進的功能,下面是一些常用的類和模塊級函數(shù)
模塊級函數(shù)
logging.getLogger([name]):返回一個logger對象,如果沒有指定名字將返回root logger
logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical():設定root logger的日志級別
logging.basicConfig():用默認Formatter為日志系統(tǒng)建立一個StreamHandler,設置基礎配置并加到root logger中
每個程序在輸出信息之前都要獲得一個Logger。Logger通常對應了程序的模塊名,比如聊天工具的圖形界面模塊可以這樣獲得它的Logger:
LOG=logging.getLogger(”chat.gui”)
而核心模塊可以這樣:
LOG=logging.getLogger(”chat.kernel”)
Logger.setLevel(lel):指定最低的日志級別,低于lel的級別將被忽略。debug是最低的內(nèi)置級別,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():可以設置的日志級別
設置logger的level, level有以下幾個級別:
NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL
如果把looger的級別設置為INFO, 那么小于INFO級別的日志都不輸出, 大于等于INFO級別的日志都輸出
Handlers
handler對象負責發(fā)送相關(guān)的信息到指定目的地。Python的日志系統(tǒng)有多種Handler可以使用。有些Handler可以把信息輸出到控制臺,有些Logger可以把信息輸出到文件,還有些 Handler可以把信息發(fā)送到網(wǎng)絡上。如果覺得不夠用,還可以編寫自己的Handler。可以通過addHandler()方法添加多個多 handler
Handler.setLevel(lel):指定被處理的信息級別,低于lel級別的信息將被忽略
Handler.setFormatter():給這個handler選擇一個格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個filter對象
Formatters
Formatter對象設置日志信息最后的規(guī)則、結(jié)構(gòu)和內(nèi)容,默認的時間格式為%Y-%m-%d %H:%M:%S,下面是Formatter常用的一些信息
%(name)s
Logger的名字
%(levelno)s
數(shù)字形式的日志級別
%(levelname)s
文本形式的日志級別
%(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
當前時間,用UNIX標準的表示時間的浮 點數(shù)表示
%(relativeCreated)d
輸出日志信息時的,自Logger創(chuàng)建以 來的毫秒數(shù)
%(asctime)s
字符串形式的當前時間。默認格式是 “2003-07-08 16:49:45,896”。逗號后面的是毫秒
%(thread)d
線程ID。可能沒有
%(threadName)s
線程名。可能沒有
%(process)d
進程ID。可能沒有
%(message)s
用戶輸出的消息
設置過濾器
細心的朋友一定會發(fā)現(xiàn)前文調(diào)用logging.getLogger()時參數(shù)的格式類似于“A.B.C”。采取這樣的格式其實就是為了可以配置過濾器。看一下這段代碼:
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)
和前面不同的是我們在Handler上添加了一個過濾器。現(xiàn)在我們輸出日志信息的時候就會經(jīng)過過濾器的處理。名為“A.B”的過濾器只讓名字帶有 “A.B”前綴的Logger輸出信息。可以添加多個過濾器,只要有一個過濾器拒絕,日志信息就不會被輸出。當然名為“A”前綴的Logger會輸出信息。另外,在Logger中也可以添加過濾器。
每個Logger可以附加多個Handler。接下來我們就來介紹一些常用的Handler:
- logging.StreamHandler
使用這個Handler可以向類似與sys.stdout或者sys.stderr的任何文件對象(file object)輸出信息。它的構(gòu)造函數(shù)是:
StreamHandler([strm])
其中strm參數(shù)是一個文件對象。默認是sys.stderr - logging.FileHandler
和StreamHandler類似,用于向一個文件輸出日志信息。不過FileHandler會幫你打開這個文件。它的構(gòu)造函數(shù)是:
FileHandler(filename[,mode])
filename是文件名,必須指定一個文件名。
mode是文件的打開方式。參見Python內(nèi)置函數(shù)open()的用法。默認是’a',即添加到文件末尾。 - logging.handlers.RotatingFileHandler
這個Handler類似于上面的FileHandler,但是它可以管理文件大小。當文件達到一定大小之后,它會自動將當前日志文件改名,然后創(chuàng)建 一個新的同名日志文件繼續(xù)輸出。比如日志文件是chat.log。當chat.log達到指定的大小之后,RotatingFileHandler自動把 文件改名為chat.log.1。不過,如果chat.log.1已經(jīng)存在,會先把chat.log.1重命名為chat.log.2。。。最后重新創(chuàng)建 chat.log,繼續(xù)輸出日志信息。它的構(gòu)造函數(shù)是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode兩個參數(shù)和FileHandler一樣。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes為0,意味著日志文件可以無限大,這時上面描述的重命名過程就不會發(fā)生。
backupCount用于指定保留的備份文件的個數(shù)。比如,如果指定為2,當上面描述的重命名過程發(fā)生時,原有的chat.log.2并不會被更名,而是被刪除。 - logging.handlers.TimedRotatingFileHandler
這個Handler和RotatingFileHandler類似,不過,它沒有通過判斷文件大小來決定何時重新創(chuàng)建日志文件,而是間隔一定時間就 自動創(chuàng)建新的日志文件。重命名的過程與RotatingFileHandler類似,不過新的文件不是附加數(shù)字,而是當前時間。它的構(gòu)造函數(shù)是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename參數(shù)和backupCount參數(shù)和RotatingFileHandler具有相同的意義。
interval是時間間隔。
when參數(shù)是一個字符串。表示時間間隔的單位,不區(qū)分大小寫。它有以下取值:
S 秒
M 分
H 小時
D 天
W 每星期(interval==0時代表星期一)
midnight 每天凌晨 - logging.handlers.SocketHandler
- logging.handlers.DatagramHandler
以上兩個Handler類似,都是將日志信息發(fā)送到網(wǎng)絡。不同的是前者使用TCP協(xié)議,后者使用UDP協(xié)議。它們的構(gòu)造函數(shù)是:
Handler(host, port)
其中host是主機名,port是端口名 - logging.handlers.SysLogHandler
- logging.handlers.NTEventLogHandler
- logging.handlers.SMTPHandler
- logging.handlers.MemoryHandler
- 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")
# # 下面這行會同時打印在文件和終端上
#infoLogger.error("error message")
# 40 #errorLogger.error("error message")
#errorLogger.critical("critical message")
"""
Created on 2016年8月18日
@author: apple
"""
#-*- coding:utf-8 -*-
#開發(fā)出一個日志系統(tǒng),既要把日志輸出到控制臺,還要寫入日志文件
import logging 11 import time
import os
import os.path
class Logger():
def __init__(self, log_name, logger_name):
'''
指定保存日志的文件路徑,日志級別以及調(diào)用文件
將日志 存入到指定的文件中
'''
#設置日志文件名稱:time.time()取得當前時間;time.localtime()取得本地時間;time.strftime()格式化日期;
time_str = time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime(time.time()))
logname = time_str + '_' + log_name + '.log'
#設置日志文件所在的路徑
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)建一個logger以及設置日志級別
#logging有6個日志級別:NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL對應的值分別為:0,10,20,30,40,50
#例如:logging.DEBUG和10是等價的表示方法
#可以給日志對象(Logger Instance)設置日志級別,低于該級別的日志消息將會被忽略,也可以給Hanlder設置日志級別
#對于低于該級別的日志消息, Handler也會忽略。
self.logger = logging.getLogger(logger_name)
self.logger.setLevel(logging.DEBUG)
#創(chuàng)建文件handler,用于寫入日志文件并設置文件日志級別
file_handler = logging.FileHandler(logname)
file_handler.setLevel(logging.DEBUG)
#創(chuàng)建控制端輸出handler,用于輸出到控制端并設置輸出日志級別
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
#在控制端handler添加過濾器,將含有chat或者gui的handler信息輸出
filter = logging.Filter("chat.gui")
console_handler.addFilter(filter)
#定義handler的輸出格式并將格式應用到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("這個是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")
# 模塊級函數(shù)
#
# logging.getLogger([name]):返回一個logger對象,如果沒有指定名字將返回root logger
# logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical():設定root logger的日志級別
# logging.basicConfig():用默認Formatter為日志系統(tǒng)建立一個StreamHandler,設置基礎配置并加到root logger中
#
# Loggers
#
# Logger.setLevel(lel):指定最低的日志級別,低于lel的級別將被忽略。debug是最低的內(nèi)置級別,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():可以設置的日志級別
# Handlers
#
# handler對象負責發(fā)送相關(guān)的信息到指定目的地。可以通過addHandler()方法添加多個多handler
# Handler.setLevel(lel):指定被處理的信息級別,低于lel級別的信息將被忽略
# Handler.setFormatter():給這個handler選擇一個格式
# Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個filter對象
# Formatters
#
# Formatter對象設置日志信息最后的規(guī)則、結(jié)構(gòu)和內(nèi)容,默認的時間格式為%Y-%m-%d %H:%M:%S,下面是Formatter常用的一些信息
# %(name)s Logger的名字
#
# %(levelno)s 數(shù)字形式的日志級別
#
# %(levelname)s 文本形式的日志級別
%(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 當前時間,用UNIX標準的表示時間的浮 點數(shù)表示
#
# %(relativeCreated)d 輸出日志信息時的,自Logger創(chuàng)建以 來的毫秒數(shù)
#
# %(asctime)s 字符串形式的當前時間。默認格式是 “2003-07-08 16:49:45,896”。逗號后面的是毫秒
#
# %(thread)d 線程ID。可能沒有
#
# %(threadName)s 線程名。可能沒有
#
# %(process)d 進程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>