Skip to main content
GreenSlope

Python setup

Picks up from the Python quickstart. Read that first.

Zero-code vs. programmatic

The quickstart uses zero-code auto-instrumentation via opentelemetry-instrument. That's the right default. The programmatic path is needed when:

Programmatic bootstrap:

# otel.py
from opentelemetry import trace
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
import os
 
resource = Resource.create({
    "service.name": "api",
    "service.version": os.getenv("APP_VERSION", "0.0.0"),
    "greenslope.release.id": os.getenv("GIT_SHA", "local"),
})
 
provider = TracerProvider(resource=resource)
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(
    endpoint="https://ingest.greenslope.io/v1/otel/v1/traces",
    headers={"x-greenslope-key": os.environ["GREENSLOPE_INGEST_KEY"]},
)))
trace.set_tracer_provider(provider)

Import otel at the top of your entry file, before importing Flask, FastAPI, or Django.

ASGI vs. WSGI

FastAPI and recent Django are ASGI; Flask and older Django are WSGI. Auto-instrumentation picks the right one based on what's installed, so you don't have to pick manually.

If you run FastAPI under Gunicorn, use gunicorn -k uvicorn.workers.UvicornWorker — the UvicornWorker is what the instrumentation hooks into.

Manual spans

from opentelemetry import trace
 
tracer = trace.get_tracer(__name__)
 
def process_order(order_id: str):
    with tracer.start_as_current_span("checkout.process") as span:
        span.set_attribute("order.id", order_id)
        try:
            result = run(order_id)
        except Exception as exc:
            span.record_exception(exc)
            span.set_status(trace.Status(trace.StatusCode.ERROR))
            raise
        return result

Use start_as_current_span in sync code and start_as_current_span inside async with blocks in async code — it works in both.

Django gotcha: instrument the management command

Running manage.py migrate under opentelemetry-instrument will instrument the migration. Usually that's what you want. If you'd rather skip instrumentation for one-off commands:

OTEL_TRACES_EXPORTER=none python manage.py migrate

Logs and metrics

Python, like the other SDKs, should be configured to send traces only in V1. If you set OTEL_METRICS_EXPORTER or OTEL_LOGS_EXPORTER, they'll 404 against our ingest endpoint. Leave them as none.

Related