Skip to main content

Django/Daphne middleware and log filter to attach a unique ID to every log message generated as part of a request using contextvars

Project description

django-log-request-id

Django/Daphne middleware and log filter to attach a unique ID to every log message generated as part of a request using context vars.

Author: Aryan Kapoor

Build Status

Example

DEBUG [33031a43fc244539895fef70c433337e] myproject.apps.myapp.views: Doing something in a view
DEBUG [33031a43fc244539895fef70c433337e] myproject.apps.myapp.forms: The form validated successfully!
DEBUG [33031a43fc244539895fef70c433337e] myproject.apps.myapp.models: Doing some model magic
DEBUG [33031a43fc244539895fef70c433337e] myproject.apps.myapp.views: Redirecting to form success page

Why?

So you can grep (or otherwise search) a set of logs for a high-traffic application to isolate all messages associated with a single request.

How?

The request ID is stored in a thread local. Use of thread locals is not generally considered best practice for Django applications, but seems to be the only viable approach in this case. Pull requests with better ideas are welcome.

Any other neat features?

In some cases, components further up the HTTP stack such as load balancers or proxies may generate request IDs. For example, Heroku's http-request-id feature adds a header to the request called X_REQUEST_ID. If such a header is present (and configured in your settings, see below), this ID will be used (instead of generating one). You can configure your settings to use a generated ID or return a default request_id when you expect the ID in the request header but it is not available.

The ID also gets added to the HttpRequest object that is handed to your views, in case you need to use it in your application.

If you need to pass on the ID to other services in a multi-tier architecture, the log_request_id.session module contains a wrapper for requests.Session which will include the ID in outgoing requests, using the same header as configured in your settings.

Installation and usage

First, install the package: pip install django-log-request-id

Add the middleware to your MIDDLEWARE_CLASSES setting. It should be at the very top.

MIDDLEWARE_CLASSES = (
    'log_request_id.middleware.RequestIDMiddleware',
    # ... other middleware goes here
)

Add the log_request_id.filters.RequestIDFilter to your LOGGING setting. You'll also need to update your formatters to include a format with the new request_id variable, add a handler to output the messages (eg to the console), and finally attach the handler to your application's logger.

If none of the above made sense, study Django's logging documentation.

An example LOGGING setting is below:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'request_id': {
            '()': 'log_request_id.filters.RequestIDFilter'
        }
    },
    'formatters': {
        'standard': {
            'format': '%(levelname)-8s [%(asctime)s] [%(request_id)s] %(name)s: %(message)s'
        },
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'filters': ['request_id'],
            'formatter': 'standard',
        },
    },
    'loggers': {
        'myapp': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
    }
}

You can then output log messages as usual:

import logging
logger = logging.getLogger(__name__)
logger.debug("A wild log message appears!")

If you wish to use an ID provided in a request header, add the following setting:

LOG_REQUEST_ID_HEADER = "HTTP_X_REQUEST_ID"

Setting this value as above will enable requests having the header X-Request-Id to be logged with the header value supplied.

Note that this value must conform to the format for Django META keys, otherwise it will be ignored.

If you wish to fall back to a generated ID when you have the LOG_REQUEST_ID_HEADER set but it was not provided in the request, add the following setting:

GENERATE_REQUEST_ID_IF_NOT_IN_HEADER = True

If you wish to include the request id in the response headers, add the following setting, where RESPONSE_HEADER_NAME is the name of the custom header you are going to use:

REQUEST_ID_RESPONSE_HEADER = "RESPONSE_HEADER_NAME"

If you wish to change the default request_id in the log output, the the following settings, where none (default) is the value you want to be the default value in case it's missing.

NO_REQUEST_ID = "none"

Logging all requests

The RequestIDMiddleware also has the ability to log all requests received by the application, including some useful information such as the user ID (if present). To enable this feature, add LOG_REQUESTS = True to your settings. The messages are sent to the log_request_id.middleware logger at INFO level.

Logging other user attributes

If you would like to log another user attribute instead of user ID, this can be specified with the LOG_USER_ATTRIBUTE setting. Eg. to log the username, use: LOG_USER_ATTRIBUTE = "username"

Passing on the ID

from log_request_id.session import Session
session = Session()
session.get('http://myservice.myapp.com/')

You can customise the header used in the outgoing request with the OUTGOING_REQUEST_ID_HEADER setting.

License

Copyright © 2012-2018, DabApps.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Code of conduct

For guidelines regarding the code of conduct when contributing to this repository please review https://www.dabapps.com/open-source/code-of-conduct/

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

context-vars-log-request-id-1.0.0.tar.gz (11.9 kB view details)

Uploaded Source

Built Distribution

File details

Details for the file context-vars-log-request-id-1.0.0.tar.gz.

File metadata

  • Download URL: context-vars-log-request-id-1.0.0.tar.gz
  • Upload date:
  • Size: 11.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.6.1 pkginfo/1.7.1 requests/2.22.0 requests-toolbelt/0.9.1 tqdm/4.61.2 CPython/3.8.10

File hashes

Hashes for context-vars-log-request-id-1.0.0.tar.gz
Algorithm Hash digest
SHA256 60c1230ed9edf154d63a508bd3e6d4a24a13c0d0b95a421c75ffc2a6470a082a
MD5 e4339cd40607fa06cdbdd42b4084a2fc
BLAKE2b-256 6f655b6833f69078ce450a5397c0b40b72f4fdb92e540caf164a31a6d364745f

See more details on using hashes here.

File details

Details for the file context_vars_log_request_id-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: context_vars_log_request_id-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 11.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.6.1 pkginfo/1.7.1 requests/2.22.0 requests-toolbelt/0.9.1 tqdm/4.61.2 CPython/3.8.10

File hashes

Hashes for context_vars_log_request_id-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b1945cccfffb05d67d0fe647720d015dd417c06242e4d937aea11924d24c3638
MD5 2a0fdb56574126789e17abb39d6ff01a
BLAKE2b-256 f1d6ed07a6c08588f4e969a47f20b83779db5c76ce4a3723530deadbb120f65c

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page