# Observe-only frameworks

> Send traces from LlamaIndex, CrewAI or anything instrumented with OpenInference or OpenLLMetry to Pyrula Cloud over OTLP, and what you get and do not get without an adapter.

Source: https://docs.pyrula.io/getting-started/recipes/observe-only/

Pyrula has no adapter for LlamaIndex or CrewAI, so their calls are not journaled and cannot be
replayed, paused or cancelled by Pyrula. If you already trace them with OpenTelemetry you can
still see their runs, tokens and cost in Pyrula Cloud: the Cloud intake reads GenAI spans over
OTLP/HTTP. This is **observe-only**.

| | Observe-only (this page) | Adapter-backed |
|---|---|---|
| Journaled, replayable, resumable | No | Yes, inside a Pyrula run |
| What Cloud shows | A run per trace, a step per model, tool and agent span, tokens, cost | The run's full event stream |
| Cancel, terminate, answering a pause | Disabled on imported runs | Available |
| Prompt and completion text | Never imported | See [What leaves your runtime](https://docs.pyrula.io/getting-started/what-leaves-your-runtime.md) |
| Code change | A tracer provider and an instrumentor | An import or a wrapper |

For comparison, the adapter-backed paths are
[LangGraph](https://docs.pyrula.io/agents/integrations/langgraph.md), [LangChain chat models](https://docs.pyrula.io/agents/integrations/durable-vs-not.md#durable_chat_model),
[Pydantic AI](https://docs.pyrula.io/agents/integrations/pydantic-ai.md) and the provider drop-ins on
[LLM providers](https://docs.pyrula.io/getting-started/recipes/llm-providers.md). The
[guarantee matrix](https://docs.pyrula.io/agents/integrations/guarantees.md) states what each guarantees.

## Point the exporter at Cloud

The environment variables are the ones on [Send existing traces](https://docs.pyrula.io/getting-started/otel.md#2-point-the-exporter-at-cloud):
the endpoint, `http/protobuf`, your project key as a bearer header, and
`deployment.environment`. Set a stable `service.name`; Cloud groups runs by it.

## OpenInference (LlamaIndex, CrewAI and others)

[OpenInference](https://github.com/Arize-ai/openinference) publishes instrumentors for LlamaIndex,
CrewAI, LangChain and others. Install the one for your framework and add a span processor that
exports to Cloud. Cloud reads `openinference.span.kind` (`LLM`, `EMBEDDING`, `TOOL`, `AGENT`),
`llm.model_name`, `llm.token_count.*`, `tool.name` and `agent.name`; `CHAIN`, `RETRIEVER`,
`RERANKER`, `GUARDRAIL` and `EVALUATOR` spans are dropped.

```python
# pip install openinference-instrumentation-llama-index opentelemetry-sdk \
#   opentelemetry-exporter-otlp-proto-http
from openinference.instrumentation.llama_index import LlamaIndexInstrumentor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))  # reads the OTEL_* variables
LlamaIndexInstrumentor().instrument(tracer_provider=provider)
```

For CrewAI, install `openinference-instrumentation-crewai` and use `CrewAIInstrumentor` the
same way. The exporter half is the same for every framework, and it is the half that runs here:

```python
import os

from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

os.environ.setdefault("OTEL_EXPORTER_OTLP_ENDPOINT", "https://api.pyrula.io/otel")
os.environ.setdefault("OTEL_EXPORTER_OTLP_PROTOCOL", "http/protobuf")

provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
```

Nothing here has been run with LlamaIndex or CrewAI installed. The instrumentor names and calls
above come from OpenInference, so check its documentation for your framework's version. OpenInference
attaches prompts and completions to spans by default; Cloud does not import them, and OpenInference's
`OPENINFERENCE_HIDE_INPUTS` and `OPENINFERENCE_HIDE_OUTPUTS` settings are meant to keep them out
of the export; confirm in its documentation.

## OpenLLMetry

OpenLLMetry (Traceloop) exports GenAI spans, and Cloud reads its older `llm.*` and
`*.prompt_tokens` attribute spellings as well as the standard `gen_ai.*` ones. Point its OTLP
exporter at the endpoint above with the same variables. Anything else that emits GenAI spans over
OTLP/HTTP takes the same route.

## If the app also runs on Pyrula

An app that already reports through a Pyrula runtime does not need this: the runtime's connector
reports its runs with replay included, and importing the same work as traces would count it twice
toward runs per month. Traces that carry a Pyrula run id are skipped for that reason.
