🐍 Python Integration Guide

Learn how to instrument your Python applications with OpenTelemetry to send distributed traces to TraceKit.

90% Automatic Tracing!

With the right libraries, most of your application will be traced automatically with minimal setup. No need to manually instrument every function.

📋

Prerequisites

  • • Python 3.8 or higher
  • • An active TraceKit account
  • • A generated API key from the API Keys page

🔍 What Gets Traced Automatically?

With proper setup, these operations are traced automatically with zero manual instrumentation:

ComponentSetupAuto-Traced?
HTTP EndpointsAuto-instrument Flask/Django/FastAPI✓ Yes
Database QueriesSQLAlchemy, psycopg2, pymongo auto-instrumentation✓ Yes
HTTP Client Callsrequests, httpx, aiohttp instrumentation✓ Yes
Redis Operationsredis-py instrumentation✓ Yes
Celery TasksCelery instrumentation✓ Yes
Custom Business LogicManual spans (optional)Manual

📦 Installation

Install the required OpenTelemetry packages:

pip install opentelemetry-api opentelemetry-sdk
pip install opentelemetry-exporter-otlp-proto-http
pip install opentelemetry-instrumentation-flask  # or django, fastapi

⚙️ Basic Setup

Create a tracing initialization module in your application:

Create tracing.py

# tracing.py
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.resources import Resource
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.semconv.resource import ResourceAttributes

def init_tracer(service_name: str, endpoint: str, api_key: str):
    """Initialize OpenTelemetry tracer for TraceKit"""

    # Create resource with service name
    resource = Resource(attributes={
        ResourceAttributes.SERVICE_NAME: service_name,
        ResourceAttributes.SERVICE_VERSION: "1.0.0",
    })

    # Create tracer provider
    provider = TracerProvider(resource=resource)

    # Configure OTLP exporter
    otlp_exporter = OTLPSpanExporter(
        endpoint=f"{endpoint}/v1/traces",
        headers={"X-API-Key": api_key}
    )

    # Add span processor
    provider.add_span_processor(BatchSpanProcessor(otlp_exporter))

    # Set as global tracer provider
    trace.set_tracer_provider(provider)

    return provider

🚀 Framework Integration

TraceKit works seamlessly with popular Python web frameworks through OpenTelemetry instrumentation.

Flask

# app.py
from flask import Flask
from opentelemetry.instrumentation.flask import FlaskInstrumentor
import os
from tracing import init_tracer

# Initialize tracing
init_tracer(
    service_name="my-flask-app",
    endpoint=os.getenv("TRACEKIT_ENDPOINT", "{ appURL }"),
    api_key=os.getenv("TRACEKIT_API_KEY")
)

# Create Flask app
app = Flask(__name__)

# Auto-instrument Flask (all routes will be traced automatically!)
FlaskInstrumentor().instrument_app(app)

@app.route("/api/users")
def get_users():
    return {"users": ["alice", "bob", "charlie"]}

if __name__ == "__main__":
    app.run(port=5000)

Django

# settings.py
from tracing import init_tracer
import os

# Initialize tracing at Django startup
init_tracer(
    service_name="my-django-app",
    endpoint=os.getenv("TRACEKIT_ENDPOINT", "{ appURL }"),
    api_key=os.getenv("TRACEKIT_API_KEY")
)

# Add Django instrumentation to INSTALLED_APPS (not required but recommended)
# Then use:
# opentelemetry-instrument python manage.py runserver

# Or instrument manually in your WSGI/ASGI file:
from opentelemetry.instrumentation.django import DjangoInstrumentor
DjangoInstrumentor().instrument()

FastAPI

# main.py
from fastapi import FastAPI
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
import os
from tracing import init_tracer

# Initialize tracing
init_tracer(
    service_name="my-fastapi-app",
    endpoint=os.getenv("TRACEKIT_ENDPOINT", "{ appURL }"),
    api_key=os.getenv("TRACEKIT_API_KEY")
)

# Create FastAPI app
app = FastAPI()

# Auto-instrument FastAPI
FastAPIInstrumentor.instrument_app(app)

@app.get("/api/users")
async def get_users():
    return {"users": ["alice", "bob", "charlie"]}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

Automatic Instrumentation Libraries

These libraries automatically create child spans for common operations. Set them up once, and every call is traced automatically.

Database Queries

