postgres - django gunicorn service
¿Cómo ver los detalles de los errores de Django con Gunicorn? (5)
1. Enviar errores a la consola.
Estos son los loggers
que usan mail_admins
por defecto (ver django/utils/log.py
):
''django.request'': {
''handlers'': [''mail_admins''],
''level'': ''ERROR'',
''propagate'': False,
},
''django.security'': {
''handlers'': [''mail_admins''],
''level'': ''ERROR'',
''propagate'': False,
},
necesitaría cambiar los controladores para ir a la console
para que aparezca en su registro de Gunicorn en lugar de enviar correos electrónicos con mail_admins
. Tenga en cuenta que no es tan hablador como cuando DEBUG=True
.
''loggers'': {
''django'': {
''level'': ''ERROR'',
''handlers'': [''console''],
},
}
2. enviando errores vía mail_admins
También basado en la configuración del registro, cree explícitamente un controlador que llame a mail_admins
; Por ejemplo, basado en django/utils/log.py
:
''handlers'': {
''mail_admins'': {
''level'': ''ERROR'',
''class'': ''django.utils.log.AdminEmailHandler''
},
},
''loggers'': {
''django'': {
''handlers'': [''mail_admins''],
},
}
Esto requiere que establezca la settings
relacionada con el correo electrónico.
3. otras soluciones
Si no estaba buscando la solución # 1, entonces su pregunta es un duplicado de: ¿Cómo se registran los errores del servidor en los sitios de django?
Acabo de implementar mi proyecto Django (1.6) con gunicorn y Nginx.
Parece que funciona bien, pero tengo una página en la que recibo un error HTTP 500 y no puedo encontrar ningún detalle sobre el error en ningún lado.
¿Cómo consigo gunicorn para mostrarme errores?
Aquí está todo lo que veo actualmente en el archivo de registro cuando llego a la página con el error:
>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/
Aquí está mi script de bash que utilizo para iniciar gunicorn:
>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
Más información:
Estoy iniciando / deteniendo gunicorn con esta secuencia de comandos init.d que copié y modifiqué utilizando 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
Respuesta corta:
Con la siguiente configuración de registro, sus errores comenzarán a aparecer en la salida de Gunicorn (sin demonios) o en el servidor de ejecución incluso cuando DEBUG es Falso. De todos modos, deberían aparecer cuando DEBUG es Verdadero.
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,
},
}
}
Si desea ver los errores de Django en el registro de errores de gunicorn, ejecute gunicorn con --capture-output.
http://docs.gunicorn.org/en/stable/settings.html#capture-output
Respuesta larga
Hay dos confusiones involucradas cuando se registra:
- Si
runserver
proporciona mejor registro quegunicorn
- ¿
settings.DEBUG=True
proporciona mejor registro quesettings.DEBUG=False
Cualquier registro de registro que vea con runserver puede verse también con Gunicorn siempre que tenga la configuración de registro adecuada.
Cualquier registro de registro que vea con DEBUG = Verdadero puede verse mientras DEBUG = Falso también, siempre y cuando tenga la configuración de registro apropiada.
Puede ver la configuración de registro de Django predeterminada en:
https://github.com/django/django/blob/1.10.8/django/utils/log.py#L18
Parece que: (He eliminado partes que no conciernen a esta respuesta)
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'',
},
}
}
Lo que esto dice es:
Envíe el registro de registro del registrador
django
a laconsole
manejadores y a losmail_admins
.La
console
controlador tiene un filtrorequire_debug_true
en él. Cuando settings.DEBUG es True, laconsole
controlador envía / imprime el registro en el Stream (debido alogging.StreamHandler
).
Cuando settings.DEBUG es False, entonces la console
controlador ignora el mensaje de registro que le envió el registrador django
.
Si desea que los registros se impriman con DEBUG = False, agregue un handler
y haga que el registrador django
use.
El manejador se vería así:
''console_on_not_debug'': {
''level'': ''WARNING'',
''filters'': [''require_debug_false''],
''class'': ''logging.StreamHandler'',
},
Y usa este manejador con logger django
:
''django'': {
''handlers'': [''console'', ''mail_admins'', ''console_on_not_debug''],
''level'': ''INFO'',
},
Puedes ver el fragmento completo en breve respuesta.
Con esto, los registros se imprimirán en secuencia independientemente de si está utilizando runserver o gunicorn.
Si desea que los registros se muestren en el registro de errores de gunicorn, entonces necesita ejecutar gunicorn con --capture-output.
Desde su comentario, creo que este es un problema de configuración en su sitio de django, no es una cuestión de registro de Gunicorn, los registros no mostrarán más que el envío de django.
Este es un ejemplo de cómo puede configurar la configuración de django para enviar el registro a su archivo (en lugar de enviarlo a los administradores por correo electrónico de manera predeterminada):
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,
},
}
}
Lea la configuración del registro (proporciona una muy buena explicación de las opciones de configuración de registro) y estudie el archivo django/utils/log.py para configurar el django/utils/log.py de django para que aparezca más detallado en los registros de gunicorn.
También verifique esta respuesta y this proporciona ejemplos de configuración para enviar errores de registros directamente a un archivo. Y considere usar Sentry para manejar los errores de registro, como lo recomended los chicos de Django.
Espero que esto ayude.
Esta configuración funcionó para mí. Agregue --capture-output --enable-stdio-inheritance
inheritance con el comando gunicorn como se muestra a continuación.
/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
Con esta configuración, habilite el registro de esta manera
import logging
logging.basicConfig(level=''DEBUG'')
logging.info(''hello world'')
De esta manera también podrás ver los errores en la aplicación.
La solución más sencilla es configurar la variable ADMINS con direcciones de correo electrónico de personas que deben recibir notificaciones de error. Cuando DEBUG = False y una vista genera una excepción, Django enviará un correo electrónico a estas personas con la información completa de la excepción.
settings.py
ADMINS = ((''John'', ''[email protected]''), (''Mary'', ''[email protected]''))
# or only ADMINS = ((''John'', ''[email protected]''),)
Quizás también necesite EMAIL_HOST y EMAIL_PORT si el servidor SMTP correcto no es localhost
en el puerto 25
. Esta solución simple es lo suficientemente buena para la operación de producción de prueba, de lo contrario puede producir de repente demasiados correos electrónicos.