2009-09-05 4 views

Antwort

78

Das folgende Skript, log1.py:

import logging, sys 

class SingleLevelFilter(logging.Filter): 
    def __init__(self, passlevel, reject): 
     self.passlevel = passlevel 
     self.reject = reject 

    def filter(self, record): 
     if self.reject: 
      return (record.levelno != self.passlevel) 
     else: 
      return (record.levelno == self.passlevel) 

h1 = logging.StreamHandler(sys.stdout) 
f1 = SingleLevelFilter(logging.INFO, False) 
h1.addFilter(f1) 
rootLogger = logging.getLogger() 
rootLogger.addHandler(h1) 
h2 = logging.StreamHandler(sys.stderr) 
f2 = SingleLevelFilter(logging.INFO, True) 
h2.addFilter(f2) 
rootLogger.addHandler(h2) 
logger = logging.getLogger("my.logger") 
logger.setLevel(logging.DEBUG) 
logger.debug("A DEBUG message") 
logger.info("An INFO message") 
logger.warning("A WARNING message") 
logger.error("An ERROR message") 
logger.critical("A CRITICAL message") 

wenn ausführen, erzeugt die folgenden Ergebnisse.

 
C:\temp>log1.py 
A DEBUG message 
An INFO message 
A WARNING message 
An ERROR message 
A CRITICAL message 

Wie zu erwarten war, da auf einem Terminal sys.stdout und sys.stderr sind gleich. Nun lassen Sie uns umleiten stdout in eine Datei, tmp:

 
C:\temp>log1.py >tmp 
A DEBUG message 
A WARNING message 
An ERROR message 
A CRITICAL message 

So ist die INFO-Nachricht an das Terminal wurde nicht gedruckt - aber die Nachrichten gerichtet sys.stderrhaben gedruckt. Lassen Sie uns sehen, was ist in tmp:

 
C:\temp>type tmp 
An INFO message 

Damit Ansatz zu tun scheint, was Sie wollen.

+0

Vielen Dank, das ist genau das, was ich brauche. By the way eclipe markieren die std's. – L1ker

+11

Eine Antwort vom Autor selbst! Ordentlich-o! – twneale

11

Generell halte ich es für sinnvoll, Nachrichten umleiten niedriger als WARNING zu stdout, statt nur INFO Nachrichten macht.

Basierend auf Vinay Sajip ‚s ausgezeichnete Antwort, kam ich mit auf den Punkt:

class MaxLevelFilter(Filter): 
    '''Filters (lets through) all messages with level < LEVEL''' 
    def __init__(self, level): 
     self.level = level 

    def filter(self, record): 
     return record.levelno < self.level # "<" instead of "<=": since logger.setLevel is inclusive, this should be exclusive 


MIN_LEVEL= DEBUG 
#... 
stdout_hdlr = StreamHandler(sys.stdout) 
stderr_hdlr = StreamHandler(sys.stderr) 
lower_than_warning= MaxLevelFilter(WARNING) 
stdout_hdlr.addFilter(lower_than_warning)  #messages lower than WARNING go to stdout 
stdout_hdlr.setLevel(MIN_LEVEL) 
stderr_hdlr.setLevel(max(MIN_LEVEL, WARNING)) #messages >= WARNING (and >= STDOUT_LOG_LEVEL) go to stderr 
#... 
7

Da meine bearbeiten abgelehnt wurde, hier ist meine Antwort. @ Goncalopps Antwort ist gut, aber nicht alleine oder out of the box. Hier ist meine verbesserte Version:

import sys, logging 


class LogFilter(logging.Filter): 
    """Filters (lets through) all messages with level < LEVEL""" 
    # http://stackoverflow.com/a/24956305/408556 
    def __init__(self, level): 
     self.level = level 

    def filter(self, record): 
     # "<" instead of "<=": since logger.setLevel is inclusive, this should 
     # be exclusive 
     return record.levelno < self.level 

MIN_LEVEL = logging.DEBUG 
stdout_hdlr = logging.StreamHandler(sys.stdout) 
stderr_hdlr = logging.StreamHandler(sys.stderr) 
log_filter = LogFilter(logging.WARNING) 
stdout_hdlr.addFilter(log_filter) 
stdout_hdlr.setLevel(MIN_LEVEL) 
stderr_hdlr.setLevel(max(MIN_LEVEL, logging.WARNING)) 
# messages lower than WARNING go to stdout 
# messages >= WARNING (and >= STDOUT_LOG_LEVEL) go to stderr 

rootLogger = logging.getLogger() 
rootLogger.addHandler(stdout_hdlr) 
rootLogger.addHandler(stderr_hdlr) 
logger = logging.getLogger(__name__) 
logger.setLevel(logging.DEBUG) 

# Example Usage 
>>> logger.debug("A DEBUG message") 
>>> logger.info("An INFO message") 
>>> logger.warning("A WARNING message") 
>>> logger.error("An ERROR message") 
>>> logger.critical("A CRITICAL message") 
Verwandte Themen