在创建自定义日志记录 TimedRotatingFileHandler 时,有没有办法获取记录器名称(例如 getLogger(__name__) 中的模块名称)?

问题描述 投票:0回答:1

我正在尝试创建一个自定义 TimedRotatingFileHandler。对于应该位于单个日志文件中的记录器,我创建这样的自定义文件处理程序,以自动为日志文件创建目录(如果不存在):

class CustomTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
    def __init__(self, filename: str, *args, **kwargs):
        log_path = os.path.dirname(filename) # filename passes full path, seperate path from filename
        pathlib.Path(log_path).mkdir(parents=True, exist_ok=True) # Use the seperated path to create directories for logfile
        logging.handlers.TimedRotatingFileHandler.__init__(self, log_name, *args, **kwargs)

我想要知道的是创建一个特殊的处理程序,它不会根据预定义的名称创建日志文件,而是根据我在使用logging.getLogger(name)创建记录器时传递的模块名称创建日志文件。使用此处理程序的记录器将使用自己的模块名称创建自己的日志文件:

class CustomTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
    def __init__(self, filename: str, *args, **kwargs):
        log_path = os.path.dirname(filename) # filename passes full path, seperate path from filename
        pathlib.Path(log_path).mkdir(parents=True, exist_ok=True) # Use the seperated path to create directories for logfile
        logger_name = # Somehow get the logger name e.g module name from __name__
        new_filename  f"{log_path}/{logger_name}.log" # create new filename for the __init__
        logging.handlers.TimedRotatingFileHandler.__init__(self, new_filename, *args, **kwargs)

目前,为了实现相同的功能,我必须为每个记录器创建单独的处理程序,以便将它们记录在单独的文件中。

所以问题是:如何获取 Handler 中的记录器名称?

python python-logging
1个回答
0
投票

您可以将所需的任何参数添加到自定义处理程序的

__init__
方法中,那么为什么不只添加一个
logger_name
参数,然后在调用
logger.addHandler(CustomTimedRotatingLogHandler(filename, __name__))
时设置该参数呢?

如果您仍然想尝试获取调用模块的

__name__
,您可以使用
inspect
模块获取它,如 [https://stackoverflow.com/a/7272464/17030540](详细信息请参见此处),但是这是一个脆弱的解决方案并且破坏了封装。一般来说,函数或方法不应该知道或关心调用者是谁。

作为额外的更改,我还更新了最后一行以调用

super().__init__()
,而不是直接引用父类。

自定义_logger.py

import inspect
import logging
import logging.handlers
import os
import pathlib


class CustomTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
    def __init__(self, filename: str, logger_name=None, *args, **kwargs):
        if logger_name is None:
            logger_name = inspect.currentframe().f_back.f_locals.get("__name__", "<unknown>")
        log_path = os.path.dirname(filename) # filename passes full path, seperate path from filename
        pathlib.Path(log_path).mkdir(parents=True, exist_ok=True) # Use the seperated path to create directories for logfile

        new_filename = f"{log_path}/{logger_name}.log" # create new filename for the __init__
        super().__init__(new_filename, *args, **kwargs)

my_module.py

import logging

from custom_logger import CustomTimedRotatingFileHandler

logger=logging.getLogger("")
# Use default logger_name in handler
logger.addHandler(custom.CustomTimedRotatingFileHandler("./logs/custom_log_from_module.log"))
logger.critical("Message from Module")

# Submit a logger_name to handler
second=logging.getLogger("SecondLogger")
second.addHandler(custom.CustomTimedRotatingFileHandler("./logs/custom_log_2_from_module.log", logger_name="Second_logger_Override"))
logger.debug("Message from Module")

main.py

import logging

import custom_logger
import my_module

logger = logging.getLogger()

def main():
    # Send override name to handler
    logger.addHandler(custom_logger.CustomTimedRotatingFileHandler("./logs/Log_From_Main.txt", logger_name="From_main"))
    logger.warning("Logging a message from main")
    
    # Have handler use default
    second_main = logging.getLogger("2ndMain")
    second_main.addHandler(custom_logger.CustomTimedRotatingFileHandler("./logs/FromMain2.log"))
    second_main.warning("Second message from main")

if __name__=="__main__":
    main()

您可以看到传入的

logger_name
值在可用时用作文件名。
my_module.py
中的默认情况使用了
"my_module"
,而我的
__main__
脚本中的默认情况无法从帧堆栈中获取名称,而是使用了
"_unknown_"
的后备。

在我看来,最好将

logger_name
设置为必需参数,而不是尝试从框架堆栈中提取信息。

© www.soinside.com 2019 - 2024. All rights reserved.