43

我刚刚使用 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

更多信息:

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

>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
4

6 回答 6

25

根据您的评论,我认为这是您的 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,
        },
    }
}

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

还要检查this answerthis提供设置示例以将日志错误直接发送到文件。并考虑使用Sentry来处理日志错误,这是django 人推荐的。

希望这可以帮助。

于 2014-02-24T16:17:21.570 回答
14

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

/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')

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

于 2018-08-07T09:13:35.340 回答
7

1.向控制台发送错误

这些是默认loggers使用的(请参阅 参考资料):mail_adminsdjango/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. 请注意,它不像 when 那样健谈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,那么您的问题与以下内容重复: 您如何在 django 站点上记录服务器错误

于 2014-02-26T08:31:33.940 回答
7

简短的回答:

通过以下日志配置,即使 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. djangologger 日志记录发送到处理程序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',
    },

并将此处理程序与 logger 一起使用django

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

您可以在简短的回答中看到整个片段。

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

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

于 2017-11-09T19:33:33.373 回答
2

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

设置.py

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

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

于 2014-02-25T07:43:25.683 回答
1

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

为了解决这个问题,我所要做的就是将Django 文档中推荐的最小日志配置添加到 settings.py:

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

这是必要的,因为在生产环境中Django 的默认日志配置(when DEBUGis False)中,django 记录器将消息发送到AdminEmailHandler,而不是控制台。

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

于 2021-10-29T10:14:42.333 回答