python - 如何在 python 中为整个程序定义一个记录器?
问题描述
我想在我的 Python 项目中设置一次记录器并在整个项目中使用它。
main.py
:
import logging
import test
hostname = {"hostname": socket.gethostname()}
logger = logging.getLogger()
syslog = logging.StreamHandler()
formatter = logging.Formatter("{\"label\":\"%(name)s\", \"level\":\"%(levelname)s\", \"hostname\":\"%(hostname)s\", \"logEntry\": %(message)s, \"timestamp\", \"%(asctime)s\"}")
syslog.setFormatter(formatter)
logger.setLevel(logging.DEBUG)
logger.addHandler(syslog)
logger = logging.LoggerAdapter(logger, hostname)
def entry_point():
logger.debug("entry_point")
test.test_function()
entry_point()
test.py
:
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
def test_function():
logger.debug("test_function")
这应该给我:
entry_point
test_function
...都使用格式提供程序进行了格式化。
但是我实际上得到了一个错误KeyError: 'hostname'
,因为第二个记录器似乎不知道hostname
格式提供程序。我也尝试过初始化两个记录器,__name__
但后来我得到了No handlers could be found for logger "test"
.
有没有一种方法可以定义我的日志配置一次并在整个应用程序中重复使用它?
解决方案
ALoggingAdapter
是一个单独的对象,它不会替换logging.getLogger()
调用的结果。您需要将它存储在可以在不同模块之间共享的地方。例如,您可以使用一个单独的模块,您的项目中的所有其他内容都可以从中导入。
我将在下面详细说明如何处理这个问题,但还有一个根本不涉及适配器的替代方案,而是使用附加到您创建的处理程序的过滤器,让您不必完全处理适配器。再往下看。
我也将配置和日志对象处理分开;让主模块调用“设置”函数来配置处理程序和日志级别,并在模块中设置适配器以供其他人导入:
log.py
:
import logging
import socket
def setup_logging():
"""Adds a configured stream handler to the root logger"""
syslog = logging.StreamHandler()
formatter = logging.Formatter(
'{"label":"%(name)s", "level":"%(levelname)s",'
' "hostname":"%(hostname)s", "logEntry": %(message)s,'
' "timestamp", "%(asctime)s"}')
syslog.setFormatter(formatter)
logger = logging.getLogger()
logger.addHandler(syslog)
logger.setLevel(logging.DEBUG)
def host_log_adapter(logger):
hostname = {"hostname": socket.gethostname()}
return logging.LoggerAdapter(logger, hostname)
logger = host_log_adapter(logging.getLogger())
然后在main
做:
import log
import test
log.setup_logging()
def entry_point():
log.logger.debug("entry_point")
test.test_function()
entry_point()
并在test
:
from log import logger
def test_function():
logger.debug("test_function")
或者,您可以通过(ab)使用过滤器将信息添加到日志记录,而不是使用适配器:
class HostnameInjectingFilter(logging.Filter):
def __init__(self):
self.hostname = socket.gethostname()}
def filter(self, record):
record.hostname = self.hostname
return True
这会直接在记录对象上添加额外字段并始终返回True
。然后只需将此过滤器添加到需要主机名可用的处理程序中:
syslog = logging.StreamHandler()
formatter = logging.Formatter(
'{"label":"%(name)s", "level":"%(levelname)s",'
' "hostname":"%(hostname)s", "logEntry": %(message)s,'
' "timestamp", "%(asctime)s"}')
syslog.setFormatter(formatter)
syslog.setFilter(HostnameInjectingFilter())
这消除了完全使用适配器的需要,因此您可以host_log_adapter()
完全删除该功能并在logging.getLogger()
任何地方使用。
推荐阅读
- asp.net - 我在哪里可以获得用于在 Stripe 中创建客户的 SourceToken?
- java - 简化java中复杂的if语句
- java - 无法在 Redis 数据存储中存储数据 - Spring Boot
- git - Git忽略文件在Windows 10下不起作用
- python - IndexError:列表索引超出范围 - Python/Arduino
- python - 根据条件获取索引和列
- laravel - 如何在 Laravel Passport 中创建角色?
- docker - 在 Flask 中使用 Sentry 查找 Heroku H10 错误的原因
- angular - 配置中的 Angular 设置构建命令行参数(--host / --disable-host-check for --configuration=production)
- laravel - Dockerize Laravel 流明