J'essaie d'enregistrer les messages du journal d'application à partir d'une application flask très simple dans un fichier journal. Bien que cela fonctionne parfaitement lorsque j'exécute l'application avec le serveur Flask intégré, cela ne fonctionne pas du tout lors de l'exécution dans gUnicorn, fondamentalement, aucune sortie d'application n'est redirigée ni le fichier journal (celui spécifié dans mon Flask) ou sur STDOUT lors de l'exécution de gunicorn.
Cela dit, voici mon application 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)
Maintenant, si je démarre l'application en tant que:
python app.py
J'obtiens la sortie attendue:
* 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 -
Tailing test.log, je vois:
2015-03-11 09:36:18,375 DEBUG: Into /!!!! [in app.py:23]
Tout va bien jusqu'à présent, puis lorsque j'essaie d'exécuter l'application avec nginx + gunicorn, j'ai d'abord essayé d'exécuter gunicorn comme ceci:
gunicorn app:app -b localhost:8000 --debug --log-level debug
L'application fonctionne, si je vais sur http: // localhost :
curl http://localhost
Flask is running!
Mais en regardant le fichier journal, il est vide, rien n'est écrit. J'ai ajouté 777 autorisations juste pour vérifier s'il s'agissait d'un problème d'autorisation en vain. Ensuite, en regardant la sortie standard de la licorne, rien n'est écrit à part la déclaration imprimée:
2015-03-11 09:42:06 [25641] [DEBUG] GET /
Will this print?
En regardant autour , j'ai essayé de rediriger toutes les sorties vers les journaux de gunicorn, puis de démarrer gunicorn comme ceci:
gunicorn app:app -b localhost:8000 --debug --log-file /tmp/test.log --log-level debug --error-logfile /tmp/error.log
Mais maintenant, je ne reçois même plus d'instructions d'impression dans les fichiers gunicorn, c'est la sortie à la fois de test.log et error.log (ils sont identiques):
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 /
Il y a une question très similaire ici , l'une des réponses semble suggérer qu'aucun enregistreur d'application n'est disponible lors de l'exécution dans gunicorn ??? Cela semble, au moins, assez étrange ... comment suis-je censé me connecter alors?
Un autre solution proposée semble suggérer de ne pas utiliser l'enregistreur Flask, mais n'est pas lié à gunicorn (je pense) ...
Qu'est-ce qui me manque? Dois-je abandonner le gunicorn et opter pour Apache-mod wsgi? Nginx-uWSGI? FastCGI? Des idées?
Merci! Alejandro
MODIFIER:
J'ai essayé cette même configuration avec uWGSI au lieu de gunicorn et le même comportement, aucune journalisation d'application n'est obtenue.
Maintenant basé sur cette réponse et ceci autre , je suis venu avec ceci (sur gUnicorn et uWSGI, dans les deux cela fonctionne)
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()
Sortie de 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]
Et en regardant mon fichier test.log:
2015-03-11 12:26:20,765 INFO: info log [in /home/mosquito/www/flask-project/flask-project/app.py:24]
Alors oui, cela fonctionne un peu, mais la question d'origine reste toujours ... pourquoi diable l'enregistreur Flask ne semble pas fonctionner lors de l'exécution à l'intérieur des conteneurs wsgi - gunicorn, uWSGI?
Flask utilise Werkzeug pour WSGI. Les "journaux de flasques" que vous voyez proviennent en fait du serveur développement intégré de Werkzeug et non de Flask lui-même).
Lorsque vous remplacez ce serveur de développement par quelque chose comme Gunicorn ou uWSGI, vous ne voyez pas ses journaux.
Il en va de même pour le débogueur. Vous pouvez voir la "page de débogage de Flask" familière même si vous n'utilisez que Débogueur de Werkzeug .
Maintenant tu sais. :)
Vous avez répondu vous-même à votre question ici. Bien que j'ajouterai ma réponse dans l'espoir que cela aiderait quelqu'un d'autre à avoir un problème similaire.
Puisque votre question comporte 2 parties, dont la première partie est résolue, je vais marquer ma réponse pour chaque partie:
PARTIE 1: Aucune journalisation ne se produit si au lieu d'exécuter directement l'application via python, vous l'exécutez sous gunicorn En effet, lors de l'exécution directe, le nom == 'principal' est True, et votre code a initialisé à la fois un FileHandler et un StreamHandler, et la journalisation a fonctionné. Mais lors de l'exécution via gunicorn, nom == 'principal' échouerait, car nom contiendrait alors le nom de votre module. Cela signifie qu'aucun gestionnaire effectif ne sera initialisé. Et donc aucune journalisation n'est vue.
PARTIE 2: Pourquoi l'enregistreur Flask ne fonctionne pas par défaut sous gunicorn/uWSGI Les dernières versions flask initialisent app.logger à partir de zéro et y attachent quelques gestionnaires comme DebugHandler, StreamHandler par défaut selon si app.debug == True. L'enregistreur ne suffit toujours pas et ne se connectera qu'à STDERR. Il y a eu plusieurs changements dans gunicorn au cours des dernières versions. La version 19.4.1 ne capture pas STDOUT et STDERR au gunicorn error.log. Mais il met à disposition des enregistreurs avec les noms 'gunicorn', 'gunicorn.access' et 'gunicorn.error'. Le dernier a un FileHandler écrit dans le error.log configuré. Dans le cas où vous voulez les journaux de votre application flask pour accéder à error.log, utilisez l'une des approches suivantes: Approche 1:
#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
Approche2:
# 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')
Je recommanderai l'approche 2, car vous pouvez conserver les gestionnaires que vous souhaitez en plus de gunicorn.error. En outre, vous pouvez choisir de ne pas ajouter de gestionnaires gunicorn.error en fonction d'une condition.
merci
Avec gunicorn 19.6, --capture-output --enable-stdio-inheritance
semble fonctionner.
La réponse d'Auguiwan explique la question d'Origine, mais n'a pas expliqué comment la résoudre. La réponse de @ indrajeet est assez complète et fournit une sorte de solution. Cependant, ils ne résolvent pas mon problème connexe.
Ma réponse essaie principalement d'aider les gens qui arrivent ici en cherchant des mots clés similaires "flask gunicorn log" comme moi. Je trouve que ce lien est très utile parmi les résultats de recherche connexes https://medium.com/@yoanis_gil/logging-with-docker-part-1-1-965cb5e17165
La partie Configuration 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
m'aide vraiment. La configuration principale est --log-level
et --log-file
partie.
Si vous utilisez supervisored
avec gunicorn.conf
comme moi, il suffit de changer la relation gunicorn.conf
fichier.
Quelqu'un peut rechercher: comment voir les erreurs avec Python
pile d'erreur lors de l'utilisation de Flask
avec Gunicorn
.
Installez simplement le drapeau --error-logfile
vers le chemin du fichier où vous souhaitez voir les piles d'erreurs. En particulier (lors de l'utilisation dans Docker
), vous pouvez le configurer dans GUNICORN_CMD_ARGS
variable d'environnement à la valeur suivante (un exemple):
--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