2008-12-04 42 views
40

Tôi đang phát triển một ứng dụng Django và tôi đang cố sử dụng mô-đun ghi nhật ký của Python để ghi nhật ký lỗi/theo dõi. Lý tưởng nhất là tôi muốn có các logger khác nhau được cấu hình cho các khu vực khác nhau của trang web. Cho đến nay tôi đã có tất cả những việc này, nhưng có một điều khiến tôi gãi đầu.Đăng nhập bằng Python ở Django

Tôi có trình ghi nhật ký gốc tới sys.stderr và tôi đã định cấu hình trình ghi nhật ký khác để ghi vào tệp. Tệp này nằm trong tệp settings.py của tôi:

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) 

Có vẻ khá đơn giản. Đây là vấn đề, mặc dù: bất cứ điều gì tôi viết vào sviewlog được ghi vào tập tin đăng nhập hai lần. Bộ ghi gốc chỉ in nó một lần. Nó giống như addHandler() đang được gọi hai lần. Và khi tôi đặt mã của mình thông qua trình gỡ lỗi, đây chính xác là những gì tôi thấy. Mã trong settings.py được thực hiện hai lần, do đó, hai FileHandlers được tạo và được thêm vào cùng một cá thể của trình ghi nhật ký. Nhưng tại sao? Và làm thế nào để tôi có được điều này?

Có ai có thể cho tôi biết điều gì đang xảy ra ở đây không? Tôi đã cố gắng di chuyển các mã instantger logger/handler instantiation vào tập tin mà nó được sử dụng (kể từ đó thực sự có vẻ như là nơi thích hợp với tôi), nhưng tôi có cùng một vấn đề đó. Hầu hết các ví dụ tôi đã thấy trực tuyến chỉ sử dụng trình ghi nhật ký gốc và tôi muốn có nhiều trình ghi nhật ký.

Trả lời

30

Cho phép tôi trả lời câu hỏi của riêng mình. Vấn đề cơ bản ở đây là settings.py được nhập hai lần, hoặc thậm chí có thể nhiều hơn (Xem here). (Tôi vẫn không hiểu tại sao điều này. Có lẽ một số chuyên gia Django có thể giải thích điều đó với tôi.) Điều này cũng đúng với một số mô-đun khác. Tại thời điểm này tôi không nghĩ rằng nó là khôn ngoan để đưa ra giả định về bao nhiêu lần settings.py sẽ được nhập khẩu. Đối với vấn đề đó, giả định như vậy không an toàn nói chung. Tôi đã có mã này ở những nơi khác ngoài settings.py và kết quả tương tự.

Bạn phải viết mã này. Đó là, bạn phải kiểm tra logger của bạn cho các trình xử lý hiện có trước khi thêm các trình xử lý bổ sung vào nó. Đây là một chút xấu xí bởi vì nó hoàn toàn hợp lý để có nhiều trình xử lý - ngay cả cùng loại - được đính kèm với một trình ghi nhật ký. Có một vài giải pháp để giải quyết vấn đề này. Một là kiểm tra các thuộc tính xử lý của đối tượng logger của bạn. Nếu bạn chỉ muốn một trình xử lý và độ dài của bạn> 0, thì đừng thêm nó. Cá nhân tôi không yêu giải pháp này, bởi vì nó bị lộn xộn với nhiều trình xử lý hơn.

tôi thích một cái gì đó như thế này (nhờ 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 

tôi phải nói, tôi muốn sự thật rằng Django nhập khẩu settings.py nhiều lần được ghi nhận tốt hơn. Và tôi sẽ tưởng tượng rằng cấu hình của tôi bằng cách nào đó gây ra nhiều lần nhập này, nhưng tôi đang gặp khó khăn trong việc tìm ra nguyên nhân gây ra sự cố và lý do tại sao. Có lẽ tôi không thể tìm thấy điều đó trong tài liệu của họ, nhưng tôi nghĩ đó là thứ bạn cần để cảnh báo người dùng của mình.

+3

Tôi không có chuyên gia Django, nhưng tôi tưởng tượng rằng settings.py sẽ được nhập mỗi khi một mô-đun được tải có một câu lệnh nhập khẩu với "cài đặt" trong đó. Càng nhiều mô-đun sử dụng settings.py, càng nhiều lần được nhập. –

+2

@HartleyBrody [python cache modules] (http://docs.python.org/release/2.6/reference/simple_stmts.html#the-import-statement) khi chúng được tải, vì vậy thường một mô-đun nhất định chỉ được thực hiện một lần, bất kể số lượng các báo cáo nhập khẩu xuất hiện ở đâu. –

+1

Theo [chú thích phát hành Django 1.4] (https://docs.djangoproject.com/en/dev/releases/1.4/#updated-default-project-layout-and-manage-py) vấn đề này có thể đã được giải quyết . –

1

Tại sao sử dụng nhật ký python thay vì django-logging? Hãy thử nó có thể chỉ giải quyết vấn đề của bạn.

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

Tại thời điểm nó sẽ chỉ cho phép để xem các logger gốc, nhưng bạn chắc chắn có thể viết thư cho nhiều người khai thác gỗ.

+5

Theo tôi được biết, django-logging không có mọi thứ cần làm với ghi nhật ký để tách các tệp. Việc sử dụng chính của nó là xuất thông điệp tường trình trên các trang ứng dụng của bạn, đây không phải là tính năng tôi cần vào thời điểm này. Vì vậy, tôi không thể nghĩ tại sao nó sẽ giải quyết vấn đề của tôi. – Jeff

+1

django-logging không còn được duy trì. Có một đề xuất trên trang dự án để sử dụng https://github.com/robhudson/django-debug-toolbar để ghi nhật ký phía máy khách – michela

14

Khó nhận xét về trường hợp cụ thể của bạn. Nếu settings.py được thực thi hai lần, thì bình thường bạn nhận được hai dòng cho mỗi bản ghi được gửi.

Chúng tôi đã có cùng một vấn đề, vì vậy chúng tôi đã thiết lập trong các dự án của mình để có một mô-đun dành riêng cho ghi nhật ký. Mô-đun đó có mẫu "mô-đun đơn", do đó chúng tôi chỉ thực thi mã thú vị một lần.

Nó trông như thế này:

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() 

Nhập các log.py lần đầu tiên sẽ cấu hình khai thác gỗ một cách chính xác.

+1

Tôi có đúng hay không - bằng cách này bạn phải 'nhập nhật ký, ghi nhật ký' hơn viết smthng như 'logger = logging.getLogger (LOG_AREA1)' và chỉ sau đó sử dụng nó như 'logger.info (bla-bla-bla)'? Có tốt hơn để trả về logger từ init_logging() ('return logging.getLogger ...') và đặt nó vào mô-đun var? Nói 'logger = init_logging()'. Bằng cách này bạn có thể import log.py và chỉ bắt đầu sử dụng nó 'import log; log.logger.info (bla-bla-bla) '? – NilColor

+1

Ồ! Và tất nhiên bạn có thể sử dụng trình ghi log cấp độ module nếu bạn muốn: 'log log; module_logger = log.logger.getLogger (__ name __) ' – NilColor

+0

Toàn bộ công cụ' logInitDone' này là vô ích. Nhìn vào nó, khi thực hiện hai lần 'logInitDone' luôn được đặt trở lại' False' để 'init_logging()' sẽ vẫn được gọi hai lần. Điều này chỉ hoạt động vì mô-đun chỉ được thực hiện một lần khi được nhập như được giải thích trong [câu trả lời này] (http://stackoverflow.com/questions/10936709/why-does-a-python-module-act-like-a-singleton). – RickyA

0

Cách tấn công, nhưng bạn có thể thử đặt mã đăng nhập bên trong admin.py. Nó được cho là chỉ được nhập một lần.

Cách khác; trước tiên bạn có thể kiểm tra xem có tồn tại nhật ký MyApp.views.scans không? Nếu nó tồn tại (có thể là một lỗi được nêu ra), bạn có thể chỉ cần bỏ qua việc tạo (và do đó không thêm trình xử lý một lần nữa). Một cách sạch hơn nhưng tôi đã không cố gắng này mặc dù.

Ngoài ra, phải có một nơi thích hợp hơn để đặt mã này (__init__.py?). settings.py dành cho cài đặt.

4

Bạn có thể khắc phục sự cố của mình bằng cách kiểm tra số lượng trình xử lý khi bạn đang thực hiện init của mình.

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) 

Tôi không nghĩ đây là cách tuyệt vời để xử lý. Cá nhân, để đăng nhập vào django với mô-đun đăng nhập python, tôi tạo một logger trong views.py cho mỗi ứng dụng mà tôi quan tâm, sau đó lấy logger trong mỗi chức năng xem.

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') 

Đây là một bài viết khá tốt về gỡ lỗi django và bao gồm một số đăng nhập: http://simonwillison.net/2008/May/22/debugging/

3

Để trả lời câu hỏi về việc tại sao không "Django nhập khẩu settings.py nhiều lần": nó không.

Có thể bạn đang chạy một máy chủ web đa xử lý/đa luồng tạo nhiều trình thông dịch phụ python, trong đó mỗi người nhập mã từ ứng dụng django của bạn một lần.

Kiểm tra trên máy chủ thử nghiệm django và bạn sẽ thấy cài đặt đó không được nhập nhiều lần. Một số thời gian trước đây, tôi đã thiết kế một singleton đẹp (phiên bản thành ngữ python borg chính xác hơn) với ứng dụng django/apache đầu tiên của tôi, trước khi tôi nhanh chóng nhận ra rằng có, tôi đã có nhiều hơn một singleton của tôi tạo ra. ..

6

'' để trả lời câu hỏi về việc tại sao không "Django nhập khẩu settings.py nhiều lần". nó không ''

Trên thực tế, nó được nhập khẩu hai lần (bỏ qua quá khứ đoạn mã đầu tiên để nhận được ngay vào nó nhưng một đọc tốt nếu bạn đã có thời gian):

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

PS-- Rất tiếc vì đã khôi phục một chuỗi cũ.

24

Kể từ phiên bản 1.3, Django sử dụng ghi nhật ký chuẩn python, được định cấu hình với cài đặt LOGGING (được ghi ở đây: 1.3, dev).

Tham chiếu khai thác Django: 1.3, dev.

3

Bạn cũng có thể sử dụng phần mềm Middleware chạy một lần để có được hiệu ứng tương tự, không có biến riêng tư. Lưu ý rằng điều này sẽ chỉ cấu hình việc ghi nhật ký các yêu cầu web - bạn sẽ cần phải tìm một giải pháp khác nếu bạn muốn đăng nhập vào trình bao hoặc lệnh của bạn chạy.

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.') 
11

Làm sống lại một chủ đề cũ, nhưng tôi đã trải qua thông điệp trùng lặp trong khi sử dụng Django 1,3 Python đăng nhập với dictConfig format.

disable_existing_loggers loại bỏ vấn đề xử lý trùng lặp/ghi nhật ký với nhiều cài đặt.py, nhưng bạn vẫn có thể nhận được thông báo tường trình trùng lặp nếu bạn không chỉ định propagate boolean phù hợp trên logger cụ thể. Cụ thể, hãy đảm bảo bạn đặt propagate=False cho nhật ký con. Ví dụ:

'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, 
    }, 
} 

Ở đây, project.customapp bộ propagate=False để nó sẽ không được đánh bắt bởi các project logger là tốt. Các Django logging docs là tuyệt vời, như mọi khi.

+1

Điều này cũng áp dụng cho cả Django 1.4. –

+1

Tương tự như vậy cho 1,6> BTW, cảm ơn cho tuyên truyền = Mẹo False, giải quyết vấn đề của tôi. –

0

Để thêm vào Một Lee bưu điện, tiểu bang tài liệu python logging này về tuyên truyền:

Logger.propagate

Nếu đây là false, đăng thông điệp không được thông qua bởi logger này hoặc bởi logger con của nó để xử lý các logger cấp cao hơn (tổ tiên). Các nhà xây dựng đặt thuộc tính này để 1.

Điều này có nghĩa rằng nếu propagate == False sau đó con logger sẽ KHÔNG chuyển thông điệp logging để logger mẹ

Các vấn đề liên quan