# Manual Spans and Attributes — OpenTelemetry

Source: https://www.skillbyai.com/en/opentelemetry/i-manual

> 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).

```python
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.

**Quiz:** What does start_as_current_span do?

- [ ] Sends a metric
- [ ] Creates a new trace every time
- [x] 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.
