【问题标题】:How to see details of Django errors with Gunicorn?如何使用 Gunicorn 查看 Django 错误的详细信息?
【发布时间】:2014-03-23 12:43:34
【问题描述】:

我刚刚使用 gunicorn 和 Nginx 部署了我的 Django (1.6) 项目。

它似乎工作正常,但我有一页是我收到 HTTP 500 错误,我无法在任何地方找到有关该错误的任何详细信息。

如何让 gunicorn 向我显示错误?

这是我当前在日志文件中看到的所有内容,当我点击页面时出现错误:

>tail gunicorn.errors 
2014-02-21 14:41:02 [22676] [INFO] Listening at: unix:/opt/djangoprojects/reports/bin/gunicorn.sock (22676)
2014-02-21 14:41:02 [22676] [INFO] Using worker: sync
2014-02-21 14:41:02 [22689] [INFO] Booting worker with pid: 22689
...
2014-02-21 19:41:10 [22691] [DEBUG] GET /reports/2/

这是我用来启动 gunicorn 的 bash 脚本:

>cat gunicorn_start
#!/bin/bash

NAME="reports"                                  # Name of the application
DJANGODIR=/opt/djangoprojects/reports          # Django project directory
SOCKFILE=/opt/djangoprojects/reports/bin/gunicorn.sock  # we will communicte using this unix socket
USER=reportsuser                                        # the user to run as
GROUP=webapps                                     # the group to run as
NUM_WORKERS=4                                     # how many worker processes should Gunicorn spawn
DJANGO_SETTINGS_MODULE=reports.settings             # which settings file should Django use
DJANGO_WSGI_MODULE=reports.wsgi                     # WSGI module name

#echo "Starting $NAME as `whoami`"

# Activate the virtual environment
cd $DJANGODIR
source pythonenv/bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH

# Create the run directory if it doesn't exist
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR

# Start your Django Unicorn
# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
exec gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $NUM_WORKERS \
  --user=$USER --group=$GROUP \
  --log-level=debug \
  --bind=unix:$SOCKFILE \
  --error-logfile /opt/djangoprojects/reports/bin/gunicorn.errors \
  --log-file /opt/djangoprojects/reports/bin/gunicorn.errors

更多信息:

我正在使用我使用 sudo service reports start|stop|restart 复制和修改的这个 init.d 脚本启动/停止 gunicorn:

>cat /etc/init.d/reports
#!/bin/sh
### BEGIN INIT INFO
# Provides:          django_gunicorn
# Required-Start:    $local_fs $network $remote_fs
# Required-Stop:     $local_fs $network $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Starts django_unicorn reports at boot time.
# Description:       Starts django_unicorn reports at boot time.
### END INIT INFO

name=`basename $0`
dir="/opt/djangoprojects/reports"
cmd="${dir}/bin/gunicorn_start"
pid_file="/var/run/$name.pid"
log_file="${dir}/bin/reports.log"

get_pid() {
    cat "$pid_file"    
}

is_running() {
    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
}

case "$1" in
    start)
    if is_running; then
        echo "Already running"
    else
        echo -n "Starting ${name}... "
        cd "$dir"
        #sudo -u "$user" $cmd &>> "$log_file"
        $cmd &>> "$log_file" &
        echo $! > "$pid_file"
        if ! is_running; then
            echo "Unable to start; see $log_file"
            exit 1
        else
            echo "[STARTED]"
        fi
    fi
    ;;
    stop)
    if is_running; then
        echo -n "Stopping ${name}... "
        kill `get_pid`
        for i in {1..10}
        do
            if ! is_running; then
                break
            fi

            echo -n "."
            sleep 1
        done
        echo

        if is_running; then
            echo "Not stopped; may still be shutting down or shutdown may have failed"
            exit 1
        else
            echo "[STOPPED]"
            if [ -f "$pid_file" ]; then
                rm "$pid_file"
            fi
        fi
    else
        echo "Not running"
    fi
    ;;
    restart)
    $0 stop
    if is_running; then
        echo "Unable to stop, will not attempt to start"
        exit 1
    fi
    $0 start
    ;;
    status)
    if is_running; then
        echo "[RUNNING]"
    else
        echo "[STOPPED]"
        exit 1
    fi
    ;;
    *)
    echo "Usage: $0 {start|stop|restart|status}"
    exit 1
    ;;
esac

exit 0

