アプリケーションエラー—フラスコのドキュメント

提供:Dev Guides
< FlaskFlask/docs/1.0.x/errorhandling
移動先:案内検索

アプリケーションエラー

バージョン0.3の新機能。


アプリケーションは失敗し、サーバーは失敗します。 遅かれ早かれ、本番環境で例外が発生します。 コードが100 % c正しい場合でも、例外が発生することがあります。 どうして? 関係する他のすべてが失敗するからです。 完全に細かいコードがサーバーエラーにつながる可能性があるいくつかの状況を次に示します。

  • クライアントはリクエストを早期に終了しましたが、アプリケーションはまだ受信データから読み取っていました
  • データベースサーバーが過負荷になり、クエリを処理できませんでした
  • ファイルシステムがいっぱいです
  • ハードドライブがクラッシュしました
  • バックエンドサーバーが過負荷
  • 使用しているライブラリのプログラミングエラー
  • サーバーの別のシステムへのネットワーク接続に失敗しました

そして、それはあなたが直面する可能性のある問題のほんの一例です。 では、そのような問題にどのように対処するのでしょうか。 デフォルトでは、アプリケーションが本番モードで実行されている場合、Flaskは非常に単純なページを表示し、例外をloggerに記録します。

しかし、できることは他にもあります。エラーに対処するためのより良いセットアップについて説明します。

エラーログツール

エラーメールの送信は、たとえ重要なものであっても、十分な数のユーザーがエラーに遭遇し、通常はログファイルが表示されない場合、圧倒される可能性があります。 このため、アプリケーションエラーの処理には Sentry の使用をお勧めします。 GitHub でオープンソースプロジェクトとして利用でき、無料で試すことができるホストバージョンとしても利用できます。 Sentryは重複エラーを集約し、デバッグ用に完全なスタックトレースとローカル変数をキャプチャし、新しいエラーまたは頻度のしきい値に基づいてメールを送信します。

Sentryを使用するには、 raven クライアントを追加の flask 依存関係とともにインストールする必要があります。

$ pip install raven[flask]

そして、これをFlaskアプリに追加します。

from raven.contrib.flask import Sentry
sentry = Sentry(app, dsn='YOUR_DSN_HERE')

または、ファクトリを使用している場合は、後で初期化することもできます。

from raven.contrib.flask import Sentry
sentry = Sentry(dsn='YOUR_DSN_HERE')

def create_app():
    app = Flask(__name__)
    sentry.init_app(app)
    ...
    return app

YOUR_DSN_HERE 値は、Sentryインストールから取得したDSN値に置き換える必要があります。

その後、障害は自動的にSentryに報告され、そこからエラー通知を受け取ることができます。


エラーハンドラ

エラーが発生したときに、カスタムエラーページをユーザーに表示したい場合があります。 これは、エラーハンドラーを登録することで実行できます。

エラーハンドラーは、応答を返す通常のビュー関数ですが、ルートに登録される代わりに、要求の処理中に発生する例外またはHTTPステータスコードに登録されます。

登録

関数をerrorhandler()で装飾して、ハンドラーを登録します。 または、register_error_handler()を使用して後で関数を登録します。 応答を返すときは、エラーコードを設定することを忘れないでください。

@app.errorhandler(werkzeug.exceptions.BadRequest)
def handle_bad_request(e):
    return 'bad request!', 400

# or, without the decorator
app.register_error_handler(400, handle_bad_request)

