3 min read

Flask + Honeycomb.io - Adding request.route and build.version columns to events

I've been using Honeycomb.io for a few months now in my day job. I introduced it to the Javascript developers to help them have insight about what was happening inside of their applications.

I'm not a Javascript dev, nor a dev at all really, but I some times dabble in writing applications in Flask, a Python web framework. I wanted take the beeline-python for a spin with an internal tool I had build a few months back at work.

I will skip over the initial configuration as this is covered in quite some detail in their docs: https://docs.honeycomb.io/getting-data-in/python/beeline/

What I'm going to run through is adding request.route and build.version columns to my events being instrumented automatically by the beeline-python library.

Adding request.route

By default the beeline-python library adds a column for request.path, this is useful but it's hard to breakdown which events came from which route within your Flask application. In the beeline-nodejs library, request.route is included by default.

Screenshot-2019-11-03-at-22.06.35

This is our sample Hello World application:

from flask import Flask

import beeline
from beeline.middleware.flask import HoneyMiddleware

beeline.init(
    writekey='REDACTED',
    dataset='my-python-app',
    service_name='my-python-app'
)

app = Flask(__name__)
HoneyMiddleware(app, db_events=False)


@app.route("/")
def hello():
        return "Hello World!"


@app.route("/profile/<username>")
def profile(username):
        return "<h1>Hello, {0}</h1>".format(username)

We have our beeline library imported, along with the HoneyMiddleware, beeline is initialised and we have a couple of routes we want to instrument.

Adding the route to each event is as simple as importing request from the Flask library and adding this piece of code:

- from flask import Flask
+ from flask import Flask, request
@app.before_request
def before_request():
        beeline.add_context_field("request.route", request.url_rule)

Flask's app.before_request runs before every request, and beeline's add_context_field() function adds context to the current open span. This results in any matching route getting this additional bit of context.

Adding build.version

Now we're going to add some information about the version of the application. This is useful to break down latencies and errors by the build version. It can also help you visualise deploys of new code.

Screenshot-2019-11-03-at-22.30.46

The beeline library provides a presend hook which we can use to scrub any data before it is sent on its way to them. We can use this to append any extra data we might also find useful.

This snippet achieves just that:

def beeline_presend(fields):
        fields['build.version'] = '1.0.0'

And then we call this function from beeline.init like so:

 beeline.init(
     writekey='REDACTED',
     dataset='my-python-app',
-    service_name='my-python-app'
+    service_name='my-python-app',
+    presend_hook=beeline_presend
 )

Further info on the presend_hook here: https://docs.honeycomb.io/getting-data-in/python/beeline/#scrubbing-sensitive-data

All together

from flask import Flask, request

import beeline
from beeline.middleware.flask import HoneyMiddleware


def honey_presend(fields):
        fields['build.version'] = '1.0.1'

beeline.init(
    writekey='REDACTED',
    dataset='my-python-app',
    service_name='my-python-app',
    presend_hook=honey_presend
)

app = Flask(__name__)
HoneyMiddleware(app, db_events=False)


@app.route("/")
def hello():
        return "Hello World!"


@app.route("/profile/<username>")
def profile(username):
        return "<h1>Hello, {0}</h1>".format(username)


@app.before_request
def before_request():
        beeline.add_context_field("request.route", request.url_rule)