Skip to main content

Django instrumentation for Watchlog APM with JSON OTLP export

Project description

django_watchlog_apm

🔗 Website: https://watchlog.io

django_watchlog_apm is a lightweight APM (Application Performance Monitoring) integration for Django applications, built on OpenTelemetry. It automatically instruments your Django application to send traces to the Watchlog Agent.

Features

  • Auto-instrumentation for Django views, middleware, and HTTP requests
  • Database query tracing (PostgreSQL via psycopg2)
  • JSON-over-HTTP exporter (OTLP) compatible with Watchlog Agent
  • Environment detection (local vs Kubernetes)
  • Configurable sampling with error and slow span filtering
  • Non-blocking - errors never crash your application
  • Zero configuration - works out of the box

Installation

From PyPI

pip install django-watchlog-apm

Optional: Database Query Tracing

To enable PostgreSQL database query tracing, install the additional package:

pip install opentelemetry-instrumentation-psycopg2==0.56b0

Note: Database query tracing is optional. The package will work without it, but database queries won't be traced.


Quick Start

Step 1: Initialize APM in wsgi.py or asgi.py

Important: You must call instrument_django() before Django loads its settings.

For WSGI (wsgi.py):

import os
from django.core.wsgi import get_wsgi_application

# 1) Import and call instrumentation BEFORE Django setup
from django_watchlog_apm.instrument import instrument_django

instrument_django(
    service_name="my-django-app",  # Your service name
    otlp_endpoint="http://watchlog-agent:3774/apm",  # Watchlog agent endpoint
)

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
application = get_wsgi_application()

For ASGI (asgi.py):

import os
from django.core.asgi import get_asgi_application

# 1) Import and call instrumentation BEFORE Django setup
from django_watchlog_apm.instrument import instrument_django

instrument_django(
    service_name="my-django-app",
    otlp_endpoint="http://watchlog-agent:3774/apm",
)

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
application = get_asgi_application()

Step 2: Run Watchlog Agent

Make sure the Watchlog Agent is running and accessible. The agent should be listening on port 3774 with the /apm endpoint.

Step 3: Test Your Application

Make requests to your Django application. Traces will be automatically sent to the Watchlog Agent.


Configuration Options

instrument_django() Parameters

Parameter Type Default Description
service_name str required Name of your Django service (appears in Watchlog dashboard)
otlp_endpoint str http://localhost:3774/apm Base OTLP URL. Final URL will be {endpoint}/{service_name}/v1/traces
headers dict {} Additional HTTP headers for OTLP requests
batch_max_size int 200 Maximum spans per batch export
batch_delay_ms int 5000 Delay (milliseconds) between batch exports
sample_rate float 1.0 Random sampling rate (0.0–1.0). Note: Internally capped at 0.3 for performance
send_error_spans bool False If True, always export spans with error status
error_tps int None Max error spans to export per second (None = unlimited)
slow_threshold_ms int 0 If >0, always export spans slower than this threshold (milliseconds)
export_timeout float 10.0 HTTP request timeout (seconds) for exporter POSTs

Example: Advanced Configuration

instrument_django(
    service_name="my-django-app",
    otlp_endpoint="http://watchlog-agent:3774/apm",
    sample_rate=1.0,              # Try to sample all requests (capped at 0.3 internally)
    send_error_spans=True,        # Always export error spans
    error_tps=10,                 # Max 10 error spans per second
    slow_threshold_ms=200,       # Always export spans >200ms
    batch_delay_ms=1000,          # Export batches every 1 second
    batch_max_size=50,           # Smaller batches for faster export
    export_timeout=5.0,          # 5 second timeout
)

Docker Setup

Connecting to Watchlog Agent in Docker

If your Django app and Watchlog Agent are in separate Docker containers, use the container name as the host:

instrument_django(
    service_name="my-django-app",
    otlp_endpoint="http://watchlog-agent:3774/apm",  # Use container name
)

Make sure both containers are on the same Docker network:

# Create network
docker network create my-network

# Run Watchlog Agent
docker run -d --name watchlog-agent --network my-network -p 3774:3774 watchlog/agent:latest

# Run Django app
docker run -d --name django-app --network my-network -p 8000:8000 my-django-app

What Gets Traced?

