Django Setup Default Logging

94

Nie wiem jak ustawić "domyślny" program rejestrujący dla mojej instalacji Django. Chciałbym użyć nowego LOGGINGustawienia Django 1.3 w settings.py.

Przyjrzałem się przykładowi Django Logging Doc , ale wydaje mi się, że konfigurują one tylko programy obsługi, które będą rejestrować dane dla poszczególnych rejestratorów. W ich przykładzie ustawili program obsługi dla loggerów o nazwach „django”, „django.request” i „myproject.custom”.

Chcę tylko ustawić domyślną, logging.handlers.RotatingFileHandlerktóra będzie obsługiwać wszystkie rejestratory. tzn. jeśli zrobię nowy moduł gdzieś w moim projekcie i będzie oznaczony przez coś takiego my_app_name.my_new_module:, powinienem być w stanie to zrobić i mieć wszystkie dzienniki przechodzące do rotujących dzienników plików.

# In file './my_app_name/my_new_module.py'
import logging
logger = logging.getLogger('my_app_name.my_new_module')
logger.debug('Hello logs!') # <-- This should get logged to my RotatingFileHandler that I setup in `settings.py`!
Chris W.
źródło

Odpowiedzi:

154

Domyśliłam się...

Ustawić „catch all” rejestratora poprzez odniesienie go z pustym ciągiem: ''.

Na przykład w poniższej konfiguracji zapisywane są wszystkie zdarzenia dziennika logs/mylog.log, z wyjątkiem django.requestzdarzeń dziennika, w których zostaną zapisane logs/django_request.log. Ponieważ 'propagate'jest ustawiony Falsena mój django.requestrejestrator, zdarzenie dziennika nigdy nie dotrze do programu rejestrującego „catch all”.

LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'standard': {
            'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
        },
    },
    'handlers': {
        'default': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': 'logs/mylog.log',
            'maxBytes': 1024*1024*5, # 5 MB
            'backupCount': 5,
            'formatter':'standard',
        },  
        'request_handler': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': 'logs/django_request.log',
            'maxBytes': 1024*1024*5, # 5 MB
            'backupCount': 5,
            'formatter':'standard',
        },
    },
    'loggers': {
        '': {
            'handlers': ['default'],
            'level': 'DEBUG',
            'propagate': True
        },
        'django.request': {
            'handlers': ['request_handler'],
            'level': 'DEBUG',
            'propagate': False
        },
    }
}
Chris W.
źródło
2
Chris, dokumentacja Django na ten temat nie jest myląca. Dzięki za to.
5
Drobna poprawka: komentarz sugeruje, że rejestrowanie sql będzie miało wpływ na rejestrator django.request. Aby przekierować rejestrowanie sql, należy zdefiniować program rejestrujący dla „django.db”. Rejestrator django.request obsługuje odpowiedzi http 5xx i 4xx.
rych
W tym pomaga innym noobom takim jak ja: Logger utworzy pliki dziennika, ale najpierw musisz utworzyć logs/folder :-). W przeciwnym razie po uruchomieniu pojawi się błąd ./manange.py runserver. @Chris W. Dzięki za przykładowe ustawienia logowania. Bardzo mi to pomogło!
hobbes
3
@arindamroychowdhury Z powyższej konfiguracji, jeśli nie logger = logging.getLogger('foo'); logger.warn('bar');wtedy defaultobsługi złapie że rejestrowanie i coś jak <time> WARN: foo: barzakończy sięlogs/mylog.log
Chris W.
8
Dzięki, wygląda na to, że to '' oznacza root logger. Ta przydatna informacja nie została znaleziona w dokumentacji Django.
Eino Mäkitalo
25

Jak powiedziałeś w swojej odpowiedzi , Chris, jedną z opcji definiowania domyślnego programu rejestrującego jest użycie pustego ciągu jako jego klucza.

Myślę jednak, że zamierzonym sposobem jest zdefiniowanie specjalnego rejestratora pod rootkluczem słownika konfiguracji logowania. Znalazłem to w dokumentacji Pythona :

root - będzie to konfiguracja dla głównego programu rejestrującego. Konfiguracja będzie przetwarzana jak w przypadku każdego rejestratora, z tą różnicą, że propagateustawienie nie będzie miało zastosowania.

