Używam rejestratora Pythona. Oto mój kod:
import os
import time
import datetime
import logging
class Logger :
def myLogger(self):
logger = logging.getLogger('ProvisioningPython')
logger.setLevel(logging.DEBUG)
now = datetime.datetime.now()
handler=logging.FileHandler('/root/credentials/Logs/ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
Problem polega na tym, że podczas każdego logger.info
połączenia otrzymuję wiele wpisów w pliku dziennika . Jak mogę to rozwiązać?
Odpowiedzi:
To
logging.getLogger()
już jest singleton. ( Dokumentacja )Problem polega na tym, że za każdym razem, gdy dzwonisz
myLogger()
, dodaje on kolejną procedurę obsługi do instancji, co powoduje zduplikowane dzienniki.Może coś takiego?
źródło
loggers.update(dict(name=logger))
? nie jestloggers[name] = logger
prostsze?loggers.update(dict(name=logger))
utworzy słownik z jednym wywołanym kluczemname
i będzie stale aktualizować ten sam klucz. Dziwię się, że nikt wcześniej o tym nie wspomniał, ponieważ ten kod jest dość zepsuty :) Wprowadzi wymagane poprawki.loggers
słownik globalny nie jest zbędnylogging.getLogger
? ponieważ naprawdę chcesz po prostu uniknąć dodawania dodatkowychOd Pythona 3.2 możesz po prostu sprawdzić, czy programy obsługi są już obecne, a jeśli tak, wyczyść je przed dodaniem nowych programów obsługi. Jest to bardzo wygodne podczas debugowania, a kod obejmuje inicjalizację programu rejestrującego
źródło
zrobił dla mnie sztuczkę
za pomocą Pythona 2.7
źródło
Użyłem już
logger
jako singletona i sprawdziłemif not len(logger.handlers)
, ale nadal otrzymałem duplikaty : było to sformatowane wyjście, a następnie niesformatowane.Rozwiązanie w moim przypadku:
logger.propagate = False
Podziękowania za tę odpowiedź i dokumenty .
źródło
Dzwonisz
Logger.myLogger()
więcej niż raz. Zapisz gdzieś zwracaną instancję rejestrującą i użyj jej ponownie .Pamiętaj również, że jeśli zalogujesz się przed dodaniem jakiegokolwiek modułu obsługi,
StreamHandler(sys.stderr)
zostanie utworzony domyślny .źródło
Implementacja loggera jest już singletonem.
Źródło - korzystanie z logowania w wielu modułach
Tak więc powinieneś to wykorzystać -
Załóżmy, że stworzyliśmy i skonfigurowaliśmy rejestrator o nazwie „main_logger” w głównym module (który po prostu konfiguruje rejestrator, nic nie zwraca).
Teraz w module podrzędnym, jeśli utworzymy rejestrator podrzędny zgodnie z hierarchią nazewnictwa „main_logger.sub_module_logger” , nie musimy go konfigurować w module podrzędnym. Wystarczy utworzyć rejestrator zgodnie z hierarchią nazewnictwa.
I nie doda również zduplikowanej obsługi.
Zobacz to pytanie, aby uzyskać bardziej szczegółową odpowiedź.
źródło
logger = logging.getLogger('my_logger') ; logger.handlers = [logger.handlers[0], ]
To jest dodatek do odpowiedzi @ rm957377, ale z wyjaśnieniem, dlaczego tak się dzieje . Kiedy uruchamiasz funkcję lambda w AWS, wywołują twoją funkcję z wewnątrz instancji opakowującej, która pozostaje aktywna dla wielu wywołań. Oznacza to, że jeśli wywołasz
addHandler()
w kodzie funkcji, będzie ona nadal dodawać zduplikowane procedury obsługi do singletonu rejestrowania za każdym razem, gdy funkcja zostanie uruchomiona. Singleton rejestrowania utrzymuje się przez wiele wywołań funkcji lambda.Aby rozwiązać ten problem, możesz wyczyścić programy obsługi przed ich ustawieniem za pomocą:
źródło
.info()
wezwanie, którego nie rozumiem.Twój rejestrator powinien działać jako singleton. Nie powinieneś go tworzyć więcej niż raz. Oto przykład, jak to może wyglądać:
źródło
Podwójne (lub potrójne lub ... - w zależności od liczby przeładowań) wyjście loggera może się również zdarzyć, gdy przeładujesz moduł przez
importlib.reload
(z tego samego powodu, co wyjaśniono w zaakceptowanej odpowiedzi). Dodaję tę odpowiedź tylko dla przyszłego odniesienia, ponieważ zajęło mi trochę czasu, aby dowiedzieć się, dlaczego mój wynik jest podwójny (potrójny).źródło
Jedno proste obejście jest podobne
W ten sposób unika się dołączania nowego modułu obsługi do bazowej listy „programów obsługi”.
źródło
Podsumowując, w większości przypadków, gdy tak się dzieje, wystarczy wywołać logger.getLogger () tylko raz na moduł. Jeśli masz wiele zajęć, tak jak ja, mogę to tak nazwać:
Oba będą miały własną pełną nazwę pakietu i metodę, w której są rejestrowane.
źródło
Możesz uzyskać listę wszystkich programów obsługi dla konkretnego rejestratora, więc możesz zrobić coś takiego
W powyższym przykładzie sprawdzamy, czy handler dla określonego pliku jest już podpięty do loggera, ale mając dostęp do listy wszystkich handlerów możesz zdecydować, które kryteria powinieneś dodać, czy nie.
źródło
Miałem ten problem dzisiaj. Ponieważ moje funkcje były @staticmethod, powyższe sugestie zostały rozwiązane za pomocą random ().
Wygląda jak:
źródło
źródło