How do I write Flask's excellent debug log message to a file in production?

前端 未结 5 1906
囚心锁ツ
囚心锁ツ 2020-12-22 17:29

I have a Flask application that works well and produces an occasional error, which is visible when it is running with debug=True:

if __name__ =         


        
5条回答
  •  挽巷
    挽巷 (楼主)
    2020-12-22 18:00

    I'm not a specialist on logging module, but regarding my experience on it + some years of on Python + Flask, you can have a good logging configuration, considering some observations:

    • at the beginning of every function (route), create a timestamp object, in order to registry the exact time when the request was made, independently if it was successful or not

    • use @app.after_request, for registering every successful request

    • use @app.errorhandler, for registering general errors + Tracebacks

    Here is an example that demonstrates this idea:

    #/usr/bin/python3
    """ Demonstration of logging feature for a Flask App. """
    
    from logging.handlers import RotatingFileHandler
    from flask import Flask, request, jsonify
    from time import strftime
    
    __author__ = "@ivanleoncz"
    
    import logging
    import traceback
    
    
    app = Flask(__name__)
    
    @app.route("/")
    @app.route("/index")
    def get_index():
        """ Function for / and /index routes. """
        return "Welcome to Flask! "
    
    
    @app.route("/data")
    def get_data():
        """ Function for /data route. """
        data = {
                "Name":"Ivan Leon",
                "Occupation":"Software Developer",
                "Technologies":"[Python, Flask, JavaScript, Java, SQL]"
        }
        return jsonify(data)
    
    
    @app.route("/error")
    def get_nothing():
        """ Route for intentional error. """
        return foobar # intentional non-existent variable
    
    
    @app.after_request
    def after_request(response):
        """ Logging after every request. """
        # This avoids the duplication of registry in the log,
        # since that 500 is already logged via @app.errorhandler.
        if response.status_code != 500:
            ts = strftime('[%Y-%b-%d %H:%M]')
            logger.error('%s %s %s %s %s %s',
                          ts,
                          request.remote_addr,
                          request.method,
                          request.scheme,
                          request.full_path,
                          response.status)
        return response
    
    
    @app.errorhandler(Exception)
    def exceptions(e):
        """ Logging after every Exception. """
        ts = strftime('[%Y-%b-%d %H:%M]')
        tb = traceback.format_exc()
        logger.error('%s %s %s %s %s 5xx INTERNAL SERVER ERROR\n%s',
                      ts,
                      request.remote_addr,
                      request.method,
                      request.scheme,
                      request.full_path,
                      tb)
        return "Internal Server Error", 500
    
    
    if __name__ == '__main__':
        handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount=3)        
        logger = logging.getLogger(__name__)
        logger.setLevel(logging.ERROR)
        logger.addHandler(handler)
        app.run(host="127.0.0.1",port=8000)
    

    For more information regarding logrotate and logs on stdout and file at the same time: this Gist

提交回复
热议问题