Oto konfiguracja z Twojej odpowiedzi zmieniona w celu użycia rootklucza:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'standard': {
            'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
        },
    },
    'handlers': {
        'default': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': 'logs/mylog.log',
            'maxBytes': 1024*1024*5, # 5 MB
            'backupCount': 5,
            'formatter':'standard',
        },  
        'request_handler': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': 'logs/django_request.log',
            'maxBytes': 1024*1024*5, # 5 MB
            'backupCount': 5,
            'formatter':'standard',
        },
    },
    'root': {
        'handlers': ['default'],
        'level': 'DEBUG'
    },
    'loggers': {
        'django.request': {
            'handlers': ['request_handler'],
            'level': 'DEBUG',
            'propagate': False
        },
    }
}

Szczerze mówiąc, nie widzę żadnej różnicy w zachowaniu między tymi dwiema konfiguracjami. Wygląda na to, że zdefiniowanie programu rejestrującego z pustym kluczem w postaci ciągu zmodyfikuje rejestrator główny, ponieważ logging.getLogger('')zwróci rejestrator główny.

Jedynym powodem, dla którego wolę 'root'od ''niego, jest to, że wyraźnie dotyczy modyfikowania głównego programu rejestrującego. Jeśli byłeś ciekawy, 'root'nadpisuje, ''jeśli zdefiniujesz oba, tylko dlatego, że wpis root jest przetwarzany jako ostatni.

Don Kirkby
źródło
Tak, zgadza się, przepraszam za błąd! Podczas gdy używanie „” zamiast „root” jest nieco logiczne, nadal uważam, że przenoszenie rootwpisu do katalogu głównego dyktu w procesie płynnego przejścia z logiki fileConfig 2.6 do logiki 2.7 dictConfig jest nieco niespójne .
Antony Hatchkins
2
import logging
logger = logging.getLogger(__name__)

po dodaniu:

logging.basicConfig(
    level = logging.DEBUG,
    format = '%(name)s %(levelname)s %(message)s',
)

możemy zmienić format na:

format = '"%(levelname)s:%(name)s:%(message)s"  ',

lub

format = '%(name)s %(asctime)s %(levelname)s %(message)s',
Sérgio
źródło
0

Zrobiłem szybki przykład, aby sprawdzić, jaka konfiguracja jest używana, gdy zarówno rootklucz, jak i pusty ''rejestrator są przywoływane w config dict.

import logging.config

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'fmt1': {
            'format': '[FMT1] %(asctime)-15s %(message)s',
        },
        'fmt2': {
            'format': '[FMT2] %(asctime)-15s %(message)s',
        }
    },
    'handlers': {
        'console1': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'fmt1',
        },
        'console2': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'fmt2',
        },
    },
    # First config for root logger: console1 -> fmt1
    'root': {
        'handlers': ['console1'],
        'level': 'DEBUG',
        'propagate': True,
    },
    'loggers': {
        # Second config for root logger: console2 -> fmt2
        '': {
            'handlers': ['console2'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}

logging.config.dictConfig(LOGGING)

l1 = logging.getLogger()
l2 = logging.getLogger('')
root = logging.root

l1.info("l1")
l2.info("l2")
root.info("root logger")

Drukuje następujący wynik:

[FMT1] 2018-12-18 17:24:47,691 l1
[FMT1] 2018-12-18 17:24:47,691 l2
[FMT1] 2018-12-18 17:24:47,691 root logger

wskazując, że konfiguracja pod rootkluczem ma najwyższy priorytet. Jeśli blok zostanie usunięty, wynikiem jest:

[FMT2] 2018-12-18 17:25:43,757 l1
[FMT2] 2018-12-18 17:25:43,757 l2
[FMT2] 2018-12-18 17:25:43,757 root logger

W obu przypadkach, byłem w stanie do debugowania i ustalić, że wszystkie trzy rejestratory ( l1, l2a root) odniesione tego samego wystąpienia rejestratora, rejestrator korzeniowy.

Mam nadzieję, że pomoże to innym, którzy, tak jak ja, byli zdezorientowani dwoma różnymi sposobami konfiguracji głównego rejestratora.

Antwane
źródło