2

我正在尝试在我的 Django 应用程序的代码中记录 sql 语句

目前我在我的 settings.py 中使用以下记录器配置

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'sql': {
            '()': SQLFormatter,
            'format': '[%(duration).3f] %(statement)s',
        },
        'verbose': {
            'format': '%(levelname)s %(funcName)s() %(pathname)s[:%(lineno)s] %(name)s \n%(message)s'
        }
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'formatter': 'verbose',
            'class': 'logging.StreamHandler',
        },
        'sql': {
            'class': 'logging.StreamHandler',
            'formatter': 'sql',
            'level': 'DEBUG',
        }
    }
}

通常要在 django 中记录 sql,我们可以将其添加django.db.backends到 settings.py 中的 logger.config

 'loggers': {
    'django.db.backends': {
        'handlers': ['sql'],
        'level': 'DEBUG',
        'propagate': False,
    },

但问题是它会记录每个 sql 语句。那么我们如何django.db.backends在代码之间开始和停止登录。

我的views.py中有以下代码

def someview(request)
    # start logging from here
    user_set = User.objects.all()
    for user in user_set:
        print(user.last_name) 
    # stop logging from here

我还想使用sql我在日志配置中定义的处理程序。

在上面的视图函数中,什么代码将进入开始和停止记录的地方。

4

2 回答 2

1

创建一个过滤器类并将一个实例添加到记录器或处理程序。

class LoggerGate:
    def __init__(self, state='open'):
        self.state = state

    def open(self):
        self.state = 'open'

    def close(self):
        self.state = 'closed'

    def filter(self, record):
        return self.state == 'open'

创建一个过滤器,初始化为“关闭”状态。获取 'django.db.backends' 记录器并添加过滤器。

gate = LoggerGate('closed')
sql_logger = logging.getLogger('django.db.backends')
sql_logger.addFilter(gate)

然后调用openorclose方法将日志记录限制在您想要的位置。

def someview(request)
    gate.open()      # start logging from here

    user_set = User.objects.all()
    for user in user_set:
        print(user.last_name) 

    gate.close()     # stop logging here
于 2019-08-14T15:12:06.420 回答
0

只是从上面的答案和Gabriel C的答案中进行总结,两者都是相同的,也来自Sraw的答案

我的目标是使用 django django.db.backends记录 sql 。但它的问题是它会记录所有的sql。我只想在代码的特定部分或任何我想查看 sql 的地方记录 sql。所以我可以通过以下方式做到这一点。

在 settings.py 中记录配置:

# Filter class to stop or start logging for "django.db.backends"
class LoggerGate:
    def __init__(self, state='closed'):
        # We found that the settings.py runs twice and the filters are created twice. So we have to keep only one. So we delete all the previous filters before we create the new one
        import logging
        logger_database = logging.getLogger("django.db.backends")
        try:
            for filter in logger_database.filters:
                logger_database.removeFilter(filter)
        except Exception as e:
            pass
        self.state = state

    def open(self):
        self.state = 'open'

    def close(self):
        self.state = 'closed'

    def filter(self, record):
        """
        Determine if the specified record is to be logged.

        Is the specified record to be logged? Returns 0/False for no, nonzero/True for
        yes. If deemed appropriate, the record may be modified in-place.
        """
        return self.state == 'open'

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'sql': {
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
        }
    },
    'filters': {
        'myfilter': {
            '()': LoggerGate,
        }
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['sql'],
            'level': 'DEBUG',
            'propagate': False,
            'filters': ['myfilter']
        }
    }
}

然后在views.py

import logging
logger = logging.getLogger(__name__)
logger_database = logging.getLogger("django.db.backends")

def test1(request):


    logger_database.filters[0].open()
    #Will allow priting of sql satatements from here

    from django import db
    user_set = User.objects.all()

    for user in user_set: # Here sql is executed and is printed to console
        pass
    #Will stop priting of sql satatements after this
    logger_database.filters[0].close()

    from django import db
    user_set = User.objects.all()

    for user in user_set:  # Here sql is executed and is not printed to console
        pass

    now = datetime.datetime.now()
    html = "<html><body>Internal purpose</body></html>"
    return HttpResponse(html)

如果想以格式化和彩色的方式打印 sql,请在 settings.py 中使用

# SQL formatter to be used for the handler used in logging "django.db.backends"
class SQLFormatter(logging.Formatter):
    def format(self, record):

        # Check if Pygments is available for coloring 
        try:
            import pygments
            from pygments.lexers import SqlLexer
            from pygments.formatters import TerminalTrueColorFormatter
        except ImportError:
            pygments = None

        # Check if sqlparse is available for indentation
        try:
            import sqlparse
        except ImportError:
            sqlparse = None

        # Remove leading and trailing whitespaces
        sql = record.sql.strip()

        if sqlparse:
            # Indent the SQL query
            sql = sqlparse.format(sql, reindent=True)

        if pygments:
            # Highlight the SQL query
            sql = pygments.highlight(
                sql,
                SqlLexer(),
                #TerminalTrueColorFormatter(style='monokai')
                TerminalTrueColorFormatter()
            )

        # Set the record's statement to the formatted query
        record.statement = sql
        return super(SQLFormatter, self).format(record)




# Filter class to stop or start logging for "django.db.backends"
class LoggerGate:
    def __init__(self, state='closed'):
        # We found that the settings.py runs twice and the filters are created twice. So we have to keep only one. So we delete all the previous filters before we create the new one
        import logging
        logger_database = logging.getLogger("django.db.backends")
        try:
            for filter in logger_database.filters:
                logger_database.removeFilter(filter)
        except Exception as e:
            pass
        self.state = state

    def open(self):
        self.state = 'open'

    def close(self):
        self.state = 'closed'

    def filter(self, record):
        """
        Determine if the specified record is to be logged.

        Is the specified record to be logged? Returns 0/False for no, nonzero/True for
        yes. If deemed appropriate, the record may be modified in-place.
        """
        return self.state == 'open'

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'sql': {
            '()': SQLFormatter,
            'format': '[%(duration).3f] %(statement)s',
        }
    },
    'handlers': {
        'sql': {
            'class': 'logging.StreamHandler',
            'formatter': 'sql',
            'level': 'DEBUG',
        }
    },
    'filters': {
        'myfilter': {
            '()': LoggerGate,
        }
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['sql'],
            'level': 'DEBUG',
            'propagate': False,
            'filters': ['myfilter']
        }
    }
}
于 2019-09-05T15:52:46.053 回答