python - 结合 Python 跟踪信息和日志记录
问题描述
我正在尝试编写一个高度模块化的 Python 日志系统(使用日志模块)并在日志消息中包含来自跟踪模块的信息。
例如,我希望能够编写如下代码行:
my_logger.log_message(MyLogFilter, "this is a message")
并让它包含“log_message”调用的位置,而不是实际的记录器调用本身。
除了跟踪信息来自logging.debug()
调用而不是调用之外,我几乎可以使用以下代码my_logger.log_message()
。
class MyLogFilter(logging.Filter):
def __init__(self):
self.extra = {"error_code": 999}
self.level = "debug"
def filter(self, record):
for key in self.extra.keys():
setattr(record, key, self.extra[key])
class myLogger(object):
def __init__(self):
fid = logging.FileHandler("test.log")
formatter = logging.Formatter('%(pathname)s:%(lineno)i, %(error_code)%I, %(message)s'
fid.setFormatter(formatter)
self.my_logger = logging.getLogger(name="test")
self.my_logger.setLevel(logging.DEBUG)
self.my_logger.addHandler(fid)
def log_message(self, lfilter, message):
xfilter = lfilter()
self.my_logger.addFilter(xfilter)
log_funct = getattr(self.logger, xfilter.level)
log_funct(message)
if __name__ == "__main__":
logger = myLogger()
logger.log_message(MyLogFilter, "debugging")
为了进行简单的logging.debug
调用,要经历很多麻烦,但实际上,我将有一个MyLogFilter
包含不同“error_code”属性值的不同日志级别的许多不同版本的列表,我正在尝试让log_message()
电话尽可能简短和甜蜜,因为它会重复无数次。
我将不胜感激有关如何做我想做的事情的任何信息,或者我是否完全走错了路,如果是这样,我应该做什么。
如果可能的话,我想坚持使用“日志记录”和“跟踪”的内部 python 模块,而不是使用任何外部解决方案。
解决方案
或者如果我完全走错了路,如果是这样的话,我应该做什么。
我强烈建议您将日志记录视为已解决的问题,并避免重新发明轮子。
如果您需要的不仅仅是标准库的logging
模块提供的,它可能类似于structlog ( pip install structlog
)
Structlog 将为您提供:
- 数据绑定
- 云原生结构化日志
- 管道
- ...和更多
它将处理大多数本地和云用例。
下面是一种常见的配置,它将彩色日志输出到 .log 文件、标准输出,并且可以进一步扩展以记录到例如 AWS CloudWatch。
请注意,有一个包含的处理器:StackInfoRenderer
-- 这将包括堆栈信息到所有日志调用,其中 stack_info 具有“真实”值(这也在 stdlib 的日志记录中)。如果您只想要异常的堆栈信息,那么您需要为您的日志调用执行类似 exc_info=True 的操作。
主文件
from structlog import get_logger
from logging_config import configure_local_logging
configure_local_logging()
logger = get_logger()
logger.info("Some random info")
logger.debug("Debugging info with stack", stack_info=True)
try:
assert 'foo'=='bar'
catch Exception as e:
logger.error("Error info with an exc", exc_info=e)
logging_config.py
import logging
import structlog
def configure_local_logging(filename=__name__):
"""Provides a structlog colorized console and file renderer for logging in eg ING tickets"""
timestamper = structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S")
pre_chain = [
structlog.stdlib.add_log_level,
timestamper,
]
logging.config.dictConfig({
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"plain": {
"()": structlog.stdlib.ProcessorFormatter,
"processor": structlog.dev.ConsoleRenderer(colors=False),
"foreign_pre_chain": pre_chain,
},
"colored": {
"()": structlog.stdlib.ProcessorFormatter,
"processor": structlog.dev.ConsoleRenderer(colors=True),
"foreign_pre_chain": pre_chain,
},
},
"handlers": {
"default": {
"level": "DEBUG",
"class": "logging.StreamHandler",
"formatter": "colored",
},
"file": {
"level": "DEBUG",
"class": "logging.handlers.WatchedFileHandler",
"filename": filename + ".log",
"formatter": "plain",
},
},
"loggers": {
"": {
"handlers": ["default", "file"],
"level": "DEBUG",
"propagate": True,
},
}
})
structlog.configure_once(
processors=[
structlog.stdlib.add_log_level,
structlog.stdlib.PositionalArgumentsFormatter(),
timestamper,
structlog.processors.StackInfoRenderer(),
structlog.processors.format_exc_info,
structlog.stdlib.ProcessorFormatter.wrap_for_formatter,
],
context_class=dict,
logger_factory=structlog.stdlib.LoggerFactory(),
wrapper_class=structlog.stdlib.BoundLogger,
cache_logger_on_first_use=True,
)
Structlog 可以做的远不止这些。我建议你检查一下。
推荐阅读
- ruby-on-rails - 连接到用户帐户
- python - 如何将数据从views.py连续发送到Django中的html模板?
- azure-devops - azuredevops rest api:获取推送的提交总是返回 0
- python - Django DRF api 不返回任何值
- python - 如何处理'NoneType'对象在python中不可下标
- c# - Xamarin/SQLite/C# - 如何使用菜单项删除从列表视图和 SQLite 表中删除一行
- deep-learning - 为什么注意力层需要“value”、“key”和“query”?
- android - 三星屏幕镜像启动以编程方式无法在 Galaxy Tab A7 (SM-T500) 上运行
- apache - 在 htaccess 中保留查询字符串
- iis - 如何通过互联网(全球)访问基于 iis 的本地网站?