werkzeug.exceptions.HTTPException BadRequestのようなサブクラスとそれらのHTTPコードは、ハンドラーを登録するときに交換可能です。 (BadRequest.code == 400

非標準のHTTPコードは、Werkzeugに認識されていないため、コードで登録できません。 代わりに、適切なコードを使用してHTTPExceptionのサブクラスを定義し、その例外クラスを登録して発生させます。

class InsufficientStorage(werkzeug.exceptions.HTTPException):
    code = 507
    description = 'Not enough storage space.'

app.register_error_handler(InsuffcientStorage, handle_507)

raise InsufficientStorage()

ハンドラーは、HTTPExceptionサブクラスやHTTPステータスコードだけでなく、任意の例外クラスに登録できます。 ハンドラーは、特定のクラス、または親クラスのすべてのサブクラスに登録できます。


取り扱い

リクエストの処理中にFlaskによって例外がキャッチされると、最初にコードによって検索されます。 コードにハンドラーが登録されていない場合は、クラス階層によって検索されます。 最も具体的なハンドラーが選択されます。 ハンドラーが登録されていない場合、HTTPExceptionサブクラスはコードに関する一般的なメッセージを表示しますが、他の例外は一般的な500内部サーバーエラーに変換されます。

たとえば、ConnectionRefusedErrorのインスタンスが発生し、ハンドラーがConnectionErrorおよびConnectionRefusedErrorに登録されている場合、より具体的なConnectionRefusedErrorハンドラーが応答を生成するための例外インスタンス。

ブループリントが例外を発生させる要求を処理していると仮定すると、ブループリントに登録されているハンドラーは、アプリケーションにグローバルに登録されているハンドラーよりも優先されます。 ただし、ブループリントを決定する前に404がルーティングレベルで発生するため、ブループリントは404ルーティングエラーを処理できません。

バージョン0.11で変更:ハンドラーは、登録されている順序ではなく、登録されている例外クラスの特異性によって優先されます。


ロギング

管理者に電子メールで送信するなど、例外をログに記録する方法については、ロギングを参照してください。


アプリケーションエラーのデバッグ

本番アプリケーションの場合は、アプリケーションエラーの説明に従って、ログと通知を使用してアプリケーションを構成します。 このセクションでは、デプロイメント構成をデバッグし、フル機能のPythonデバッガーを使用してさらに深く掘り下げる際の指針を示します。

疑わしい場合は、手動で実行する

アプリケーションを本番用に構成する際に問題が発生しましたか? ホストへのシェルアクセスがある場合は、デプロイメント環境のシェルからアプリケーションを手動で実行できることを確認してください。 権限の問題をトラブルシューティングするために、構成されたデプロイメントと同じユーザーアカウントで実行するようにしてください。 本番ホストで debug = True を指定してFlaskの組み込み開発サーバーを使用できます。これは、構成の問題を検出するのに役立ちますが、制御された環境で一時的にこれを実行してください。しないでください debug = True を使用して本番環境で実行します。


デバッガーの操作

より深く掘り下げるために、おそらくコード実行をトレースするために、Flaskは箱から出してすぐにデバッガーを提供します(デバッグモードを参照)。 別のPythonデバッガーを使用する場合は、デバッガーが相互に干渉することに注意してください。 お気に入りのデバッガーを使用するには、いくつかのオプションを設定する必要があります。

  • debug-デバッグモードを有効にして例外をキャッチするかどうか
  • use_debugger-内部Flaskデバッガーを使用するかどうか
  • use_reloader-例外時にプロセスをリロードしてフォークするかどうか

debugは、他の2つのオプションに任意の値を設定するために、Trueである必要があります(つまり、例外をキャッチする必要があります)。

デバッグにAptana / Eclipseを使用している場合は、use_debuggeruse_reloaderの両方をFalseに設定する必要があります。

構成に役立つ可能性のあるパターンは、config.yamlで次のように設定することです(もちろん、アプリケーションに応じてブロックを変更してください)。

FLASK:
    DEBUG: True
    DEBUG_WITH_APTANA: True

次に、アプリケーションのエントリポイント(main.py)に、次のようなものを含めることができます。

if __name__ == "__main__":
    # To allow aptana to receive errors, set use_debugger=False
    app = create_app(config="config.yaml")

    if app.debug: use_debugger = True
    try:
        # Disable Flask's debugger if external debugger is requested
        use_debugger = not(app.config.get('DEBUG_WITH_APTANA'))
    except:
        pass
    app.run(use_debugger=use_debugger, debug=app.debug,
            use_reloader=use_debugger, host='0.0.0.0')