26 Stimmen

Wie kann ich aktuelle Zeile und Stack-Info mit Python protokollieren?

Ich habe eine Protokollierungsfunktion wie folgt.

logging.basicConfig(
    filename = fileName,
    format = "%(levelname) -10s %(asctime)s %(message)s",
    level = logging.DEBUG
)

def printinfo(string):
    if DEBUG:
        logging.info(string)

def printerror(string):
    if DEBUG:
        logging.error(string)
    print string

Ich muss die Zeilennummer und die Stapelinformationen anmelden. Zum Beispiel:

1: def hello():
2:    goodbye()
3:
4: def goodbye():
5:    printinfo()

---> Line 5: goodbye()/hello()

Wie kann ich das mit Python erreichen?

GELÖST

def printinfo(string):
    if DEBUG:
        frame = inspect.currentframe()
        stack_trace = traceback.format_stack(frame)
        logging.debug(stack_trace[:-1])
    if LOG:
        logging.info(string)

gibt mir diese Informationen, die genau das sind, was ich brauche.

DEBUG      2011-02-23 10:09:13,500 [
  '  File "/abc.py", line 553, in <module>\n    runUnitTest(COVERAGE, PROFILE)\n', 
  '  File "/abc.py", line 411, in runUnitTest\n    printinfo(string)\n']

3voto

mouad Punkte 63071

Hier ist ein Beispiel, das Ihnen hoffentlich helfen kann:

import inspect
import logging

logging.basicConfig(
    format = "%(levelname) -10s %(asctime)s %(message)s",
    level = logging.DEBUG
)

def test():

    caller_list = []
    frame = inspect.currentframe()
    this_frame = frame  # Save current frame.

    while frame.f_back:
        caller_list.append('{0}()'.format(frame.f_code.co_name))
        frame = frame.f_back

    caller_line = this_frame.f_back.f_lineno
    callers =  '/'.join(reversed(caller_list))

    logging.info('Line {0} : {1}'.format(caller_line, callers))

def foo():
    test()

def bar():
    foo()

bar()

Ergebnis:

INFO       2011-02-23 17:03:26,426 Line 28 : bar()/foo()/test()

1voto

yanjost Punkte 4903

Blick auf das Traceback-Modul

>>> import traceback
>>> def test():
>>>     print "/".join( str(x[2]) for x in traceback.extract_stack() )
>>> def main():
>>>     test()
>>> main()
<module>/launch_new_instance/mainloop/mainloop/interact/push/runsource/runcode/<module>/main/test

1voto

Dies basiert auf der Antwort von @mouad, ist aber nützlicher (IMO), indem auf jeder Ebene der Dateiname (aber nicht der vollständige Pfad) und die Zeilennummer des Aufrufstapels angegeben werden und der Stapel in der Reihenfolge des letzten Aufrufs (d.h. NICHT in umgekehrter Reihenfolge) belassen wird, weil ich ihn so lesen möchte :-)

Jeder Eintrag hat file:line:func(), was dieselbe Sequenz wie der normale Stacktrace ist, aber alles in derselben Zeile, was viel kompakter ist.

import inspect

def callers(self):
    caller_list = []
    frame = inspect.currentframe()
    while frame.f_back:
        caller_list.append('{2}:{1}:{0}()'.format(frame.f_code.co_name,frame.f_lineno,frame.f_code.co_filename.split("\\")[-1]))
        frame = frame.f_back
    callers =  ' <= '.join(caller_list)
    return callers

Möglicherweise müssen Sie ein zusätzliches f_back hinzufügen, wenn Sie dazwischen liegende Aufrufe haben, um den Protokolltext zu erzeugen.

        frame = inspect.currentframe().f_back

Erzeugt eine Ausgabe wie diese:

file2.py:620:func1() <= file3.py:211:func2() <= file3.py:201:func3() <= main.py:795:func4() <= file4.py:295:run() <= main.py:881:main()

Ich brauche diesen Stacktrace nur in zwei Schlüsselfunktionen, daher füge ich die Ausgabe der Aufrufer in den Text des logger.debug()-Aufrufs ein, wie hier:

logger.debug("\nWIRE: justdoit request -----\n"+callers()+"\n\n")

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X