【问题标题】:python: How to start and stop a logger whenever i wantpython:如何随时启动和停止记录器
【发布时间】:2019-08-14 14:12:47
【问题描述】:

我正在尝试在我的 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 处理程序。

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

【问题讨论】:

  • 尝试将日志级别设为INFO
  • 这种场景下也可以试试filters。来源:docs.djangoproject.com/en/2.2/topics/logging
  • 你能把代码显示一下吗,
  • 只要您想启动/停止,只需将日志级别更改为 INFO 并返回到 DEBUG
  • @TreantBG 我会试试的

标签: python django python-logging


【解决方案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)

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

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

【讨论】:

  • 如何在conf文件中添加这个类并在我想要的任何地方创建它的对象,然后打开和关闭
  • stackoverflow.com/questions/57795153/…(我已经根据您使用过滤器的回答提出了我的上述评论作为问题。您可以查看一下吗。这样您就可以了解我的需求)
【解决方案2】:

只是从上面的答案和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']
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多