web-dev-qa-db-fra.com

Pourquoi l'application Flask ne crée-t-elle aucun journal lorsqu'elle est hébergée par Gunicorn?

J'essaie d'ajouter la journalisation à une application Web qui utilise Flask.

Lorsqu'il est hébergé à l'aide du serveur intégré (c'est-à-dire python3 server.py), la journalisation fonctionne. Lorsqu'il est hébergé à l'aide de Gunicorn, le fichier journal n'est pas créé.

Le code le plus simple qui reproduit le problème est celui-ci:

#!/usr/bin/env python

import logging
from flask import Flask
flaskApp = Flask(__name__)


@flaskApp.route('/')
def index():
    flaskApp.logger.info('Log message')
    print('Direct output')
    return 'Hello World\n'


if __== "__main__":
    logHandler = logging.FileHandler('/var/log/demo/app.log')
    logHandler.setLevel(logging.INFO)
    flaskApp.logger.addHandler(logHandler)
    flaskApp.logger.setLevel(logging.INFO)
    flaskApp.run()

L'application est appelée à l'aide de:

gunicorn server:flaskApp -b :80 -w 4
    --access-gfile /var/log/demo/access.log
    --error-logfile /var/log/demo/error.log

Lorsque vous effectuez une demande sur la page d'accueil du site, les événements suivants se produisent:

  1. Je reçois le HTTP 200 "Hello World\n" attendu en réponse.

  2. Il y a une trace de la demande dans /var/log/demo/access.log.

  3. /var/log/demo/error.log reste le même (il n'y a que les événements de démarrage).

  4. Il y a la ligne "Sortie directe" dans le terminal.

  5. Il n'y a pas de '/var/log/demo/app.log'. Si je crée le fichier avant de lancer l'application, le fichier n'est pas modifié.

Notez que:

  • Le répertoire /var/log/demo est accessible à tous (lecture, écriture, exécution), ce n'est donc pas le problème des autorisations.

  • Si j'ajoute StreamHandler comme deuxième gestionnaire, il n'y a toujours aucune trace du message "Log message" ni dans le terminal, ni dans les fichiers journaux de Gunicorn.

  • Gunicorn est installé à l'aide de pip3 install gunicorn, donc il ne devrait pas y avoir de discordance avec les versions Python.

Que ce passe-t-il?

37
Arseni Mourzenko

Lorsque vous utilisez python3 server.py, Vous exécutez le script server3.py.

Lorsque vous utilisez gunicorn server:flaskApp ..., Vous exécutez le script de démarrage de gunicorn qui importe le module server et recherche la variable flaskApp dans ce module.

Étant donné que server.py Est importé, la variable __name__ Contiendra "server", Pas "__main__" Et par conséquent, le code d'installation du gestionnaire de journaux n'est pas exécuté.

Vous pouvez simplement déplacer le code de configuration du gestionnaire de journaux en dehors de la strophe if __== "__main__":. Mais assurez-vous que vous gardez flaskApp.run() dedans puisque vous voulez pas vouloir que cela soit exécuté lorsque gunicorn importe server.

En savoir plus sur que fait if __== “__main__”:?

32
Jeremy Allen

Cette approche fonctionne pour moi: importez le module de journalisation Python et ajoutez-y des gestionnaires d'erreur de gunicorn. Ensuite, votre enregistreur se connectera au fichier journal des erreurs de gunicorn:

import logging

app = Flask(__name__)

gunicorn_error_logger = logging.getLogger('gunicorn.error')
app.logger.handlers.extend(gunicorn_error_logger.handlers)
app.logger.setLevel(logging.DEBUG)
app.logger.debug('this will show in the log')

Mon script de démarrage Gunicorn est configuré pour générer des entrées de journal dans un fichier comme ceci:

gunicorn main:app \
    --workers 4 \
    --bind 0.0.0.0:9000 \
    --log-file /app/logs/gunicorn.log \
    --log-level DEBUG \
    --reload
24
pkout