django:日志

django:日志

Django 使用 Python 内置的 logging 模块处理系统日志

日志框架的组成元素

Python logging 配置由下面四个部分组成:
Loggers
Handlers
过滤器
Formatters

Loggers

logger 是日志系统的入口。每个 logger 都是命名了的 bucket, 消息写入 bucket 以便进一步处理。

logger 可以配置 日志级别。日志级别描述了由该 logger 处理的消息的严重性。Python 定义了下面几种日志级别:

DEBUG:排查故障时使用的低级别系统信息
INFO:一般的系统信息
WARNING:描述系统发生了一些小问题的信息
ERROR:描述系统发生了大问题的信息
CRITICAL:描述系统发生严重问题的信息
每一条写入 logger 的消息都是一条 日志记录。每一条日志记录也包含 日志级别,代表对应消息的严重程度。日志记录还包含有用的元数据,来描述被记录了日志的事件细节,例如堆栈跟踪或者错误码。

当 logger 处理一条消息时,会将自己的日志级别和这条消息的日志级别做对比。如果消息的日志级别匹配或者高于 logger 的日志级别,它就会被进一步处理。否则这条消息就会被忽略掉。

当 logger 确定了一条消息需要处理之后,会把它传给 Handler。

Handlers
Handler 是决定如何处理 logger 中每一条消息的引擎。它描述特定的日志行为,比如把消息输出到屏幕、文件或网络 socket。

和 logger 一样,handler 也有日志级别的概念。如果一条日志记录的级别不匹配或者低于 handler 的日志级别,对应的消息会被 handler 忽略。

一个 logger 可以有多个 handler,每一个 handler 可以有不同的日志级别。这样就可以根据消息的重要性不同,来提供不同格式的输出。例如,你可以添加一个 handler 把 ERROR 和 CRITICAL 消息发到寻呼机,再添加另一个 handler 把所有的消息(包括 ERROR 和 CRITICAL 消息)保存到文件里以便日后分析。

过滤器

在日志记录从 logger 传到 handler 的过程中,使用 Filter 来做额外的控制。

默认情况下,只要级别匹配,任何日志消息都会被处理。不过,也可以通过添加 filter 来给日志处理的过程增加额外条件。例如,可以添加一个 filter 只允许某个特定来源的 ERROR 消息输出。

Filter 还被用来在日志输出之前对日志记录做修改。例如,可以写一个 filter,当满足一定条件时,把日志记录从 ERROR 降到 WARNING 级别。

Filter 在 logger 和 handler 中都可以添加;多个 filter 可以链接起来使用,来做多重过滤操作。

Formatters
日志记录最终是需要以文本来呈现的。Formatter 描述了文本的格式。一个 formatter 通常由包含 LogRecord attributes 的 Python 格式化字符串组成,不过你也可以为特定的格式来配置自定义的 formatter。

1 装饰器增加日志效果
直接使用函数装饰器来为请求增加日志的打印效果,DEBUG要设为True
在这里插入图片描述
在这里插入图片描述

#logger.py
import logging


def wrap(func):
    def inner(*args, **kwargs):
        try:
            print("记录日志~")
            ret = func(*args, **kwargs)
        except Exception as e:
            print(f"执行路径:{__file__}")
            logger = logging.getLogger(__name__)
            logger.error(__file__)
            # CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30
            # WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
            logging.basicConfig(
                level=20,
                format='%(asctime)s  [%(levelname)s][%(filename)s line:%(lineno)d]:%(message)s',
                datefmt="%Y-%m-%d %H:%M:%S"
            )
            logger.error(f"搓搓搓,是我的搓。--{e}")
    return inner
#views.py
from utils import logger
class RegisterBasicUser(APIView):
	@logger.wrap
    def get(self, request):
        a = []
        print(a[1])
        return HttpResponse({"code": 200})

在这里插入图片描述
在这里插入图片描述
ps:这种方式优点是灵活选择希望打印日志的请求,添加装饰器即可,缺点是如果是全局打印日志,那么手动一个个添加装饰器不方便

2 为类的所有方法增加装饰器

此时可以把settings.py中的DEBUG设为False了

如果类的方法很多(比如CBV模式类下实现了get、post、put、delete方法,手动为每个实例方法增加装饰器很辛苦,还可能产生遗漏,可做如下修改)

# logger.py
import logging
import inspect
import datetime
import os


wrap_flag = False

