Skip to content

Recording Errors and Status

A Python application demonstrating OpenTelemetry error handling, status codes, and exception tracking across spans.

Configuring environment

Development Environment

You can run otel-tui as OpenTelemetry Collector, which acts as a terminal OpenTelemetry viewer

docker run -p 4317:4317 -p 4318:4318 --rm -it --name otel-tui ymtdzzz/otel-tui:latest

Install packages

Create the virtual environment and install the dependencies:

uv venv && source .venv/bin/activate

requirements.txt
opentelemetry-api
opentelemetry-sdk
opentelemetry-exporter-otlp-proto-grpc

Quick install with uv

uv pip install -r https://emdneto.github.io/opentelemetry-by-example/python/exceptions/requirements.txt

Recording Exceptions

snippet_manual.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
from opentelemetry import trace
from opentelemetry.trace import StatusCode
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
    OTLPSpanExporter,
)

# Creates a resource and adds it to the tracer provider
resource = Resource.create({"service.name": "recording-exceptions-manual"})
provider = TracerProvider(resource=resource)
trace.set_tracer_provider(provider)

# Adds span processor with the OTLP exporter to the tracer provider
provider.add_span_processor(
    BatchSpanProcessor(
        OTLPSpanExporter(endpoint="http://localhost:4317", insecure=True)
    )
)

tracer = trace.get_tracer(__name__)


def process_order(
    order_id: str,
    amount: float,
    will_fail: bool = False,
) -> str:
    """
    Processes an order. If will_fail=True, simulates a downstream exception.
    Returns "OK" on success; on failure, it raises the exception.
    """
    with tracer.start_as_current_span("process_order") as span:
        span.set_attribute("order.id", order_id)
        span.set_attribute("order.amount", amount)
        span.add_event("Begin processing order")

        try:
            # deterministic “failure”
            if will_fail:
                raise ConnectionError("Simulated payment failure")

            # success path
            span.add_event("Payment succeeded")
            return "OK"

        except Exception as exc:
            # record and mark error
            span.record_exception(
                exc,
                {
                    "error.type": type(exc).__name__,
                    "error.stage": "payment processing",
                },
            )
            span.set_status(StatusCode.ERROR, f"Payment error: {exc}")
            return f"Failed to process order {order_id}: {exc}"


# deterministic runs:
process_order("ORD-1001", 120.0, will_fail=False)
process_order("ORD-1002", 55.5, will_fail=True)

Run this Python snippet

uv run https://emdneto.github.io/opentelemetry-by-example/python/exceptions/snippet_manual.py
snippet_contextmanager.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
    OTLPSpanExporter,
)

# Creates a resource and adds it to the tracer provider
resource = Resource.create(
    {"service.name": "recording-exceptions-contextmanager"}
)
provider = TracerProvider(resource=resource)
trace.set_tracer_provider(provider)

# Adds span processor with the OTLP exporter to the tracer provider
provider.add_span_processor(
    BatchSpanProcessor(
        OTLPSpanExporter(endpoint="http://localhost:4317", insecure=True)
    )
)

tracer = trace.get_tracer(__name__)

# Simulates an operation that fail to demonstrate how to record exceptions
with tracer.start_as_current_span("risky_operation_grpc") as span:
    try:
        raise ValueError("Something went wrong in gRPC operation!")
    except Exception as e:
        pass

Run this Python snippet

uv run https://emdneto.github.io/opentelemetry-by-example/python/exceptions/snippet_contextmanager.py