81

我已经阅读了一些关于此的帖子,但我仍然感到困惑。我有这个日志记录设置:

import logging

class MongoHandler(logging.Handler):
    def __init__(self):
        logging.Handler.__init__(self)
        from pymongo import Connection
        self.db = Connection('db_server').db_name

    def emit(self, record):
        try:
            self.db.Logging.save(record.__dict__)
        except:
            print 'Logging Error:  Unable to save log entry to db'

mh = MongoHandler()
sh = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(threadName)s - %(levelname)s - %(message)s')
sh.setFormatter(formatter)
log = logging.getLogger('DeviceMonitor_%s' % hostname)
log.addHandler(mh)
log.addHandler(sh)
log.setLevel(logging.INFO)

我希望能够为 StreamHandler 和 MongoHandler 设置不同的级别。这是可能的还是我需要第二个 Logger obj?

4

4 回答 4

113

您可以为每个日志记录处理程序设置不同的日志记录级别,但似乎您必须将记录器的级别设置为“最低”。在下面的示例中,我将记录器设置为 DEBUG,将流处理程序设置为 INFO,将 TimedRotatingFileHandler 设置为 DEBUG。所以该文件有 DEBUG 条目,并且流只输出 INFO。您不能仅将 DEBUG 定向到一个处理程序,而仅将 INFO 定向到另一个处理程序。为此,您需要另一个记录器。

logger = logging.getLogger("mylog")
formatter = logging.Formatter(
    '%(asctime)s | %(name)s |  %(levelname)s: %(message)s')
logger.setLevel(logging.DEBUG)

stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
stream_handler.setFormatter(formatter)

logFilePath = "my.log"
file_handler = logging.handlers.TimedRotatingFileHandler(
    filename=logFilePath, when='midnight', backupCount=30)
file_handler.setFormatter(formatter)
file_handler.setLevel(logging.DEBUG)

logger.addHandler(file_handler)
logger.addHandler(stream_handler)

logger.info("Started");
try:
    x = 14
    y = 0
    z = x / y
except Exception as ex:
    logger.error("Operation failed.")
    logger.debug(
        "Encountered {0} when trying to perform calculation.".format(ex))

logger.info("Ended");
于 2012-06-20T00:12:08.130 回答
8

我需要时间来理解这一点

  1. 在您的子记录器(处理程序)下方设置通用记录器(您的 logging.getLogger() 的结果)
  2. 将您的子记录器级别设置为与一般记录器相同或更高的级别
于 2018-11-21T18:20:55.100 回答
6

GrantVS 回答的补充:

我不得不使用

logging.basicConfig(level=logging.DEBUG)

为了让它工作。否则很好的答案,谢谢!

马里奥

PS:由于某种原因,系统不允许我直接评论 GrantVS 的答案。

于 2014-07-28T09:19:51.090 回答
0

有同样的问题,但解决方案不适用于 iPython,因为 QtConsole 会自动创建一个没有级别集的处理程序:

import logging                                                                                                                               
root = logging.getLogger()                                                                                                                   
root.handlers                                                                                                                                
Out: [<StreamHandler <stderr> (NOTSET)>]

结果 iPython 将 DEBUG 和 INFO 都打印到控制台,尽管我的文件处理程序和流处理程序具有不同的级别。

该线程为我指出了这个问题:Logging module does not print in IPython

我制作了一个名为 custom_logging.py 的辅助模块(这个堆栈线程帮助很大!),以便在其他模块中更方便地进行日志记录:

import logging
from pathlib import Path
import sys

def _add_stream_handler(logger: logging.Logger):

    stream_handler = logging.StreamHandler()
    formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
    stream_handler.setFormatter(formatter)
    stream_handler.setLevel(logging.INFO)

    logger.addHandler(stream_handler)

    return logger


def _add_file_handler(logger: logging.Logger, log_path: Path):

    file_handler = logging.FileHandler(log_path, mode='w')
    formatter = logging.Formatter(
        fmt='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', datefmt='%m-%d %H:%M')

    file_handler.setFormatter(formatter)
    file_handler.setLevel(logging.DEBUG)

    logger.addHandler(file_handler)

    return logger


def create_logger(root_dir: Path, caller: str) -> logging.Logger:

    log_path = root_dir / 'logs' / f'{caller}.log'
    logger = logging.getLogger(caller)
    root = logging.getLogger()

    logger.setLevel(logging.DEBUG)

    # If haven't already launched handlers...
    if not len(logger.handlers):

        _add_file_handler(logger=logger, log_path=log_path)
        _add_stream_handler(logger=logger)

        logger.info('Logging started.')

    # Delete the Qtconsole stderr handler
    # ... as it automatically logs both DEBUG & INFO to stderr
    if root.handlers:
        root.handlers = []

    return logger


def log_dataframe(df, logger: logging.Logger, name: str = "DataFrame") -> None:

    logger.debug(
        f'''{name} head:\n {df.head()}\n----------\n''')


def log_dataframes(*args, logger: logging.Logger) -> None:

    for gdf in args:

        logger.debug(
            f'''DataFrame head:\n {gdf.head()}\n----------\n''')

可以通过以下方式使用其功能:

from custom_logging import create_logger, log_dataframe

或者import custom_logging等等custom_logging.create_logger()

另请参阅官方日志记录手册中的“多个处理程序和格式化程序”和“记录到多个目的地”部分: https ://docs.python.org/3/howto/logging-cookbook.html#logging-cookbook

于 2020-03-31T09:57:21.540 回答