2009-10-21 14 views
83

Muszę jeszcze znaleźć sposób na skonfigurowanie logowania w Pythonie z Django, z czego jestem zadowolony. Moje wymagania są dość proste:Elegancka konfiguracja logowania w Pythonie w Django

  • Różne koparki dziennika do różnych sytuacji - to znaczy, chcę być w stanie zalogować się do różnych plików
  • Łatwy dostęp do rejestratorów w moich modułów. Moduł powinien być w stanie znaleźć rejestrator przy niewielkim wysiłku.
  • Powinien być łatwy do zastosowania w modułach wiersza poleceń. Części systemu są niezależnymi procesami linii poleceń lub demonów. Logowanie przy użyciu tych modułów powinno być łatwe.

Moja obecna konfiguracja polega na użyciu pliku i konfiguracji instalacji w każdym module, z którego loguję. To nie jest w porządku.

Czy masz konfigurację logowania, którą lubisz? Podaj szczegóły: jak konfigurujesz konfigurację (czy używasz logging.conf lub konfigurujesz ją w kodzie), gdzie/kiedy inicjujesz rejestratory i jak uzyskujesz do nich dostęp w swoich modułach, itp.

+1

Poniższy screencast może być przydatny - http://ericholscher.com/blog/2008/aug/29/screencast-2-logging-fun-and-profit/. Lepsze wsparcie dla logowania w Django zaproponował Simon Willison (patrz http://simonwillison.net/2009/Sep/28/ponies/). –

+0

@ Dominic Rodger - Możesz już robić elastyczne rejestrowanie aplikacji w Django, propozycji Simona, głównie w celu ułatwienia logowania w wewnętrznych Django.W Pythonie jest praca do dodania konfiguracji słownikowej do logowania Pythona, z którego może skorzystać Django. –

Odpowiedz

49

Najlepszym sposobem, jaki znalazłem do tej pory, jest zainicjowanie ustawień rejestrowania w settings.py - nigdzie indziej. Możesz użyć pliku konfiguracyjnego lub programowo krok po kroku - zależy to tylko od twoich wymagań. Kluczową sprawą jest to, że zazwyczaj dodajemy obsługę do rejestratora głównego, używając poziomów, a czasami loguję. Filtry, aby uzyskać pożądane zdarzenia, do odpowiednich plików, konsoli, syslogów itp. Oczywiście można dodać programy obsługi do innych rejestratorów. też, ale nie ma takiej potrzeby w moim doświadczeniu.

W każdym module I zdefiniować rejestrator używając

logger = logging.getLogger(__name__) 

i używać do rejestrowania zdarzeń w module (i, jeśli chcę, aby różnicować dalej) używać rejestratora, który jest dzieckiem rejestratora tworzone powyżej.

Jeśli moja aplikacja ma być potencjalnie wykorzystane w miejscu, które nie konfiguruje rejestrowanie w settings.py, I zdefiniować NullHandler gdzieś w następujący sposób:

#someutils.py 

class NullHandler(logging.Handler): 
    def emit(self, record): 
     pass 

null_handler = NullHandler() 

i upewnić się, że wystąpienie to jest dodano do wszystkich rejestratorów utworzonych w modułach w moich aplikacjach, które korzystają z rejestrowania. (Uwaga: NullHandler jest już w pakiecie rejestrowanie dla Pythona 3.1, i będzie w Pythonie 2.7.) Tak więc:

logger = logging.getLogger(__name__) 
logger.addHandler(someutils.null_handler) 

Ma to na celu zapewnienie, że moduły grać ładnie w miejscu, które nie konfiguruje rejestrowanie w settings.py, i że nie dostaniesz irytujących "Nie znaleziono komunikatorów dla komunikatów XYZ" (które są ostrzeżeniami o potencjalnie błędnie skonfigurowanym protokołowaniu).

Robi to w ten sposób spełnia swoje ustalonymi wymaganiami:

  • Można skonfigurować różne programy obsługi dziennika do różnych sytuacji, jak obecnie zrobić.
  • Łatwy dostęp do rejestratorów w modułach - użyj getLogger(__name__).
  • Łatwo stosuje się do modułów wiersza poleceń - również importuje settings.py.

Aktualizacja: Zauważ, że od wersji 1.3, Django teraz wciela support for logging.

+0

