Python动态访问对象属性
#python #database #logging #pewee

在编码Python相当一段时间后,今天我需要做一些应该很简单的事情,但是花了将近半个小时的时间才能弄清楚它,结果也不是预期的。

内容

一个简单的问题

有必要根据环境变量将日志级别设置为数据库连接时,问题就会出现。作为ORM,该项目使用peewee,这使我们能够利用Python的标准日志记录LIB拦截Peewee日志流并进行一些操纵,例如更改流的日志级别。

根据Peewee的doc,当需要将所有查询打印到stderr时,我们只需要实现以下内容。

import logging

logger = logging.getLogger('peewee')
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)

那生产呢?

一旦我读取了将其部署到生产的代码,例如错误,例如,将更加适用于显示数据库中不必要的信息。

必须仔细设置日志以将应用程序安全风险保持在最低限度,因为带有太多信息的日志级别可以公开数据库的结构和敏感数据。

光在隧道的尽头

选择解决此问题的方法是将一个环境变量添加到名为db_log_level的.ENV文件,这样,该应用程序的应用程序可能会根据环境的debug和误差级别而有所不同。

接下来,我们需要一种方法来将一些metaprogramming应用于动态致电logging.debug,因为日志级别的应用程序正在采用时,随着事实来自env(“ db_log_level”)。

为此,我们可以使用内置的getattr(…)函数,该功能将返回对象的命名属性的值,其中名称必须是字符串。了解此功能,让我们看看我们的代码现在的外观。

import logging
from os import get_env

level = get_env("DB_LOG_LEVEL", "DEBUG")

logger = logging.getLogger("peewee")
logger.addHandler(logging.StreamHandler())
logger.setLevel(getattr(logging, level))

i还添加了一个验证,该验证检查get_env(...)函数返回的值是否与log levels present in the logging library相匹配,该函数显示以下实现。

import logging
from os import get_env

"""
---------------------------------------------------------------------------
 Database logging
--------------------------------------------------------------------------

Database logging will define when and how log info will be shown while
interacting with the database. Accepted log levels are CRITICAL, ERROR,
WARNING, INFO, DEBUG and NOTSET.
"""


LOG_LEVELS = [
    "CRITICAL",
    "FATAL",
    "ERROR",
    "WARNING",
    "WARN",
    "INFO",
    "DEBUG",
    "NOTSET",
]

LOG_LEVEL = get_env("DB_LOG_LEVEL", "DEBUG")

if LOG_LEVEL not in LOG_LEVELS:
    raise Exception(f"DatabaseLogError: Log level '{LOG_LEVEL}' not defined")

logger = logging.getLogger("peewee")
logger.addHandler(logging.StreamHandler())
logger.setLevel(getattr(logging, LOG_LEVEL))
logging.DEBUG

使用元编程来解决此问题,允许我们动态访问对象logging的属性,将有效的日志级传递到logger.setLevel(...)函数中。


我是巴西工程师杰克·米拉斯

快乐编码!