web-dev-qa-db-ja.com

Flask gunicorn内で実行するとアプリロガーが機能しない

非常に単純なflaskアプリからのアプリケーションログメッセージをログファイルに保存しようとしています。 Flaskサーバーを組み込んでアプリを実行している場合、これは問題なく動作しますが、gUnicorn内で実行している場合はまったく機能しません。基本的に、アプリケーション出力はログファイル(Flaskアプリ)またはgunicornを実行しているときはSTDOUTに。

つまり、これは私のFlaskアプリです。

@app.route('/')
def index():
    app.logger.debug('Into /!!!!')
    print 'Will this print?'
    return 'Flask is running!'


if __name__ == '__main__':
    #Setup the logger
    file_handler = FileHandler('test.log')
    handler = logging.StreamHandler()
    file_handler.setLevel(logging.DEBUG)
    handler.setLevel(logging.DEBUG)
    file_handler.setFormatter(Formatter(
    '%(asctime)s %(levelname)s: %(message)s '
    '[in %(pathname)s:%(lineno)d]'))
    handler.setFormatter(Formatter(
    '%(asctime)s %(levelname)s: %(message)s '
    '[in %(pathname)s:%(lineno)d]'))
    app.logger.addHandler(handler)
    app.logger.addHandler(file_handler)
    app.run(debug=True)

今私がアプリを起動すると:

python app.py

期待される出力が得られます。

 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat

--------------------------------------------------------------------------------
DEBUG in app [app.py:23]:
Into /!!!!
--------------------------------------------------------------------------------
2015-03-11 09:36:18,375 DEBUG: Into /!!!! [in app.py:23]
Will this print?
127.0.0.1 - - [11/Mar/2015 09:36:18] "GET / HTTP/1.1" 200 -

Test.logを追跡すると、次のようになります。

2015-03-11 09:36:18,375 DEBUG: Into /!!!! [in app.py:23]

これまでのところすべてが素晴らしいようですが、nginx + gunicornでアプリを実行しようとすると、最初に次のようにgunicornを実行しようとしました。

gunicorn app:app -b localhost:8000 --debug --log-level debug

http:// localhost にアクセスすると、アプリは機能しています:

curl http://localhost
Flask is running!

しかし、ログファイルを見ると、空で、何も書き込まれていません。 777の権限を追加したのは、それが権限の問題であるかどうかを確認するためだけであり、役に立たない。次に、gunicorn stdoutを見ると、printステートメント以外に何も書かれていません。

2015-03-11 09:42:06 [25641] [DEBUG] GET /
Will this print?

見回す 、私はすべての出力をgunicornログにリダイレクトし、次のようにgunicornを開始しようとしました:

gunicorn app:app -b localhost:8000 --debug --log-file /tmp/test.log --log-level debug --error-logfile /tmp/error.log

しかし今、私はgunicornファイルで印刷ステートメントも取得していません。これはtest.logとerror.logの両方からの出力です(これらは同じです)。

2015-03-11 09:46:17 [26257] [DEBUG]   tmp_upload_dir: None
2015-03-11 09:46:17 [26257] [DEBUG]   keyfile: None
2015-03-11 09:46:17 [26257] [DEBUG]   backlog: 2048
2015-03-11 09:46:17 [26257] [DEBUG]   logger_class: simple
2015-03-11 09:46:17 [26257] [INFO] Starting gunicorn 17.5
2015-03-11 09:46:17 [26257] [DEBUG] Arbiter booted
2015-03-11 09:46:17 [26257] [INFO] Listening at: http://127.0.0.1:8000 (26257)
2015-03-11 09:46:17 [26257] [INFO] Using worker: sync
2015-03-11 09:46:17 [26262] [INFO] Booting worker with pid: 26262
2015-03-11 09:48:15 [26262] [DEBUG] GET /

非常によく似た質問 here があります。回答の1つは、gunicorn内で実行しているときにアプリケーションロガーが使用できないことを示唆しているようです。これは少なくとも、かなり奇妙に聞こえます...その場合、どうやってログに記録するのですか?

別の 提案された解決策 はFlaskロガーを使用しないことを提案しているようですが、gunicornとは関係ありません(私は思う)...

何が欠けていますか?私はgunicornをあきらめてApache-mod wsgiに行くべきですか? Nginx-uWSGI? FastCGI?何か案は?

ありがとう!アレハンドロ

編集:

私は、gunicornの代わりにuWGSIを使用して同じ動作を試し、同じ動作を試しましたが、アプリケーションログはまったく取得されません。

this response とthis other one に基づいて、これを思いつきました(gUnicornとuWSGIの両方で機能します)

from flask import Flask
import logging
from logging import Formatter, FileHandler

app = Flask(__name__)

LOGGER = logging.getLogger('whatever')
file_handler = FileHandler('test.log')
handler = logging.StreamHandler()
file_handler.setFormatter(Formatter(
    '%(asctime)s %(levelname)s: %(message)s '
    '[in %(pathname)s:%(lineno)d]'
))
handler.setFormatter(Formatter(
    '%(asctime)s %(levelname)s: %(message)s '
    '[in %(pathname)s:%(lineno)d]'
))
LOGGER.addHandler(file_handler)
LOGGER.addHandler(handler)
LOGGER.setLevel(logging.INFO)

@app.route('/')
def hello():
    LOGGER.info('info log')
    LOGGER.debug('debug log')
    return 'Hello!'