def wrap(func):
    count = 0
    # 这里的__name__均为utils.logger,因为外部文件导入该logger文件,
    # __name__就是该模块名,如果自身作为脚本运行,就是__main__			 
    # 所以不管调用多少次装饰器,logger的内存空间地址始终是1个
    logger = logging.getLogger(__name__)
    # CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30
    # WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
    base_name = datetime.datetime.now().strftime("%Y-%m-%d") + "日志.txt"
    base_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "logs")
    path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "logs", base_name)
    if not os.path.exists(base_path):
        os.mkdir(base_path)
    # logger.addHandler(fh),注意,fh这个handler,每次调用装饰器都会
    # 增加1次,而settings.py执行的时候,就会导致所有添加了该装饰器的
    # 类的实例方法,都会添加1个handler,可能会出现,1个报错,打印n条日志
    # 的情况,所以我们要限制这个handler不论调用多少次装饰器,只会添加1次
    fh = logging.FileHandler(path, mode="a", encoding="utf-8")
    formatter = logging.Formatter('%(asctime)s  [%(levelname)s][%(filename)s line:%(lineno)d]:%(message)s')
    fh.setFormatter(formatter)
    logging.basicConfig(
        level=20,
        format='%(asctime)s  [%(levelname)s][%(filename)s line:%(lineno)d]:%(message)s',
        datefmt="%Y-%m-%d %H:%M:%S"
    )
    global wrap_flag
    # logger.addHandler(fh)
    if (wrap_flag == False):
        logger.addHandler(fh)
        wrap_flag = True
        count += 1
        print("添加的handler数目:", count)

    def inner(*args, **kwargs):
        global ret
        try:
            print("记录日志~")
            print("dhanler", count)
            ret = func(*args, **kwargs)
            print("结束")
        except Exception as e:
            print("执行异常日志打印:")
            logger.error(f"搓搓搓,是我的搓。--{e}")

    return inner

# 要动态的为类中的实例方法添加装饰器,需要使用inspect内置模块
def log_trace(cls):
    for func_name, func_obj in inspect.getmembers(cls, lambda x: inspect.isfunction(x) or inspect.ismethod(x)):
        print(func_name, "-----------")
        methods = ['get', 'post', 'delete', 'put']
        if func_name in methods:
            setattr(cls, func_name, wrap(func_obj))
    return cls

在实际Django开发的过程中,会发现settings.py执行了两次,可如下验证:
在这里插入图片描述
会发现print打印了两次,查询后知,开发模式下,python manage.py runserver的方式启动django项目,会启动两个线程加载settings文件,一个是服务使用的,一个是监控settings文件的改动,加上参数 --noreload即可(如果我们的日志装饰器,没有限制只加上1个文件的handler,那么会导致同一个类的get、post请求,原本加了2个handler,执行两次,就加上了4个handler,导致日志每次输入到文件的信息,都是1次4条数据,ps:因为我现在只写了1个类,仅2个接口)
在这里插入图片描述
在这里插入图片描述

# 为CBV类添加上装饰器
@logger.log_trace
class RegisterBasicUser(APIView):

运行项目:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
根据打印可知,在执行urls.py时,就为类执行了装饰器,inspect.getmembers获取了我们定义的CBV类(继承了APIView,restframework中的类)中的成员,其中就含有get和post,说明装饰器成功加上,可以调用接口测试:
在这里插入图片描述
调用接口:
在这里插入图片描述
查看日志:
在这里插入图片描述
在这里插入图片描述
可见,增加了filehandler的添加限制后,只打印了1条信息,试下去掉限制:
在这里插入图片描述
重新执行:
在这里插入图片描述
可见,没有限制,只要为类添加该装饰器,所有的类中的get、post、put、delete方法均会增加1个handler,导致异常的日志有多条,因为这里我们只有1个post和1个get方法,故而记录有两条

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Django日志配置可以在 settings.py 文件中进行配置,具体步骤如下: 1. 导入 logging 模块: ```python import logging ``` 2. 配置日志的格式: ```python LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, 'file': { 'class': 'logging.handlers.RotatingFileHandler', 'filename': 'django.log', 'maxBytes': 1024 * 1024 * 5, # 5 MB 'backupCount': 5, }, }, 'loggers': { 'django': { 'handlers': ['console', 'file'], 'level': 'DEBUG', }, }, } ``` 在上面的配置中,使用了一个 RotatingFileHandler,将日志输出到一个名为 django.log 的文件中。maxBytes 和 backupCount 参数用于控制日志文件的大小和数量。当日志文件大小超过 maxBytes 时,会自动创建一个新的日志文件,并将旧的日志文件备份到一个新的文件中。 3. 在代码中使用日志: ```python import logging logger = logging.getLogger('django') def my_view(request): logger.debug('This is a debug message') logger.info('This is an info message') logger.warning('This is a warning message') logger.error('This is an error message') logger.critical('This is a critical message') ``` 在上面的代码中,通过 getLogger 方法获取名为 django 的 Logger 对象,并使用其 debug、info、warning、error 和 critical 方法输出不同级别的日志信息。 注意:在上面的配置中,使用了一个名为 django 的 logger,这是 Django 默认使用的 logger。如果你想要使用一个不同的 logger,需要在配置中添加对应的 handlers 和 loggers。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值