https://blog.csdn.net/weixin_37590093/article/details/81536372(清晰明了)

前言
在web系统的开发环境以及生产环境中,经常要查看日志。记录日志的方法有很多(轻易不要使用print),在django中,我们可以通过 import logging 直接使用Python内建的logging模块来实现.

理解logging
网上关于logging的资料有不少,大多也都是围绕官方文档来写的,我们可以参考。如果看别人写的文档觉得发懵,那就需要先系统了解一下logging,请看官方文档。稳妥起见,请确认你查看的文档与使用的django版本一致。

快速了解
logging机制中,有四个主要的部分:

Loggers
Handlers
Filters
Formatters
Loggers
Loggers中的logger是整个日志机制的入口,一个logger对应一种类型的日志。logger通过设定日志级别(level属性),来配置logger的触发条件。Python中定义了5种日志级别:
由低到高分别为:DEBUG -> INFO -> WARNING -> ERROR -> CRITICAL。
代码中通过 logger = logging.getLogger('django') 获得一个logger的实例,’django’是一种类型的日志。
当一条日志信息发给logger时,日志信息的log level会和logger的log level对比。如果日志信息的log level达到或者是超过logger的log level的级别,这条信息会被发往handler去处理。否则,这条信息会被忽略。一旦logger决定信息要进一步被处理,这条信息会被传给给Handler(logger的handler属性).
所以,logger更像是一个日志处理的分发器。

Handlers
handler是实际上来处理日志记录的地方。它说明的是一个特殊的记录行为,比如,将这个信息写在屏幕上、写到一个文件或者写到一个Network socket中去。这一点是通过handler的class属性来配置的。
与logger一样,handler也有日志级别(level)属性,如果logger传来的记录级别没有handler高,那么这条记录也会被忽略。

为什么logger和handler都要设置level?
因为一个logger可以有多个handler,且每个handler可以有不同的log level。这样一来,一个logger可以接受一类日志的多个级别的信息,并且将不同级别的信息进行不同的处理。

Filters
filters是在信息从logger传递到handler的过程中实施一些过滤行为。
如果filters属性没有被设置,即视为默认情况。默认情况下,任何达到log level的日志信息都会被处理。
如果配置了filter,你可以在logging过程中添加一些额外的过滤功能。比如,只允许某个指定的来源的ERROR信息发给handler.
filters也可以修改日志记录的级别。比如,你可以写一个Filter, 设置在一些特殊情况,能够将ERROR级别的日志记录降级为WARNING级别。
filters可以在Loggers和handlers里面设置。多个filters可以同时作用于一个地方,起到多重过滤的作用。

Formatters
一条日志记录需要以文本的形式展现出来,Formatters定义了文本的格式。一个格式化器一般由python的格式字符串组成。不过,你也可以自定义格式。

使用Logging
使用logging的标准方法如下:

# import the logging library
import logging

# Get an instance of a logger
logger = logging.getLogger(__name__)

def my_view(request, arg1, arg):
    ...
    if bad_mojo:
        # Log an error message
        logger.error('Something went wrong!')
1
2
3
4
5
6
7
8
9
10
11
每当bad_mojo条件满足,都会发送一个error级别的日志记录。实例代码中的__name__代表logger的名称。
如果logger的定义如下,那么__name__就是’django’或’django.request’。

'loggers': {
    ...
    'django': {
        'handlers': ['console'],
        'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'),
        'propagate': True,
    },
    'django.request': {
        'handlers': ['file', 'mail_admins'],
        'level': 'WARNING',
        'propagate': False,
    },
    ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
logger的命名规则使用”.”(dot)来标识层级关系,上例中,’django’是’django.request’的上级。这种层级关系的设计,使得低层次logger接收到的日志信息,也可以被上级logger收到。实践中,我们可以定义一个顶级的logger,用来接收所有下级logger的日志信息。
这种传播可以在每个logger基础上进行控制。如果你不想让特定的logger传播到它的上级,可以关闭这个行为。通过设置'propagate': False,来实现。

记录日志
根据上述日志的5各级别,记录日志也有5个对应的方法。

logger.debug()
logger.info()
logger.warning()
logger.error()
logger.critical()
此外,还有两种日志方法

