it-swarm.com.de

So ändern Sie das Dateihandle mit der Python-Protokollierung im laufenden Betrieb mit verschiedenen Klassen und Importen

Ich kann keine fliegende Protokolldatei-Änderung durchführen.

Zum Beispiel habe ich 3 Klassen

one.py

import logging
class One():
    def __init__(self,txt="?"):
        logging.debug("Hey, I'm the class One and I say: %s" % txt)

two.py

import logging
class Two():
    def __init__(self,txt="?"):
        logging.debug("Hey, I'm the class Two and I say: %s" % txt)

config.py

import logging
class Config():
    def __init__(self,logfile=None):
        logging.debug("Reading config")
        self.logfile(logfile)

myapp

from one import One
from two import Two
from config import Config
import logging

#Set default logging
logging.basicConfig( 
    level=logging.getLevelName(DEBUG), 
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    filename=None
)

logging.info("Starting with stdout")

o=One(txt="STDOUT")
c=Config(logfile="/tmp/logfile")

# Here must be the code that change the logging configuration and set the filehandler

t=One(txt="This must be on the file, not STDOUT")

Wenn ich loggin.basicConfig() erneut versuche, funktioniert es nicht.

33
xkill

logging.basicConfig führt nothing aus, wenn bereits ein Handler eingerichtet wurde:

Diese Funktion führt nichts aus, wenn für den Root-Logger bereits Handler konfiguriert sind.

Sie müssen den aktuellen Handler auf dem Root-Logger ersetzen:

import logging

fileh = logging.FileHandler('/tmp/logfile', 'a')
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fileh.setFormatter(formatter)

log = logging.getLogger()  # root logger
for hdlr in log.handlers[:]:  # remove all old handlers
    log.removeHandler(hdlr)
log.addHandler(fileh)      # set the new handler

Siehe das Kapitel Logging konfigurieren im Python Logging-HOWTO.

43
Martijn Pieters

Ich fand einen einfacheren Weg als die obige Antwort. Wenn Sie einen Verweis auf den Handler haben, müssen Sie nur die close () - Methode aufrufen und dann die baseFilename -Eigenschaft festlegen. Wenn Sie baseFilename zuweisen, müssen Sie unbedingt os.path.abspath () verwenden. Es gibt einen Kommentar in der Bibliotheksquelle, der darauf hinweist, dass er benötigt wird. Ich behalte meine Konfigurationssachen in einem globalen dict (), so dass es einfach ist, die FileHandler-Referenzobjekte zu behalten. Wie Sie unten sehen können, sind nur zwei Zeilen Code erforderlich, um den Protokolldateinamen für einen Handler im Handumdrehen zu ändern.

import logging

def setup_logging():
  global config

  if config['LOGGING_SET']:
    config['LOG_FILE_HDL'].close()
    config['LOG_FILE_HDL'].baseFilename = os.path.abspath(config['LOG_FILE'])

    config['DEBUG_LOG_HDL'].close()
    config['DEBUG_LOG_HDL'].baseFilename = os.path.abspath(config['DEBUG_LOG'])
  else:
    format_str = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    formatter = logging.Formatter(format_str)

    log = logging.getLogger()

    log.setLevel(logging.DEBUG)

    # add file mode="w" to overwrite
    config['LOG_FILE_HDL'] = logging.FileHandler(config['LOG_FILE'], mode='a')
    config['LOG_FILE_HDL'].setLevel(logging.INFO)
    config['LOG_FILE_HDL'].setFormatter(formatter)
    log.addHandler(config['LOG_FILE_HDL'])

    # the delay=1 should prevent the file from being opened until used.
    config['DEBUG_LOG_HDL'] = logging.FileHandler(config['DEBUG_LOG'], mode='a', delay=1)
    config['DEBUG_LOG_HDL'].setLevel(logging.DEBUG)
    config['DEBUG_LOG_HDL'].setFormatter(formatter)
    log.addHandler(config['DEBUG_LOG_HDL'])

    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    ch.setFormatter(formatter)
    log.addHandler(ch)
    config['LOGGING_SET'] = True
6
user2179204

Die Antwort von @Martijn Pieters funktioniert gut. Der Code-Snipper entfernt jedoch alle Handler und setzt nur den File-Handler zurück. Dies ist problematisch, wenn in Ihrer Anwendung Handler von anderen Modulen hinzugefügt werden. 

Daher ist der folgende Ausschnitt so gestaltet, dass er nur den Dateihandler ersetzt.

Die Zeile if isinstance(hdlr,log.FileHander) ist der Schlüssel.

import logging

filehandler = logging.FileHandler('/tmp/logfile', 'a')
formatter = logging.Formatter('%(asctime)-15s::%(levelname)s::%(filename)s::%(funcName)s::%(lineno)d::%(message)s')
filehandler.setFormatter(formatter)
log = logging.getLogger()  # root logger - Good to get it only once.
for hdlr in log.handlers[:]:  # remove the existing file handlers
    if isinstance(hdlr,log.FileHander):
        log.removeHandler(hdlr)
log.addHandler(filehandler)      # set the new handler
# set the log level to INFO, DEBUG as the default is ERROR
logging.setLevel(log.DEBUG)      

Ich habe versucht, die Vorschläge auf dieser Seite von @Martijn Pieters in Kombination mit @Arun Thundyill Saseendran umzusetzen. Ich bin zu neu, um einen Kommentar abgeben zu können, deshalb muss ich eine angepasste Antwort posten. Beim Aufruf von isinstance musste ich 'logging' anstelle von 'log' verwenden, um Zugriff auf die Typen zu erhalten (log war eine Instanz) und dann sollte 'FileHander' 'FileHandler' sein. Ich verwende Python 3.6.

import logging

filehandler = logging.FileHandler('/tmp/logfile', 'a')
formatter = logging.Formatter('%(asctime)-15s::%(levelname)s::%(filename)s::%(funcName)s::%(lineno)d::%(message)s')
filehandler.setFormatter(formatter)
log = logging.getLogger()  # root logger - Good to get it only once.
for hdlr in log.handlers[:]:  # remove the existing file handlers
    if isinstance(hdlr,logging.FileHandler): #fixed two typos here
        log.removeHandler(hdlr)
log.addHandler(filehandler)      # set the new handler
# set the log level to INFO, DEBUG as the default is ERROR
logging.setLevel(log.DEBUG)      
0
T. Haggis