🐍 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:
| Component | Setup | Auto-Traced? |
|---|---|---|
| HTTP Endpoints | Auto-instrument Flask/Django/FastAPI | ✓ Yes |
| Database Queries | SQLAlchemy, psycopg2, pymongo auto-instrumentation | ✓ Yes |
| HTTP Client Calls | requests, httpx, aiohttp instrumentation | ✓ Yes |
| Redis Operations | redis-py instrumentation | ✓ Yes |
| Celery Tasks | Celery instrumentation | ✓ Yes |
| Custom Business Logic | Manual spans (optional) | Manual |
📦 Installation
Install the required OpenTelemetry packages:
# Install TraceKit Python SDK
pip install tracekit-apm
# Framework-specific installation
pip install tracekit-apm[flask] # For Flask
pip install tracekit-apm[django] # For Django
pip install tracekit-apm[fastapi] # For FastAPI
pip install tracekit-apm[all] # All frameworks⚙️ Basic Setup
Create a tracing initialization module in your application:
Create tracing.py
# Simple initialization with TraceKit SDK
import tracekit
import os
# Initialize TraceKit with code monitoring enabled
client = tracekit.init(
api_key=os.getenv('TRACEKIT_API_KEY'),
service_name=os.getenv('SERVICE_NAME', 'my-python-app'),
endpoint=os.getenv('TRACEKIT_ENDPOINT', '{ appURL }'),
enable_code_monitoring=True # Enable live debugging
)
# That's it! TraceKit handles all OpenTelemetry setup automatically🚀 Framework Integration
TraceKit works seamlessly with popular Python web frameworks through OpenTelemetry instrumentation.
Flask
# app.py
from flask import Flask, request, jsonify
import tracekit
from tracekit.middleware.flask import init_flask_app
import os
# Create Flask app
app = Flask(__name__)
# Initialize TraceKit with code monitoring
client = tracekit.init(
api_key=os.getenv("TRACEKIT_API_KEY"),
service_name="my-flask-app",
endpoint=os.getenv("TRACEKIT_ENDPOINT", "{ appURL }"),
enable_code_monitoring=True # Enable live debugging
)
# Add TraceKit middleware (auto-traces all routes!)
init_flask_app(app, client)
@app.route("/api/users/<int:user_id>")
def get_user(user_id):
# Capture snapshot for debugging (optional)
if client.get_snapshot_client():
client.capture_snapshot('get-user', {
'user_id': user_id,
'request_path': request.path,
'request_method': request.method
})
return jsonify({"id": user_id, "name": "Alice"})
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)📸 Code Monitoring (Live Debugging)
TraceKit includes production-safe code monitoring for live debugging without redeployment. Capture variable state and stack traces at any point in your code.
Key Features
- • Synchronous API - No
awaitneeded (works in both sync and async code) - • Auto-Registration - Breakpoints automatically created on first call
- • Background Sync - SDK polls for active breakpoints every 30 seconds
- • Rate Limited - Max 1 capture per second per breakpoint
- • Production Safe - No performance impact when inactive
Adding Snapshots
@app.route("/api/checkout")
def checkout():
cart = request.get_json()
user_id = cart['user_id']
# Capture snapshot at this point (synchronous - no await)
if client.get_snapshot_client():
client.capture_snapshot('checkout-validation', {
'user_id': user_id,
'cart_items': len(cart.get('items', [])),
'total_amount': cart.get('total', 0),
})
# Process payment...
result = process_payment(cart)
# Another checkpoint
if client.get_snapshot_client():
client.capture_snapshot('payment-complete', {
'user_id': user_id,
'payment_id': result['payment_id'],
'success': result['success'],
})
return jsonify({'status': 'success', 'result': result})What Gets Captured
- • Variable values at capture point
- • Full call stack with file/line numbers
- • Request context (HTTP method, URL, headers)
- • Execution timestamp
🔗 Nested Spans (Parent-Child Relationships)
Create nested spans to track operations within requests. Parent spans are created automatically by the Flask middleware, and child spans link automatically.
from opentelemetry import trace
@app.route("/api/users/<int:user_id>")
def get_user(user_id):
# Get the tracer
tracer = trace.get_tracer(__name__)
# Parent span is auto-created by Flask middleware
# Create child span using context manager
with tracer.start_as_current_span('db.query.user') as span:
span.set_attributes({
'db.system': 'postgresql',
'db.operation': 'SELECT',
'db.table': 'users',
'db.statement': 'SELECT * FROM users WHERE id = ?',
'user.id': user_id
})
user = fetch_user_from_db(user_id)
span.set_attributes({
'user.found': user is not None,
'user.role': user.get('role') if user else None
})
return jsonify(user)Trace Hierarchy
GET /api/users/1 (parent - auto-created) └─ db.query.user (child - manually created)
⚡ 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!🚀 Local UI (Development Mode)
Debug your Python application locally without creating an account. TraceKit Local UI runs on your machine at http://localhost:9999 and automatically receives traces when you run your app in development mode.
Automatic Detection
The Python SDK automatically detects when Local UI is running on port 9999 and sends traces to both Local UI and cloud (if you have an API key configured).
Quick Start
1. Install the Local UI:
npm install -g @tracekit/local-ui2. Start the Local UI:
tracekit-local3. Run your app in development mode:
ENV=development python app.py4. Open your browser:
http://localhost:9999Features
Auto-Detection
SDK checks for Local UI at localhost:9999 on startup
Real-Time Updates
See traces instantly with WebSocket live updates
Development Only
Only activates when ENV=development
Works Offline
No internet connection required - everything runs locally
Benefits
- See your first trace in under 60 seconds
- Debug locally without switching to the cloud dashboard
- Stay in your flow - everything runs on your machine
- Works completely offline
- Perfect for development and demos
Troubleshooting
If traces aren't appearing in Local UI, check:
- Local UI is running (
curl http://localhost:9999/api/health) ENV=developmentis set- SDK version is v0.3.2 or higher
- Check console for "🔍 Local UI detected" message
🌐 Service Discovery
TraceKit automatically instruments outgoing HTTP calls to create service dependency graphs. When your service makes an HTTP request to another service, TraceKit creates CLIENT spans and injects trace context headers.
Supported HTTP Clients
- requests - Python requests library
- httpx - Modern HTTP client
- aiohttp - Async HTTP client
- urllib3 - Low-level HTTP client
Custom Service Name Mappings
For local development or when service names can't be inferred from hostnames, configure service name mappings:
import tracekit
import os
client = tracekit.init(
api_key=os.getenv('TRACEKIT_API_KEY'),
service_name='my-service',
# Map localhost URLs to actual service names
service_name_mappings={
'localhost:8082': 'payment-service',
'localhost:8083': 'user-service',
'localhost:8084': 'inventory-service',
}
)
# Now requests to localhost:8082 will show as "payment-service"
import requests
response = requests.get('http://localhost:8082/charge')
# -> Creates CLIENT span with peer.service = "payment-service"This maps localhost:8082 to "payment-service" in your service graph.
Service Name Detection
TraceKit intelligently extracts service names from URLs:
| URL | Extracted Service Name |
|---|---|
| http://payment-service:3000 | payment-service |
| http://payment.internal | payment |
| http://payment.svc.cluster.local | payment |
| https://api.example.com | api.example.com |
Viewing Service Dependencies
Visit your TraceKit dashboard to see the Service Map - a visual graph showing which services call which, with health metrics and latency data.
🔧 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
@app.route("/api/users/<int:user_id>")
def get_user(user_id):
# Get the tracer
tracer = trace.get_tracer(__name__)
# Parent span is auto-created by Flask middleware
# Create child span using context manager
with tracer.start_as_current_span('db.query.user') as span:
span.set_attributes({
'db.system': 'postgresql',
'db.operation': 'SELECT',
'db.table': 'users',
'db.statement': 'SELECT * FROM users WHERE id = ?',
'user.id': user_id
})
user = fetch_user_from_db(user_id)
span.set_attributes({
'user.found': user is not None,
'user.role': user.get('role') if user else None
})
return jsonify(user)
# Creates a nested trace:
# GET /api/users/1 (parent span - auto-created)
# └─ db.query.user (child span - manually created)🔐 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?
- Verify your API key is correct and not revoked
- Check the endpoint URL matches your TraceKit instance
- Ensure all required packages are installed
- Check application logs for OpenTelemetry errors
- Verify TraceKit is running and accessible
✅ Complete Example
Here's a complete working example with Flask:
# Complete Flask example with TraceKit SDK
from flask import Flask, request, jsonify
from opentelemetry import trace
import tracekit
from tracekit.middleware.flask import init_flask_app
import os
import time
# Create Flask app
app = Flask(__name__)
# Initialize TraceKit with code monitoring
client = tracekit.init(
api_key=os.getenv("TRACEKIT_API_KEY"),
service_name=os.getenv("SERVICE_NAME", "flask-api"),
endpoint=os.getenv("TRACEKIT_ENDPOINT", "{ appURL }"),
enable_code_monitoring=True
)
# Add TraceKit middleware
init_flask_app(app, client)
@app.route("/api/users")
def get_users():
return jsonify({"users": ["alice", "bob", "charlie"]})
@app.route("/api/users/<int:user_id>")
def get_user(user_id):
# Capture snapshot for debugging
if client.get_snapshot_client():
client.capture_snapshot('get-user', {
'user_id': user_id,
'request_path': request.path,
'request_method': request.method
})
# Create nested span for database query
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span('db.query.user') as span:
span.set_attributes({
'db.system': 'postgresql',
'db.operation': 'SELECT',
'db.table': 'users',
'user.id': user_id
})
time.sleep(0.01) # Simulate DB query
return jsonify({"id": user_id, "name": "Alice"})
if __name__ == "__main__":
print("Flask app starting with TraceKit tracing and code monitoring 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.
Custom Metrics
Track custom metrics like request counts, queue sizes, and response times using the TraceKit metrics API.
Counter
Track monotonically increasing values (requests, events):
import tracekit
client = tracekit.init(
api_key="your-api-key",
service_name="my-service"
)
# Create a counter with optional tags
counter = client.counter("http.requests.total", tags={"service": "api"})
# Increment by 1
counter.inc()
# Add a specific value
counter.add(5)Gauge
Track values that can go up or down (queue size, connections):
# Create a gauge
gauge = client.gauge("http.connections.active")
# Set to specific value
gauge.set(42)
# Increment/decrement
gauge.inc()
gauge.dec()Histogram
Track value distributions (latencies, sizes):
# Create a histogram with tags
histogram = client.histogram("http.request.duration", tags={"unit": "ms"})
# Record values
histogram.record(45.2)
histogram.record(123.5)🚀 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