web-dev-qa-db-ja.com

Flask logging-ファイルへの書き込みを取得できません

OK、すべてをセットアップするコードを次に示します。

if __== '__main__':
    app.debug = False

    applogger = app.logger

    file_handler = FileHandler("error.log")
    file_handler.setLevel(logging.DEBUG)

    applogger.setLevel(logging.DEBUG)
    applogger.addHandler(file_handler)

    app.run(Host='0.0.0.0')

何が起こる

  1. error.logが作成されます
  2. 何も書かれていない
  3. StreamHandlerを追加せず、debugをfalseに設定しているにもかかわらず、まだすべてがSTDOUTになります(これは正しいかもしれませんが、それでも奇妙に思えます)

私はどこかで完全にここにいるのですか、それとも何が起こっていますか?

46
fleshgolem

次のようにしないでください:

if __== '__main__':
    init_db()  # or whatever you need to do

    import logging
    logging.basicConfig(filename='error.log',level=logging.DEBUG)

    app.run(Host="0.0.0.0")

アプリケーションを起動すると、error.logに以下が含まれていることがわかります。

INFO:werkzeug: * Running on http://0.0.0.0:5000/

詳細については、 http://docs.python.org/2/howto/logging.html をご覧ください。

さて、あなたが示したメソッドで2つのハンドラーを使用することはできないと主張しているので、これを非常に明確にする例を追加します。まず、このロギングコードをメインに追加します。

import logging, logging.config, yaml
logging.config.dictConfig(yaml.load(open('logging.conf')))

また、デバッグコードを追加して、セットアップが機能することを確認します。

logfile    = logging.getLogger('file')
logconsole = logging.getLogger('console')
logfile.debug("Debug FILE")
logconsole.debug("Debug CONSOLE")

残っているのは「logging.conf」プログラムだけです。それを使用しましょう:

version: 1
formatters:
  hiformat:
    format: 'HI %(asctime)s - %(name)s - %(levelname)s - %(message)s'
  simple:
    format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
handlers:
  console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: hiformat
    stream: ext://sys.stdout
  file:
    class: logging.FileHandler
    level: DEBUG
    formatter: simple
    filename: errors.log
loggers:
  console:
    level: DEBUG
    handlers: [console]
    propagate: no
  file:
    level: DEBUG
    handlers: [file]
    propagate: no
root:
  level: DEBUG
  handlers: [console,file]

この設定は必要以上に複雑ですが、ロギングモジュールのいくつかの機能も示しています。

さて、アプリケーションを実行すると、次の出力が表示されます(werkzeug-およびconsole-logger):

HI 2013-07-22 16:36:13,475 - console - DEBUG - Debug CONSOLE
HI 2013-07-22 16:36:13,477 - werkzeug - INFO -  * Running on http://0.0.0.0:5000/

また、「HI」のカスタムフォーマッタが使用されたことにも注意してください。

「errors.log」ファイルを見てください。を含む:

2013-07-22 16:36:13,475 - file - DEBUG - Debug FILE
2013-07-22 16:36:13,477 - werkzeug - INFO -  * Running on http://0.0.0.0:5000/
79
HolgerSchurig

わかりました、私の失敗は2つの誤解から生じました:

1)Flaskは、実稼働モードで実行されていない限り、すべてのカスタムロギングを無視するようです。

2)debug = Falseは、実稼働モードで実行するには不十分です。そのためには、あらゆる種類のWSGIサーバーでアプリをラップする必要があります

GeventのWSGIサーバーからアプリを起動した後(およびロギングの初期化をより適切な場所に移動した後)、すべてが正常に動作するようです

13
fleshgolem

アプリのコンソールに表示される出力は、logging.getLogger( 'werkzeug')からアクセスできる、基礎となるWerkzeugロガーからのものです。

ロギングは、開発者とリリースの両方で、ハンドラーをFlask one。

詳細とコード例: Write Flask Access Logへのリクエスト

9
AsksAnyway

私は他の答えが気に入らなかったので、それを守り、Flask独自のセットアップを行った後、ロギング設定を作成しなければならなかったようです。

@app.before_first_request
def initialize():

    logger = logging.getLogger("your_package_name")
    logger.setLevel(logging.DEBUG)
    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    formatter = logging.Formatter(
    """%(levelname)s in %(module)s [%(pathname)s:%(lineno)d]:\n%(message)s"""
    )
    ch.setFormatter(formatter)
    logger.addHandler(ch)

私のアプリは次のように構成されています

/package_name
    __main__.py <- where I put my logging configuration
    __init__.py <- conveniance for myself, not necessary
    /tests
    /package_name <- Actual flask app
    __init__.py
    /views
    /static
    /templates
    /lib

これらの指示に従う http://flask.pocoo.org/docs/0.10/patterns/packages/

3
David

コードを詳しく見てみてください...

着陸するモジュールは_flask.logging.py_で、create_logger(app)という名前の関数を定義します。その機能を検査すると、Flaskのロギングの問題のトラブルシューティングを行う際に、潜在的な犯人に関するいくつかの手がかりが得られます。

