Skip to main content
Unomiq uses the unomiq_unit span attribute to link traces to a unit — a logical entity in your application such as a customer ID, app ID, agent ID, or tenant ID. This allows you to view and filter traces by unit in the Unomiq dashboard or Unomiq Engine API. You can also optionally set unomiq_parent_unit to create a hierarchy of entities, such as linking an app to the organization it belongs to. This guide shows how to attach the unomiq_unit and unomiq_parent_unit attributes to your spans using the OpenTelemetry SDK.

What is a Unit?

A unit represents the entity that a trace belongs to. Common examples:
Use caseUnit value
Multi-tenant SaaSTenant ID or customer ID
Agentic SystemAgent ID
Per-user trackingUser ID
Per-application trackingApplication ID
The value should be a stable identifier that uniquely represents the entity across requests. You can optionally set unomiq_parent_unit alongside unomiq_unit to express a parent-child relationship between entities. For example, in a multi-tenant SaaS application you might set unomiq_unit to an app ID and unomiq_parent_unit to the tenant or organization that app belongs to.

Setting unomiq_unit on Individual Spans

The most straightforward approach is to set the attribute directly on a span:
from opentelemetry import trace

tracer = trace.get_tracer(__name__)

with tracer.start_as_current_span("process-request") as span:
    span.set_attribute("unomiq_unit", user_id)
    span.set_attribute("unomiq_parent_unit", tenant_id)  # optional: parent entity
    # ... your code here
unomiq_parent_unit is optional. Set it when you want to place the unit within a broader entity hierarchy. This works with both manual and automatic instrumentation — as long as you have access to a span, you can set the attribute.

Setting unomiq_unit Automatically with a SpanProcessor

To attach the unit to every span without modifying each call site, use a custom SpanProcessor. This is useful when the unit is available from a request context (e.g., an HTTP header, JWT claim, or path parameter).
from opentelemetry.sdk.trace import SpanProcessor


class UnitSpanProcessor(SpanProcessor):
    """Attaches unomiq_unit to every span from a context resolver."""

    def __init__(self, resolve_unit):
        """
        Args:
            resolve_unit: A callable that returns the current unit value,
                          or None if no unit is available.
        """
        self._resolve_unit = resolve_unit

    def on_start(self, span, parent_context=None):
        unit = self._resolve_unit()
        if unit:
            span.set_attribute("unomiq_unit", unit)

    def on_end(self, span):
        pass

    def shutdown(self):
        pass

    def force_flush(self, timeout_millis=None):
        pass

Example: Resolving Unit from a Flask Request

from flask import request, Flask
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider

app = Flask(__name__)


def resolve_unit_from_request():
    """Extract the unit from the current request context."""
    try:
        # Option 1: From a request header
        return request.headers.get("X-Customer-Id")

        # Option 2: From a JWT claim (after auth middleware)
        # return g.current_user.get("tenant_id")

        # Option 3: From a path parameter
        # return request.view_args.get("customer_id")
    except RuntimeError:
        # Outside of a request context
        return None


# Register the processor with the tracer provider
provider = TracerProvider()
provider.add_span_processor(UnitSpanProcessor(resolve_unit_from_request))
trace.set_tracer_provider(provider)

Example: Resolving Unit from Django

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider

# Use threading.local or contextvars to store the unit per-request
import contextvars

_current_unit = contextvars.ContextVar("current_unit", default=None)


# In your Django middleware:
class UnitMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        _current_unit.set(request.headers.get("X-Customer-Id"))
        return self.get_response(request)


# Register the processor
provider = TracerProvider()
provider.add_span_processor(UnitSpanProcessor(lambda: _current_unit.get()))
trace.set_tracer_provider(provider)

Summary

MethodWhen to use
span.set_attribute()One-off spans where you have the unit value at hand
UnitSpanProcessorAutomatically attach unit to all spans from request context
unomiq_unit must be set as a span attribute. Resource attributes and collector-level processors are not supported for this field.