Announcing Blackfire middleware support for WSGI Python applications

By Thomas di Luccio, on Feb 08, 2023

WSGI is the Web Server Gateway Interface. It is a convention that describes how a web server communicates with web applications and how those can be organized to process one request.

Django, Flask, and many other popular Python frameworks are WSGI-based. Blackfire has dedicated support for Django, Flask, and Odoo. Our new  custom middleware aims at easing the configuration of other WSGI applications

BlackfireWSGIMiddleware to the rescue

The Blackfire Middleware extends the framework scope by adding observability-related features. The BlackfireWSGIMiddleware is provided with the Python SDK. The SDK itself is available with the Blackfire Python Package.

Let’s implement a middleware for a Bottle application by extending the BlackfireWSGIMiddleware. Three elements need to be configured. The first mandatory step is to set the FRAMEWORK constant as a class variable.

from blackfire.hooks.wsgi import BlackfireWSGIMiddleware


class BlackfireBottleMiddleware(BlackfireWSGIMiddleware):


    FRAMEWORK = 'bottle'


    ...

Two methods could then be defined.  get_view_name would enable the monitoring of the WSGI application, while build_blackfire_yml_response is required to trigger builds.

Both functions are required only for the monitoring and the synthetic monitoring of your application, respectively. Their definitions can be omitted if you are not considering one or the other.

Activating Blackfire Monitoring

To have the requests of your WSGI-based application instrumented by Blackfire Monitoring, the get_view_name method must be defined. 

The get_view_name method retrieves the view name executing or handling the HTTP request. Blackfire Monitoring relies on this information to group requests in the monitoring dashboard.

Please check the documentation for a complete description of the function signature.

class BlackfireBottleMiddleware(BlackfireWSGIMiddleware):


   FRAMEWORK = 'bottle'


   def get_view_name(self, environ):
   	return request.path

Keeping critical user journeys under control with Blackfire builds

Blackfire builds allow the performance assessment of a collection of scenarios that represent the various steps of critical user journeys. A build_blackfire_yml_response method is required to trigger builds.

When a Build POST request is received, this function gets called to build a framework specific response that contains the .blackfire.yaml file contents. It should return a framework specific HTTP response.

For more info, check the complete documentation of the build_blackfire_yml_response function signature.

Here is the code of a Bottle application with Blackfire fully enabled:

from bottle import app, route, run, request, Response
from blackfire.hooks.wsgi import BlackfireWSGIMiddleware


class BlackfireBottleMiddleware(BlackfireWSGIMiddleware):

	FRAMEWORK = 'bottle'


	def get_view_name(self, environ):
    	     return request.path
    


	def build_blackfire_yml_response(
    	self, blackfireyml_content, agent_response, environ, start_response
	):
    	# The .blackfire.yaml file should only be sent for authentified request
    	     if agent_response:
        	    return Response(
            	    body=blackfireyml_content or '',
            	    headers=[agent_response]
        	    )(environ, start_response)
    	     return Response()(environ, start_response)


my_app = BlackfireBottleMiddleware(app())


@route('/')
def home():
	return 'hello world!'


run(app=my_app)

Do you want to dig further to see the observability of Python applications? 

Check theSümer Cip’s series of articles on the Challenges of Async Python Observability: part 1, part 2, and part 3.

Have you built a middleware for a WSGI framework? Reach out to us on Reddit or Twitter to contribute and share it with the Blackfire community.

And as always, Happy Python Performance Optimization!

Thomas di Luccio

Thomas is a Developer Relations Engineer at Platform.sh for Blackfire.io. He likes nothing more than understanding the users' needs and helping them find practical and empowering solutions. He’ll support you as a day-to-day user.