2012-06-11 14 views
65

Ich versuche zu lernen, wie eine Anwendung funktioniert. Und dazu füge ich debug-Befehle als erste Zeile in den Body jeder Funktion ein mit dem Ziel, den Namen der Funktion sowie die Zeilennummer (innerhalb des Codes) zu protokollieren, wo ich eine Nachricht an die Log-Ausgabe sende. Da diese Anwendung viele Dateien umfasst, möchte ich schließlich eine einzelne Protokolldatei erstellen, damit ich den Kontrollfluss der Anwendung besser verstehen kann. HierPython Logging (Funktionsname, Dateiname, Zeilennummer) mit einer einzigen Datei

ist, was ich weiß:

  1. für Funktionsnamen bekommen, kann ich function_name.__name__ verwenden, aber ich will nicht die function_name verwenden (so dass ich schnell kopieren könnte, und fügen Sie eine generische Log.info("Message") in der Körper aller Funktionen). Ich weiß, das könnte in C mit __func__ Makro getan werden, aber ich bin mir nicht sicher über Python.

  2. für die Dateinamen und die Zeilennummer bekommen, ich habe gesehen (und ich glaube, dass) meine Anwendung locals() Funktion Python verwenden, aber in einer Syntax, die ich nicht ganz von zB bewusst bin: options = "LOG.debug('%(flag)s : %(flag_get)s' % locals()) und ich versuchte, es zu benutzen wie LOG.info("My message %s" % locals()), die etwas wie {'self': <__main__.Class_name object at 0x22f8cd0>} produziert. Irgendwelche Eingaben bitte?

  3. Ich weiß, wie Logging und fügen Sie Handler, um es in eine Datei zu loggen, aber ich bin nicht sicher, ob eine einzige Datei verwendet werden kann, um alle Protokollnachrichten in der richtigen Reihenfolge der Funktionsaufrufe im Projekt aufzuzeichnen.

Ich würde jede Hilfe sehr schätzen.

Danke!

+0

Sie können den Python-Debugger mit 'import pdb; pdb.set_trace() ', und interaktiv durch den Code gehen. Dadurch können Sie den Programmablauf verfolgen. –

+0

Tolle Idee! Danke, Matt. Es wäre immer noch hilfreich, ein Protokoll wie in der Frage erwähnt zu bekommen, so dass ich nicht jedes Mal debuggen muss. Kennen Sie auch eine IDE für Python, die so gut wie Eclipse für Java ist (Strg + Klick bringt Sie zur Funktionsdefinition), die ich verwenden kann, um Debugging einfacher zu machen? – user1126425

Antwort

17

Sie haben hier ein paar marginal verwandte Fragen.

Ich werde mit dem einfachsten beginnen: (3). Mit logging können Sie alle Aufrufe in einer einzigen Protokolldatei oder einem anderen Ausgabeziel aggregieren: Sie werden in der Reihenfolge angezeigt, in der sie aufgetreten sind.

Als nächstes: (2). locals() bietet ein Diktat des aktuellen Umfangs. Daher haben Sie in einer Methode, die keine anderen Argumente hat, self im Gültigkeitsbereich, der einen Verweis auf die aktuelle Instanz enthält. Der Trick, der verwendet wird, der Sie stopft, ist die Schnurformatierung, die ein dict als RHS des % Operators verwendet. "%(foo)s" % bar wird durch den Wert bar["foo"] ersetzt.

Schließlich können Sie einige Selbstbeobachtung Tricks, ähnlich denen von pdb verwendet verwenden, die weitere Informationen anmelden können:

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 
    )) 

Dies wird die Nachricht in vergangen einzuloggen, sowie die (original) Funktionsnamen, den Dateinamen in dem die Definition erscheint und die Zeile in dieser Datei. Weitere Informationen finden Sie unter inspect - Inspect live objects.

Wie bereits in meinem Kommentar erwähnt, können Sie auch jederzeit in eine interaktive Debugging-Eingabeaufforderung pdb wechseln, indem Sie die Zeile import pdb; pdb.set_trace() eingeben und das Programm erneut ausführen. Auf diese Weise können Sie den Code schrittweise durchlaufen und die Daten nach Belieben überprüfen.

+0

Danke Matt! Ich werde diese Autolog-Funktion versuchen. Ich habe ein wenig Verwirrung in Bezug auf die Verwendung von Dict als RHS von% Operator: Würde ''% (foo) s:% (bar) s'' auch den' bar ["foo"] 's Wert drucken? Oder ist es etwas anders als dein Beispiel? – user1126425

+0

Grundsätzlich wird alles in der Form '% () s' durch den Wert des Objekts ersetzt, auf das im Dict von' ' verwiesen wird. Es gibt weitere Beispiele/Details unter http://docs.python.org/library/stdtypes.html#string-formatting –

+0

@synthesizerpatels Antwort ist viel hilfreicher. – Jan

276

Die richtige Antwort für diese ist es, die bereits zur Verfügung gestellt funcName Variable

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

Dann möchten Sie überall zu verwenden, fügen Sie einfach:

logger.debug('your message') 

Beispiel Ausgabe von einem Skript, das ich auf der rechten Seite gerade arbeite jetzt:

[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

Das sollte die Antwort sein! – user3885927

+1

Great .. Eine Sache hinzuzufügen, können wir das Logfile als Codefile dynamisch gleich nennen? Ich habe versucht logging.basicConfig (Dateiname = "% (Dateiname)", Format = FORMAT) , um Dateinamen dynamisch zu nehmen, aber es dauerte statischer Wert. irgendein Vorschlag? – Outlier

+2

@Outlier Nein, der empfohlene Weg, um dies zu erreichen, ist über 'getLogger (__ Name __)' – farthVader

Verwandte Themen