1

我在 Django 中记录我的数据库查询以及路径名和行号。

现在我得到这些日志:

07/Dec/2018 14:25:00 DEBUG django.db.backends utils **/Users/XXXXX/.idea/lib/python2.7/site-packages/django/db/backends/utils.py:89** (0.340) SELECT "metadata"."metaname", "metadata"."description", "metadata"."attributes" FROM "metadata" WHERE "metadata"."metaname" = 'date_type'; args=('date_type',)

对于所有查询,我得到相同的路径和行号。有什么方法可以从我的主应用程序中捕获行号,而不是从 utils 中捕获行号。

当前的日志记录实现:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'color'
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propogate': True,
        }
    }
}

使用 python 2.7 和 django 1.9

4

2 回答 2

2

来自用户@will-keeling 的略微优化的版本

Django 的日志配置,用于每个 db 请求的输出行号。

注意:如果你想将它用于测试,你需要设置 DEBUG=True 进行测试运行 Django 测试时如何将 DEBUG 设置为 True?

import logging
import traceback
from django.conf import settings


class StackInfoHandler(logging.StreamHandler):
    trim = 5

    def emit(self, record):
        super(StackInfoHandler, self).emit(record)
        trace = traceback.format_stack()
        stack1 = [str(row) for row in trace]
        stack2 = [s for s in stack1 if settings.BASE_DIR in s and 'format_stack' not in s]
        stack3 = [s for s in stack2 if 'test' not in s]
        if not stack3:
            stack3 = stack2  # include test call
        if stack3:
            stack4 = ''.join(stack3[-self.trim:])  # take only last records
            stack5 = f"Stack {self.terminator} {''.join(stack4)}"
            self.stream.write(stack5)
            self.stream.write(self.terminator)
            self.flush()

日志配置 (部分)

LOGGING = {
    'handlers': {
        'db-console': {
            'level': 'DEBUG',
            'class': 'settings.local.StackInfoHandler',  # Reference the custom handler
            'formatter': 'simple',
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['db-console'],
                'level': 'DEBUG',
                'propagate': False
            },
        }
    }
}

这将只显示来自 Django 代码库的堆栈跟踪,如下所示

[2020-05-25 17:49:17,977]: (0.000) INSERT INTO `contacts_contactscount` (`user_id`, `date`, `amount`) VALUES (338, '2020-05-25 17:49:17', 7); args=[338, '2020-05-25 17:49:17', 7]
Stack
   File "<project-root>/api/views/contacts.py", line 164, in create
    Contact.objects.filter(pk__in=to_delete).delete()
  File "<project-root>/<folder>/contacts/models.py", line 54, in delete
    create_deletion_log.delay(obj, deleted_timestamp)
  File "<project-root>/<folder>/contacts/tasks.py", line 31, in create_deletion_log
    contact.save()
  File "<project-root>/<folder>/contacts/models.py", line 118, in save
    Contact.objects.contacts_added_hook(self.user)
  File "<project-root>/<folder>/contacts/models.py", line 67, in contacts_added_hook
    current_total = user.profile.contacts_total
  File "<project-root>/<folder>/profile/models.py", line 631, in contacts_total
    ContactsCount.objects.create(user=self.user, amount=count)

于 2020-05-25T16:01:39.677 回答
1

我猜您正在尝试确定应用程序中的哪些行负责运行哪些查询。

实现此目的的一种方法是创建一个自定义处理程序,该处理程序在 Django 记录查询的位置打印出当前堆栈。这将允许您查看应用程序中的哪一行正在执行。

您可以创建一个自定义处理程序,例如:

import logging
import traceback

class StackInfoHandler(logging.StreamHandler):

    trim = 5

    def emit(self, record):
        super(StackInfoHandler, self).emit(record)
        stack = ''.join(
            str(row) for row in traceback.format_stack()[:-self.trim]
        )
        self.stream.write(stack)

然后在您的日志记录配置中,您可以切换处理程序类以使用StackInfoHandler

'handlers': {
    'console': {
        'level': 'DEBUG',
        'class': 'my.package.StackInfoHandler',  # Reference the custom handler
        'formatter': 'color'
    },
},

请注意,StackInfoHandler从堆栈中修剪 5 行,这样它就不会显示来自日志框架本身的堆栈帧。您可能需要调整这个数字(5 在本地对我有用)。

于 2018-12-07T21:42:36.810 回答