編集:この回答は、バージョン1より前のFlaskを対象としていました。それ以降、_flask.logging.py_モジュールは大幅に変更されました。答えは、pythonロギングに関するいくつかの一般的な警告とアドバイスに役立ちますが、その点に関するFlaskの特性の一部はバージョン1で対処されており、適用されない可能性があることに注意してください。

その機能の競合の最初の考えられる原因はこの行です:

_logger = getLogger(app.logger_name)
_

理由を見てみましょう:

変数_app.logger_name_は、Flask.__init__()メソッドで_import_name_の値に設定されます。これは、それ自体がFlask(__name__)の受信パラメーターです。 _app.logger_name_には___name___の値が割り当てられます。これはおそらくメインパッケージの名前になります。この例では「awesomeapp」と呼びましょう。

ここで、独自のロガーを手動で構成および作成することにしたと想像してください。プロジェクトの名前が「awesomeapp」である場合、その名前を使用してロガーを構成する可能性は何だと思いますか。

_my_logger = logging.getLogger('awesomeapp') # doesn't seem like a bad idea
fh = logging.FileHandler('/tmp/my_own_log.log')
my_logger.setLevel(logging.DEBUG)
my_logger.addHandler(fh)
_

これを行うのは理にかなっています...いくつかの問題を除いて。

_Flask.logger_プロパティが初めて呼び出されると、関数flask.logging.create_logger()が呼び出され、次のアクションが実行されます。

_logger = getLogger(app.logger_name)
_

プロジェクトの後にロガーにどのように名前を付け、_app.logger_name_もその名前を共有するか覚えていますか?上記のコード行で発生することは、関数logging.getLogger()が以前に作成したロガーを取得し、次の指示が後で頭を悩ませるような方法でそれを混乱させることです。例えば

_del logger.handlers[:]
_

失礼、ロガーに以前に登録した可能性のあるすべてのハンドラーを失っただけです。

関数内で発生するその他のこと。詳細にはあまり触れません。 _logging.StreamHandler_やResponseオブジェクトに吐き出すことができる2つの_sys.stderr_オブジェクトを作成して登録します。 1つはログレベル「デバッグ」用で、もう1つは「本番」用です。

_class DebugLogger(Logger):
    def getEffectiveLevel(self):
        if self.level == 0 and app.debug:
            return DEBUG
        return Logger.getEffectiveLevel(self)

class DebugHandler(StreamHandler):
    def emit(self, record):
        if app.debug and _should_log_for(app, 'debug'):
            StreamHandler.emit(self, record)

class ProductionHandler(StreamHandler):
    def emit(self, record):
        if not app.debug and _should_log_for(app, 'production'):
            StreamHandler.emit(self, record)

debug_handler = DebugHandler()
debug_handler.setLevel(DEBUG)
debug_handler.setFormatter(Formatter(DEBUG_LOG_FORMAT))

prod_handler = ProductionHandler(_proxy_stream)
prod_handler.setLevel(ERROR)
prod_handler.setFormatter(Formatter(PROD_LOG_FORMAT))

logger.__class__ = DebugLogger
logger.addHandler(debug_handler)
logger.addHandler(prod_handler)
_

上記の詳細が明らかになると、手動で構成されたロガーとハンドラーがFlaskが関与したときに誤動作する理由が明らかになるはずです。新しい情報は新しいオプションを提供します。それでも個別のハンドラを保持したい場合、最も簡単なアプローチは、ロガーにプロジェクトとは異なる名前を付けることです(例:my_logger = getLogger('awesomeapp_logger'))。別のアプローチは、Flaskのロギングプロトコルとの整合性を保ちたい場合、Flaskと同様のアプローチを使用して_logging.FileHandler_オブジェクトを_Flask.logger_に登録することです。

_import logging
def set_file_logging_handler(app):

    logging_path = app.config['LOGGING_PATH']

    class DebugFileHandler(logging.FileHandler):
        def emit(self, record):
            # if your app is configured for debugging
            # and the logger has been set to DEBUG level (the lowest)
            # Push the message to the file
            if app.debug and app.logger.level==logging.DEBUG:
                super(DebugFileHandler, self).emit(record)

    debug_file_handler = DebugFileHandler('/tmp/my_own_log.log')
    app.logger.addHandler(debug_file_handler)

app = Flask(__name__)
# the config presumably has the debug settings for your app
app.config.from_object(config)
set_file_logging_handler(app)

app.logger.info('show me something')
_
3
Michael Ekoka

これは動作します:

if __== '__main__':
    import logging
    logFormatStr = '[%(asctime)s] p%(process)s {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s'
    logging.basicConfig(format = logFormatStr, filename = "global.log", level=logging.DEBUG)
    formatter = logging.Formatter(logFormatStr,'%m-%d %H:%M:%S')
    fileHandler = logging.FileHandler("summary.log")
    fileHandler.setLevel(logging.DEBUG)
    fileHandler.setFormatter(formatter)
    streamHandler = logging.StreamHandler()
    streamHandler.setLevel(logging.DEBUG)
    streamHandler.setFormatter(formatter)
    app.logger.addHandler(fileHandler)
    app.logger.addHandler(streamHandler)
    app.logger.info("Logging is set up.")
    app.run(Host='0.0.0.0', port=8000, threaded=True)
2
nicodjimenez