Logowanie błędów w web aplikacji to dość ważna rzecz. Czasami taki podsystem działa out-of-the-box, czasami wystarczy dobrze skonfigurować. Czasami coś po prostu nie działa :) ... i to zdarzyło się właśnie wtedy gdy postanowiłem w aplikacji opartej na Django zastosować logowanie do systemowego loggera.
Szybkie googlowanie wykazało że by dodać logowanie wiadomości do systemowego loggera w django wystarczy dodać do konfiguracji:
from logging.handlers import SysLogHandler LOGGING = { #... 'syslog':{ 'level':'INFO', 'class': 'logging.handlers.SysLogHandler', 'facility': SysLogHandler.LOG_LOCAL5 } #... }
... po uruchomieniu okazuje się że.. sposób ten nie działa :)
Okazuje się że domyślnym zachowaniem SysLogHandler'a jest łączenie się z procesem sysloga poprzez port 514. W moim systemie używany jest unix-socket w /dev/log.
Musimy więc dodać nowy klucz do naszej konfiguracji, wskazując tym samym na nasz socket:
LOGGING = { 'syslog':{ #to samo co wcześniej 'address': '/dev/log' }, }
Część osób w tym momencie będzie miała już działające logowanie, ja nie miałem tego szczęścia - nie wiedzieć czemu, wiadomości wciąż nie były łapane przez syslog'a. Po chwili gimnastyki z kodem wiedziałem że socket jest używany, wiadomość jest wysyłana lecz z jakiegoś powodu nie jest odczytywana przez logera systemowego. Dlaczego?
O pomoc zwróciłem się do google :) W końcu natrafiłem na maila z 2010 roku.
Okazuje się że problemem był fakt posiadania Metalog'a - składnia wiadomości była przez niego odrzucana. Rozwiązanie jest dość proste:
Rozwiązanie z klassą
Osobiście nie przepadam za umieszczaniem "magicznych tekstów" (patrz - Rozwiązanie "szybko i prosto") w konfiguracji więc napisałem klasę MetaLogHandler:
# -*- coding: utf-8 -*- ''' Created on 13-12-2012 @author: Arkadiusz Dzięgiel ''' from logging.handlers import SysLogHandler import logging class MetaLogHandler(SysLogHandler): def __init__(self, *args, **kwargs): super(MetaLogHandler, self).__init__(*args, **kwargs) self.formatter = logging.Formatter('%(asctime)s %(name)s: %(levelname)s %(message)s', '%b %e %H:%M:%S')
Jej użycie:
from glorpenlib.logging.handlers import MetaLogHandler LOGGING = { 'handlers': { 'syslog':{ 'level':'INFO', 'class': 'glorpenlib.logging.handlers.MetaLogHandler', 'facility': MetaLogHandler.LOG_LOCAL5, 'address': '/dev/log' }, } }
Rozwiązanie "szybko i prosto"
Można też umieścić tekst formatujący prosto w konfiguracji, wyglądałaby ona wtedy następująco:
from logging.handlers import SysLogHandler LOGGING = { 'formatters': { 'metalog': { 'format': '%(asctime)s %(name)s: %(levelname)s %(message)s', 'dateformat': '%b %e %H:%M:%S'} }, 'handlers': { 'syslog':{ 'level':'INFO', 'class': 'logging.handlers.SysLogHandler', 'formatter': 'metalog', 'facility': SysLogHandler.LOG_LOCAL5, 'address': '/dev/log' }, } }