python模塊logging

在現(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中

image

每個程序在輸出信息之前都要獲得一個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有以下幾個級別:

image
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:

  1. logging.StreamHandler
    使用這個Handler可以向類似與sys.stdout或者sys.stderr的任何文件對象(file object)輸出信息。它的構(gòu)造函數(shù)是:
    StreamHandler([strm])
    其中strm參數(shù)是一個文件對象。默認是sys.stderr
  2. logging.FileHandler
    和StreamHandler類似,用于向一個文件輸出日志信息。不過FileHandler會幫你打開這個文件。它的構(gòu)造函數(shù)是:
    FileHandler(filename[,mode])
    filename是文件名,必須指定一個文件名。
    mode是文件的打開方式。參見Python內(nèi)置函數(shù)open()的用法。默認是’a',即添加到文件末尾。
  3. 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并不會被更名,而是被刪除。
  4. 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 每天凌晨
  5. logging.handlers.SocketHandler
  6. logging.handlers.DatagramHandler
    以上兩個Handler類似,都是將日志信息發(fā)送到網(wǎng)絡。不同的是前者使用TCP協(xié)議,后者使用UDP協(xié)議。它們的構(gòu)造函數(shù)是:
    Handler(host, port)
    其中host是主機名,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")
# # 下面這行會同時打印在文件和終端上
#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>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,076評論 2 375

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