Automatically Traced:

  • HTTP Requests: All incoming requests to Django views
  • Database Queries: PostgreSQL queries (if opentelemetry-instrumentation-psycopg2 is installed)
  • External HTTP Calls: Outgoing requests made with the requests library
  • View Execution: Django view function execution
  • Middleware: Django middleware processing

Trace Structure:

Each trace contains:

  • Root Span: The HTTP request (e.g., GET /api/users/)
  • Child Spans: Database queries, external HTTP calls, etc.

Example trace hierarchy:

GET /api/users/
  ├── SELECT * FROM users WHERE id = 1
  ├── GET https://external-api.com/data
  └── POST /api/users/1/update

Manual Custom Spans

You can create custom spans using the OpenTelemetry API:

from opentelemetry import trace

tracer = trace.get_tracer(__name__)

def my_view(request):
    with tracer.start_as_current_span("custom.operation") as span:
        span.set_attribute("user.id", request.user.id)
        span.set_attribute("operation.type", "data_processing")
        
        # Your business logic here
        result = process_data()
        
        span.set_attribute("result.count", len(result))
        return JsonResponse({"result": result})

Environment Detection

The package automatically detects the environment:

  • Local (non-Kubernetes): Uses the provided otlp_endpoint (default: http://localhost:3774/apm)
  • Kubernetes (in-cluster): Automatically switches to http://watchlog-python-agent.monitoring.svc.cluster.local:3774/apm

Detection checks (in order):

  1. Existence of /var/run/secrets/kubernetes.io/serviceaccount/token
  2. Presence of kubepods in /proc/1/cgroup
  3. DNS lookup of kubernetes.default.svc.cluster.local

Error Handling

Important: This package is designed to never crash your application. All errors are silently handled:

  • ✅ Export failures are swallowed (traces are lost, but app continues)
  • ✅ Instrumentation failures are logged but don't prevent Django from starting
  • ✅ Missing optional dependencies (like psycopg2 instrumentation) are gracefully handled

If you want to see error logs, configure logging:

import logging
logging.getLogger("django_watchlog_apm").setLevel(logging.INFO)

Troubleshooting

Traces Not Appearing in Watchlog

  1. Check Agent Connection: Verify the Watchlog Agent is running and accessible

    curl http://watchlog-agent:3774/
    
  2. Check Network: Ensure Django container can reach the agent

    docker exec django-app ping watchlog-agent
    
  3. Check Logs: Look for export errors in Django logs

    docker logs django-app | grep "django_watchlog_apm"
    
  4. Verify Endpoint: The final URL should be http://watchlog-agent:3774/apm/{service_name}/v1/traces

Database Queries Not Traced

  • Ensure opentelemetry-instrumentation-psycopg2==0.56b0 is installed
  • Check that you're using psycopg2 (not psycopg2-binary for instrumentation, though psycopg2-binary works)
  • Verify the package is imported before Django starts

High Memory Usage

  • Reduce batch_max_size (default: 200)
  • Increase batch_delay_ms to export less frequently
  • Lower sample_rate (though it's capped at 0.3 internally)

Sample Rate Limitation

Important: The sample_rate parameter is internally capped at 0.3 (30%) for performance reasons. Even if you set sample_rate=1.0, only approximately 30% of spans will be exported.

To export more spans:

  • Set slow_threshold_ms=0 to export all slow spans
  • Set send_error_spans=True to always export error spans
  • Use both in combination for maximum coverage

License

MIT © Mohammadreza

Built for Watchlog.io

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

django_watchlog_apm-1.1.0.tar.gz (8.2 kB view details)

Uploaded Source

File details

Details for the file django_watchlog_apm-1.1.0.tar.gz.

File metadata

  • Download URL: django_watchlog_apm-1.1.0.tar.gz
  • Upload date:
  • Size: 8.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.4

File hashes

Hashes for django_watchlog_apm-1.1.0.tar.gz
Algorithm Hash digest
SHA256 f45f6dbd07609d5a85698ff2ee6846662a6eb2f6253300ba809f67092222ce66
MD5 98804f9df595b0281ad0a41837c0ae17
BLAKE2b-256 d8425e2931de405bfadfc079785dc8374ef23a0c72375dcad7a461af7cd1e93e

See more details on using hashes here.

Supported by

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