Skip to content

#65: Log from Flask to Seq

Now that we can log from Python to Seq it is time to do the same from our Flask web application.

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:

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:

The messages as we know them from previous examples

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:

@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(fObject 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:

pip install jsonpickle

This allows us to convert our objects to JSON and then pass them to SeqLog:

# 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:

The whole object logged 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.