2016-07-05 21 views
0

Dies ist mein BeispielcodePython Testsuite zeigt keine Ausgabe auf Konsole

class StreamToLogger(object): 
    def __init__(self, logger, log_level=logging.INFO): 
     self.logger = logger 
     self.log_level = log_level 
     self.linebuf = '' 

    def write(self, buf): 
     for line in buf.rstrip().splitlines(): 
      self.logger.log(self.log_level, line.rstrip()) 



logging.basicConfig(level=logging.DEBUG, 
        format='%(asctime)s:%(levelname)s:%(name)s:%(message)s', 
        filename="logger.log", 
        filemode='w' 
        ) 

stdout_logger = logging.getLogger('STDOUT') 
sl = StreamToLogger(stdout_logger, logging.INFO) 
sys.stdout = sl 

stderr_logger = logging.getLogger('STDERR') 
sl = StreamToLogger(stderr_logger, logging.ERROR) 
sys.stderr = sl 

suite = suite() 
tests = unittest.TextTestRunner(descriptions=True, verbosity=2).run(suite) 

Als TextTestRunner verwendet standardmäßig Stream als stderr. Ich habe den Stderr verwendet, um die Ausgabe in die Protokolldatei zu schreiben, und es funktioniert. Können wir stderr mehrmals im selben Skript verwenden?

Antwort

0

Für mich ist es nicht wirklich klar, was Sie tun möchten. Schreiben Sie alle Konsolenausgaben des Logging-Moduls in eine Datei und auf die Konsole? Wenn dies der Fall tun:

# Create a logging object 
logger = logging.getLogger ('STDOUT+FILE') 
logger.setLevel (logging.DEBUG) 

# Create a file handler and set level to INFO (or other value) 
file_ch = logging.FileHandler('logger.log', 'w') 
file_ch.setLevel (logging.DEBUG) 
# ... and add it to the logging object 
logger.addHandler(file_ch) 

# Create a stream handler and set level to INFO 
console_ch = logging.StreamHandler() 
console_ch.setLevel (logging.DEBUG) 
# ... and add it to the logging object 
logger.addHandler(console_ch) 

# Do some logging 
logger.debug('Logging Test') 
logger.debug('------------') 
logger.info('this is an info log') 
logger.warn('this is a warn log') 
logger.debug('this is a debug log') 
logger.error('this is an error log') 
logger.critical('this is a critical log') 

Inhalt des myLogFile.log jetzt ist

Logging Test 
------------ 
this is an info log 
this is a warn log 
this is a debug log 
this is a critical log 

Der gleiche Text auf der Konsole

Mehr Infos here

+0

Ich möchte die Ausgabe schreiben von 'Tests = unittest.TextTestRunner (Beschreibungen = True, Ausführlichkeit = 2) .run (suite) ' Logger-Datei und Konsole. Tatsächlich schreibt es nur in Logger-Datei, aber nicht auf der Konsole. –

+0

Die Antwort von Amith Koujalgi in [diesem Beitrag] (http://stackoverflow.com/questions/14906764/how-to-redirect-stdout-to-both-file-and-console-with-scripting) ist die Lösung. Fügen Sie einfach einen 'stream = sys.stdout' im TextTestRunner() - Aufruf und der erwähnten Klasse' Logger' hinzu. – Humbalan

+0

diese Lösung funktioniert nicht für mich. Ich denke, es gibt einen Konflikt zwischen testrunnners "stderr" und "sys.stderr = sl", das in meinem Beispielcode ist (siehe Frage) –

1

ich ein neues tat erscheint analysieren Sie Ihren Code. Das Problem dort ist

  1. Sie definieren zwei Ströme für stdout und stderr. TextTextRunner verwendet nur einen Stream: sys.stderr standardmäßig.
  2. TextTestRunner verwendet standardmäßig sys.stderr und dies ist nicht Ihre sys.stderr. Das scheint seltsam, siehe später. Ihr Code funktioniert so, als hätte er keinen anderen Ausgabestream definiert.

Die Situation ändert sich, wenn Sie TextTextRunner() aufrufen, nicht mit ihren Standardeinstellungen, aber wenn Sie passieren explizit Ihre neu definiert sys.stderr. Nun wird die Ausgabe auf Ihre Datei umgeleitet werden:

# does not at all what you want (writes output to stderr): 
tests = unittest.TextTestRunner(descriptions=True, verbosity=2).run(suite) 
# does not everything what you want (writes output to file only): 
tests = unittest.TextTestRunner\ 
          (stream=sys.stderr, descriptions=True, verbosity=2).run(suite) 

Eine Anforderung erfüllt ist (schreiben in eine Datei) aber der andere nicht. Dies liegt daran, dass nur einer Ihrer definierten Streams verwendet wird (der Stream, den Sie an TextTestRunner übergeben haben). Für die zweite Anforderung (in die Konsole schreiben) muss es eine Möglichkeit geben, von einem Stream (dem umgeleiteten stderr) in zwei Ausgabegeräte zu schreiben. Dies ist meiner Meinung nach nur möglich, wenn Sie die Ihrer StreamToLogger.write() Methode in geeigneter Weise ändern:

def write(self, buf) : 
    my_console_stream_instance.write(buf) 
    my_file_stream_instance.write(buf) 

wo my_console_stream_instance der Strom ist, der in die Konsole schreibt und my_file_stream_instance ist der Strom, der in die Datei schreibt. Also schauen Sie bitte auf das folgende Beispiel, das tun sollten, was Sie wollen:

class StreamToLogger(object): 
    def __init__(self): 
     self.terminal = sys.stderr 
     self.log = open("logger.log", "w") 

    def write(self, buf): 
     self.terminal.write(buf) # write to stderr 
     self.log.write(buf) # write to file 

sys.stderr = StreamToLogger() 

suite = suite() 
tests = unittest.TextTestRunner\ 
         (stream=sys.stderr, descriptions=True, verbosity=2).run(suite) 

Nun gibt es wirklich zwei Ausgänge: eine auf dem Bildschirm und einer in die Datei.

Aber warum müssen Sie sys.stderr an den Stream-Parameter von TextTestRunner übergeben? Auf den ersten Blick scheint es dasselbe zu sein. Aber in der Referenz Python Sprache im Kapitel function definitions ist die Erklärung:

Standardparameterwerte ausgewertet werden, wenn die Funktionsdefinition ist ausgeführt.Dies bedeutet, dass der Ausdruck einmal ausgewertet wird, wenn die -Funktion definiert ist und derselbe "vorberechnete" Wert für jeden Aufruf verwendet wird. Dies ist besonders wichtig, um zu verstehen, wenn ein Standardparameter ein veränderbares Objekt ist.

Der Standard sys.stderr des stream-Parameters in TextTestRunner wird vor der Ausführung der stderr-Neudefinition ausgewertet. Deshalb müssen wir unseren neu definierten sys.stderr sowieso bestehen. Ein kleiner Beweis ist: Definieren Sie sys.stderr vor importieren Sie unittest: Der Code funktioniert gut, ohne die neu definierte sys.stderr übergeben.

+0

Danke Humbalan! Für eine lange und verständliche Antwort. Dieser Code & Logik funktionierte für meinen Fall. –

+0

Ich bin froh, helfen zu können. Das Nachdenken über deine Frage war auch ein Vorteil für mich, da die Gründe für das "Default-Parameterverhalten" für mich nicht wirklich klar waren, jetzt sind sie es. – Humbalan