Web Framework Integration

The MDK provide integration points for common web frameworks. The number of supported frameworks will grow over time.

Hooking up the MDK will do the following:

  1. Provide a catch-all error handler for your distributed system. If an internal server error occurs this will activate the circuit breaker. The circuit breaker affects any nodes resolved using MDK discovery while handling that particular request. Repeated errors will cause the MDK to temporarily blacklist those nodes, ensuring errors don’t take down the whole system.
  2. The MDK will parse the X-MDK-CONTEXT HTTP header, and either join the resulting trace session or start a new one if no header was present. This means logging via the MDK will be able to trace requests across multiple servers so long as the HTTP client includes the appropriate X-MDK-CONTEXT header.
  3. Provide access to a corresponding MDK Session object to enable logging, discovery and other MDK functionality form within your web application.
  4. If appropriately configured, propagate a session timeout with the session context, allowing different servers to cooperate in enforcing a global timeout.

Javascript

Express integration

Express support requires adding an additional dependency:

npm install datawire_mdk_express

You will then need to:

  • Add a mdkSessionStart middleware at the beginning of your application configuration. This will ensure the MDK session is started and stopped appropriately.
  • Add a mdkErrorHandler error-handling middleware at the end of your application configuration. This catches errors passed into Express and ensures the circuit breaker will be called in that case.

Unfortunately not all errors end up being passed back to Express. For example, if an exception is thrown in a callback somewhere Express will have no way of knowing about it.

To ensure that these cases also trigger the circuit breaker, and that some sort of response is sent even when unhandled errors occur, we highly recommend you add a timeout middleware. The connect-timeout package (https://www.npmjs.com/package/connect-timeout) works well for this since it can be configured to trigger an Express error when the timeout occurs.

Once you’ve configured the MDK as above you can access the session via req.mdk_session. Here’s an example showing the full configuration:

var express = require('express');
var timeout = require('connect-timeout');
var mdk_express = require('datawire_mdk_express');

// Configure a 5 second global timeout on MDK sessions passing through this
// process:
mdk_express.mdk.setDefaultDeadline(5.0);
// Register the server with Discovery:
mdk_express.mdk.register("myservice", "1.0", "http://localhost:8080/")

var app = express();

// Configure a 5 second timeout which will cause an Express error on
// timeouts within this process:
app.use(timeout('5s', {respond: true}));

// Start and stop the MDK session:
app.use(mdk_express.mdkSessionStart);


// Your application logic goes here:
app.get('/', function (req, res) {
    // Log a message using the MDK:
    req.mdk_session.info("myapp", "logging some info");
    res.send("hello world");
});
// ... more application logic ...


// Error handler which has to go at the end of your middleware:
app.use(mdk_express.mdkErrorHandler);

Using Winston logging with the MDK

If you’re using the Express integration you can also add [Winston](http://github.com/winstonjs/winston) integration, routing logs from Winston into Mission Control via the MDK.

var express = require('express');
var winston = require('winston');
var mdk_express = require('datawire_mdk_express');
var mdk_winston = require('datawire_mdk_winston');

// Route Winston logging to the MDK:
winston.add(mdk_winston.MDKTransport, {mdk: mdk_express.mdk,
                                       name: 'myapp'});
// Start and stop the MDK session:
app.use(mdk_express.mdkSessionStart);

app.get('/', function (req, res) {
    // Log a message using Winston; it will be sent to the MDK:
    winston.info("logging some info");
    res.send("hello world");
});

// etc.

Python

Django integration

To enable MDK integration you need to add the appropriate middleware to your settings.py. In Django 1.9 or earlier you add mdk.django.MDKSessionMiddleware to MIDDLEWARE_CLASSES:

MIDDLEWARE_CLASSES = [
 ...
 'django.middleware.csrf.CsrfViewMiddleware',

 # MDK middleware:
 'mdk.django.MDKSessionMiddleware',

 'django.contrib.auth.middleware.AuthenticationMiddleware',
  ...
]

In Django 1.10 you add it to MIDDLEWARE:

MIDDLEWARE = [
 ...
 'django.middleware.csrf.CsrfViewMiddleware',

 # MDK middleware:
 'mdk.django.MDKSessionMiddleware',

 'django.contrib.auth.middleware.AuthenticationMiddleware',
  ...
]

You will also need to add either mdk.django.MDKAppConfig or a subclass to INSTALLED_APPS in your settings.py. Subclassing and overriding the MDKAppConfig.mdk_ready method will allow you to run MDK setup on startup, e.g. registering your server with discovery or setting a default timeout. For example, if you have a Django project in package myproject, you’d add a subclass to myproject/apps.py:

from mdk.django import MDKAppConfig

class LocalMDKAppConfig(MDKAppConfig):
    def mdk_ready(self, mdk):
        mdk.register("myapp", "1.0", "https://example.com")
        mdk.setDefaultDeadline(5.0)

And then in settings.py you would do the following:

INSTALLED_APPS = [
    'myproject.apps.LocalMDKAppConfig',
    # ... default Django apps
]

In order to access the MDK session you can use request.mdk_session in your view. For example:

from django.http import HttpResponse

def myview(request):
    # Log a message using the MDK:
    request.mdk_session.info("djangoapp", "myview was viewed")
    return HttpResponse("hello!")

Flask integration

To enable MDK integration with Flask simply call mdk.flask.mdk_setup(app) before app.run(). This will return the MDK instance. You can access an automatically setup MDK session via flask.g.mdk_session.

from flask import g, Flask

from mdk.flask import mdk_setup

app = Flask(__name__)

@app.route("/")
def hello():
    g.mdk_session.info("myservice", "Hello world!")
    return "hello"

if __name__ == '__main__':
    mdk = mdk_setup(app)
    mdk.setDefaultDeadline(10.0)
    mdk.register("helloservice", "1.0", "http://localhost:7070/")
    app.run(port=7070)

You can also integrate Python’s standard library logging module. mdk.flask.MDKLoggingHandler is a logging.StreamHandler. It routes messages from logging to the MDK and from there to Mission Control. The messages will be part of the MDK session context set up by the Flask integration.

import logging

from flask import Flask
from mdk.flask import mdk_setup, MDKLoggingHandler

app = Flask(__name__)
# ... setup routes ...

if __name__ == '__main__':
    mdk = mdk_setup(app)
    handler = MDKLoggingHandler(mdk)
    # Set a handler for all logging messages from Python:
    logging.getLogger().addHandler(handler)
    app.run(port=7070)

Ruby

Rack

Rack is the basis for many Ruby web frameworks, including Sinatra and Ruby on Rails. The MDK Rack middleware therefore allows integrating the MDK into all these web frameworks.

You will need to install the rack-mdk gem, e.g.:

gem install rack-mdk

Then register the Rack::MDK::Session middleware with your Rack configuration. You can access the current session from the Rack env via env[:mdk_session].

For example, here’s how you would do so in Sinatra:

require 'sinatra'
require 'rack-mdk'

# Register the MDK middleware using the Sinatra use API
use Rack::MDK::Session do |mdk|
  mdk.setDefaultDeadline(10)
  mdk.register("myservice", "1.0", "http://localhost:8080")
end

get '/' do
  # Log using the MDK
  env[:mdk_session].info('myapp', 'Logging something')
  'hello!'
end