Django Instrumentation
======================

This shows how to use ``opentelemetry-instrumentation-django`` to automatically instrument a
Django app.

The source files of these examples are available :scm_web:`here <docs/examples/django/>`.

Preparation
-----------

This example will be executed in a separate virtual environment:

.. code-block::

    $ mkdir django_auto_instrumentation
    $ virtualenv django_auto_instrumentation
    $ source django_auto_instrumentation/bin/activate


Installation
------------

.. code-block::

    $ pip install opentelemetry-sdk
    $ pip install opentelemetry-instrumentation-django
    $ pip install requests


Execution
---------

Execution of the Django app
...........................

This example uses Django features intended for development environment.
The ``runserver`` option should not be used for production environments.

Set these environment variables first:

#. ``export DJANGO_SETTINGS_MODULE=instrumentation_example.settings``

The way to achieve OpenTelemetry instrumentation for your Django app is to use
an ``opentelemetry.instrumentation.django.DjangoInstrumentor`` to instrument the app.

Clone the ``opentelemetry-python`` repository and go to ``opentelemetry-python/docs/examples/django``.

Once there, open the ``manage.py`` file. The call to ``DjangoInstrumentor().instrument()``
in ``main`` is all that is needed to make the app be instrumented.

Run the Django app with ``python manage.py runserver --noreload``.
The ``--noreload`` flag is needed to avoid Django from running ``main`` twice.

Execution of the client
.......................

Open up a new console and activate the previous virtual environment there too:

``source django_auto_instrumentation/bin/activate``

Go to ``opentelemetry-python/docs/examples/django``, once there
run the client with:

``python client.py hello``

Go to the previous console, where the Django app is running. You should see
output similar to this one:

.. code-block::

    {
        "name": "home_page_view",
        "context": {
            "trace_id": "0xed88755c56d95d05a506f5f70e7849b9",
            "span_id": "0x0a94c7a60e0650d5",
            "trace_state": "{}"
        },
        "kind": "SpanKind.SERVER",
        "parent_id": "0x3096ef92e621c22d",
        "start_time": "2020-04-26T01:49:57.205833Z",
        "end_time": "2020-04-26T01:49:57.206214Z",
        "status": {
            "status_code": "OK"
        },
        "attributes": {
            "http.request.method": "GET",
            "server.address": "localhost",
            "url.scheme": "http",
            "server.port": 8000,
            "url.full": "http://localhost:8000/?param=hello",
            "server.socket.address": "127.0.0.1",
            "network.protocol.version": "1.1",
            "http.response.status_code": 200
        },
        "events": [],
        "links": []
    }

The last output shows spans automatically generated by the OpenTelemetry Django
Instrumentation package.

Disabling Django Instrumentation
--------------------------------

Django's instrumentation can be disabled by setting the following environment variable:

``export OTEL_PYTHON_DJANGO_INSTRUMENT=False``

Auto Instrumentation
--------------------

This same example can be run using auto instrumentation. Comment out the call
to ``DjangoInstrumentor().instrument()`` in ``main``, then Run the django app
with ``opentelemetry-instrument python manage.py runserver --noreload``.
Repeat the steps with the client, the result should be the same.

Usage with Auto Instrumentation and uWSGI
-----------------------------------------

uWSGI and Django can be used together with auto instrumentation. To do so,
first install uWSGI in the previous virtual environment:

``pip install uwsgi``

Once that is done, run the server with ``uwsgi`` from the directory that
contains ``instrumentation_example``:

``opentelemetry-instrument uwsgi --http :8000 --module instrumentation_example.wsgi``

This should start one uWSGI worker in your console. Open up a browser and point
it to ``localhost:8000``. This request should display a span exported in the
server console.

References
----------

* `Django <https://djangoproject.com/>`_
* `OpenTelemetry Project <https://opentelemetry.io/>`_
* `OpenTelemetry Django extension <https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-django>`_
