在 Python Django 中启用调试时,如何仅关闭 SqlAlchemy 数据库池的日志记录?
Posted
技术标签:
【中文标题】在 Python Django 中启用调试时,如何仅关闭 SqlAlchemy 数据库池的日志记录?【英文标题】:How to turn off logging for SqlAlchemy db pool only, when debugging is enabled in Python Django? 【发布时间】:2021-06-20 23:09:15 【问题描述】:上下文/环境
我有一个 Python Django 项目使用 SqlAlchemy django-postgrespool2
数据库池连接到 PostgreSQL 数据库。
我正在努力实现的目标
在settings.py
中,我设置了DEBUG = True
,它将生成程序日志。但是,我只想禁用来自 SqlAlchemy 数据库池的日志记录,同时将 DEBUG
设置为 True
。换句话说,在调试时,我想查看除来自 SqlAlchemy 数据库池的日志之外的所有日志。
我测试过的内容
下面的代码显示了我为禁用数据库池日志所做的不同尝试:
def turnOffLog(self):
# --- Attempt 1, db pool logs still show ---
logging.basicConfig()
logging.getLogger('sqlalchemy').setLevel(logging.ERROR)
# --- Attempt 2, db pool logs still show ---
sqla_logger = logging.getLogger('sqlalchemy.engine.base.Engine')
for hdlr in sqla_logger.handlers:
sqla_logger.removeHandler(hdlr)
我还在创建 QueuePool 实例时将 echo=False
传递给它,它仍然不会删除日志:
dbPool = pool.QueuePool(dbConnection, max_overflow=dbConfig.poolMaxOverflow, pool_size=dbConfig.poolSize, recycle=dbConfig.poolRecycleTime, pre_ping=dbConfig.prePing, dialect=postgresql.dialect(), echo=False)
我的settings.py
文件(在 env-config 文件中将 DEBUG 设置为 True):
"""
myapp
"""
import os
import logging
import socket
import sys
from decouple import Config, RepositoryEnv
import time
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# DECOUPLE
# env_config = Config(RepositoryEnv(BASE_DIR.replace('myapp-gui','')+'.env'))
env_config = Config(RepositoryEnv("c:\\Users\\myteam\\Documents\\django\\ATT49882.env"))
print('Using database: \x1b[97m[\033[92m '+env_config.get('DB_NAME')+' \x1b[97m]\033[0m');
print('Using database host: \x1b[97m[\033[92m '+env_config.get('DB_HOST')+' \x1b[97m]\033[0m');
print('Using database port: \x1b[97m[\033[92m '+env_config.get('DB_PORT')+' \x1b[97m]\033[0m');
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env_config.get('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
# OLD DEBUG = bool(env_config.get('DEBUG'))
try:
DEBUG = bool(int(env_config.get('DEBUG')))
except Exception as err:
DEBUG = True
# LOGLEVEL
if DEBUG:
LOGLEVEL = "DEBUG"
else:
LOGLEVEL = "INFO"
ALLOWED_HOSTS = ['*']
# myapp version
if DEBUG:
myapp_VERSION = time.time()
else:
myapp_VERSION = 2.0
# myapp constants
myapp_CONSTANTS =
'myapp_VERSION': myapp_VERSION
# Application definition
INSTALLED_APPS = [
...
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'core.mrank-middleware.MrankMiddleware',
'core.context_processor.LoginRequiredMiddleware',
]
LOGIN_URL = '/login/'
LOGIN_EXEMPT_URLS = []
REQUEST_WHITELIST_IP = ['127.0.0.1']
ROOT_URLCONF = 'myapp.urls'
CSRF_FAILURE_VIEW = 'core.views.csrf_failure'
# Setting for searching for html files in all templates folders, even in subfolders
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
TEMPLATES = [
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS':
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'core.context_processor.serverconfig',
'core.context_processor.phraseconfig',
'core.context_processor.myapp_constants'
],
,
,
]
WSGI_APPLICATION = 'myapp.wsgi.application'
# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
# FOR DEVELOPMENT :-)
try:
hostname = socket.gethostname()
except:
hostname = ''
# bool(int(env_config.get('DEBUG')))
DATABASES =
'default':
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': env_config.get('DB_NAME'),
'OPTIONS':
'options': '-c search_path=myappdjango'
,
'USER': env_config.get('DB_USER'),
'PASSWORD': env_config.get('DB_PASSWORD'),
'HOST': env_config.get('DB_HOST'), # Or an IP Address that your DB is hosted on
'PORT': env_config.get('DB_PORT')
,
'pool':
'ENGINE': 'django_postgrespool2',
'NAME': env_config.get('DB_NAME'),
'OPTIONS':
'options': '-c search_path=myappdjango'
,
'USER': env_config.get('DB_USER'),
'PASSWORD': env_config.get('DB_PASSWORD'),
'HOST': env_config.get('DB_HOST'),
'PORT': env_config.get('DB_PORT'),
'POOL_SIZE': int(env_config.get('DB_POOL_SIZE', 100)),
'POOL_MAX_OVERFLOW': int(env_config.get('DB_POOL_MAX_OVERFLOW', 100)),
'POOL_RECYCLE_TIME': int(env_config.get('DB_POOL_RECYCLE_TIME', 3600)),
"PRE_PING": bool(int(env_config.get('DB_POOL_PRE_PING', 0)))
# Password validation
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
...
]
# Internationalization
# https://docs.djangoproject.com/en/2.1/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, javascript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
# Upload directory
MEDIA_URL = '/upload/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'upload')
# Custom settings
TIME = 60*60*60*60
SESSION_COOKIE_AGE = TIME
SESSION_IDLE_TIMEOUT = TIME
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
LOGGING =
'version': 1,
'disable_existing_loggers': False,
'formatters':
'default':
'format': '%(asctime)s:%(levelname)s:%(name)s: %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S'
,
'handlers':
'console':
'class': 'logging.StreamHandler',
'formatter': 'default',
'stream': sys.stdout
,
,
'root':
'handlers': ['console'],
'level': LOGLEVEL,
,
数据库池日志示例
只是我要删除的日志外观示例:
2021-03-24 09:38:00:DEBUG:z.pool: new connection
2021-03-24 09:38:00:DEBUG:z.pool: retrieved from pool
2021-03-24 09:38:00:DEBUG:z.pool: returned to pool
谢谢!
更新 #0
我也试过了,但它仍然没有删除数据库池日志:
logging.basicConfig()
logging.getLogger('sqlalchemy').disable = True
【问题讨论】:
您是否也尝试过sqlalchemy.pool
作为记录器名称?
【参考方案1】:
通过设置 engine.echo = False where engine = create_engine()
解决了这个问题似乎 sqlalchemy 创建了自己的日志输出:
请务必注意,这两个标志独立于任何现有的日志记录配置工作,并且将无条件地使用 logging.basicConfig()。除了任何现有的记录器配置之外,这还具有配置的效果。因此,在显式配置日志记录时,请确保所有回显标志始终设置为 False,以避免出现重复的日志行。
您应该将 engine.echo 和/或 engine.echo_pool 设置为 False (engine = create_engine())。
在我的情况下(几乎与这个相同)engine.echo = False 解决了问题,并且未找到 engine.echo_pool。
这里有更多描述:https://docs.sqlalchemy.org/en/14/core/engines.html#more-on-the-echo-flag
【讨论】:
以上是关于在 Python Django 中启用调试时,如何仅关闭 SqlAlchemy 数据库池的日志记录?的主要内容,如果未能解决你的问题,请参考以下文章
当调试关闭时,启用 Django 语言环境的应用程序总是返回 404
如何在 python 中启用 Django shell 中的历史记录
如何将 django 项目的默认 IP 设置为 0.0.0.0 以在 Visual Studio 2015 中进行调试?
如何在 Django Python 中使用 PostgreSQL 为 SQLAlchemy 连接池设置方言?需要启用预 ping 功能