The Honeycomb Beeline for Python is an easy way to instrument your Python web application for observability. It is compatible with the frameworks Django (>1.10), Flask, Bottle, and Tornado, automatically instrumenting them to send useful events to Honeycomb.
Compatible with both Python 2.7 and Python 3. Sign up for a Honeycomb trial to obtain an API key before starting.
pip install honeycomb-beeline
Note: Make sure your version of setuptools
is up to date (pip install -U setuptools
).
The Beeline will automatically send events if you are using Django (>1.10), Flask, Bottle, or Tornado.
You'll need to configure your Honeycomb API key so that your app can identify itself to Honeycomb. You can find your API key on your Account page.
You'll also need to configure the name of a dataset in your Honeycomb account to send events to. The name of your app is a good choice.
You can specify the configuration by passing arguments to beeline.init()
:
beeline.init(
writekey='<MY HONEYCOMB API KEY>',
dataset='my-app',
service_name='my-app'
)
Note that Honeycomb API keys have the ability to create and delete data, and should be managed in the same way as your other application secrets. For example you might prefer to configure production API keys via environment variables, rather than checking them into version control.
The beeline uses Django's request/response middleware (>1.10) and database query execution wrapper (>2.0) to automatically instrument your HTTP requests and database queries, and also supports tracing.
To begin, add the middleware to your settings.py file. Choose HoneyMiddlewareHttp
if you do not want db instrumentation, or HoneyMiddleware
if you do want db instrumentation.
MIDDLEWARE = [
'beeline.middleware.django.HoneyMiddleware',
]
Then, initialize the beeline in app's apps.py
file:
from django.apps import AppConfig
import beeline
class MyAppConfig(AppConfig):
def ready(self):
beeline.init(
writekey='<MY HONEYCOMB API KEY>',
dataset='my-app',
service_name='my-app'
)
Don't forget to set your app's default config in your app's __init__.py
file:
default_app_config = 'myapp.apps.MyAppConfig'
The beeline makes use of WSGI middleware to instrument HTTP requests and also supports tracing. If you are using Flask's SQLAlchemy extension, you can also include our database middleware to get built-in query instrumentation.
To use it, add the following code where your Flask app is initialized:
import beeline
from beeline.middleware.flask import HoneyMiddleware
beeline.init(
writekey='<MY HONEYCOMB API KEY>',
dataset='my-app',
service_name='my-app'
)
app = Flask(__name__)
# db_events defaults to True, set to False if not using our db middleware with Flask-SQLAlchemy
HoneyMiddleware(app, db_events=True)
The beeline makes use of WSGI middleware to instrument HTTP requests and also supports tracing.
To use it, add the following code where your Bottle app is initialized:
import beeline
from beeline.middleware.bottle import HoneyWSGIMiddleware
beeline.init(
writekey='<MY HONEYCOMB API KEY>',
dataset='my-app',
service_name='my-app'
)
app = bottle.app()
myapp = HoneyWSGIMiddleware(app)
bottle.run(app=myapp)
In our initial release, we have limited instrumentation support for Tornado Web RequestHandlers. To instrument HTTP requests and exceptions, simply add a few lines of code to your app init:
import beeline
import libhoney
from beeline.patch import tornado
beeline.init(
writekey='<MY HONEYCOMB API KEY>',
dataset='my-app',
service_name='my-app',
# use a tornado coroutine rather than a threadpool to send events
transmission_impl=libhoney.transmission.TornadoTransmission(),
)
Full tracing support is on our roadmap, as is support for other asynchronous frameworks.
Now your app is instrumented and sending events, try using Honeycomb to ask these questions:
- Which of my app's routes are the slowest?
BREAKDOWN: request.path
CALCULATE: P99(duration_ms)
FILTER: type == http_server
ORDER BY: P99(duration_ms) DESC
- Where's my app spending the most time?
BREAKDOWN: type
CALCULATE: SUM(duration_ms)
ORDER BY: SUM(duration_ms) DESC
- Which users are using the endpoint that I'd like to deprecate? First add a
custom field
user.email
, then try:
BREAKDOWN: user.email
CALCULATE: COUNT
FILTER: request.path == /my/deprecated/endpoint
Here is an example of an HTTP event (type: http_server) emitted by the Beeline:
{
"service_name": "my-test-app",
"type": "http_server",
"request.host": "my-test-app.example.com",
"request.method": "GET",
"request.path": "/dashboard",
"request.query": "",
"request.remote_addr": "172.217.1.238",
"request.content_length": "0",
"request.user_agent":
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"request.scheme": "HTTP",
"trace.trace_id": "b694512a-833f-4b35-be5f-6c742ba18e12",
"trace.span_id": "c35cc326-ed90-4881-a4a8-68526d252f2e",
"response.status_code": 200,
"duration_ms": 303.057396
}
Here is an example of a database query (type: db) event emitted by the Beeline:
{
"service_name": "my-test-app",
"type": "db",
"db.query": "SELECT todo.id FROM todo WHERE %s = todo.todolist_id",
"db.query_args": "[1]",
"db.duration": "0.41",
"db.error": "",
"db.last_insert_id": "0",
"db.rows_affected": "1",
"trace.trace_id": "b694512a-833f-4b35-be5f-6c742ba18e12",
"trace.span_id": "c35cc326-ed90-4881-a4a8-68526d252f2e",
"duration_ms": "0.82"
}
The Beeline will automatically instrument your incoming HTTP requests and database queries to send events to Honeycomb. However, it can be very helpful to extend these events with additional context specific to your app. You can add your own fields by calling beeline.add_field(name, value)
.
The Beeline will automatically add tracing to your incoming HTTP requests and database queries before sending events to Honeycomb. However, it can be very helpful to add tracing in additional places within your code. For example, if you have some code that does an expensive computation, you could simply wrap it in the tracer context manager like so:
with beeline.tracer("my expensive computation"):
recursive_fib(100)
This beeline is still young, so please reach out to [email protected] or ping us with the chat bubble on our website for assistance. We also welcome bug reports and contributions. Also check out our official docs.