python-Django-Logging 用法详解

宗政欣可
2023-12-01

Django Logging Settings

Django 官方文档地址 https://docs.djangoproject.com/en/2.0/topics/logging/#examples

Python dictConfig 的配置,参考 **Python ** 官方手册

https://docs.python.org/3/library/logging.config.html#logging-config-dictschema

1. 简介

​ 本文针对 Django 配置日志输出、控制台日志全部输出到文件、日志/控制台 console 重定向到文件。

Django 利用的就是 Python 提供的 logging 模块,但 Django 中要用 logging,还得有一定的配置规则,需要在 settings.py 中设置。

​ 默认情况下,Django 使用 dictConfig 格式。为了配置日志记录,您可以使用 LOGGING 定义日志记录设置的字典。这些设置描述了您希望在日志记录设置

中使用的日志记录器,处理程序,过滤器和格式化程序,以及希望这些组件具有的日志级别和其他属性。

​ 如果将 dictConfig 中的 disable_existing_loggersLOGGING 设置为 True(默认值),则将禁用默认配置中的所有记录器。禁用的记录器与已删除的记

录器不同;记录器仍将存在,但会静默丢弃记录到它的所有内容,甚至不会将条目传播到父记录器。因此,您应该非常小心地使用;这可能不是您想要的。相反,

您可以设置为并重新定义一些或所有默认记录器;或者您可以自定义设置。

配置如下:

disable_existing_loggers: True 禁用默认配置中的所有记录器

disable_existing_loggers: False 启动默认配置中的所有记录器

2. 文件日志示例

2.1 日志配置

​ 一个简单的文件日志配置,它将所有日志记录从 Django 记录器写入本地文件。

import os

LOGGING = {
    'version': 1,                                    # 定义版本 1
    'disable_existing_loggers': False,               # 允许使用已有的默认过滤器
    'handlers': {                                    # 日志处理器
        'file': {                                    # 定义一个处理器 file
            'level': 'DEBUG',                        # 定义 handelr 的日志级别
            'class': 'logging.FileHandler',          # 使用文件类处理器,可以将日志写入文件中
            'filename': '/path/to/django/debug.log', # 定义 DEBUG 日志信息的存储路径,文件路径需要确认有可写权限
        },
    },
    'loggers': {                                     # 日志记录器
        'django': {                                  # 记录 django 项目中的信息
            'handlers': ['file'],                    # 使用处理器 file
            'level': 'DEBUG',                        # 日志的等级为 DEBUG 
            'propagate': True,                       # 允许传播至上级记录器
        },
    },
}

2.2 配置说明

​ 字典中的 version 指明了配置的版本;disable_existing_loggers 指明是否禁止默认配置的记录器。(这两项通常不需要去改动)

重点看 loggershandlers 的配置:

​ 如前面说,一条消息首先传递给 loggerDjango 中内置了几种记录器,比如这里用到的 Django 记录器,它会接收 Django 层次结构中的所有消息。

然后我们定义了需要处理 DEBUG 以上级别的消息,并把这些消息传递给名叫file的处理器。

‘propagate’: True 可以基于每个记录器控制该传播,如果您不希望特定记录器传播到其父项,则可以关闭此行为。

​ 现在消息来到名叫 filehandlers 中了。这个处理器定义了消息处理级别仍然为 DEBUG,在 class 中定义将消息输出到文件中去,文件地址为项目目录的 /path/to/django/debug.log

​ 因为这里没有配置 filtersformatters,因此会采用默认的设置。

​ 需要注意的是日志的输出文件的目录 /path/to/django/ 一定要提前创建好,并且确保项目拥有此目录的写入权限。

3. 控制台日志示例

3.1 日志配置

​ 默认情况下,此配置仅将日志等级为 INFO 的日志向 console 控制台发送消息,其他级别或更高级别的消息则不发送至控制台。

​ 与 Django 的默认日志记录配置相同,但默认情况下仅在 DEBUG=True 时显示日志记录。

Django 不会记录许多此类消息。但是,通过此配置,您还可以设置环境变量 DJANGO_LOG_LEVEL=DEBUG 以查看 Django 的所有调试日志记录,这非常

冗长,因为它包含所有数据库查询。

import os

