Lesson 8 / 25

Manual Spans and Attributes

Instrument business logic.

Tracer, spans and context managers

Get a tracer from the API, then start spans around important operations. In Python, with tracer.start_as_current_span("name") creates a child of the current span and ends it automatically. Add attributes describing business context (order value, item count, customer tier, but not personal data), record exceptions and set status. Use clear, low-cardinality span names such as price_quote rather than names containing IDs.

A manual span in Python

Using the OpenTelemetry API (a sketch; assumes the SDK is configured by zero-code instrumentation or at start-up).

from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode

tracer = trace.get_tracer("orders.pricing")

def quote_price(cart):
    with tracer.start_as_current_span("price_quote") as span:
        span.set_attribute("app.cart.items", len(cart.items))
        span.set_attribute("app.customer.tier", cart.customer_tier)
        try:
            total = apply_discounts(cart)          # child spans created inside are nested
            span.set_attribute("app.quote.total", float(total))
            return total
        except Exception as exc:
            span.record_exception(exc)
            span.set_status(Status(StatusCode.ERROR, "pricing failed"))
            raise

Put IDs in attributes, not span names

Span names are grouped for analysis; "GET /orders/{id}" works, "GET /orders/12345" creates endless distinct names.

Quick check: What does start_as_current_span do?

  • Sends a metric
  • Creates a new trace every time
  • Starts a span, makes it the current (parent) context, and ends it when the block exits
  • Deletes the parent span
Answer

Starts a span, makes it the current (parent) context, and ends it when the block exits — Children nest automatically.