【问题讨论】:

  • 设置 django 设置 DEBUG 为 True,然后重新加载,它应该会显示更多的错误细节
  • 好的,我试过了,我确实在页面上看到了有帮助的错误。但我正在寻找一个更通用的解决方案,这是一个生产环境,所以我不能真正离开 debug=True 。它似乎也无助于在 gunicorn 日志文件中显示错误。

标签: django bash nginx gunicorn django-errors


【解决方案1】:

在 Heroku 上使用 gunicorn 20.1 运行 Django 3.8,我遇到了应用程序错误未显示在 Papertrail 日志中的问题。

要解决这个问题,我只需将 Django 文档中的 minimal recommended logging configuration 添加到 settings.py:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'root': {
        'handlers': ['console'],
        'level': 'WARNING',
    },
}

这是必要的,因为在生产中的Django's default logging configuration 中(当DEBUGFalse 时)django 记录器将消息发送到AdminEmailHandler,而不是控制台。

我在 Procfile 中使用 web: gunicorn my_project.wsgi 启动 gunicorn,我不需要更改它(即我不需要使用 --capture-output--enable-stdio-inheritance)。

【讨论】:

    【解决方案2】:

    此配置对我有用。使用 gunicorn 命令添加 --capture-output --enable-stdio-inheritance,如下所示。

    /home/ubuntu/inside-env/bin/gunicorn --access-logfile /var/log/access_file_g.log --error-logfile /var/log/error_file_g.log --capture-output --enable-stdio-inheritance --workers 3 --bind unix:/home/ubuntu/path-to-project/webapp.sock project.wsgi:application
    

    使用此设置,请以这种方式启用日志记录

    import logging 
    logging.basicConfig(level='DEBUG')
    
    logging.info('hello world')
    

    这样您也可以看到应用程序中的错误。

    【讨论】:

    • 被低估的答案,这就是我一直在寻找的东西。谢谢!
    • 非常感谢,伙计。这对我来说很完美。
    【解决方案3】:

    简答:

    使用以下日志记录配置,即使 DEBUG 为 False,您的错误也会开始显示在 Gunicorn 输出(未后台处理)或运行服务器中。当 DEBUG 为 True 时,它​​们无论如何都应该出现。

    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)s] %(message)s',
        }
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
        },
        # Custom handler which we will use with logger 'django'.
        # We want errors/warnings to be logged when DEBUG=False
        'console_on_not_debug': {
            'level': 'WARNING',
            'filters': ['require_debug_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', 'console_on_not_debug'],
            'level': 'INFO',
        },
        'django.server': {
            'handlers': ['django.server'],
            'level': 'INFO',
            'propagate': False,
        },
    }
    }
    

    如果您想在 gunicorn 错误日志中查看 Django 错误,请使用 --capture-output 运行 gunicorn。

    http://docs.gunicorn.org/en/stable/settings.html#capture-output

    长答案

    记录时涉及到两个混淆:

    1. runserver 是否提供比gunicorn 更好的日志
    2. settings.DEBUG=True 是否提供比settings.DEBUG=False 更好的日志

    只要您有适当的日志配置,您在 runserver 中看到的任何日志记录也可以在 Gunicorn 中看到。

    只要您有适当的日志记录配置,您在 DEBUG=True 时看到的任何日志记录都可以在 DEBUG=False 时看到。

    您可以在以下位置查看默认的 Django 日志记录配置:

    https://github.com/django/django/blob/1.10.8/django/utils/log.py#L18

    看起来像:(我已经删除了与此答案无关的部分)

    DEFAULT_LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
        },
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django': {
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
        },
    }
    }
    

    这句话是:

    1. django logger 日志记录发送到处理程序consolemail_admins

    2. 处理程序console 上有一个过滤器require_debug_true。当 settings.DEBUG 为 True 时,处理程序 console 在 Stream 上发送/打印日志(因为 logging.StreamHandler)。

    当 settings.DEBUG 为 False 时,处理程序 console 会忽略 logger django 发送给它的日志消息。

    如果您也希望使用 DEBUG=False 打印日志,请添加 handler 并使记录器 django 使用它。

    处理程序看起来像:

        'console_on_not_debug': {
            'level': 'WARNING',
            'filters': ['require_debug_false'],
            'class': 'logging.StreamHandler',
        },
    

    将此处理程序与记录器django一起使用:

        'django': {
            'handlers': ['console', 'mail_admins', 'console_on_not_debug'],
            'level': 'INFO',
        },
    

    您可以在简短的回答中看到整个 sn-p。

    这样,无论您使用的是 runserver 还是 gunicorn,日志都将打印在流上。

    如果您希望日志显示在 gunicorn 错误日志中,则需要使用 --capture-output 运行 gunicorn。

    【讨论】:

      【解决方案4】:

      1。向控制台发送错误

      这些是默认使用mail_adminsloggers(参见django/utils/log.py):

          'django.request': {
              'handlers': ['mail_admins'],
              'level': 'ERROR',
              'propagate': False,
          },
          'django.security': {
              'handlers': ['mail_admins'],
              'level': 'ERROR',
              'propagate': False,
          },
      

      您需要更改处理程序以转到console,以便它出现在您的gunicorn 日志中,而不是使用mail_admins 发送电子邮件。请注意,它不像DEBUG=True那样健谈。

       'loggers': {
          'django': {
              'level': 'ERROR',
              'handlers': ['console'],
          },
       }
      

      2。通过mail_admins发送错误

      同样基于配置日志,显式创建一个调用mail_admins的处理程序;例如基于django/utils/log.py:

       'handlers': {
          'mail_admins': {
              'level': 'ERROR',
              'class': 'django.utils.log.AdminEmailHandler'
          },
       },
       'loggers': {
          'django': {
              'handlers': ['mail_admins'],
          },
       }
      

      这需要您设置电子邮件相关的settings

      3。其他解决方案

      如果您不是在寻找解决方案 #1,那么您的问题与以下内容重复: How do you log server errors on django sites

      【讨论】:

        【解决方案5】:

        最简单的解决方案是将变量 ADMINS 配置为应收到错误通知的人员的电子邮件地址。 当 DEBUG=False 并且视图引发异常时,Django 将通过电子邮件向这些人发送完整的异常信息。

        settings.py

        ADMINS = (('John', 'john@example.com'), ('Mary', 'mary@example.com'))
        # or only ADMINS = (('John', 'john@example.com'),)
        

        如果正确的 SMTP 服务器不是端口 25 上的 localhost,也许您还需要 EMAIL_HOST 和 EMAIL_PORT。这个简单的解决方案足以进行试产操作,否则会突然产生过多的电子邮件。

        【讨论】:

          【解决方案6】:

          根据您的评论,我认为这是您的 django 站点中的配置问题,而不是 gunicorn 日志的问题,日志不会显示超过 django 发送给它的内容。

          这是一个示例,说明如何配置 django 设置以将日志发送到您的文件(而不是默认通过电子邮件将其发送给管理员):

          LOGGING = {
              'version': 1,
              'disable_existing_loggers': True,
              'formatters': {
                  'verbose': {
                      'format': '%(asctime)s %(levelname)s [%(name)s:%(lineno)s] %(module)s %(process)d %(thread)d %(message)s'
                  }
              },
              'handlers': {
                  'gunicorn': {
                      'level': 'DEBUG',
                      'class': 'logging.handlers.RotatingFileHandler',
                      'formatter': 'verbose',
                      'filename': '/opt/djangoprojects/reports/bin/gunicorn.errors',
                      'maxBytes': 1024 * 1024 * 100,  # 100 mb
                  }
              },
              'loggers': {
                  'gunicorn.errors': {
                      'level': 'DEBUG',
                      'handlers': ['gunicorn'],
                      'propagate': True,
                  },
              }
          }
          

          阅读configuring logging(它对日志设置选项提供了很好的解释)并研究文件django/utils/log.py 以配置django loggin 以在gunicorn 日志上显示更详细。

          还要检查this answerthis,它们提供了将日志错误直接发送到文件的设置示例。并考虑使用Sentry 来处理日志错误,就像 django 人的recomended 一样。

          希望这会有所帮助。

          【讨论】:

          • 哦,所以你是说新版本的 Django 默认不记录错误?在运行内置 Django 服务器时,我一直在看到回溯,所以我假设通过 Gunicorn 运行时我会得到相同的输出。
          • 默认 ERROR 和 CRITICAL 级别通过电子邮件发送给管理员,我认为内置的 Django 开发服务器不使用此功能,因此它会在控制台中显示回溯
          猜你喜欢
          • 2015-12-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-09-25
          • 2012-06-02
          • 1970-01-01
          • 2020-10-15
          相关资源
          最近更新 更多