LOGGING = {
    'version': 1,                                           # 定义版本 1
    'disable_existing_loggers': False,                      # 允许使用已有的默认过滤器
    'handlers': {                                           # 日志处理器
        'console': {                                        # 定义一个处理器 console
            'class': 'logging.StreamHandler',               # 使用流处理类,可以将信息打印到控制台
        },
    },
    'loggers': {                                            # 日志记录器
        'django': {                                         # 记录 django 项目中的信息
            'handlers': ['console'],                        # 使用处理器 console
            'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'), # 日志的等级为 INFO 
        },
    },
}

4. 复杂日志示例

4.1 日志配置

​ 所有与日志有关的配置默认在 LOGGING ={} 中,distConfig 格式。如果我们没有进行特别配置,Django 会执行默认的日志配置。

Django settings 默认配置:

DEBUG = True

django logger 及其(除 django.server 之外)所有下级的 INFO 以上的日志,都会被 StreamHandler 处理(输出到 console

DEBUG = Flase

django logger 及其(除 django.server 之外)所有下级的 ERRORCRITICAL 的日志,都会被 AdminEmailHandler 处理(发送至指定邮件)

​ 如果我们不想使用默认的配置,可以将 LOGGING 中的 ‘disable_existing_loggers’ 设置为 True(默认也是 True ),这样一来,默认的配置就会被禁用。

但是设置 ‘disable_existing_loggers’: True,必须要非常小心,因为可能产生一些令人意外的结果(官网这么说的,还没试过),所以比较建议的方法

‘disable_existing_loggers’: False,然后重写部分或者全部的默认 logger

LOGGING = {
    'version': 1,                                    # 定义版本 1
    'disable_existing_loggers': False,               # 允许使用已有的默认过滤器
    'formatters': {                                  # 日志格式器
        'verbose': {                                 # 定义一个格式器 verbose
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
                                                     # 输出日志级别名称,日志消息以及生成日志消息的时间,进程,线程和模块
        },
        'simple': {                                  # 定义一个格式器 simple
            'format': '%(levelname)s %(message)s'    # 仅输出日志级别名称(例如 DEBUG)和日志消息
        },
    },
    'filters': {                                     # 日志过滤器
        'special': {                                 # 定义一个过滤器 sepcial
            '()': 'project.logging.SpecialFilter', 
            'foo': 'bar',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': { 									 # 日志处理器
        'console': {                                 # 定义一个处理器 console,将 INFO 级别的日志使用 stream 流处理打印到控制台
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'                    # 过滤规则使用 simple,只输出日志等级以及 messages 信息
        },
        'mail_admins': {                             # 定义一个处理器 mail_admis,将 ERROR 级别的日志使用 AdminEmailHandler 处理器
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
            'filters': ['special']                   # 将错误信息发送到该网站的 admin 超级用户的邮箱,错误信息格式采用 special 格式处理
        }
    },
    'loggers': {                                     # 日志记录器
        'django': {                                  # 定义一个记录器 django,使用 console 处理器,即将记录的信息打印到控制台
            'handlers': ['console'],                 
            'propagate': True,                       # 允许传播至上级记录器
        },
        'django.request': {                          # 定义一个记录器 django.request,使用 main_admins 处理器,只处理邮件发送的错误信息
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,                      # 禁用传播至上级记录器 django
        },
        'myproject.custom': {                        # 定义一个记录器 myproject.custome,同时使用 console、mail_admis 处理器
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
            'filters': ['special'] 
        }
    }
}

4.2 配置说明

  • 将配置文件的格式标识为 “ 版本1 ” 格式。也是目前唯一的版本格式。

  • 定义两个格式化程序:

    • simple

      ​ 仅输出日志级别名称(例如 DEBUG )和日志消息。

      ​ 该 format 字符串是普通的 Python 格式化字符串,描述了将在每条记录行上输出的详细信息。

      ​ 可以输出的详细信息的完整列表可以在 Formatter Objects 中找到。

    • verbose

      ​ 输出日志级别名称,日志消息以及生成日志消息的时间,进程,线程和模块。

  • 定义两个过滤器:

    • project.logging.SpecialFilter (special)

      ​ 如果此过滤器需要其他参数,则可以在过滤器配置字典中将它们作为其他关键字提供,在这种情况下,实例化时 foo 将为参数提供值。

    • django.utils.log.RequireDebugTrue

      ​ 该记录在 DEBUG is True 时传递。

  • 定义两个处理程序:

    • console,StreamHandler

      ​ 将任何 INFO (或更高版本的)消息打印到 sys.stderr。该处理程序使用 simple 输出格式。

    • mail_admins,AdminEmailHandler

      ​ 通过电子邮件将任何 ERROR (或更高版本)消息发送到该网站 ADMINS。该处理程序使用 special 过滤器。

  • 配置三个记录器:

    • django

      ​ 将所有消息传递给 console 处理程序。

    • django.request

      ​ 将所有 ERROR 消息传递给 mail_admins 处理程序。另外,该记录器被标记为不传播消息。

      ​ 这意味着记录器 django.request 将不会处理写入日志消息至 django

    • myproject.custom

      ​ 将所有 INFO 或更高级别的消息传递给该消息,也将 special 过滤器传递给两个处理程序 consolemail_admins

      ​ 这意味着所有 INFO 级别的消息(或更高级别的消息)将被打印到控制台。ERRORCRITICAL 消息也将通过电子邮件输出。

4.3 邮件配置

​ 上面的日志配置提到需要在日志中发送错误信息至 admin 的邮箱,Django 项目中需要在 settings 配置好邮件发送的相关配置

'The email address that error messages come from, such as those sent to ADMINS and MANAGERS.'

# 邮件配置
EMAIL_HOST = 'smtp.maildomain.com'                    # SMTP地址
EMAIL_PORT = 25                                       # SMTP端口
EMAIL_HOST_USER = 'sender@maildomain.com'             # 发送邮件的邮箱
EMAIL_HOST_PASSWORD = '******'                        # 我的邮箱密码
EMAIL_SUBJECT_PREFIX = u'[prefix]'                    # 为邮件 Subject-line 前缀,默认是 '[django]'
EMAIL_USE_TLS = True                                  # 与 SMTP 服务器通信时,是否启动 TLS 链接(安全链接),默认 false
# 管理员站点
SERVER_EMAIL = 'adminli@163.com'  
ADMINS = (('receiver', 'receiver@maildomain.com'),)   # 接收邮件的邮箱(或邮件组)

5. 自定义日志配置

​ 如果您不想使用 PythondictConfig 格式配置记录器,则可以指定自己的配置方案。

​ 该 LOGGING_CONFIG 设置定义了用于配置 Django 记录器的可调用对象。默认情况下,它指向 Pythonlogging.config.dictConfig() 函数。但是,如果

要使用其他配置过程,则可以使用带有单个参数的任何其他可调用对象。LOGGING 配置日志记录时,将提供的内容作为该参数的值。

​ 设置 LOGGING_CONFIGNone 仅表示禁用自动配置过程。如果禁用配置过程,Django 仍将进行日志记录调用,而回退到定义的默认日志记录行为。

settings 配置如下:

LOGGING_CONFIG = None
 
import logging.config
logging.config.dictConfig(...)

6. Django 日志记录扩展

6.1 Django 内建 logger

1. django

django 只是一个最上级的 logger,但实际上并不接收什么实际的信息,所有的信息都是通过下级 logger 接收。

2. django.request
  • 处理请求处理有关的日志消息

    • 5XX 响应作为 ERROR 消息引发;出现 4XX 响应作为 WARNING 消息。
  • 发送给该记录器的消息具有以下额外的上下文:

    • status_code:与请求关联的 HTTP 响应代码。
    • request: 生成日志消息的请求对象。
3. django.server
  • runserver 命令调用的服务器接收的请求处理相关的日志消息

    • HTTP 5XX 响应记录为 ERROR 消息,4XX 响应记录为 WARNING 消息,其他所有记录为 INFO
  • 发送给该记录器的消息具有以下额外的上下文:

    • status_code:与请求关联的 HTTP 响应代码。
    • request: 生成日志消息的请求对象。
4. django.template
  • 记录与模板渲染有关的消息

    • 缺少的上下文变量将记录为 DEBUG 消息。

    • 在调试模式关闭时,在关闭期间引发的未捕获异常将会记录为消息(这是有用的,因为在这种情况下使异常屏蔽并返回空字符串)。

      {%include %} WARNING {% include %}

5. django.db.backends
  • 与代码与数据库的交互有关的消息

    • 请求执行的每个应用程序级 SQL 语句都在 DEBUG 该记录器级别记录。
  • 发送给该记录器的消息具有以下额外的上下文:

    • duration:执行 SQL 语句所花费的时间。
    • sql: 执行的 SQL 语句。
    • params: 在 SQL 调用中使用的参数。
  • 出于性能方面的考虑,仅在 settings.DEBUGSQL 日志记录设置为 True 才启用 SQL 日志记录,而不考虑日志记录级别或已安装的处理程序。

  • 此日志记录不包括框架级初始化(例如:SET TIMEZONE )或事务管理查询(例如:**SET TIMEZONE BEGIN COMMIT ROLLBACK **)。

  • 如果要查看所有数据库查询,请打开数据库中的查询日志记录。

6.2 Handlers 日志邮件处理器

class AdminEmailHandler(include_html=False, email_backend=None)[source]
  • Django 除了提供 Python 日志记录 loggging 模块所提供的日志处理程序外,还提供了一个特别的日志处理程序。

  • 该处理程序 ADMINS 针对收到的每个日志消息都会向该站点 admin 用户发送一封电子邮件。

  • 如果日志记录包含 request 属性,则请求的完整详细信息将包含在电子邮件中。

​ 如果客户的 IP 地址在 INTERNAL_IPS 设置中,则电子邮件主题将包含短语“内部 IP” ;如果没有,它将包括 “EXTERNAL IP”。

​ 如果日志记录包含堆栈跟踪信息,则该堆栈跟踪将包含在电子邮件中。

  • AdminEmailHandlerinclude_html 参数用于控制回溯电子邮件是否包含 HTML 附件,该附件包含调试 Web 页面的完整内容。要在您的配置中设置此值,请将其包含在的处理程序定义中 django.utils.log.AdminEmailHandler,如下所示:
'handlers': {
    'mail_admins': {
        'level': 'ERROR',
        'class': 'django.utils.log.AdminEmailHandler',
        # 设置为 True 则包含 HTML 附件
        'include_html': True, 
    }
},

注意

​ 此电子邮件的 HTML 版本包含完整的追溯,在堆栈的每个级别上都包含局部变量的名称和值,以及 Django 设置的值。

​ 所以此信息可能非常敏感,您可能不想通过电子邮件发送它。考虑使用诸如 Sentry 之类的东西来获得两全其美的体验。既有全面的回溯的丰富信息以及不通

过电子邮件发送信息的安全性。

​ 您还可以明确指定要从错误报告中过滤掉的某些敏感信息,可以了解有关过滤错误报告的更多信息 。

​ 通过设置 email_backend 的参数 AdminEmailHandler,可以覆盖处理程序正在使用的电子邮件后端,如下所示:

'handlers': {
    'mail_admins': {
        'level': 'ERROR',
        'class': 'django.utils.log.AdminEmailHandler',
        'email_backend': 'django.core.mail.backends.filebased.EmailBackend',
    }
},

默认情况下,EMAIL_BACKEND 将使用指定的电子邮件

send_mail(subject,message,*args,**kwargs)[源代码]**

​ 向管理员用户发送电子邮件。若要自定义此行为,可以对 AdminEmailHandler 类进行子类化并重写此方法。

6.3 Filters 过滤器扩展

Django 除了提供 Python 日志记录模块所提供的日志过滤器外,还提供了一些特别日志过滤器。

  • classCallbackFilter(callback)source

    • 该过滤器接受一个回调函数(该函数应接受一个参数,即要记录的信息),并为通过过滤器的每条记录调用该函数。
    • 如果回调返回 False,则该记录的处理将不会继续。
  • 示例

    • UnreadablePostError 要从管理员电子邮件中过滤掉,您可以创建过滤器功能:
    from django.http import UnreadablePostError
     
    def skip_unreadable_post(record):
        if record.exc_info:
            exc_type, exc_value = record.exc_info[:2]
            if isinstance(exc_value, UnreadablePostError):
                return False
        return True
    
    • 将其添加到您的日志记录配置中:
    'filters': {
        'skip_unreadable_posts': {
            '()': 'django.utils.log.CallbackFilter',
            'callback': skip_unreadable_post,
        }
    },
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['skip_unreadable_posts'],
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    
  • class RequireDebugFalse[source]

    仅当 settings.DEBUGFalse 时,此过滤器才会传递记录。

    该过滤器被用作在默认如下 LOGGING 配置,以确保 AdminEmailHandler 当只发送错误电子邮件到管理员:

    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse',
        }
    },
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    
  • class RequireDebugTrue[source]

    这个过滤器 filter 类似于 RequireDebugFalse ,只有当 settings.DEBUGTrue 的时候,才会被调用。

 类似资料: