---
title: "Monitoring Django performance with Datadog"
description: "Monitor Django performance for applications running on NGINX, Gunicorn, and PostgreSQL"
author: "Bruce Wang"
date: 2018-03-22
tags: ["infrastructure monitoring", "apm", "log management", "django", "python"]
blog_type_id: the-monitor
locale: en
---

[Django](https://www.djangoproject.com/) is an open source Python-based web framework that dynamically renders web content based on the incoming HTTP request. Designed to follow the [MVT](https://www.tutorialspoint.com/django/django_overview.htm) design pattern and provide out-of-the-box functionality, the Django framework prioritizes rapid development and clean, reusable code. Django also puts an emphasis on versatility: the framework can support most web content formats, such as HTML and XML, and since Django is Python-based, it can run on all common server operating systems.

Deploying a Django application requires a few supporting technologies. A database stores application data. A web server listens for incoming HTTP requests and is responsible for sending responses back to clients, as well as serving static files and routing any other requests to the Web Server Gateway Interface (WSGI). A WSGI facilitates communication between the web server and the Python application. We will be using [PostgreSQL](https://www.postgresql.org/) for our database, [NGINX](https://www.nginx.com/) as our web server, and [Gunicorn](http://gunicorn.org/) as our WSGI in this guide.

This guide will cover how to monitor your Django application performance (along with PostgreSQL, NGINX, and Gunicorn) using Datadog so that you can collect metrics, logs, and request traces from the various parts of your application. Command snippets in this guide are provided for Linux hosts; if you are using a different operating system, some commands may differ from the ones presented.

## Getting started with Datadog

To collect metrics, request traces, and logs from your application, you'll need to install the latest version of the [Datadog Agent](https://docs.datadoghq.com/agent.md) on your application host. You can download and install the Agent with the following command, which will prompt you for your system root password:

<!-- Agent install command (platform=linux) omitted -->

If you have a Datadog account set up, you can find your API key [here](https://app.datadoghq.com/account/settings#api). If you haven't tried Datadog yet, you can get started with a <!-- Sign-up trigger (free trial) omitted -->.

[Log collection](https://docs.datadoghq.com/logs.md), which we'll cover below, requires version 6 of the Agent. If you're using a previous version, run the following command to upgrade the Agent and carry over your pre-existing configuration files:

<!-- Agent install command (platform=linux) omitted -->

### Configuring the Datadog Agent

Next we'll ensure that the Agent is properly configured to collect logs and request traces. Open up the datadog.yaml configuration file in the Agent directory:

```text
sudo vi /etc/datadog-agent/datadog.yaml
```

By default, [APM](https://docs.datadoghq.com/tracing.md) request tracing is enabled on versions 5.13 and greater of the Datadog Agent. To enable APM tracing on older compatible versions (5.11 or greater), add the parameter `apm_enabled: true` to the configuration file.

To enable [log collection](https://docs.datadoghq.com/logs.md) (Agent version 6), set `log_enabled: true` in `/etc/datadog-agent/datadog.yaml`. [Restart the Agent](https://docs.datadoghq.com/agent/basic_agent_usage.md) to reload the configuration file:

```text
sudo service datadog-agent restart
```

## Setting up Django performance monitoring

Using Datadog [APM](https://docs.datadoghq.com/tracing.md), you can trace requests across all the different services supporting your application. With our [Django integration](https://ddtrace.readthedocs.io/en/stable/integrations.html#django), requests, template renders, and database queries are all automatically traced. To set up the trace client for Python applications, install the [ddtrace library](https://ddtrace.readthedocs.io/en/stable/index.html) in your application's environment:

```text
pip install ddtrace
```

![Monitor Django Performance, Services, and Traces](https://web-assets.dd-static.net/42588/1776302457-monitoring-django-performance-monitor-django-performance-normal-trace.png)
*Datadog APM traces a request to a Django application from end to end.*

After installing the ddtrace client, run the ddtrace-run wrapper with your Gunicorn command, keeping all the arguments intact:

```text
ddtrace-run gunicorn [...] myapp.wsgi:application [...]
```

To enable the Django integration, add the following under the `INSTALLED_APPS` header in your application's `settings.py` file:

```text
INSTALLED_APPS = [
  # your Django apps...
  'ddtrace.contrib.django',
]
```

Restart Gunicorn to reload your settings configuration:

```text
sudo service gunicorn restart
```

After sending a few requests to your web app, services should start showing up in the [Datadog APM page](https://app.datadoghq.com/apm/home) under your app's [environment tag](https://docs.datadoghq.com/tracing/setup/environment.md).

### Keeping track of PostgreSQL

Datadog is now automatically recording services and request traces from your Django application. In this section, you'll learn how to integrate Datadog with PostgreSQL directly, allowing you to visualize and alert on dozens of database-specific metrics, as well as any data contained in your Postgres logs.

#### PostgreSQL metrics

To prepare [PostgreSQL](https://www.datadoghq.com/blog/collect-postgresql-data-with-datadog.md) for metric collection, start a `psql` session as a user with [CREATEROLE](https://www.postgresql.org/docs/10/static/sql-createrole.html) privileges. In your session, run these commands to create a `datadog` user with access to `pg_stat_database`:

```text
create user datadog with password '<PASSWORD>';
grant SELECT ON pg_stat_database to datadog;
```

To confirm that the new user has the right read access, run the following shell command:

```text
psql -h localhost -U datadog postgres -c \ "select * from pg_stat_database LIMIT(1);" && echo -e "\e[0;32mPostgres connection - OK\e[0m" || \ || echo -e "\e[0;31mCannot connect to Postgres\e[0m"
```

If you see `Postgres connection - OK`, then you have successfully created the correct user.

To configure the Agent to collect PostgreSQL metrics, create a `conf.yaml` file from the provided template.

```text
sudo cp /etc/datadog-agent/conf.d/postgres.d/conf.yaml.example /etc/datadog-agent/conf.d/postgres.d/conf.yaml
```

Add the following to your newly created file:

```text
init_config:

instances:
  - host: localhost
    port: 5432
    username: datadog
    password: <PASSWORD>
```

![Monitor Django Performance With Datadog’s Default PostgreSQL Screenboard](https://web-assets.dd-static.net/42588/1776302462-monitoring-django-performance-monitor-django-performance-postgres-default-timeboard.png)
*Datadog’s built-in dashboard for PostgreSQL provides in-depth visibility into your databases out of the box.*

#### PostgreSQL logs

To set up PostgreSQL for log collection, edit the `/etc/postgresql/<version>/main/postgresql.conf` file and make sure the following parameters are set under the `Error Reporting and Logging` header:

```text
logging_collector = on
log_directory = '/var/log/postgresql'    
log_filename = 'pg.log'
log_statement = 'all'     
log_line_prefix= '%m [%p] %d %a %u %h %c '
log_file_mode = 0644
```

Restart PostgreSQL to reload the configuration.

```text
sudo service postgresql restart
```

If you restart PostgreSQL and the log file at `/var/log/postgresql/pg.log` isn't showing up, or is empty, you may have to create the file yourself and give ownership of the `/var/log/postgresql` directory to user `postgres`.

```text
sudo chown postgres /var/log/postgresql/
```

To configure the Datadog Agent to collect PostgreSQL logs, add the following lines to the end of `/etc/datadog-agent/conf.d/postgres.d/config.yaml`:

```text
logs:
    - type: file
      path: /var/log/postgresql/pg.log
      source: postgresql
      sourcecategory: database
      service: my_database
```

Restart the Datadog Agent to reload the configuration.

```text
sudo service datadog-agent restart
```

You can check to see if your configuration is correct by running the following command:

```text
sudo datadog-agent status
```

You should see output similar to the following:

```text
Collector
=========

  Running Checks
  ==============
    postgres
    --------
    Total Runs: 5
    Metrics: 29, Total Metrics: 145
    Events: 0, Total Events: 0
    Service Checks: 1, Total Service Checks: 5

[...]

Logs-agent
==========
  postgres
  --------
  Type: file
  Path: /var/log/postgresql/pg.log
  Status: OK
  Inputs: /var/log/postgresql/pg.log
```

### Integrating NGINX with Datadog

In this section, you'll learn how to collect [NGINX](https://www.datadoghq.com/blog/how-to-monitor-nginx-with-datadog.md) metrics and logs with Datadog, giving you insights into the traffic coming in and out of your application, as well as the overall health of your web server.

#### NGINX metrics

The NGINX Agent Check retrieves metrics from the NGINX status page, which depends on the [stub status module](http://nginx.org/en/docs/http/ngx_http_stub_status_module.html). If you don't have the stub status module installed, you may need to reinstall or rebuild NGINX. Use the following command to check if your version of NGINX was compiled with the module:

```text
nginx -V 2>&1| grep -o http_stub_status_module
```

If the stub status module is installed, the command will output `http_stub_status_module`.

To prepare NGINX for metrics reporting, create a `status.conf` file in `/etc/nginx/conf.d` and populate it with the following, replacing `stub_status;` with `status;` if you are using NGINX Plus:

```text
server {
  listen 81;
  server_name localhost;
  access_log off;

  allow 127.0.0.1;
  deny all;

  location /nginx_status {
    stub_status;
  }
}
```

To configure the agent for NGINX metric collection, create a `conf.yaml` file from the provided example.

```text
sudo cp /etc/datadog-agent/conf.d/nginx.d/conf.yaml.example /etc/datadog-agent/conf.d/nginx.d/conf.yaml
```

Add the following to your newly created file to start collecting NGINX metrics from the status page:

```text
init_config:
instances:
  - nginx_status_url: http://localhost:81/nginx_status/
```

#### NGINX logs

For collection of NGINX logs, uncomment the following lines in the same `conf.yaml` file:

```text
logs:
  - type: file
    path: /var/log/nginx/access.log
    service: my_web_app
    source: nginx
    sourcecategory: http_web_access

  - type: file
    path: /var/log/nginx/error.log
    service: my_web_app
    source: nginx
    sourcecategory: http_web_access
```

Restart the Datadog Agent to reload the configuration.

```text
sudo service datadog-agent restart
```

You can check to see if your configuration is correct by running the following command:

```text
sudo datadog-agent status
```

Error-free NGINX sections should appear under both the `Collector` and `Logs-agent` headers.

![Monitor Django Performance and NGINX logs with Datadog](https://web-assets.dd-static.net/42588/1776302466-monitoring-django-performance-monitor-django-performance-nginx-logs.png)
*An example of an NGINX log stream collected by Datadog.*

### Gathering Gunicorn metrics

This section will cover the collection of Gunicorn metrics using Datadog, giving you access to important information about the requests being handled by your application.

The Gunicorn Agent Check requires the `setproctitle` Python package to be installed in the Gunicorn application's Python environment. To install the package, activate your app's Python environment and run:

```text
pip install setproctitle
```

To start collecting Gunicorn metrics, create a `conf.yaml` file from the provided example.

```text
sudo cp /etc/datadog-agent/conf.d/gunicorn.d/conf.yaml.example /etc/datadog-agent/conf.d/gunicorn.d/conf.yaml
```

Add the following to your newly created `conf.yaml` file, where my_web_app is the name of your application (you can check your application's name using the command `ps -ef | grep 'gunicorn'`):

```text
init_config:

instances:
 - proc_name: my_web_app
```

Restart the Datadog Agent to reload the configuration.

```text
sudo service datadog-agent restart
```

Datadog's Gunicorn integration collects information on the number and status of worker processes. To collect metrics about request rates, status codes, request durations, and more, you can configure Gunicorn to send metrics to the Datadog Agent using the StatsD protocol. Simply append `--statsd-host=localhost:8125` to your Gunicorn command and restart Gunicorn to see your changes take effect.

```text
sudo service gunicorn restart
```

Running `sudo datadog-agent status` should give output similar to the following:

```text
[...]

  gunicorn
  --------
  Total Runs: 1
  Metrics: 2, Total Metrics: 2
  Events: 0, Total Events: 0
  Service Checks: 1, Total Service Checks: 1

[...]

=========
DogStatsD
=========

Checks Metric Sample: 882
Event: 1
Events Flushed: 1
Number Of Flushes: 4
Series Flushed: 403
Service Check: 64
Service Checks Flushed: 52
```

You should also see metrics start to show up on Datadog's out-of-the-box [Gunicorn dashboard](https://app.datadoghq.com/screen/integration/46/gunicorn).

![Monitor Django Performance With Datadog’s Default Gunicorn Dashboard](https://web-assets.dd-static.net/42588/1776302471-monitoring-django-performance-monitor-django-performance-gunicorn-default-dashboard.png)
*Datadog’s out-of-the-box Gunicorn dashboard*

### Custom Python metrics and events

If you'd like to collect your own custom metrics and events, install [Datadog's Python library](http://datadogpy.readthedocs.io/en/latest/#datadog-api-module) in your application's environment:

```text
pip install datadog
```

Once you've installed the library, you gain access to the Datadog [HTTP API](https://docs.datadoghq.com/api.md?lang=python), [DogStatsD](http://datadogpy.readthedocs.io/en/latest/#datadog-dogstatsd-module), and [ThreadStats](http://datadogpy.readthedocs.io/en/latest/#datadog-threadstats-module) Python modules. With these tools, you can instrument your code to send custom metrics and events to the Datadog Agent.

### Django-specific dashboards

Creating a [custom dashboard](https://docs.datadoghq.com/graphing/dashboards.md) allows you to monitor your Django application at a glance. If you aren't sure what to put on your dashboard, see the out-of-the-box dashboards for [Gunicorn](https://app.datadoghq.com/screen/integration/46/gunicorn), [NGINX](https://app.datadoghq.com/dash/integration/30278/NGINX), or [Postgres](https://app.datadoghq.com/dash/integration/235/Postgres).

#### Track Django applications and their associated technologies with Datadog.
Get started

To import the example dashboard into your Datadog app, run the following curl command:

```text
curl -X POST -H "Content-type: application/json" \
-d '<CONTENTS_OF_EXAMPLE_JSON_GIST>' \
"https://app.datadoghq.com/api/v1/screen?api_key=${<YOUR_DATADOG_API_KEY>}&application_key=${<YOUR_DATADOG_APP_KEY>}"
```

![Monitor Django Performance with custom dashboards](https://web-assets.dd-static.net/42588/1776302475-monitoring-django-performance-monitor-django-performance-example-dashboard.png)
*An example dashboard for Django performance monitoring*

## Diving into Django application performance

After configuring Datadog to monitor your Django application, you'll have access to data from across your stack for performance monitoring and rapid troubleshooting. Let's look at an example scenario: you've just received a Datadog [alert](https://docs.datadoghq.com/monitors.md) notifying you that Gunicorn is reporting a large number of 5xx responses.

![Monitor Django Performance and Alerts with Datadog](https://web-assets.dd-static.net/42588/1776302479-monitoring-django-performance-monitor-django-performance-alert-triggered.png)

You can dive right into a dashboard graph for some further context. It's clear that some event—in this case, a code change, which is overlaid on the graph as a pink bar—has caused the number of 5xx responses to spike.

![Monitor Django Performance, Metrics, and Events](https://web-assets.dd-static.net/42588/1776302483-monitoring-django-performance-monitor-django-performance-5xx-graph.png)
*A code change event, depicted by a pink vertical line, causes an increase in 5xx status codes returned.*

To gather more information on the nature of the errors, you can pivot to Datadog APM, drilling down to all the traces returning 5xx codes in the relevant timeframe. It seems that the request error is the result of a faulty PostgreSQL query. Also note that the error is being caused by a POST request to the `/create/` URL path.

![Monitor Django Performance and Traces](https://web-assets.dd-static.net/42588/1776302488-monitoring-django-performance-monitor-django-performance-error-trace.png)
*A POST request triggers a faulty PostgreSQL query, resulting in a 5xx error being returned.*

To find the issue with the PostgreSQL query, you can pull up the error logs for the query. The logs reveal the source of the problem: our application is attempting to insert a long string—longer than the limit of 3,000 characters.

![Monitor Django Performance and Logs](https://web-assets.dd-static.net/42588/1776302492-monitoring-django-performance-monitor-django-performance-postgres-error-log.png)

Thanks to our comprehensive monitoring coverage, we can smoothly pivot between data from logs, metrics, and request traces to determine that the most recent code change is causing some POST requests to the `/create/` URL path to attempt PostgreSQL string inserts that exceed the character limit.

## Get started today

If you're already using Datadog, check out our [documentation](https://docs.datadoghq.com/) for further information on how to monitor Django performance for your applications and their accompanying technologies. And if you don't yet have a Datadog account, here's a <!-- Sign-up trigger (free trial) omitted --> to get you started.