web-dev-qa-db-fra.com

Pourquoi Flask logger ne se connecte pas à docker lors de l'utilisation d'UWSGI en face?

J'ai une application Flask à l'intérieur de Docker qui se connectait à docker logs Lorsqu'elle s'exécutait sans UWSGI devant. Maintenant, j'ai utilisé UWSGI avec la configuration ci-dessous pour exécuter mon application à l'intérieur de Docker:

[uwsgi]

master = true

processes = 5
threads = 2

socket = 127.0.0.1:3031
chmod-socket = 664
stats=0.0.0.0:30310

chdir = /etc/fantas

uid = root
gid = root

wsgi-file=uwsgi_fantas.py
callable=app

vacuum = true

Le fichier uwsgi_fantas.py Contient:

from fantas.fantas_app import FantasApp

app = FantasApp().setup()

La méthode setup renvoie app:

from flask_restful import Api
from fantas import app

class FantasApp(object):
    def setup(self):
        api = Api(app)
        api.add_resource(Token, '/users')

        return app

Enfin la partie qui initie le framework Flask est à l'intérieur de __init__.py Dans le répertoire racine du projet:

from flask import Flask
import logging

app = Flask(__name__)

s_handler = logging.StreamHandler()
s_handler.setLevel(logging.DEBUG)
app.logger.addHandler(s_handler)

Comme UWSGI fonctionne directement avec l'objet app, j'ai configuré l'enregistreur à l'intérieur de __init__.py, Mais le problème est qu'il ne se connecte à rien dans Docker quand il est exécuté, il enregistre simplement les requêtes UWSGI.

Qu'est-ce qui ne va pas dans le processus de configuration de app.logger?

Le problème a été résolu, mais maintenant les journaux sont dupliqués!


EDIT-1: J'ai défini app.logger.setLevel(logging.DEBUG) et il semble que Flask se connecte avec succès à Docker. La partie bizarre est qu'il se connecte 3 fois! J'ai supprimé toutes les configurations et les gestionnaires d'enregistreurs et j'ai simplement utilisé:

app.logger.setLevel(logging.DEBUG)

Mais maintenant, il se connecte 2 fois:

proj_fantas.1.huagnqqpzo1n@linuxkit-025000000001    | [2018-07-13 07:02:38,008] DEBUG in token: [Token] authenticating user...
proj_fantas.1.huagnqqpzo1n@linuxkit-025000000001    | DEBUG:flask.app:[Token] authenticating user...

Pourquoi c'est comme ça?


EDIT-2:

La sortie de app.logger.handlers Est [<logging.StreamHandler object at 0x7f0f430ca8d0>]. Cela montre simplement le StreamHandler que j'ai initialisé plus tôt, rien de plus.


EDIT-3:

La sortie de la commande ps -ef À l'intérieur de Docker:

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 15:26 ?        00:00:00 uwsgi uwsgi_coconuty.ini
root        10     1  0 15:26 ?        00:00:00 uwsgi uwsgi_coconuty.ini
root        12     1  0 15:26 ?        00:00:00 uwsgi uwsgi_coconuty.ini
root        13     1  0 15:26 ?        00:00:00 uwsgi uwsgi_coconuty.ini
root        15     1  0 15:26 ?        00:00:00 uwsgi uwsgi_coconuty.ini
root        16     1  0 15:26 ?        00:00:00 uwsgi uwsgi_coconuty.ini
root        20     0  0 15:27 pts/0    00:00:00 /bin/bash
root       112    20  0 15:28 pts/0    00:00:00 ps -ef

Aucun autre processus n'est en cours d'exécution à l'intérieur de Docker.

12
ALH

Tout d'abord, il y a eu des changements récents dans la façon dont Flask sont initialisés de la version 0.9 à la version stable 1.0.2, par exemple. Vous pouvez vérifier cela ici Je suppose que votre image Docker utilise la version la plus récente.

Si tel est le cas, même sans configuration de journalisation personnalisée, il s'agit en fait de la journalisation de votre flux de sortie, mais il est filtré plus bas que les journaux WARNING (DEBUG et INFO). Cela se produit lorsque vous comptez sur Flask initialisant le journal pour vous et que vous ne définissez pas d'indicateur --debug (cas uwsgi).

Il existe plusieurs stratégies qui peuvent être examinées lorsque vous configurez la journalisation. Une suggestion est d'utiliser l'initialisation dictConfig mentionnée par la bibliothèque elle-même , au niveau du maître uwsgi, avant de définir l'application, qui bifurque ensuite. En suivant votre exemple, à __init__.py:

from flask import Flask
from logging.config import dictConfig

dictConfig({
    'version': 1,
    'formatters': {'default': {
        'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
    }},
    'handlers': {'wsgi': {
        'class': 'logging.StreamHandler',
        'formatter': 'default'
    }},
    'root': {
        'level': 'DEBUG',
        'handlers': ['wsgi']
    }
})

app = Flask(__name__)

Le problème que vous mentionnez dans EDIT-1 ressemble à un python problème de propagation de la journalisation . Il existe un cas autonome, plus facile à déboguer, ici .

Même si vous n'avez défini qu'un seul gestionnaire de flux, comme le montre votre journal, il a probablement un parent attaché. Si vous vérifiez son parent, un gestionnaire sera probablement attaché différent de celui que vous avez mentionné dans EDIT-2 :

print logger.handlers
[<logging.StreamHandler object at 0x7f15669c1550>]
print logger.parent.handlers
[<logging.StreamHandler object at 0x7f15669c1610>]

Cela se produit lorsque la propagation de la journalisation est activée et qu'une initialisation de la journalisation s'est produite ailleurs. Vous pouvez vérifier le fonctionnement de la propagation en regardant callHandlers in le code source de python :

    ...
    hdlr.handle(record)
    if not c.propagate:
        c = None    #break out
    else:
        c = c.parent
    ...

De retour à votre cas (Flask), en regardant les traces dans vos logs, il y a un logger nommé flask.app, qui est celui créé par Flask lui-même . Il y a la version formatée et la version non formatée ( logging.BASIC_FORMAT ), respectivement. Il est donc probablement en cours d'initialisation quelque part dans votre code ou dans l'une des bibliothèques que vous importez.

Il existe plusieurs façons de résoudre ce problème:

  • Définition de la propagation sur faux (solution facile, mais solution de contournement)
  • Recherche de la configuration "invalide" et suppression
  • Utilisez l'initialisation dictConfig, avant d'instancier l'application, comme le suggère le didacticiel de journalisation Flask
3
null