Подтвердить что ты не робот

Как увидеть подробности ошибок Django с Gunicorn?

Я только что развернул проект Django (1.6) с помощью пушки и Nginx.

Кажется, он работает нормально, но у меня есть одна страница, я получаю ошибку HTTP 500, и я не могу найти никаких подробностей об ошибке где-нибудь.

Как я могу получить оружие, чтобы показать мне ошибки?

Здесь все, что я вижу в файле журнала, когда я попал на страницу, давая мне ошибку:

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

Здесь мой bash script Я использую, чтобы начать стрельбу:

>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 script Я скопировал и изменил с помощью 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
4b9b3361

Ответ 1

Из вашего комментария я думаю, что это проблема с конфигурацией на вашем сайте django, а не в журнале ружейного оружия, журналы не будут отображаться больше, чем отправить 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 на более подробные сведения о журналах о стрельбе.

Также проверьте этот ответ и , в котором приведены примеры для отправки ошибок журналов непосредственно в файл. И рассмотрите возможность использования Sentry для обработки ошибок журнала, а также Рекомендовано ребятами из django.

Надеюсь, что это поможет.

Ответ 2

1. отправка ошибок на консоль

Это loggers, которые используют mail_admins по умолчанию (см. django/utils/log.py):

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

вам нужно будет изменить обработчики, чтобы перейти к console, чтобы он отображался в вашем журнале стрельбы, а не отправлял сообщения с помощью 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, то ваш вопрос является дубликатом: Как вы регистрируете ошибки сервера на сайтах django

Ответ 3

Самое простое решение - настроить переменную ADMINS с адресами электронной почты людей, которые должны получать уведомления об ошибках, Когда DEBUG = False и представление вызывает исключение, Django отправит эти люди с полной информацией об исключениях.

settings.py

ADMINS = (('John', '[email protected]'), ('Mary', '[email protected]'))
# or only ADMINS = (('John', '[email protected]'),)

Возможно, вам также нужны EMAIL_HOST и EMAIL_PORT, если правильный SMTP-сервер не является localhost на порту 25. Это простое решение достаточно хорошо для пробной производственной деятельности, в противном случае оно может привести к появлению слишком большого количества электронных писем.

Ответ 4

Краткий ответ:

При следующей конфигурации ведения журнала ваши ошибки начнут отображаться в выходном файле Gunicorn (undaemonized) или на сервере запуска, даже если DEBUG - False. Они всегда должны появляться, когда 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,
    },
}
}

Если вы хотите увидеть ошибки Django в журнале ошибок пушки, запустите gunicorn с -capture-output.

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

Длинный ответ

При регистрации: есть два путаницы:

  • Если runserver обеспечивает лучший журнал, чем gunicorn
  • Обеспечивает ли settings.DEBUG=True лучший журнал, чем settings.DEBUG=False

Любая запись журнала, которую вы видите с помощью сервера запуска, также видна с помощью 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',
    },
}
}

Что это говорит:

  • Отправьте django запись журнала регистрации в обработчики console и mail_admins.

  • Обработчик console имеет на нем фильтр require_debug_true. Когда settings.DEBUG имеет значение True, тогда обработчик console отправляет/распечатывает журнал в потоке (из-за logging.StreamHandler).

Когда settings.DEBUG является False, обработчик console игнорирует сообщение журнала, отправленное ему журналом django.

Если вы хотите, чтобы журналы были напечатаны с помощью DEBUG = False, добавьте handler и сделайте logger 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',
    },

Вы можете увидеть весь фрагмент в коротком ответе.

При этом журналы будут печататься в потоке, независимо от того, используете ли вы серверы или пушки.

Если вы хотите, чтобы журналы отображались в журнале ошибок стрельбы, вам нужно запустить gunicorn с -capture-output.