405 Stimmen

Die Verwendung von Protokollierung in mehreren Modulen

Ich habe ein kleines Python-Projekt mit folgender Struktur -

Projekt 
 -- pkg01
   -- test01.py
 -- pkg02
   -- test02.py
 -- logging.conf

Ich plane, das Standard-Logging-Modul zu verwenden, um Nachrichten sowohl auf stdout als auch in eine Protokolldatei zu drucken. Um das Logging-Modul zu verwenden, ist eine Initialisierung erforderlich -

import logging.config

logging.config.fileConfig('logging.conf')
logger = logging.getLogger('pyApp')

logger.info('testing')

Derzeit führe ich diese Initialisierung in jedem Modul durch, bevor ich Log-Nachrichten protokolliere. Ist es möglich, diese Initialisierung nur einmal an einem Ort durchzuführen, so dass die gleichen Einstellungen im gesamten Projekt wiederverwendet werden?

13voto

phil_20686 Punkte 3862

Einige dieser Antworten deuten darauf hin, dass Sie am Anfang eines Moduls Folgendes tun:

import logging
logger = logging.getLogger(__name__)

Meines Wissens nach gilt dies als sehr schlechte Praxis. Der Grund dafür ist, dass die Dateikonfiguration standardmäßig alle vorhandenen Logger deaktiviert. Zum Beispiel:

#my_module
import logging

logger = logging.getLogger(__name__)

def foo():
    logger.info('Hi, foo')

class Bar(object):
    def bar(self):
        logger.info('Hi, bar')

Und in Ihrem Hauptmodul:

#main
import logging

# lade mein Modul - das konfiguriert jetzt den Logger
import my_module

# Dies deaktiviert nun standardmäßig den Logger in meinem Modul, [siehe die Dokumentation][1]
logging.config.fileConfig('logging.ini')

my_module.foo()
bar = my_module.Bar()
bar.bar()

Jetzt wird das im logging.ini festgelegte Protokoll leer sein, da der vorhandene Logger durch den Aufruf von fileconfig deaktiviert wurde.

Es ist sicherlich möglich, dies zu umgehen (disable_existing_Loggers=False), aber realistisch betrachtet werden viele Kunden Ihrer Bibliothek dieses Verhalten nicht kennen und keine Protokolle erhalten. Machen Sie es Ihren Kunden einfach, indem Sie logging.getLogger immer lokal aufrufen. Hut ab: Ich habe dieses Verhalten auf Victor Lins Website gelernt.

Die gute Praxis besteht also darin, logging.getLogger immer lokal aufzurufen. Zum Beispiel:

#my_module
import logging

logger = logging.getLogger(__name__)

def foo():
    logging.getLogger(__name__).info('Hi, foo')

class Bar(object):
    def bar(self):
        logging.getLogger(__name__).info('Hi, bar')    

Außerdem, wenn Sie fileconfig in Ihrem Hauptmodul verwenden, setzen Sie disable_existing_loggers=False, nur für den Fall, dass die Designer Ihrer Bibliothek Logger-Instanzen auf Modulebene verwenden.

5voto

deeshank Punkte 3801

Sie könnten auch etwas Ähnliches wie dies erstellen!

def get_logger(name=None):
    default = "__app__"
    formatter = logging.Formatter('%(levelname)s: %(asctime)s %(funcName)s(%(lineno)d) -- %(message)s',
                              datefmt='%Y-%m-%d %H:%M:%S')
    log_map = {"__app__": "app.log", "__basic_log__": "file1.log", "__advance_log__": "file2.log"}
    if name:
        logger = logging.getLogger(name)
    else:
        logger = logging.getLogger(default)
    fh = logging.FileHandler(log_map[name])
    fh.setFormatter(formatter)
    logger.addHandler(fh)
    logger.setLevel(logging.DEBUG)
    return logger

Jetzt könnten Sie mehrere Logger im selben Modul und im gesamten Projekt verwenden, wenn das oben Definierte in einem separaten Modul definiert und in anderen Modulen importiert wird, in denen Logging erforderlich ist.

a=get_logger("__app___")
b=get_logger("__basic_log__")
a.info("Starte Logging!")
b.debug("Debug-Modus")

5voto

deeshank Punkte 3801

Die Lösung von @Yarkee schien besser zu sein. Ich würde gerne noch etwas hinzufügen -

class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances.keys():
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class LoggerManager(object):
    __metaclass__ = Singleton

    _loggers = {}

    def __init__(self, *args, **kwargs):
        pass

    @staticmethod
    def getLogger(name=None):
        if not name:
            logging.basicConfig()
            return logging.getLogger()
        elif name not in LoggerManager._loggers.keys():
            logging.basicConfig()
            LoggerManager._loggers[name] = logging.getLogger(str(name))
        return LoggerManager._loggers[name>    

log=LoggerManager().getLogger("Hello")
log.setLevel(level=logging.DEBUG)

LoggerManager kann also in die gesamte Anwendung integriert werden. Ich hoffe, es ergibt Sinn und Wert.

2voto

Ben Yitzhaki Punkte 1316

Es gibt mehrere Antworten. Ich habe mich für eine ähnliche, aber dennoch unterschiedliche Lösung entschieden, die für mich Sinn macht, vielleicht macht sie auch für dich Sinn. Mein Hauptziel war es, Logs nach ihrem Level an Handler weiterzugeben (Debug-Level-Logs an die Konsole, Warnungen und höher an Dateien):

from flask import Flask
import logging
from logging.handlers import RotatingFileHandler

app = Flask(__name__)

# Standardeinstellungen für das Logging, alles wird auf die Konsole ausgegeben
logging.basicConfig(level=logging.DEBUG)

rotating_file_handler = RotatingFileHandler(filename="logs.log")
rotating_file_handler.setLevel(logging.INFO)

app.logger.addHandler(rotating_file_handler)

habe eine nützliche Datei namens logger.py erstellt:

import logging

def get_logger(name):
    return logging.getLogger("flask.app." + name)

das flask.app ist ein fest codierter Wert in Flask. Der Anwendungslogger beginnt immer mit flask.app, da es der Modulname ist.

jetzt kann ich es in jedem Modul auf folgende Weise verwenden:

from logger import get_logger
logger = get_logger(__name__)

logger.info("neues Log")

Dadurch wird ein neues Log für "app.flask.MODULE_NAME" mit minimalem Aufwand erstellt.

2voto

Mousam Singh Punkte 608

Die beste Praxis wäre es, ein Modul separat zu erstellen, das nur eine Methode hat, deren Aufgabe es ist, einem Aufrufenden eine Logger-Handler zu geben. Speichern Sie diese Datei als m_logger.py

import logger, logging

def getlogger():
    # logger
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)
    # create console handler and set level to debug
    #ch = logging.StreamHandler()
    ch = logging.FileHandler(r'log.txt')
    ch.setLevel(logging.DEBUG)
    # create formatter
    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    # add formatter to ch
    ch.setFormatter(formatter)
    # add ch to logger
    logger.addHandler(ch)
    return logger

Rufen Sie jetzt die Methode getlogger() auf, wenn der Logger-Handler benötigt wird.

from m_logger import getlogger
logger = getlogger()
logger.info('Meine Nachricht')

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