Flask - 如何使用RotatingFileHandler将werkzeug日志写入日志文件?

7

我发现了一些相似的问题,但没有一个直接解决这个问题。

我正在尝试将所有Werkzeug日志输出到日志文件中。我可以将部分日志输出到文件中,但我似乎无法捕获任何错误或超出基本路由/请求行之外的内容。

这是我的代码。如何包括Werkzeug的所有输出?

if __name__ == '__main__':
    configure_app(app)
    handler=RotatingFileHandler('server_werkzeug.log', maxBytes=10000000, backupCount=5)
    log = logging.getLogger('werkzeug')
    log.setLevel(logging.DEBUG)
    log.addHandler(handler)
3个回答

10

这段代码可以完美记录日志。至于无法记录错误的问题,似乎需要指定除'werkzeug'之外的其他记录器。在Flask中,要记录回溯错误,请使用app.logger。别忘了将级别设置为WARNING。

import logging
import logging.handlers

app = Flask(__name__)

handler = logging.handlers.RotatingFileHandler(
        'log.txt',
        maxBytes=1024 * 1024)
logging.getLogger('werkzeug').setLevel(logging.DEBUG)
logging.getLogger('werkzeug').addHandler(handler)
app.logger.setLevel(logging.WARNING)
app.logger.addHandler(handler)

如果您的应用程序使用一些第三方工具,例如数据库查询、定期任务等,您还可以添加其他记录器。

logging.getLogger('apscheduler.scheduler').setLevel(logging.DEBUG)
logging.getLogger('apscheduler.scheduler').addHandler(handler)

在终端窗口中可以找到日志记录器的名称:

INFO:werkzeug:127.0.0.1 - - [10/Mar/2018 15:41:15] "GET /file.js HTTP/1.1" 200 -
DEBUG:apscheduler.scheduler:Next wakeup is due at 2018-03-10 16:00:00+03:00 (in 1124.668881 seconds)

2
使用dictConfig是一种更可扩展的方式来进行操作。最初的回答。
from logging.config import dictConfig

dictConfig({
    'version': 1,
    'handlers': {
        'file.handler': {
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': 'server_werkzeug.log',
            'maxBytes': 10000000,
            'backupCount': 5,
            'level': 'DEBUG',
        },
    },
    'loggers': {
        'werkzeug': {
            'level': 'DEBUG',
            'handlers': ['file.handler'],
        },
    },
})

1
如果您有兴趣将访问日志与其他 werkzeug 日志调用分开,您可以实现以下猴子补丁。
这对于进行开发工作非常方便,因为访问日志对于故障排除非常有用,但是如果在其他日志旁边打印werkzeug,对可读性不是很有帮助。
__access_log_enabled__ = False # Override to enable logger (eg when running code outside of wsgi server)

def log_request(self:werkzeug.serving.WSGIRequestHandler, 
                code: typing.Union[int, str] = "-", 
                size: typing.Union[int, str] = "-") -> None:
    if not __access_log_enabled__: return
    _server_.log_request(handler=self, code=code, size=size)
    # where _server_ is your own class for managing the server

werkzeug.serving.WSGIRequestHandler.log_request = log_request

以下是一个使用示例:

import werkzeug
import typing
import logging
from logging.handlers import RotatingFileHandler
from datetime import datetime

_server_ = None

class MyServer():
    def __init__(self, in_wsgi:bool):
        global _server_
        _server_ = self
        
        # ...
        log_werkzeug = logging.getLogger('werkzeug')
        log_werkzeug.setLevel(logging.ERROR)
        # This will suppress all logs from werkzeug below Error
        #  with the exception of the redirected access logs

        if not in_wsgi:
            self.acc_log = logging.getLogger('qflask_access_log')
            handler = RotatingFileHandler('./log/access_non_wsgi.log', 
                                          maxBytes=100000, 
                                          backupCount=5)
            handler.setFormatter(logging.Formatter("%(message)s"))
            self.acc_log.addHandler(handler)
            self.acc_log.setLevel(logging.INFO)
            global __access_log_enabled__
            __access_log_enabled__ = True

        # ...
            
    # ...
    def log_request(self, 
                    handler:werkzeug.serving.WSGIRequestHandler, 
                    code: typing.Union[int, str] = "-", 
                    size: typing.Union[int, str] = "-") -> None:
        try:
            path = werkzeug.urls.uri_to_iri(handler.path)
            msg = f"{handler.command} {path} {handler.request_version}"
        except AttributeError:
            # path isn't set if the requestline was bad
            msg = handler.requestline
        code = str(code)

        self.acc_log.warning(
            f"[{datetime.now().strftime('%y%m%d-%H%M%S.%f')}] {code} {msg} {size}")

这可能是一个很好的功能,可以内置到werkezug中。实际上,如果access_log_enabled = False,则会使任何服务器稍微快一点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接