Lightweight OpenTelemetry wrapper with UnifyApps-aware defaults for tracing LLM/agent applications.
Project description
unifyapps-otel
Send your LLM/agent traces to UnifyApps in one call. A thin, opinionated wrapper around OpenTelemetry that points it at your UnifyApps ingestion endpoint and stays out of your way.
Installation
pip install unifyapps-otel
# plus whatever you want to trace, e.g.:
pip install openinference-instrumentation-langchain
Quickstart
from unifyapps.otel import register
tracer_provider = register(
endpoint="https://<your-unifyapps-domain>/api-endpoint/agent-otel-exporter-otlp/<agent-id>",
api_key="your-unifyapps-api-key", # optional
auto_instrument=True, # instrument all installed OpenInference libraries
)
That's the whole configuration. Copy the endpoint from the UnifyApps
onboarding screen for your agent — it already identifies your agent, so there is
nothing else to wire up.
register(...) only sets up OpenTelemetry — it does not instrument your app
by itself. Use auto_instrument=True, or call a specific instrumentor:
tracer_provider = register(endpoint="...")
from openinference.instrumentation.langchain import LangChainInstrumentor
LangChainInstrumentor().instrument(tracer_provider=tracer_provider)
Configuration
register() takes only what a user genuinely needs:
| Argument | Required | Purpose |
|---|---|---|
endpoint |
yes* | Your UnifyApps OTLP URL (from onboarding). /v1/traces is appended if missing. |
api_key |
no | Auth Token, sent as the authorization header. Omit if your endpoint needs no auth. |
auto_instrument |
no | Instrument every installed OpenInference library. Default False. |
set_global_tracer_provider |
no | Register as the global OTel provider. Default True. |
headers |
no | Extra request headers (advanced — e.g. a non-default auth header). |
span_processors |
no | Processors run before export, to enrich/redact spans (advanced). |
* endpoint and api_key fall back to environment variables:
| Variable | Maps to |
|---|---|
UNIFYAPPS_COLLECTOR_ENDPOINT |
endpoint |
UNIFYAPPS_API_KEY |
api_key |
from unifyapps.otel import register
tracer_provider = register(auto_instrument=True) # endpoint + key from env
One trace = one export
This library exports each trace as exactly one OTLP request. When a turn's root span ends, the complete trace — root and every child — is shipped in a single request, on a background thread, so:
- the backend always receives a whole trace (a turn is never split across exports), and
- your user never waits on ingestion (the export happens off the request thread).
This is the only export model, and there is nothing to configure. Different turns ship as separate exports; that is expected.
Short-lived scripts: call
tracer_provider.shutdown()(or.force_flush()) before the process exits so buffered traces are sent. Long-running servers can rely on the global provider'satexitflush.
Sessions & users
Session and user identity are not computed by this package or derived from
the span tree. They are flat span attributes — session.id and user.id —
stamped on every span produced inside a context. This is the standard
OpenInference model for identity: the application supplies the id, and the
backend groups by it.
Wrap a conversation with using_session(...); add using_user(...) to tag who
it belongs to:
from unifyapps.otel import using_session, using_user
with using_user("user-42"), using_session(session_id="conversation-123"):
agent.invoke(...) # every span here carries user.id + session.id
Or set both at once with using_attributes(...):
from unifyapps.otel import using_attributes
with using_attributes(session_id="conversation-123", user_id="user-42"):
agent.invoke(...)
Rules of thumb:
- Use one stable
session.idfor the whole multi-turn conversation — reuse it across turns. Onesession.idspans many traces (many turns). session.idonly groups traces for observability. It does not give the model memory — feeding prior turns back to the LLM is your app's job.- These helpers stamp spans created by OpenInference instrumentors. If you
create spans by hand (e.g. wrapping a raw SDK call), set the attributes
yourself:
span.set_attribute("session.id", session_id).
Scope
Intentionally thin. It builds the TracerProvider, the OTLP HTTP exporter, and
the auth headers; guarantees one-export-per-trace; and (optionally) discovers
installed OpenInference instrumentors. Everything else — how spans are parsed and
how traces roll up into sessions — is an ingestion-side concern.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file unifyapps_otel-0.1.0.tar.gz.
File metadata
- Download URL: unifyapps_otel-0.1.0.tar.gz
- Upload date:
- Size: 15.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7795e3d10421e49dfcced25da4d6adf51c9b2dc60c5123c63d0d940e46e7178b
|
|
| MD5 |
cac238114f9c9c1d9804e08ff269c904
|
|
| BLAKE2b-256 |
3769c9f46bc3c3843c5cdd8b84915bad3931736504a97432b1c58f32453356ac
|
File details
Details for the file unifyapps_otel-0.1.0-py3-none-any.whl.
File metadata
- Download URL: unifyapps_otel-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de171b06905b53ced12b22508aae11d0ee1875883b69d48a866423d750650c40
|
|
| MD5 |
cb3b2407b13602fd62853693e5c79257
|
|
| BLAKE2b-256 |
376bda202d68ec9c18d887e219bd36cd11799221460ab9aa4447f2857da44a44
|