Integrate Events, Exceptions, and Status into Spans

OpenTelemetry (OTEL) provides support for adding Events, Exceptions, and Status into spans.

About

Spans capture timing and attributes, but they do not automatically record what happened during execution or whether it succeeded. Events, exceptions, and status fill that gap.

  • Events: Timestamped messages that mark key moments during a span, similar to log lines.
  • Status: Marks the span as OK or ERROR so failures are visible in the dashboard and alerting.
  • Exceptions: Attaches full error details (type, message, stack trace) to the span for debugging.

When to use

  • Mark key moments during execution: Add events at important steps (e.g. “cache miss”, “retrying request”) to understand what happened inside a span without creating child spans.
  • Surface errors in traces: Set an ERROR status on a span so failures are immediately visible when scanning traces in the dashboard.
  • Capture full failure context: Record exceptions alongside status so the error type, message, and stack trace are available for debugging.

How to

Add events to a span

Events mark specific moments during a span’s execution. Use them to log readable messages at key points in your code.

from opentelemetry import trace

current_span = trace.get_current_span()

if current_span.is_recording():
    current_span.add_event("Attempting the operation!")

    # Execute the operation
    # For example: result = some_operation()

    current_span.add_event("Operation completed!")
import { trace, context } from "@opentelemetry/api";

const currentSpan = trace.getSpan(context.active());

if (currentSpan) {
    currentSpan.addEvent("Attempting the operation!");

    // Execute the operation
    // For example: const result = someOperation();

    currentSpan.addEvent("Operation completed!");
}

Define span status

Set the span status to indicate success or failure of the code executed within the span.

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

current_span = trace.get_current_span()

if current_span.is_recording():
    try:
        # operation that might fail
        # For example: risky_operation()
        # If successful, you might explicitly set OK status, though it's often the default.
        # current_span.set_status(Status(StatusCode.OK))
        pass
    except:
        current_span.set_status(Status(StatusCode.ERROR, "An error occurred"))
import { trace, context, SpanStatusCode } from "@opentelemetry/api";

const currentSpan = trace.getSpan(context.active());

if (currentSpan) {
    try {
        // operation that might fail
        // For example: riskyOperation();
        // If successful, you might explicitly set OK status, though it's often the default.
        // currentSpan.setStatus({ code: SpanStatusCode.OK });
    } catch (error) {
        currentSpan.setStatus({ code: SpanStatusCode.ERROR, message: "An error occurred" });
    }
}

Log exceptions in spans

Record exceptions when they occur, alongside setting the span status, to get full failure context in the trace.

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

current_span = trace.get_current_span()

if current_span.is_recording():
    try:
        # operation that might fail
        # For example: result = 1 / 0
        pass
    # Consider catching a more specific exception in your code
    except Exception as ex:
        current_span.set_status(Status(StatusCode.ERROR, str(ex)))
        current_span.record_exception(ex)
import { trace, context, SpanStatusCode } from "@opentelemetry/api";

const currentSpan = trace.getSpan(context.active());

if (currentSpan) {
    try {
        // operation that might fail
        // For example:
        // const riskyCall = () => { throw new Error("Something went wrong!"); };
        // riskyCall();
    } catch (error) {
        // Ensure the error is an instance of Error for proper recording
        if (error instanceof Error) {
            currentSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
            currentSpan.recordException(error);
        } else {
            // Handle cases where the caught object is not an Error instance
            const errorMessage = typeof error === 'string' ? error : 'Unknown error during operation';
            currentSpan.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage });
            currentSpan.recordException(errorMessage);
        }
    }
}

Key concepts

  • add_event() / addEvent():Attaches a timestamped message to the span at the moment it’s called. Useful for logging discrete actions without creating a new span.
  • set_status() / setStatus():Sets the span’s status to OK or ERROR. An ERROR status with a message surfaces the failure in trace UIs and alerting.
  • record_exception() / recordException():Attaches full exception details (type, message, stack trace) as a span event. Always pair with set_status(ERROR) for complete failure context.
  • is_recording():Guards against no-op spans. Always check before setting attributes or events on a span retrieved from get_current_span().

Next Steps

Was this page helpful?

Questions & Discussion