2015-02-11 133 views
0

有沒有辦法將屬於一個web請求的python web應用程序的日誌分組?Python日誌記錄:屬於一個請求的組日誌

實施例:

2015-02-11 13:06:32 myapp.middleware.MYAPPMiddleware: INFO  Login of user foo was successful 
2015-02-11 13:06:32 myapp.middleware.MYAPPMiddleware: INFO  Login of user bar failed 
2015-02-11 13:06:32 myapp.send_mails: INFO  failed to send mail to [email protected] 

上述日誌行是相互無關的。

你怎麼能解決這個pythonic的方式?

回答

3

其實質上的日誌條目被設計爲彼此獨立。
將它們連接在一起的正確方法是在條目中包含一些上下文信息,以便稍後查看日誌時進行過濾。

下面是與這樣的信息一個SharePoint日誌記錄的一個例子:

Timestamp    Process    TID  Area     Category     EventID Level  Message  Correlation 
02/26/2015 17:49:19.65 w3wp.exe (0x1F40) 0x2358 SharePoint Foundation Logging Correlation Data xmnv Medium  Name=Request (POST:http://reserver2:80/pest/_vti_bin/sitedata.asmx) d1e2b688-e0b2-481e-98ce-497a11acab44 

在Python logging文檔,Adding contextual information to your logging output建議兩種方法:使用LoggerAdapterFilter

LoggerAdapter使用這樣的(例子是基於那些在文檔中):

class AddConnIdAdapter(logging.LoggerAdapter): 
    def process(self, msg, kwargs): 
     return <augment_message(msg,arbitrary_info)>, kwargs 
la = AddConnIdAdapter(<logger>,extra=<parameters, saved in self.extra>) 
<...> 
la.info(<message>) 

Filter使用這樣的:

#Either all messages should have custom fields 
# or the Formatter used should support messages 
# both with and without custom fields 
logging.basicConfig(<...>,format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s') 
class AddClientInfo(logging.Filter): 
    #override __init__ or set attributes to specify parameters 
    def filter(self, record): 
     record.ip = <get_client_ip()> 
     record.user = <get_client_name()> 
     return True #do not filter out anything 
l=<logger()> 
l.addFilter(AddClientInfo()) #can attach to either loggers or handlers 
<...> 
l.info('message') 

正如你可以看到,不同的是LoggerAdapter是不透明,而Filter是透明的。在這些例子中,前者修改了消息文本,而後者設置了自定義屬性(並且實際上編寫它們需要使用Formatter的合作),但事實上,兩者都可以同時執行。

因此,前者更有用,如果您只需要將上下文添加到某些消息,而後者更適合擴充所有或大部分被記錄的消息。

2

您可以在init方法中爲每個請求分配隨機UUID,並將其添加到所有日誌消息中。

例如,在龍捲風:

class MainRequestHandler(RequestHandler): 
    def __init__(self, application, request): 
     super(MainRequestHandler, self).__init__(application, request) 
     self.uuid = uuid.uuid4() 
     logging.info("%s | %s %s %s", 
        self.uuid, 
        request.method, 
        request.full_url(), 
        request.remote_ip) 

至於結果,你將能夠通過這個UUID到grep日誌找到屬於單獨的請求的所有消息。

+0

這種方法通常很有用,而且在您記錄到多個獨立日誌時很有必要,例如, Python日誌框架加上Web服務器日誌。如果沒有這些,很難在日誌間進行關聯。 – 2015-03-06 14:37:59