Automatically trace all database operations:

SQLAlchemy

from sqlalchemy import create_engine
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor

# Create engine
engine = create_engine("postgresql://user:pass@localhost/mydb")

# Instrument SQLAlchemy (one line!)
SQLAlchemyInstrumentor().instrument(engine=engine)

# Now all queries are automatically traced
from sqlalchemy.orm import Session
with Session(engine) as session:
    users = session.query(User).all()  # This query is traced!

HTTP Client Calls

Automatically trace all outgoing HTTP requests:

from opentelemetry.instrumentation.requests import RequestsInstrumentor
import requests

# Instrument requests library (one line!)
RequestsInstrumentor().instrument()

# Now all HTTP requests are automatically traced
response = requests.get("https://api.example.com/users")  # Traced!

Redis Operations

Trace Redis commands automatically:

from redis import Redis
from opentelemetry.instrumentation.redis import RedisInstrumentor

# Instrument Redis
RedisInstrumentor().instrument()

# Create Redis client
redis_client = Redis(host='localhost', port=6379)

# All operations are now traced!
redis_client.set("key", "value")  # Traced!
value = redis_client.get("key")   # Traced!

🔧 Manual Instrumentation (Optional)

For custom business logic that isn't covered by auto-instrumentation libraries, you can manually create spans. This is optional and only needed for specific operations you want to measure.

from opentelemetry import trace

def process_order(order_id: str):
    tracer = trace.get_tracer(__name__)

    # Start a parent span
    with tracer.start_as_current_span("process_order") as span:
        span.set_attribute("order.id", order_id)
        span.set_attribute("order.status", "processing")

        # Child spans automatically link to parent
        with tracer.start_as_current_span("validate_order") as child_span:
            child_span.set_attribute("order.id", order_id)
            # Validation logic here

        with tracer.start_as_current_span("charge_payment") as child_span:
            child_span.set_attribute("order.id", order_id)
            # Payment logic here

        span.set_attribute("order.status", "completed")

🔐 Environment Variables

Best practice: Store sensitive configuration in environment variables:

# .env
TRACEKIT_API_KEY=ctxio_your_generated_api_key_here
TRACEKIT_ENDPOINT={ appURL }
SERVICE_NAME=my-python-app

🏭 Production Configuration

⚠️

Production Checklist

  • • Use HTTPS/TLS for the OTLP endpoint
  • • Store API keys in a secrets manager (AWS Secrets Manager, HashiCorp Vault)
  • • Set appropriate service names and versions
  • • Configure resource attributes (deployment.environment, host.name, etc.)
  • • Adjust sampling rates if needed for high-traffic services

🔧 Troubleshooting

Traces Not Appearing?

  1. Verify your API key is correct and not revoked
  2. Check the endpoint URL matches your TraceKit instance
  3. Ensure all required packages are installed
  4. Check application logs for OpenTelemetry errors
  5. Verify TraceKit is running and accessible

Complete Example

Here's a complete working example with Flask:

# Complete Flask example
from flask import Flask
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
import os
from tracing import init_tracer

# Initialize tracing
init_tracer(
    service_name=os.getenv("SERVICE_NAME", "flask-api"),
    endpoint=os.getenv("TRACEKIT_ENDPOINT", "{ appURL }"),
    api_key=os.getenv("TRACEKIT_API_KEY")
)

# Create Flask app
app = Flask(__name__)

# Auto-instrument Flask and requests
FlaskInstrumentor().instrument_app(app)
RequestsInstrumentor().instrument()

@app.route("/api/users")
def get_users():
    return {"users": ["alice", "bob", "charlie"]}

@app.route("/api/users/<int:user_id>")
def get_user(user_id):
    return {"id": user_id, "name": "Alice"}

if __name__ == "__main__":
    print("Flask app starting with TraceKit tracing enabled")
    app.run(host="0.0.0.0", port=5000)
🎉

You're all set!

Your Python application is now sending traces to TraceKit. Visit the Dashboard to see your traces.

🚀 Next Steps

  • Add auto-instrumentation libraries for components you use (Redis, Celery, MongoDB, etc.)
  • Explore your traces on the Traces page to identify performance bottlenecks
  • Optionally add custom spans for specific business logic you want to measure
  • Configure sampling for high-traffic services to reduce overhead
  • Set up alert rules to get notified when issues occur