Skip to content

Instantly share code, notes, and snippets.

@ivanleoncz
Last active May 23, 2021 07:25
Show Gist options
  • Star 43 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save ivanleoncz/dbf29670761cbaed4c5c787d9c9c006b to your computer and use it in GitHub Desktop.
Save ivanleoncz/dbf29670761cbaed4c5c787d9c9c006b to your computer and use it in GitHub Desktop.
Demonstration of logging feature for a Flask App.
#/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__':
# maxBytes to small number, in order to demonstrate the generation of multiple log files (backupCount).
handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount=3)
# getLogger(__name__): decorators loggers to file + werkzeug loggers to stdout
# getLogger('werkzeug'): decorators loggers to file + nothing to stdout
logger = logging.getLogger(__name__)
logger.setLevel(logging.ERROR)
logger.addHandler(handler)
app.run(host="127.0.0.1",port=8000)
# ---> getLogger(__name__)
#
# $ python3 simple_app_logging.py
# * Running on http://127.0.0.1:8000/ (Press CTRL+C to quit)
# 127.0.0.1 - - [11/Mar/2018 18:55:39] "GET / HTTP/1.1" 200 -
# 127.0.0.1 - - [11/Mar/2018 18:55:47] "GET /data HTTP/1.1" 200 -
# 127.0.0.1 - - [11/Mar/2018 18:55:50] "GET /error HTTP/1.1" 500 -
#
# $ cat app.log
# [2018-Mar-11 18:55] 127.0.0.1 GET http /? 200 OK
# [2018-Mar-11 18:55] 127.0.0.1 GET http /data? 200 OK
# [2018-Mar-11 18:55] 127.0.0.1 GET http /error? 5xx INTERNAL SERVER ERROR
# Traceback (most recent call last):
# File "/usr/local/lib/python3.4/dist-packages/flask/app.py", line 1612, in full_dispatch_request
# rv = self.dispatch_request()
# File "/usr/local/lib/python3.4/dist-packages/flask/app.py", line 1598, in dispatch_request
# return self.view_functions[rule.endpoint](**req.view_args)
# File "simple_app_logging.py", line 37, in get_nothing
# return foobar # intentional non-existent variable
# NameError: name 'foobar' is not defined
# ---> getLogger('werkzeug')
#
# $ python3 simple_app_logging.py
#
#
#
# $ cat app.log
# [2018-Mar-11 18:44] 127.0.0.1 GET http /? 200 OK
# [2018-Mar-11 18:44] 127.0.0.1 GET http /data? 200 OK
# [2018-Mar-11 18:45] 127.0.0.1 GET http /error? 5xx INTERNAL SERVER ERROR
# Traceback (most recent call last):
# File "/usr/local/lib/python3.4/dist-packages/flask/app.py", line 1612, in full_dispatch_request
# rv = self.dispatch_request()
# File "/usr/local/lib/python3.4/dist-packages/flask/app.py", line 1598, in dispatch_request
# return self.view_functions[rule.endpoint](**req.view_args)
# File "simple_app_logging.py", line 37, in get_nothing
# return foobar # intentional non-existent variable
# NameError: name 'foobar' is not defined
# For more info: https://stackoverflow.com/questions/14037975/how-do-i-write-flasks-excellent-debug-log-message-to-a-file-in-production/39284642#39284642
#
@LeCoupa
Copy link

LeCoupa commented Jul 17, 2017

Thanks a lot!

@sfsekaran
Copy link

Note that if you're using werkzeug you must use the following line instead:

logger = logging.getLogger('werkzeug')

@ivanleoncz
Copy link
Author

I made an update on this Gist. Check it out, please.
This example above, is focused on maintaining log messages recorded in a file and in the stdout. If you use 'werkzeug', it will supress he stdout messages from Werkzeug and will only record the loggers that are executed via the decorators.
If you have a better idea on how to improve this Gist, please, do it. I just know the basic from Python logging, and maybe there could another approach, more efficient.
Thanks guys for getting in contact :)!

@maximveksler
Copy link

Could you add a "full request" logger? I would like to log the parameters that have been send to the server as well as the headers and co.

@Sumanniroula
Copy link

Thank you very very much !!

@ivanleoncz
Copy link
Author

@maximveksler, I have to check this. I believe that this is possible, since that there's a lot of information that you can extract from flask.request module. I'll make an update, as soon as I can :).

@ivanleoncz
Copy link
Author

@Sumanniroula: you're welcome :).

@sergejschelle
Copy link

That's exactly what I was looking for.

@srikanthjeeva
Copy link

Thanks a lot!

@MichaelSEA
Copy link

Thanks Ivan!

@ivanleoncz
Copy link
Author

ivanleoncz commented Feb 28, 2018

Everyone: you're welcome.
Please, make it better! I'm pretty sure that it can be :)

Best Regards,
@ivanleoncz

@Enr1g
Copy link

Enr1g commented Mar 11, 2018

Is line 76 logger = logging.getLogger('__name__') intended? I guess, you'd like to use logger = logging.getLogger(__name__) (without single quotes).

@ivanleoncz
Copy link
Author

No, @Enr1g, it wasn't. But indeed, the single quotes are not necessary for __name__, since that the variable already holds the namespace where the Python module, script, app, etc., is running. I'll make an update. Thanks for observing this 👍 :)

@Yoyoyoyoyoyoyo
Copy link

Yoyoyoyoyoyoyo commented Jun 1, 2018

Flask's documentation reads "As of Flask 0.7 this function might not be executed at the end of the request in case an unhandled exception occurred." That's the situation where I care about logging. Anyone encountered problems with that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment