web-dev-qa-db-ja.com

GunicornでのDjangoエラーの詳細を確認する方法は?

Django(1.6)プロジェクトをgunicornとNginxでデプロイしました。

正常に動作しているようですが、HTTP 500エラーが発生していて、エラーの詳細をどこにも見つけることができなかったページが1つあります。

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
26
Greg

あなたのコメントから、これはあなたの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ロギンをgunicornログでより詳細に表示します。

また、 this answerthis も確認してください。ログエラーを送信するための設定例が提供されていますファイルに直接。また、 Sentry を使用してログエラーを処理することを検討してください recomended by Djangoみんな。

お役に立てれば。

16
juliocesar

1.コンソールにエラーを送信する

これらは、デフォルトでmail_adminsを使用するloggersです(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でメールを送信するのではなく、gunicornログに表示されるようにする必要があります。 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サイト)でサーバーエラーをログに記録する方法

7
dnozay

簡潔な答え:

以下のロギング構成では、DEBUGがFalseの場合でも、Gunicorn出力(非デーモン化)またはrunserverにエラーが表示され始めます。とにかく、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を指定してgunicornを実行します。

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

長い答え

ログを記録する際には、2つの混乱があります。

  1. runservergunicornよりも優れたログを提供するかどうか
  2. settings.DEBUG=Truesettings.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ロガーログレコードをハンドラーconsoleおよびmail_adminsに送信します。

  2. ハンドラーconsoleにはフィルターrequire_debug_trueがあります。 settings.DEBUGがTrueの場合、ハンドラconsoleはストリームにログを送信/印刷します(logging.StreamHandlerのため)。

Settings.DEBUGがFalseの場合、ハンドラconsoleは、ロガー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',
    },

スニペット全体を短い回答で見ることができます。

これにより、runserverまたはgunicornを使用しているかどうかに関係なく、ログがストリームに出力されます。

ログをgunicornエラーログに表示する場合は、-capture-outputを指定してgunicornを実行する必要があります。

4
Akshar Raaj

この構成でうまくいきました。追加 --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')

このようにして、アプリ内のエラーも確認できます。

2
SuperNova

最も簡単な解決策は、変数[〜#〜] admins [〜#〜]を設定することです。エラー通知を受け取る必要があります。 DEBUG = Falseでビューが例外を発生させると、Djangoはこれらのユーザーに完全な例外情報をメールで送信します。

settings.py

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

正しいSMTPサーバーがポート25localhostでない場合は、EMAIL_HostとEMAIL_PORTも必要になる可能性があります。この単純なソリューションは、試作運用には十分ですが、それ以外の場合、突然大量のメールを生成する可能性があります。

2
hynekcer