Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
Hand-writing spans for your HTTP server, your database driver and your HTTP client is wasted effort — those libraries have maintained instrumentation that is more accurate than what you would write, because it knows where the framework's real boundaries are. Start there, get a working trace in an afternoon, and only then look at what is missing. What auto-instrumentation reliably cannot see is your business logic: the branch that chose the slow path, the cache decision, the retry loop, the queue hop, and anything that matters to your domain rather than to the transport. That gap list is short and specific, which makes it a much better guide to manual instrumentation than starting from a blank file.
Turn it on with no code change, look at the resulting trace, and write down the gap list. The trace below is real in shape: notice the eight-second hole between the handler starting and the first database span, which is your code doing something no library knows about.
# 1. Install, then run with zero code changes:
# pip install opentelemetry-distro opentelemetry-exporter-otlp
# opentelemetry-bootstrap -a install # detects your libs
# OTEL_SERVICE_NAME=checkout \
# OTEL_TRACES_EXPORTER=console \
# opentelemetry-instrument python app.py
# 2. The trace you get for free:
#
# POST /checkout 8210ms SERVER [flask]
# ├─ (8100ms unaccounted) <-- YOUR CODE
# ├─ SELECT cart_items 12ms CLIENT [psycopg]
# ├─ POST /v1/charges 81ms CLIENT [requests]
# └─ INSERT orders 9ms CLIENT [psycopg]
#
# 3. What it CANNOT see, and therefore your gap list:
# - which pricing branch ran, and why it was the slow one
# - the cache lookup that missed (in-process, no library boundary)
# - the retry loop: 3 attempts collapse into one CLIENT span
# - work handed to a queue: the consumer is a separate trace
# - tenant.id, plan tier, feature flags — all domain, all invisible
#
# 4. Only now write manual spans, one per gap, highest first.
# Selectively silence what you do not want, rather than turning it all off:
# OTEL_PYTHON_DISABLED_INSTRUMENTATIONS=urllib3,sqlalchemypython3 main.py