django

Django DEGUB=False 时,异常和堆栈信息记录

2020-04-11  本文已影响0人  Su_yj

一直以来都有一个疑惑,django在 DEBUG = True 时,程序出错时会把错误的堆栈信息打印到控制台,然而当 DEBUG = False 时,程序异常只是显示一条状态码为500 的记录,而堆栈信息不会显示。

[11/Apr/2020 23:10:19] "GET /api/v1/course/1/ HTTP/1.1" 500 145

由于服务器上一般用 uwsgi 来部署,所以 uwsgi 拿到的日志即 Django 的控制台输出日志,因此应该只需要修改 Django 控制台输出的日志,uwsgi 就能拿到的异常时的堆栈信息了。

在查看 StackOverflow 的这条问题 How do you log server errors on Django sites 后,发现有两种方法可以实现错误信息的堆栈输出。

方法一:通过中间件处理异常

在项目中创建一个py文件(名字随便),我这里创建在 utils/middleware.py ,并创建一个类通过 process_exception 方法处理异常

# utils/middleware.py
import logging
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin

class ErrorMiddleware(MiddlewareMixin):
    def process_exception(self, request, exception):
        if not settings.DEBUG:
            logging.exception(exception)

settings.py 添加该中间件

# settings.py
DEBUG = False

MIDDLEWARE = [
    ......
    'utils.middleware.ErrorMiddleware',  # 这是你写的类的导入路径
]

方法二:修改 Django 的 log 日志配置

Django 的 log 默认配置如下

# django\utils\log.py

DEFAULT_LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'formatters': {
        'django.server': {
            '()': 'django.utils.log.ServerFormatter',
            'format': '[{server_time}] {message}',
            'style': '{',
        }
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
        },
        'django.server': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'django.server',
        },
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django': {
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
        },
        'django.server': {
            'handlers': ['django.server'],
            'level': 'INFO',
            'propagate': False,
        },
    }
}

查看 Django 的 log 配置发现,原来控制台输出的日志时做了过滤,因此最简单的方法就是把 handlersconsolefilters 注释了就可以,因此在 settings.py 文件下添加一下配置:

# settings.py

DEFAULT_LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'formatters': {
        'django.server': {
            '()': 'django.utils.log.ServerFormatter',
            'format': '[{server_time}] {message}',
            'style': '{',
        }
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            # 'filters': ['require_debug_true'],  # 把该条件注释,使得debug不管True或False都有效
            'class': 'logging.StreamHandler',
        },
        'django.server': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'django.server',
        },
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django': {
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
        },
        'django.server': {
            'handlers': ['django.server'],
            'level': 'INFO',
            'propagate': False,
        },
    }
}

根据上面的配置,还可以进行自定义,把日志写入到本地,配置如下

# settings.py

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        # Include the default Django email handler for errors
        # This is what you'd get without configuring logging at all.
        'mail_admins': {
            'class': 'django.utils.log.AdminEmailHandler',
            'level': 'ERROR',
             # But the emails are plain text by default - HTML is nicer
            'include_html': True,
        },
        # Log to a text file that can be rotated by logrotate
        'logfile': {
            'class': 'logging.handlers.WatchedFileHandler',
            'filename': '/var/log/django/myapp.log'
        },
    },
    'loggers': {
        # Again, default Django configuration to email unhandled exceptions
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
        # Might as well log any errors anywhere else in Django
        'django': {
            'handlers': ['logfile'],
            'level': 'ERROR',
            'propagate': False,
        },
        # Your own app - this assumes all your logger names start with "myapp."
        'myapp': {
            'handlers': ['logfile'],
            'level': 'WARNING', # Or maybe INFO or DEBUG
            'propagate': False
        },
    },
}

参考:

  1. How do you log server errors on django sites
  2. Django logging 配置
  3. Django 系统日志logging
上一篇 下一篇

猜你喜欢

热点阅读