ZadaniePython: zwyczaj rejestrowania we wszystkich modułach
Mam zbiór skryptów i chciałbym im produkować jednolite logu z minimalnymi zmianami modułów robi zalogowaniu aktualne wiadomości.
Napisałem mały moduł "custom_logger", który mam zamiar wywołać z głównej aplikacji, gdy zwrócę logger, który będę dalej używał.
Submoduły będę importowania do aplikacji należy tylko (albo raczej życzę im)
- powinien jedynie „rejestrowanie import jako log” - tak, że wymagana jest nic konkretnego do mojej strony, aby one po prostu działają, gdy ktoś inny uzna je za przydatne.
- powinien po prostu rejestrować wiadomości za pomocą log.info/error('message ") bez dodawania niczego związanego z konkretną witryną.
- powinien używać już skonfigurowanego programu rejestrującego" root "z całym formatowaniem i handlerami i nie wpływać na program rejestrujący root konfiguracja
* custom_logger.py *
import logging
import logging.handlers
import os
import sys
def getLogger(name='root', loglevel='INFO'):
logger = logging.getLogger(name)
# if logger 'name' already exists, return it to avoid logging duplicate
# messages by attaching multiple handlers of the same type
if logger.handlers:
return logger
# if logger 'name' does not already exist, create it and attach handlers
else:
# set logLevel to loglevel or to INFO if requested level is incorrect
loglevel = getattr(logging, loglevel.upper(), logging.INFO)
logger.setLevel(loglevel)
fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s'
fmt_date = '%Y-%m-%dT%T%Z'
formatter = logging.Formatter(fmt, fmt_date)
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)
if logger.name == 'root':
logger.warning('Running: %s %s',
os.path.basename(sys.argv[0]),
' '.join(sys.argv[1:]))
return logger
Potem przychodzi submodule który ma kilka wiadomości testowych z przykładów tego, co działa, a co nie.
submodule.py
import sys
import custom_logger
import logging
class SubClass(object):
def __init__(self):
# NOK (no idea why since by default (no name parameter), it should return the root logger)
#log = logging.getLogger()
#log.info('message from SubClass/__init__')
# OK (works as expected)
#log = logging.getLogger('root')
#log.info('message from SubClass/__init__')
# OK (works as expected)
log = custom_logger.getLogger('root')
log.info('message from SubClass/__init__')
def SomeMethod(self):
# OK but I'd have to define `log` for every method, which is unacceptable
# Please see question below all code snippets
log = custom_logger.getLogger('root')
log.info('message from SubClass/SomeMethod')
A głównym app: app.py Nic specjalnego tutaj:
#!/usr/bin/python
import custom_logger
import submodule
log = custom_logger.getLogger('root', loglevel='DEBUG')
log.debug('debug message')
log.info('info message')
log.warning('warning message')
log.error('error message')
a = submodule.SubClass() # this should produce a log message
a.SomeMethod() # so should this
wyjściowa, że jestem po i że dostaję, po prostu w wyjątkowo brzydki sposób:
% ./app.py
2013-04-08T03:07:46BST custom_logger.py WARNING : Running: app.py
2013-04-08T03:07:46BST app.py DEBUG : debug message
2013-04-08T03:07:46BST app.py INFO : info message
2013-04-08T03:07:46BST app.py WARNING : warning message
2013-04-08T03:07:46BST app.py ERROR : error message
2013-04-08T03:07:46BST submodule.py INFO : message from SubClass/__init__
2013-04-08T03:07:46BST submodule.py INFO : message from SubClass/SomeMethod
Chcę móc zdefiniować program rejestrujący w aplikacji app.py, a następnie w submodułach używać tylko standardowej biblioteki rejestrowania w języku Python, aby użyć już skonfigurowanego rejestratora w pliku app.py.
Również brzydki obejście: gdybym umieścić poniższy kod po importu w submodule.py:
log = custom_logger.getLogger('root')
zostanie wykonany przed moja rejestrator jest skonfigurowany w app.py, skutecznie czyniąc submodule, nie moja rejestracja konfiguracji aplikacji.
Innym obejście Uważałem: w constuctor klasy podklasy, mógłbym określić
self.log = custom_logger.getLogger('root')
a następnie użyć self.log.error ('jakiś błąd'). Musi istnieć milsza droga - jeśli możesz zasugerować coś pożytecznego lub wskazać, gdzie źle zrozumiałem dokumentację, byłbym bardzo wdzięczny!
PS. Sporo czasu spędziłem czytając podręcznik logowania do Pythona (podstawowy i zaawansowany) oraz książkę kucharską, więc jeśli przegapiłem coś pożytecznego, proszę wskazać.
Dziękujemy!
Dziękuję Mihai. Myślałem, że będę miał więcej czasu, żeby się temu przyjrzeć, ale będę musiał poczekać na weekend. Do tej pory udało mi się uczynić moją klasę, która robi to wszystko (dołączanie formaterów, procedur obsługi i ustawiania języka), definiując log jako obiekt getLogger w submodule.py. Miałem nadzieję, że da się to zrobić bez umieszczania rzeczy poza definicją klasy. Moje pytanie brzmiało bardziej "dlaczego niektóre podejścia, które podjąłem, nie zadziałały zgodnie z oczekiwaniami, ponieważ chciałbym zrozumieć przyczynę tego, w przeciwieństwie do otrzymania przekazanego mi kodu, ale doceniam twoją pomoc:) –
Zaktualizowałem moją odpowiedź, poza tym, że możesz zajrzeć do kodu modułu, możesz zobaczyć, że główny dziennik jest tworzony podczas importowania, ja też tak naprawdę nie rozumiem, dlaczego getLogger ("root") nie działa tak samo we wszystkich sytuacjach (możesz zrobić getLogger() w app.py i getLogger ("root") w submodule.py i otrzymasz to, czego potrzebujesz, ale nie na odwrót) – Mihai
Jak zrobić to z przekierowaniem standardowym do pliku np. python ./app.py >> file.log? –