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')
何が起こる
私はどこかで完全にここにいるのですか、それとも何が起こっていますか?
次のようにしないでください:
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/
わかりました、私の失敗は2つの誤解から生じました:
1)Flaskは、実稼働モードで実行されていない限り、すべてのカスタムロギングを無視するようです。
2)debug = Falseは、実稼働モードで実行するには不十分です。そのためには、あらゆる種類のWSGIサーバーでアプリをラップする必要があります
GeventのWSGIサーバーからアプリを起動した後(およびロギングの初期化をより適切な場所に移動した後)、すべてが正常に動作するようです
アプリのコンソールに表示される出力は、logging.getLogger( 'werkzeug')からアクセスできる、基礎となるWerkzeugロガーからのものです。
ロギングは、開発者とリリースの両方で、ハンドラーをFlask one。
詳細とコード例: Write Flask Access Logへのリクエスト 。
私は他の答えが気に入らなかったので、それを守り、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/
コードを詳しく見てみてください...
着陸するモジュールは_flask.logging.py
_で、create_logger(app)
という名前の関数を定義します。その機能を検査すると、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')
_
これは動作します:
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)