if __name__ == '__main__':
    app.run()

Gunicornからの出力:

2015-03-11 12:25:01 [11540] [INFO] Starting gunicorn 17.5
2015-03-11 12:25:01 [11540] [INFO] Listening at: http://127.0.0.1:8000 (11540)
2015-03-11 12:25:01 [11540] [INFO] Using worker: sync
2015-03-11 12:25:01 [11545] [INFO] Booting worker with pid: 11545
2015-03-11 12:26:20,765 INFO: info log [in /home/mosquito/www/flask-project/flask-project/app.py:24]

そして私のtest.logファイルを見てください:

2015-03-11 12:26:20,765 INFO: info log [in /home/mosquito/www/flask-project/flask-project/app.py:24]

ええ、それはちょっとうまくいきますが、元の質問はまだ残っています... wsgiコンテナー内で実行しているときにFlaskロガーが動作しないのはなぜですか-gunicorn、uWSGI?

20
AlejandroVK

FlaskはWSGIに Werkzeug を使用します。表示される「Flaskログ」は、実際には Werkzeugの組み込み開発 サーバーからのものであり、Flask自体からのものではありません。

その開発サーバーをGunicornやuWSGIなどに置き換えると、ログが表示されません。

デバッガについても同様です。 Werkzeug's Debugger のみを使用しても、おなじみの「Flaskデバッグページ」を表示できます。

今あなたは知っています。 :)

9
Augiwan

ここで自分で質問に答えました。他の誰かが同様の問題を抱えているのを助けることを期待して私の答えを追加しますが。

あなたの質問には2つの部分があり、最初の部分が解決されているので、各部分に対する私の回答にマークを付けます。

パート1:アプリをPython経由で直接実行する代わりに、gunicornの下で実行した場合、ロギングは発生しません。これは、直接実行するとname == 'main'が原因でしたTrueであり、コードはFileHandlerとStreamHandlerの両方を初期化し、ロギングは機能しました。しかし、gunicornを実行すると、-nameにモジュールの名前が含まれるため、-name == 'main'は失敗します。つまり、有効ハンドラーは初期化されません。したがって、ロギングは見られません。

パート2:なぜFlaskロガーはデフォルトでgunicorn/uWSGIの下で動作しません)最新のflaskバージョンはapp.loggerを最初から初期化し、以下のようないくつかのハンドラーをアタッチしますDebugHandler、デフォルトではStreamHandlerは、app.debug == Trueかどうかによって異なります。それでも、ロガーは十分ではなく、STDERRにのみログを記録します。最近のいくつかのバージョンでは、gunicornに複数の変更が加えられています。バージョン19.4.1では、STDOUTとSTDERRをgunicorn error.logに送信します。ただし、「gunicorn」、「gunicorn.access」、「gunicorn.error」という名前のロガーを利用できます。最後のログには、設定されたerror.logに書き込むFileHandlerがあります。 flaskアプリからのログをerror.logに移動するには、次のいずれかの方法を使用します。

#only use gunicorn.error logger for all logging
LOGGER = logging.getLogger('gunicorn.error')
LOGGER.info('my info')
LOGGER.debug('debug message')
# this would write the log messages to error.log

アプローチ2:

# Only use the FileHandler from gunicorn.error logger
gunicorn_error_handlers = logging.getLogger('gunicorn.error').handlers
app.logger.handlers.extend(gunicorn_error_handlers )
app.logger.addHandler(myhandler1)
app.logger.addHandler(myhandler2)
app.logger.info('my info')
app.logger.debug('debug message')

Gunicorn.errorに加えて任意のハンドラーを保持できるため、アプローチ2をお勧めします。また、条件に基づいてgunicorn.errorハンドラーを追加しないように選択することもできます。

ありがとう

22
indrajeet

Gunicorn 19.6の場合、--capture-output --enable-stdio-inheritanceは動作するようです。

5
Mssl

@Auguiwanの回答はOriginの質問を説明していますが、それを解決する方法については触れていません。@ indrajeetの回答は非常に包括的であり、一種のソリューションを提供します。しかし、それらは私の関連する問題を解決しません。

私の答えは主に、私と同じような「フラスコガンニコーンログ」という類似のキーワードを検索することで、ここにたどり着く人々を助けようとするものです。このリンクは、関連する検索結果の中で非常に役立ちます https://medium.com/@yoanis_gil/logging-with-docker-part-1-1-965cb5e17165

パーツGunicorn構成

exec gunicorn ${WSGI_MODULE}:${WSGI_APP} \
  --name $NAME \
  --workers $NUM_WORKERS \
  --user=$USER --group=$GROUP \
  --bind=unix:$SOCKFILE \
  --log-level=info \
  --log-file=/dev/stdout

本当に助けてくれます。コア構成は--log-level--log-fileの部分です。
_supervisoredgunicorn.confと一緒に使用している場合は、関連するgunicorn.confファイルを変更してください。

1
Shihe Zhang

誰かが検索できます:PythonFlaskで使用するときにGunicornエラースタックでエラーを表示する方法

フラグ--error-logfileを、エラースタックを表示するファイルパスに設定するだけです。特に(Dockerで使用する場合)GUNICORN_CMD_ARGS環境変数で次の値に設定できます(例):

--bind=0.0.0.0:8000 --access-logfile=/logs/rest.app/access.log --error-logfile=/logs/rest.app/error.log --capture-output --enable-stdio-inheritance

0
sergzach