[英]Python logging - config file in multiple modules with root logger
[英]Python logging from multiple package hierarchies (without using root logger)
我需要为相当具体的设置设置日志记录。 简而言之,我想处理来自两个不同“父”模块中的公共库代码的日志记录。
app_one \
app_one_main.py
app_two \
app_two_main.py
lib_package \
lib_module.py
app_one_main和app_two_main 都导入lib_module (代码如下)。
这些模块显然不共享相同的包结构,因此如果我使用getLogger(__name__)
,默认情况下来自 lib_module 的日志消息不会传播到 app_one 或 app_two
logging.Logger
并覆盖Logger.parent
以便它在其封闭范围内找到任何记录器。 我过去已经实现了类似的东西,但它似乎有点过度设计,它会破坏默认日志系统的许多功能。(这段代码甚至不能假装工作。这只是一个粗略的起点。)
# app_one_main.py
import logging
from lib_package import lib_module
logger = logging.getLogger(__name__)
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(logging.Formatter("APP ONE: %(message)s"))
logger.addHandler(stream_handler)
def log_app_one():
logger.warning("hello from app_one_main")
lib_module.do_the_thing()
# app_two_main.py
import logging
from lib_package import lib_module
logger = logging.getLogger(__name__)
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(logging.Formatter("APP TWO: %(message)s"))
logger.addHandler(stream_handler)
def log_app_two():
logger.warning("hello from app_two_main")
lib_module.do_the_thing()
# lib_module.py
import logging
logger = logging.getLogger(__name__)
def do_the_thing():
logger.warning("hello from library code")
app_one和app_two最终将在另一个平台上运行,比如 Maya,它提供了一个 Python 会话。 两个模块都将导入到同一个会话中。
所以,如果我运行app_one_main.log_app_one()
,我会想要:
APP ONE: hello from app_one_main
APP ONE: hello from library code
和app_two_main.log_app_two()
:
APP TWO: hello from app_two_main
APP TWO: hello from library code
主要问题是您直接实例化Logger
对象,而不是使用getLogger
为您获取它们。 记录器对象文档说记录器不应该被直接实例化,而总是通过模块级函数 logging.getLogger(name)。 当getLogger
创建一个Logger
它也会将它插入到日志层次结构中,以便其他人可以配置它们。 您只有自由浮动的Logger
对象。
您的库记录器称为lib_package.lib_module
。 一旦你移动到getLogger
任何其他模块都可以获取包记录器lib_package
,配置它,然后它的任何子记录器也将工作。
app_one_main.py
import logging
from lib_package import lib_module
# setup logging output for this module
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(logging.Formatter("APP ONE: %(message)s"))
logger = logging.getLogger(__name__)
#logger.setLevel(logging.INFO)
logger.addHandler(stream_handler)
# add handler other modules / packages
pkg_logger = logging.getLogger('lib_package')
pkg_logger.addHandler(stream_handler)
#pkg_logger.setLevel(logging.INFO)
del pkg_logger
logger.warning("hello from app_one_main")
lib_module.do_the_thing()
lib_package/lib_module.py
# lib_module.py
import logging
logger = logging.getLogger(__name__)
def do_the_thing():
logger.warning("hello from library code")
这是我降落的地方。
我正在为我的所有工具创建一个通用记录器,并为生活在它上面的处理程序创建一个新的 Filter 子类。 过滤器确保仅处理源自与过滤器本身相同的父模块的依赖项的消息。 理论上,您可以在根记录器上使用这个 Filter 类和堆栈查找机制,而不是这个“基本记录器”。
特殊的酱汁在StackFilter
。 它将当前执行堆栈中的模块与实例化时存储的模块进行比较。 可能有一些边缘情况这不起作用,但我还没有找到它们。
import logging
import inspect
# Loggers
BASE_LOGGER_NAME = "_base_logger_"
def get_base_logger():
return logging.getLogger(BASE_LOGGER_NAME)
def get_logger(name):
return logging.getLogger(BASE_LOGGER_NAME + "." + name)
# Filtering
class StackFilter(logging.Filter):
def __init__(self):
self.stack = set(enclosing_modules())
super(StackFilter, self).__init__()
def filter(self, record):
calling_stack = set(enclosing_modules())
return self.stack.issubset(calling_stack)
def enclosing_modules():
frame = inspect.currentframe()
frame_count = 0
_frame = frame
while _frame:
frame_count += 1
_frame = _frame.f_back
mods = [None] * frame_count
i = 0
while frame:
try:
mods[i] = frame.f_globals["__name__"]
except:
pass
i += 1
frame = frame.f_back
return mods
# Logging Handlers
def add_console_output(formatter=None):
base_logger = get_base_logger()
handler = logging.StreamHandler()
if formatter:
handler.setFormatter(formatter)
handler.addFilter(StackFilter())
base_logger.addHandler(handler)
其余代码与原始问题非常相似,但我添加了一个新模块来检查我的工作。
这将在今天扮演 Maya 的角色,只是我的各种工具将被导入和运行的地方。
from app_one import app_one_main
from app_two import app_two_main
app_one_main.log_it()
app_two_main.log_it()
from lib_package import lib_module
import logging
import custom_logging
logger = custom_logging.get_logger(__name__)
formatter = logging.Formatter("APP ONE: %(message)s")
custom_logging.add_console_output(formatter)
def log_it():
logger.warning("hello from app_one_main")
lib_module.do_the_thing()
from lib_package import lib_module
import logging
import custom_logging
logger = custom_logging.get_logger(__name__)
formatter = logging.Formatter("APP TWO: %(message)s")
custom_logging.add_console_output(formatter)
def log_it():
logger.warning("hello from app_two_main")
lib_module.do_the_thing()
import custom_logging
logger = custom_logging.get_logger(__name__)
def do_the_thing():
logger.warning("hello from library code")
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.