logger.log() 手动记录一个日志,随便你想记录什么都行
logger.exception() 为了捕获某些异常,创建一个ERROR级别的日志
配置日志
logger的配置都是在settings.py中进行的。看下栗子:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
    },
    'filters': {
        'special': {
            '()': 'project.logging.SpecialFilter',
            'foo': 'bar',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
            'filters': ['special']
        }
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'propagate': True,
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
        'myproject.custom': {
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
            'filters': ['special']
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
所有与日志有关的配置默认在LOGGING ={}中,distConfig格式。如果我们没有进行特别配置,Django会执行默认的日志配置。

默认配置

DEBUG = True
‘django’这个logger以及其(除了django.server之外的)所有下级的INFO以上的日志,都会被StreamHandler处理(输出到console)
DEBUG = Flase
‘django’这个logger以及其(除了django.server之外的)所有下级的ERROR和CRITICAL的日志,都会被AdminEmailHandler处理(发送至指定邮件)
如果我们不想使用默认的配置,可以将LOGGING中的'disable_existing_loggers'设置为True(默认也是True),这样一来,默认的配置就会被禁用。但是设置'disable_existing_loggers': True,必须要非常小心,因为可能产生一些令人意外的结果(官网这么说的,还没试过),所以比较建议的方法是'disable_existing_loggers': False,然后重写部分或者全部的默认logger。

文件形式输出日志
以下代码是将日志文件输出到文件的例子,如果需要参照,注意把'filename'换成自己的文件路径和文件名。

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': '/path/to/django/debug.log',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
在控制台中输出日志
这种方式在本地开发环境进行调试时比较有帮助,很直观,需要的时候马上就能看到输出,不必切换到文件或者查收邮件。不过在生产环境下最好不要输出到控制台。默认情况下,只有在DEBUG = True的时候才会将日志输出到控制台,而且只处理INFO以上级别的日志。默认情况下,这种日志并不会输出很多信息,如果你想看到操作数据库的细节,可以在logger的level中设置'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'),这样就可以了。不过这样产生的日志也有点太多了。

import os

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
        },
    },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
再回头看看第一段例子代码,这里再拿出来晒一次

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
    },
    'filters': {
        'special': {
            '()': 'project.logging.SpecialFilter',
            'foo': 'bar',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
            'filters': ['special']
        }
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'propagate': True,
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
        'myproject.custom': {
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
            'filters': ['special']
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
这个例子相比之前的会稍微复杂一些。
formatters中有两个格式的配置,'verbose'和'simple',这里'simple'定义的输出格式很简单,因为只是用来输出一些INFO信息,并不是重要的日志,因此也并不需要复杂的格式。'verbose'输出的信息就比较丰富了,可以用在ERROR或CRITICAL日志的输出。具体的格式请参考这里。

学习例子代码,不仅仅是学习用法,更重要的是领会意图

handlers中定义了两个handler:'console'和'mail_admins'。'console'配置'class': 'logging.StreamHandler',这个我们不用过多去说。重点看看'mail_admins',配置'class': 'django.utils.log.AdminEmailHandler',那么既然要配置为通过邮件发送日志,那么是不是有必要设置一下发送和接收的邮件呢?
邮箱的配置也在settings.py中:

# 邮件配置
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 = 'xinxinyu2011@163.com'  # The email address that error messages come from, such as those sent to ADMINS and MANAGERS.
ADMINS = (('receiver', 'receiver@maildomain.com'),)  # 接收邮件的邮箱(或邮件组)
1
2
3
4
5
6
7
8
9
10
Loggers
Django提供了一些内建的logger,比如上面例子中的'django'。

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

django.request
django.request是要受理关于请求(request)的日志记录。如果response是5XX,则被认为是ERROR级别的日志信息,4XX则是WARNING级别。

django.server
django.server是要受理关于服务器端处理请求的结果的日志记录。如果response是5XX,则被认为是ERROR级别的日志信息,4XX则是WARNING级别,其他的都是INFO级别。

django.template
django.template受理关于模板(templates)的信息。语法错误是DEBUG级别,未被捕获的异常会产生WARNING。

django.db.backends
django.db.backends受理代码与数据库交互过程产生的日志信息。只记录application级别的SQL操作信息,并且都会产生DEBUG级别的信息。信息中包含耗时、SQL语句、参数信息。此logger只能在DEBUG = True时才有效。
这个logger并不记录framework-level的信息,如SET TIMEZONE,也不记录事务管理相关的查询,如BEGIN、COMMIT、ROLLBACK等。想知道这方面的信息,只有去查数据库的日志了,Django并不提供。

以上是摘取的例子,其他logger,请自行查阅

Filters
未完

————————————————
版权声明:本文为CSDN博主「老王不需要昵称」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_37590093/article/details/81536372