Now that we can log from Python to Seq it is time to do the same from our Flask web application.
This post is part of my journey to learn Python. You can find the other parts of this series here.
Prerequisites
We need to install SeqLog and make sure that we import current_app if we use Bootstrap.
Configure SeqLog
In the file you initialise your Flask app you need to add the configuration for SeqLog:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import flask from flask import render_template from flask import request import seqlog import logging app = flask.Flask(__name__) seqlog.log_to_seq( server_url="http://127.0.0.1:5341/", api_key="xjy**********U6hIg4X", level=logging.NOTSET, batch_size=10, auto_flush_timeout=1, # seconds override_root_logger=True ) |
With the exception of the application key this is the exact same configuration as we used to write log messages from a script to Seq.
Log to Seq
With the logger configuration in place, our messages go directly to Seq:
Caveat: Logging whole objects
The default logger of Flask turns objects like my view model into a string before it logs it to the console. That allows us to log whole view models without any effort from us:
1 2 3 4 5 6 7 8 9 10 11 12 |
@blueprint.route('/contact', methods=['POST']) def contact_post(): vm = ContactViewModel() vm.validate() if vm.error: return render_template('contact/contact.html', **vm.to_dict()) current_app.logger.debug(vm) resp = flask.redirect('/thanks') return resp |
The resulting log entry looks like this:
[2021-02-28 21:50:02,663] DEBUG in contact_views: Johnny Graber [[email protected]]: This is a test.
SeqLog tries to convert the object to JSON what may results in an error like this one:
— Logging error —
Traceback (most recent call last):
File “C:\Users\jgraber\AppData\Local\Programs\Python\Python38-32\lib\site-packages\seqlog\structured_logging.py”, line 384, in publish_log_batch
request_body_json = json.dumps(request_body, cls=self.json_encoder_class)
File “C:\Users\jgraber\AppData\Local\Programs\Python\Python38-32\lib\json\__init__.py”, line 234, in dumps
return cls(
File “C:\Users\jgraber\AppData\Local\Programs\Python\Python38-32\lib\json\encoder.py”, line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File “C:\Users\jgraber\AppData\Local\Programs\Python\Python38-32\lib\json\encoder.py”, line 257, in iterencode
return _iterencode(o, 0)
File “C:\Users\jgraber\AppData\Local\Programs\Python\Python38-32\lib\json\encoder.py”, line 179, in default
raise TypeError(f’Object of type {o.__class__.__name__} ‘
TypeError: Object of type ContactViewModel is not JSON serializable
One possible way to fix this problem is to use the Python library jsonpickle, that we can install with PIP:
1 |
pip install jsonpickle |
This allows us to convert our objects to JSON and then pass them to SeqLog:
1 2 |
# line to replace: current_app.logger.debug(vm) current_app.logger.debug("Posted: {formdata}", formdata=jsonpickle.encode(vm)) |
With this additional step we can keep logging whole objects to Seq:
Conclusion
Logging from Python and Flask to Seq is possible and with the right libraries it even supports complex objects. This is great news for me, then this allows me to use a single centralized log server to collect the logs from all my applications – regardless of whether the application is written in C# or Python.