Czy to nie będzie wymagać, aby każdy moduł miał zdefiniowany handler w konfiguracji (nie możesz użyć handler'a dla foo do obsługi foo.bar)? Zobacz rozmowę, którą odbyliśmy wiele lat temu pod adresem http://groups.google.com/group/comp.lang.python/browse_thread/thread/6a199393bcee6c1b/2ddf482a44bc4bb1 –

+1

@andrew cooke: * możesz * użyć programu do obsługi 'foo' do obsłużyć zdarzenia zarejestrowane do 'foo.bar'. Re. ten wątek - zarówno fileConfig, jak i dictConfig mają teraz opcje, które zapobiegają wyłączaniu starych rejestratorów. Zobacz ten problem: http://bugs.python.org/issue3136, który pojawił się kilka miesięcy po Twoim wydaniu http://bugs.python.org/issue2697 - tak czy inaczej, został rozwiązany od czerwca 2008. –

+0

lepiej byłoby zrobić polecenie 'logger = someutils.getLogger (__ nazwa __)' gdzie 'someutils.getLogger' zwraca logger z' logging.getLogger' z już dodaną obsługą typu null_handler? – 7yl4r

6

Obecnie korzystam z systemu logowania, który sam stworzyłem. Do rejestrowania używa formatu CSV.

django-csvlog

Projekt ten nadal nie ma pełnej dokumentacji, ale pracuję nad tym.

6

Inicjujemy logowanie do najwyższego poziomu urls.py przy użyciu pliku logging.ini.

Lokalizacja logging.ini jest podana w settings.py, ale to wszystko.

Każdy moduł następnie robi

logger = logging.getLogger(__name__) 

Aby odróżnić badania, rozwój i instancje produkcyjne, mamy różne pliki logging.ini. W większości przypadków mamy "dziennik konsoli", który trafia na stderr tylko z błędami. Mamy "dziennik aplikacji", który używa zwykłego ruchomego pliku dziennika, który trafia do katalogu dzienników.

+0

Skończyło się na tym, z wyjątkiem inicjowania w settings.py zamiast urls.py – Parand

+0

Jak używać ustawień z pliku settings.py w pliku logging.ini? Na przykład potrzebuję ustawienia BASE_DIR, więc mogę powiedzieć, gdzie przechowywać moje pliki dziennika. – slypete

+0

@slypete: Nie używamy ustawień w pliku logging.ini. Ponieważ rejestrowanie jest w dużej mierze niezależne, nie używamy żadnego z ustawień Django. Tak, istnieje możliwość powtórzenia czegoś. Nie, nie ma dużej różnicy praktycznej. –

114

Wiem, że to już rozwiązana odpowiedź, ale zgodnie z django> = 1.3 jest nowe ustawienie rejestrowania.

Przeprowadzka ze starego na nowy nie jest automatyczna, więc pomyślałem, że zapiszę to tutaj.

I oczywiście kasy the django doc po więcej.

Jest to podstawowa conf, domyślnie tworzone z django-admin createproject v1.3 - przebieg może się zmienić z najnowszych wersji django:

LOGGING = { 
    'version': 1, 
    'disable_existing_loggers': False, 
    'handlers': { 
     'mail_admins': { 
      'level': 'ERROR', 
      'class': 'django.utils.log.AdminEmailHandler', 
     } 
    }, 
    'loggers': { 
     'django.request': { 
      'handlers': ['mail_admins'], 
      'level': 'ERROR', 
      'propagate': True, 
     } 
    } 
} 

Struktura ta bazuje na standardowym Python logging dictConfig, że narzuca następujące bloki:

  • formatters - odpowiednia wartość będzie DICT, w której każdy klawisz jest id formater i każda wartość jest DICT opisujący jak skonfigurować odpowiednią instancję formatyzatora.
  • filters - odpowiednia wartość będzie dict, w którym każdy klucz jest identyfikatorem filtra, a każda wartość jest dyktando opisujące, jak skonfigurować odpowiednią instancję Filter.
  • handlers - odpowiednią wartością będzie dyktat, w którym każdy klucz jest identyfikatorem osoby obsługującej, a każda wartość jest dict opisującym, jak skonfigurować odpowiednią instancję Handler. Każdy handler ma następujące klucze:

    • class (obowiązkowe). Jest to w pełni kwalifikowana nazwa klasy obsługi.
    • level (opcjonalnie). Poziom obsługi.
    • formatter (opcjonalnie). Identyfikator formatyzatora dla tego programu obsługi.
    • filters (opcjonalnie). Lista identyfikatorów filtrów dla tego programu obsługi.

zwykle zrobić przynajmniej to:

  • dodać plik .log
  • skonfigurować swoje aplikacje, by napisać do tego dziennika

co przekłada się na:

LOGGING = { 
    'version': 1, 
    'disable_existing_loggers': False, 
    'formatters': { 
     'verbose': { 
      'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' 
     }, 
     'simple': { 
      'format': '%(levelname)s %(message)s' 
     }, 
    }, 
    'filters': { 
     'require_debug_false': { 
      '()': 'django.utils.log.RequireDebugFalse' 
     } 
    }, 
    'handlers': { 
     'null': { 
      'level':'DEBUG', 
      'class':'django.utils.log.NullHandler', 
     }, 
     'console':{ 
      'level': 'DEBUG', 
      'class': 'logging.StreamHandler', 
      'formatter': 'simple' 
     }, 
     # I always add this handler to facilitate separating loggings 
     'log_file':{ 
      'level': 'DEBUG', 
      'class': 'logging.handlers.RotatingFileHandler', 
      'filename': os.path.join(VAR_ROOT, 'logs/django.log'), 
      'maxBytes': '16777216', # 16megabytes 
      'formatter': 'verbose' 
     }, 
     'mail_admins': { 
      'level': 'ERROR', 
      'filters': ['require_debug_false'], 
      'class': 'django.utils.log.AdminEmailHandler', 
      'include_html': True, 
     } 
    }, 
    'loggers': { 
     'django.request': { 
      'handlers': ['mail_admins'], 
      'level': 'ERROR', 
      'propagate': True, 
     }, 
     'apps': { # I keep all my of apps under 'apps' folder, but you can also add them one by one, and this depends on how your virtualenv/paths are set 
      'handlers': ['log_file'], 
      'level': 'INFO', 
      'propagate': True, 
     }, 
    }, 
    # you can also shortcut 'loggers' and just configure logging for EVERYTHING at once 
    'root': { 
     'handlers': ['console', 'mail_admins'], 
     'level': 'INFO' 
    }, 
} 

edit

Zobacz request exceptions are now always logged i Ticket #16288:

zaktualizowałem powyższy przykładowy conf jawnie zawierać poprawną filtr dla mail_admins tak, że domyślnie, e-maile nie są wysyłane podczas debugowania jest prawda.

Należy dodać filtr:

'filters': { 
    'require_debug_false': { 
     '()': 'django.utils.log.RequireDebugFalse' 
    } 
}, 

i zastosować go do obsługi mail_admins:

'mail_admins': { 
     'level': 'ERROR', 
     'filters': ['require_debug_false'], 
     'class': 'django.utils.log.AdminEmailHandler', 
     'include_html': True, 
    } 

Inaczej django.core.handers.base.handle_uncaught_exception nie przechodzi do 'błędów' django.request rejestratorze Jeśli ustawienia .DEBUG jest prawdziwe.

Jeśli nie to zrobić w Django 1.5 dostaniesz

DeprecationWarning: Nie masz filtry zdefiniowane na rejestrowanie obsługi do „mail_admins”: dodawanie niejawna debug-fałszywie tylko filtrować

ale rzeczy nadal będą działały poprawnie ZARÓWNO w django 1.4 i django 1.5.

** edit koniec **

To conf jest silnie inspirowana konf próbki w doc django, ale dodając część pliku dziennika.

często również wykonać następujące czynności:

LOG_LEVEL = 'DEBUG' if DEBUG else 'INFO' 

... 
    'level': LOG_LEVEL 
... 

Wtedy w moim kodu Pythona zawsze dodać NullHandler w przypadku rejestrowania conf nie jest zdefiniowana w ogóle. Zapobiega to ostrzeżeniom dla określonego Handler'a. Szczególnie przydatny dla bibliotekami, które niekoniecznie są wywoływane tylko w Django (ref)

import logging 
# Get an instance of a logger 
logger = logging.getLogger(__name__) 
class NullHandler(logging.Handler): #exists in python 3.1 
    def emit(self, record): 
     pass 
nullhandler = logger.addHandler(NullHandler()) 

# here you can also add some local logger should you want: to stdout with streamhandler, or to a local file... 

[...]

logger.warning('etc.etc.') 

Nadzieja to pomaga!

+0

Stefano, wielkie dzięki za szczegółową odpowiedź, bardzo pomocne. To może sprawić, że warto będzie przejść na wersję 1.3. – Parand

+0

Parand, zdecydowanie jest (IMHO!), Warto wkroczyć do django 1.3, ale jest kilka punktów, które warto zadbać o płynne przejście - otwórz nowe pytanie SO, jeśli wpadniesz w kłopoty ;-) – Stefano

+0

przy okazji: Nadal używam tego rodzaju ustawień i dziennika plików, ale przeniosłem się do [sentry] (https://github.com/dcramer/sentry) do produkcji! – Stefano

Powiązane problemy