2012-06-11 9 views
65

Próbuję się dowiedzieć, jak działa aplikacja. I do tego wstawiam polecenia debugowania jako pierwszy wiersz ciała każdej funkcji w celu zarejestrowania nazwy funkcji, a także numeru linii (w ramach kodu), w której wysyłam komunikat do wyjścia logu. Wreszcie, ponieważ ta aplikacja zawiera wiele plików, chcę utworzyć pojedynczy plik dziennika, aby lepiej zrozumieć przepływ sterowania aplikacji.Logowanie w języku Python (nazwa funkcji, nazwa pliku, numer wiersza) przy użyciu pojedynczego pliku

Oto, co wiem:

  1. uzyskania nazwy funkcji, można użyć function_name.__name__ ale nie chcę używać nazwa_funkcji (tak, że mogę szybko skopiować i wkleić w rodzajowe Log.info("Message") Ciało wszystkich funkcji). Wiem, że można to zrobić w C przy użyciu makra __func__, ale nie jestem pewien co do pythona.

  2. uzyskania nazwę pliku i numer linii, widziałem, że (i wierzę, że) Moja aplikacja jest przy użyciu Python locals() funkcji ale w składni, że nie jestem całkowicie świadom np options = "LOG.debug('%(flag)s : %(flag_get)s' % locals()) i próbowałem go przy jak LOG.info("My message %s" % locals()), który produkuje coś takiego jak {'self': <__main__.Class_name object at 0x22f8cd0>}. Jakieś dane wejściowe na ten temat proszę?

  3. W jaki sposób korzystać z rejestrowania i dodawać do niego procedurę obsługi, aby zalogować się do pliku, ale nie jestem pewien, czy można użyć pojedynczego pliku do rejestrowania wszystkich komunikatów dziennika w prawidłowej kolejności wywołań funkcji w projekcie.

Byłbym wdzięczny za każdą pomoc.

Dzięki!

+0

Możesz wkroczyć do debugera Pythona używając 'import pdb; pdb.set_trace() ', a następnie interaktywnie przejść przez kod. To może pomóc w prześledzeniu przebiegu programu. –

+0

Świetny pomysł! Dzięki Matt. Pomocne byłoby uzyskanie logu, o którym mowa w pytaniu, aby nie musieć debugować za każdym razem. Również znasz IDE dla Pythona, który jest tak dobry jak Eclipse dla Java (ctrl + click przenosi cię do definicji funkcji), z którego mogę skorzystać, aby ułatwić debugowanie? – user1126425

Odpowiedz

17

Masz tutaj kilka pytań związanych z marginalnie.

Zacznę od najprostszych: (3). Za pomocą logging można agregować wszystkie wywołania do pojedynczego pliku dziennika lub innego docelowego wyniku: będą one w kolejności, w jakiej wystąpiły w procesie.

Dalej: (2). locals() zapewnia dyktowanie bieżącego zakresu. Tak więc w metodzie, która nie ma innych argumentów, masz zasięg w zakresie self, który zawiera odwołanie do bieżącej instancji. Używana sztuczka, która Cię obciąża, to formatowanie ciągów przy użyciu dyktafonu jako RHS operatora %. "%(foo)s" % bar zostanie zastąpiony przez dowolną wartość bar["foo"].

Wreszcie, można użyć kilku sztuczek introspekcji podobnych do tych używanych przez pdb które mogą logować więcej info:

def autolog(message): 
    "Automatically log the current function details." 
    import inspect, logging 
    # Get the previous frame in the stack, otherwise it would 
    # be this function!!! 
    func = inspect.currentframe().f_back.f_code 
    # Dump the message + the name of this function to the log. 
    logging.debug("%s: %s in %s:%i" % (
     message, 
     func.co_name, 
     func.co_filename, 
     func.co_firstlineno 
    )) 

To zalogować komunikat przekazany w, plus (oryginalna) nazwę stanowiska, nazwy pliku w którym pojawia się definicja i wiersz w tym pliku. Zajrzyj na stronę inspect - Inspect live objects, aby uzyskać więcej informacji.

Jak już wspomniałem we wcześniejszym komentarzu, można również w dowolnym momencie wprowadzić podpowiedź interaktywnego debugowania pdb, wstawiając wiersz import pdb; pdb.set_trace() i ponownie uruchamiając program. Dzięki temu możesz przejść przez kod, przeglądając dane według własnego uznania.

+0

Dzięki Matt! Spróbuję tej funkcji autologu. Mam małe zamieszanie dotyczące użycia dyktafonu jako RHS operatora%: Czy '% (foo) s:% (bar) s'' również wypisze wartość' bar ["foo"]? Czy jest nieco inny niż twój przykład? – user1126425

+0

Zasadniczo wszystko w postaci '% () s' jest zastępowane przez wartość obiektu, do którego odwołuje się dyktafon,' '. Więcej przykładów/szczegółów można znaleźć na http://docs.python.org/library/stdtypes.html#string-formatting –

+0

odpowiedź @synthesizerpatel jest o wiele bardziej pomocna. – Jan

276

Prawidłowa odpowiedź na to jest użycie już przewidziane funcName zmienną

import logging 
logger = logging.getLogger('root') 
FORMAT = "[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s" 
logging.basicConfig(format=FORMAT) 
logger.setLevel(logging.DEBUG) 

Następnie gdziekolwiek chcesz, wystarczy dodać:

logger.debug('your message') 

Przykâadowa ze skryptu pracuję na prawo teraz:

[invRegex.py:150 -   handleRange() ] ['[A-Z]'] 
[invRegex.py:155 -  handleRepetition() ] [[<__main__.CharacterRangeEmitter object at 0x10ba03050>, '{', '1', '}']] 
[invRegex.py:197 -   handleMacro() ] ['\\d'] 
[invRegex.py:155 -  handleRepetition() ] [[<__main__.CharacterRangeEmitter object at 0x10ba03950>, '{', '1', '}']] 
[invRegex.py:210 -  handleSequence() ] [[<__main__.GroupEmitter object at 0x10b9fedd0>, <__main__.GroupEmitter object at 0x10ba03ad0>]] 
+20

To powinna być odpowiedź! – user3885927

+1

Świetne .. Jedną z rzeczy, które można dodać, czy możemy nazwać plik logu dynamicznie takim samym jak kodek? np. Próbowałem próbowałem logging.basicConfig (filename = "% (filename)", format = FORMAT) , aby pobrać nazwę pliku dynamicznie, ale zajęło to wartość statyczną. jakieś sugestie? – Outlier

+2

@Outlier Nie, zalecanym sposobem osiągnięcia tego celu jest 'getLogger (__ nazwa __)' – farthVader