Installation and configuration

Installation

At the command line:

$ pip install django-cid

Configuration

You need to add cid.apps.CidAppConfig to your list of installed apps.

INSTALLED_APPS = (
    # some apps
    'cid.apps.CidAppConfig',
    # some other apps
)

Generation of the correlation id

The correlation id may be generated by django-cid itself or come from upstream through an incoming HTTP header.

To let django-cid generate an id, set CID_GENERATE to true in the settings:

CID_GENERATE = True

By default, django-cid uses str(uuid.uuid4()) to generate the correlation id but you can customize this generation to suit your needs in the settings:

CID_GENERATOR = lambda: f'{time.time()}-{random.random()}'

Letting django-cid generate a new correlation id is perfectly acceptable but does suffer one drawback. If you host your Django application behind another web server such as nginx, then nginx logs won’t contain the correlation id. django-cid can handle this by extracting a correlation id created in nginx and passed through as a header in the HTTP request. For this to work, you must enable a middleware in the settings, like this:

MIDDLEWARE = (
    'cid.middleware.CidMiddleware',
    # other middlewares
)

The middleware takes care of getting the correlation from the HTTP request header. By default it looks for a header named X_CORRELATION_ID, but you can change this with the CID_HEADER setting:

CID_HEADER = 'X_MY_CID_HEADER'

Note

Most WSGI implementations sanitize HTTP headers by appending an HTTP_ prefix and replacing - by _. For example, an incoming X-Correlation-Id header would be available as HTTP_X_CORRELATION_ID in Django. When using such a WSGI server in front of Django, the latter, sanitized value should be used in the settings.

If a correlation id is provided upstream (e.g. “1234”), it is possible to concatenate it with a newly generated one. The cid will then look like 1234, 1aa38e4e-89c6-4655-9b8e-38ca349da017. To do so, use the following settings:

CID_GENERATE = True
CID_CONCATENATE_IDS = True

This is useful when you use a service-oriented architecture and want to be able to follow a request amongst all systems (by looking at logs that have the first correlation id that was set upstream), and also on a particular system (by looking at logs that have the id added by the system itself).

Inclusion of the correlation id in the response

By default django-cid sets an HTTP header in the HTTP response with the same name as configured in CID_HEADER. You may customize it with CID_RESPONSE_HEADER in the settings:

CID_RESPONSE_HEADER = 'X-Something-Completely-Different'

Note

As indicated in the note above, if Django is behind a WSGI server that sanitizes HTTP headers, you need to customize CID_RESPONSE_HEADER if you want the same header name in the response as in the request.

# Nginx sets ``X-Correlation-Id`` but it is sanitized by the WSGI server.
CID_HEADER = 'HTTP_X_CORRELATION_ID'
# Don't use the default value (equal to CID_HEADER) for the response header.
CID_RESPONSE_HEADER = 'X-Correlation-Id'

If you don’t want the header to appear in the HTTP response, you must explicitly set CID_RESPONSE_HEADER to None.

# Don't include the header in the HTTP response.
CID_RESPONSE_HEADER = None

Inclusion of the correlation id in logs

The most useful feature of django-cid is to include the correlation id in logs. For this you need to add the cid.log.CidContextFilter log filter in your log settings, apply it to each logger, and customize the formatter(s) to include the cid variable.

Here is what it looks like on the the default logging configuration provided by Django’s startproject. Changed lines are highlighted.

LOGGING = {
    'version': 1,
    'formatters': {
        'verbose': {
            'format': '[cid: %(cid)s] %(levelname)s %(asctime)s %(module)s %(message)s'
        },
        'simple': {
            'format': '[cid: %(cid)s] %(levelname)s %(message)s'
        },
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
            'filters': ['correlation'],
        },
    },
    'filters': {
        'correlation': {
            '()': 'cid.log.CidContextFilter'
        },
    },
    'loggers': {
        'testapp': {
            'handlers': ['console'],
            'filters': ['correlation'],
            'propagate': True,
        },
    },
}

You can then use your loggers as you normally do, safe in the knowledge that you can tie them all back to the correlation id.

If you want to include the correlation id in all logs, you need to tweak the “root” key like this:

LOGGING = {
    # ...
    'root': {
        'level': 'INFO',
        'handlers': ['console'],
        'filters': ['correlation'],
    },
    # ...
}

Inclusion of the correlation id in SQL queries

django-cid can add the correlation id as a comment before the SQL query so that the correlation id appears in your database logs like this:

/* cid: 1234567-68e8-45fc-85c1-e025e5dffd1e */
SELECT col FROM table

For this you need to change your database backend to one that is provided by django-cid. For example, for sqlite3 you need to use the following:

DATABASES = {
    'default': {
        'ENGINE': 'cid.backends.sqlite3',
        'NAME': location('db.sqlite3'),
    }
}

django-cid has a wrapper for all backends that are currently supported by Django. Here is the full list:

mysql
cid.backends.mysql
oracle
cid.backends.oracle
postgis
cid.backends.postgis
postgresql
cid.backends.postgresql
sqlite3
cid.backends.sqlite3

By default, the correlation id appears as shown in the example above. You may change that by defining a CID_SQL_COMMENT_TEMPLATE that is a string with a cid format parameter:

CID_SQL_COMMENT_TEMPLATE = 'correlation={cid}'

Inclusion of the correlation id in templates

django-cid provides a template context processor that adds the correlation id to the template context if it is available. To enable it, you need to add it in the list of TEMPLATE_CONTEXT_PROCESSORS in the settings:

TEMPLATE_CONTEXT_PROCESSORS = (
    # other template processors
    'cid.context_processors.cid_context_processor',
)

It will add a context variable correlation_id if a correlation id is available. You may include it in your template with the follwing snippet:

{% if correlation_id %}
    <meta name="correlation_id" content="{{ correlation_id }}">
{% endif %}