簡體   English   中英

Django中的Python日志記錄

[英]Python logging in Django

我正在開發一個Django應用程序,我正在嘗試使用Python的日志記錄模塊進行錯誤/跟蹤記錄。 理想情況下,我希望為站點的不同區域配置不同的記錄器。 到目前為止,我已經完成了所有這些工作,但有一件事讓我摸不着頭腦。

我有根記錄器轉到sys.stderr,我已經配置了另一個記錄器來寫入文件。 這是在我的settings.py文件中:

sviewlog = logging.getLogger('MyApp.views.scans')
view_log_handler = logging.FileHandler('C:\\MyApp\\logs\\scan_log.log')
view_log_handler.setLevel(logging.INFO)
view_log_handler.setFormatter(logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s'))
sviewlog.addHandler(view_log_handler)

看起來很簡單。 不過這是問題所在:無論我寫入sviewlog還是寫入日志文件兩次。 根記錄器只打印一次。 就像addHandler()被調用兩次一樣。 當我將代碼放入調試器時,這正是我所看到的。 settings.py中的代碼執行兩次,因此創建了兩個FileHandler並將其添加到同一個logger實例中。 但為什么? 我該如何解決這個問題呢?

誰能告訴我這里發生了什么? 我已經嘗試將sviewlog記錄器/處理程序實例化代碼移動到它所使用的文件中(因為這實際上對我來說似乎是合適的地方),但我有同樣的問題。 我在網上看到的大多數例子都只使用根記錄器,而我更喜歡使用多個記錄器。

請允許我回答我自己的問題。 這里的根本問題是settings.py被導入兩次,甚至更多(見這里 )。 (我仍然不明白為什么會這樣。也許一些Django專家可以向我解釋。)這似乎也適用於其他一些模塊。 在這一點上,我認為假設將導入settings.py的次數是不明智的。 就此而言,這種假設一般不安全。 我在settings.py以外的地方有這個代碼,結果很相似。

你必須圍繞這個編碼。 也就是說,在向其添加其他處理程序之前,您必須檢查記錄器中的現有處理程序。 這有點難看,因為將多個處理程序(即使是相同類型)連接到一個記錄器是完全合理的。 有一些解決方案可以解決這個問題。 一個是檢查記錄器對象的處理程序屬性。 如果您只需要一個處理程序且長度> 0,則不要添加它。 就個人而言,我不喜歡這個解決方案,因為它會讓更多處理程序變得混亂。

我更喜歡這樣的東西(感謝Thomas Guettler):

# file logconfig.py
if not hasattr(logging, "set_up_done"):
    logging.set_up_done=False

def set_up(myhome):
    if logging.set_up_done:
        return
    # set up your logging here
    # ...
    logging.set_up_done=True

我必須說,我希望Django多次導入settings.py更好地記錄下來。 而且我會想象我的配置會以某種方式導致這種多重導入,但我無法找到導致問題的原因以及原因。 也許我只是在他們的文檔中找不到,但我認為這是你需要警告用戶的事情。

從版本1.3開始,Django使用標准的python日志記錄,使用LOGGING設置進行配置(此處記錄: 1.3dev )。

Django日志參考: 1.3dev

很難對您的具體案例發表評論。 如果settings.py執行兩次,那么每發送一次日志就會得到兩行是正常的。

我們遇到了同樣的問題,所以我們在項目中設置了一個專門用於記錄的模塊。 那些模塊有一個“模塊單例”模式,所以我們只執行一次有趣的代碼。

它看起來像這樣:

def init_logging():
    stdoutHandler = logging.StreamHandler( sys.stdout )
    stdoutHandler.setLevel( DEBUG )
    stdoutHandler.setFormatter( logging.Formatter( LOG_FORMAT_WITH_TIME ) )
    logging.getLogger( LOG_AREA1 ).addHandler( stdoutHandler )

logInitDone=False #global variable controlling the singleton.
if not logInitDone:
    logInitDone = True
    init_logging()

首次導入log.py將正確配置日志記錄。

恢復舊線程,但在使用dictConfig格式的 Django 1.3 Python日志記錄時,我遇到了重復的消息。

disable_existing_loggers通過多個settings.py加載消除了重復的處理程序/日志記錄問題,但如果未在特定logger上正確指定propagate布爾值,則仍可以獲取重復的日志消息。 即,確保為子記錄器設置propagate=False 例如,

'loggers': {
    'django': {
        'handlers':['null'],
        'propagate': True,
        'level':'INFO',
    },
    'django.request': {
        'handlers': ['console'],
        'level': 'ERROR',
        'propagate': False,
    },
    'project': {
        'handlers': ['console', 'project-log-file'],
        'level': 'DEBUG',
        'propagate': True,
    },
    'project.customapp': {
        'handlers': ['console', 'customapp-log-file'],
        'level': 'DEBUG',
        'propagate': False,
    },
}

這里, project.customapp設置propagate=False以便它也不會被project記錄器捕獲。 Django日志記錄文檔一如既往地非常出色。

回答關於為什么“Django多次導入settings.py”的問題:它沒有。

實際上,它確實會被導入兩次(跳過第一個代碼塊以進入它,但如果你有時間則讀取一個好的):

http://blog.dscpl.com.au/2010/03/improved-wsgi-script-for-use-with.html

PS-抱歉恢復舊線程。

您可以通過在執行init時檢查處理程序的數量來解決您的問題。

def init_logging():
    stdoutHandler = logging.StreamHandler( sys.stdout )
    stdoutHandler.setLevel( DEBUG )
    stdoutHandler.setFormatter( logging.Formatter( LOG_FORMAT_WITH_TIME ) )
    logger = logging.getLogger( LOG_AREA1 )
    if len(logger.handlers) < 1:
        logger.addHandler( stdoutHandler )

我不認為這是處理它的好方法。 就個人而言,為了使用python日志記錄模塊登錄django,我在views.py中為我感興趣的每個應用程序創建一個記錄器,然后在每個視圖函數中獲取記錄器。

from django.http import HttpResponse
from magic import makeLogger
from magic import getLogger

makeLogger('myLogName', '/path/to/myLogName.log')
def testLogger(request):
    logger = getLogger('myLogName')
    logger.debug('this worked')
    return HttpResponse('TEXT, HTML or WHATEVER')

這是關於調試django的一篇非常好的文章,並涵蓋了一些日志記錄: http//simonwillison.net/2008/May/22/debugging/

回答關於為什么“Django多次導入settings.py”的問題:它沒有。

您可能正在運行一個多進程/多線程Web服務器,它創建了幾個python子解釋器,其中每個子解釋器都會從您的django應用程序中導入一次代碼。

在django測試服務器上測試,您應該看到多次導入設置。

前段時間,我用我的第一個django / apache應用程序設計了一個不錯的單例(python borg成語版本更加精確),然后我很快意識到是的,我創建了多個單例實例...

您還可以使用一次運行的中間件來獲得類似的效果,而不使用私有變量。 請注意,這只會配置Web請求的日志記錄 - 如果要在shell或命令運行中登錄,則需要找到不同的解決方案。

from django.conf import settings
from django.core.exceptions import MiddlewareNotUsed
import logging
import logging.handlers
import logging.config

__all__ = ('LoggingConfigMiddleware',)


class LoggingConfigMiddleware:
    def __init__(self):
        '''Initialise the logging setup from settings, called on first request.'''
        if hasattr(settings, 'LOGGING'):
            logging.config.dictConfig(settings.LOGGING)
        elif getattr(settings, 'DEBUG', False):
            print 'No logging configured.'
        raise MiddlewareNotUsed('Logging setup only.')

為什么使用python logger而不是django-logging? 試一試它可能只是解決你的問題。

http://code.google.com/p/django-logging/wiki/Overview

目前它只允許查看根記錄器,但您可以確保寫入多個記錄器。

一種hackish方式,但您可以嘗試將日志代碼放在admin.py中。 它應該只導入一次。

另外; 你能先檢查MyApp.views.scans日志是否存在嗎? 如果它存在(可能引發錯誤),您可以簡單地跳過創建(因此不再添加處理程序)。 一個更干凈的方式,但我沒有嘗試過這個。

還有一個更適合放置此代碼的地方( __init__.py ?)。 settings.py用於設置。

要添加到A Lee帖子,python日志記錄文檔說明了有關傳播的內容:

Logger.propagate

如果此計算結果為false,則此記錄器或其子記錄器不會將記錄消息傳遞給更高級別(祖先)記錄器的處理程序。 構造函數將此屬性設置為1。

這意味着如果propagate == False子記錄器不會將記錄消息傳遞給其父記錄器

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM