> ## Documentation Index
> Fetch the complete documentation index at: https://arize-ax.mintlify.site/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Configure Your Tracer

> Understand OpenTelemetry and OpenInference, configure span processors, resource attributes, and multi-project routing

Take full control of OpenTelemetry. The getting started pages cover `register()` and OpenInference integrations — this page is for when you need more: batch processing for production, routing spans to multiple projects, or configuring resource attributes directly via the [OpenTelemetry](https://opentelemetry.io) SDK.

# OpenInference Instrumentation Packages

OpenInference provides auto-instrumentors for popular frameworks. Install the package for your provider and attach it once — `.instrument()` in Python, `registerInstrumentations({...})` / package-specific setup in JS/TS, or `option.WithMiddleware(...)` on the SDK client in Go — and every call is traced automatically.

<Accordion title="Python packages">
  | Package                                     | Description                               |
  | :------------------------------------------ | :---------------------------------------- |
  | `openinference-semantic-conventions`        | Semantic conventions for tracing LLM apps |
  | `openinference-instrumentation-openai`      | OpenAI SDK                                |
  | `openinference-instrumentation-anthropic`   | Anthropic SDK                             |
  | `openinference-instrumentation-langchain`   | LangChain                                 |
  | `openinference-instrumentation-llama-index` | LlamaIndex                                |
  | `openinference-instrumentation-bedrock`     | AWS Bedrock                               |
  | `openinference-instrumentation-mistralai`   | MistralAI                                 |
  | `openinference-instrumentation-dspy`        | DSPy                                      |
  | `openinference-instrumentation-crewai`      | CrewAI                                    |
  | `openinference-instrumentation-litellm`     | LiteLLM                                   |
  | `openinference-instrumentation-groq`        | Groq                                      |
  | `openinference-instrumentation-instructor`  | Instructor                                |
  | `openinference-instrumentation-haystack`    | Haystack                                  |
  | `openinference-instrumentation-guardrails`  | Guardrails AI                             |
  | `openinference-instrumentation-vertexai`    | VertexAI                                  |
</Accordion>

<Accordion title="JavaScript packages">
  | Package                                            | Description            |
  | :------------------------------------------------- | :--------------------- |
  | `@arizeai/openinference-semantic-conventions`      | Semantic conventions   |
  | `@arizeai/openinference-core`                      | Core utility functions |
  | `@arizeai/openinference-instrumentation-openai`    | OpenAI SDK             |
  | `@arizeai/openinference-instrumentation-langchain` | LangChain.js           |
  | `@arizeai/openinference-vercel`                    | Vercel AI SDK          |
</Accordion>

<Accordion title="Go packages">
  | Package                                                                               | Description                                                                                                          |
  | :------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------- |
  | `github.com/Arize-ai/arize-otel-go`                                                   | One-line TracerProvider setup pointed at Arize AX                                                                    |
  | `github.com/Arize-ai/openinference/go/openinference-semantic-conventions`             | Semantic conventions (attribute keys, span kinds)                                                                    |
  | `github.com/Arize-ai/openinference/go/openinference-instrumentation`                  | Context helpers (`WithSession`, `WithUser`, `WithMetadata`, `WithTags`, `WithSuppression`) and `TraceConfig` masking |
  | `github.com/Arize-ai/openinference/go/openinference-instrumentation-openai-go`        | Auto-instrumentor middleware for [`openai/openai-go`](https://github.com/openai/openai-go)                           |
  | `github.com/Arize-ai/openinference/go/openinference-instrumentation-anthropic-sdk-go` | Auto-instrumentor middleware for [`anthropics/anthropic-sdk-go`](https://github.com/anthropics/anthropic-sdk-go)     |
</Accordion>

# Set up your tracer

The quickest setup is a single helper that creates an OpenTelemetry `TracerProvider` wired to Arize AX, attaches the span exporter, and sets it as the global provider. Each SDK reads your space, API key, and project from the environment, so the minimal call needs no explicit credentials. For the full Python SDK reference, see [OpenTelemetry Tracing](/api-clients/python/version-8/tracing).

<Tabs>
  <Tab title="Python">
    `arize-otel`'s `register()` returns a `TracerProvider` you hand to each OpenInference instrumentor's `.instrument(tracer_provider=...)` call. All parameters are keyword-only:

    | Parameter                    | Default                                        | Description                                                                                                                                |
    | :--------------------------- | :--------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------- |
    | `space_id`                   | `ARIZE_SPACE_ID` env var                       | Arize space the spans are sent to.                                                                                                         |
    | `api_key`                    | `ARIZE_API_KEY` env var                        | Arize API key used to authenticate.                                                                                                        |
    | `project_name`               | `ARIZE_PROJECT_NAME` env var, else `"default"` | Project the spans are grouped under. This is the only project/name argument — `register()` has no `model_id` or `model_version` parameter. |
    | `endpoint`                   | `ARIZE_COLLECTOR_ENDPOINT` env var, else Arize | OTLP collector endpoint spans are exported to.                                                                                             |
    | `transport`                  | `Transport.GRPC`                               | Export transport: `Transport.GRPC`, `Transport.HTTP`, or `Transport.HTTPS`.                                                                |
    | `batch`                      | `True`                                         | Use a `BatchSpanProcessor` (production) rather than a `SimpleSpanProcessor`.                                                               |
    | `headers`                    | `None`                                         | Extra headers to include on requests to the collector.                                                                                     |
    | `set_global_tracer_provider` | `True`                                         | Set the returned provider as the global OpenTelemetry default.                                                                             |
    | `verbose`                    | `True`                                         | Print the tracing configuration to stdout on startup.                                                                                      |
    | `log_to_console`             | `False`                                        | Also export spans to the console, useful for debugging.                                                                                    |
    | `auto_instrument`            | `False`                                        | Automatically instrument every installed OpenInference library.                                                                            |
    | `span_processors`            | `None`                                         | Additional span processors to run before the Arize exporter.                                                                               |

    ```python theme={null}
    from arize.otel import register

    tracer_provider = register(
        space_id="your-space-id",     # or the ARIZE_SPACE_ID env var
        api_key="your-api-key",       # or the ARIZE_API_KEY env var
        project_name="my-llm-app",    # or the ARIZE_PROJECT_NAME env var
    )
    ```
  </Tab>

  <Tab title="JS/TS">
    The JavaScript SDK has no single `register()` helper — you configure an OpenTelemetry provider (or a framework hook such as Vercel's `registerOTel`) and route spans to a project with the **project-name resource attribute**. The settings that matter:

    | Setting                            | Where                        | Description                                                                                                                                                          |
    | :--------------------------------- | :--------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `SEMRESATTRS_PROJECT_NAME`         | Resource attribute           | Project the spans are grouped under. Import from `@arizeai/openinference-semantic-conventions`; without it spans land in `default`. There is no `model_id` argument. |
    | `arize-space-id` / `arize-api-key` | OTLP headers / gRPC metadata | Authenticate with your Arize space.                                                                                                                                  |
    | exporter `url`                     | OTLP exporter                | `https://otlp.arize.com/v1`.                                                                                                                                         |

    See the JS/TS tab under [Configure the OTel tracer directly](#configure-the-otel-tracer-directly) for a complete `NodeTracerProvider` example.
  </Tab>

  <Tab title="Go">
    [`arize-otel-go`](https://github.com/Arize-ai/arize-otel-go)'s `arizeotel.Register(ctx, arizeotel.Options{...})` sets the required `openinference.project.name` resource attribute, installs `otel.SetTracerProvider`, defaults to a `BatchSpanProcessor`, and falls back to environment variables when the matching `Options` fields are unset:

    | Field                     | Default                                         | Description                                                                             |
    | ------------------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------- |
    | `SpaceID`                 | `$ARIZE_SPACE_ID`                               | Required.                                                                               |
    | `APIKey`                  | `$ARIZE_API_KEY`                                | Required.                                                                               |
    | `ProjectName`             | `$ARIZE_PROJECT_NAME` or `"default"`            | Sets the `openinference.project.name` resource attribute. There is no `model_id` field. |
    | `Endpoint`                | `$ARIZE_COLLECTOR_ENDPOINT` or `otlp.arize.com` | Use `arizeotel.EndpointArizeEurope` for EU spaces.                                      |
    | `ExtraHeaders`            | *none*                                          | Merged into OTLP request headers alongside the required `space_id` / `api_key`.         |
    | `ExtraResourceAttributes` | *none*                                          | Appended to the OTel `Resource`.                                                        |
    | `Insecure`                | `false`                                         | Disables TLS — only for on-prem / local collectors.                                     |
    | `SimpleProcessor`         | `false` (batched)                               | Synchronous export. Useful for tests and short CLIs.                                    |
    | `SkipSetGlobal`           | `false`                                         | Skip `otel.SetTracerProvider`. Set if you manage the global yourself.                   |

    ```go theme={null}
    tp, err := arizeotel.Register(ctx, arizeotel.Options{
        ProjectName: "your-project-name",   // or the ARIZE_PROJECT_NAME env var
    })
    ```
  </Tab>
</Tabs>

These helpers cover most apps — but when you need more control over the tracer itself, configure OpenTelemetry directly:

# Configure the OTel Tracer Directly

<Tabs>
  <Tab title="Python">
    ```bash theme={null}
    pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-grpc openinference-semantic-conventions openinference-instrumentation-openai
    ```

    ```python theme={null}
    import os
    from opentelemetry import trace as trace_api
    from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
    from opentelemetry.sdk import trace as trace_sdk
    from opentelemetry.sdk.trace.export import ConsoleSpanExporter, BatchSpanProcessor
    from opentelemetry.sdk.resources import Resource
    from openinference.instrumentation.openai import OpenAIInstrumentor

    # Authentication — read credentials from environment
    ARIZE_SPACE_ID = os.environ["ARIZE_SPACE_ID"]
    ARIZE_API_KEY = os.environ["ARIZE_API_KEY"]
    headers = f"arize-space-id={ARIZE_SPACE_ID},arize-api-key={ARIZE_API_KEY}"
    os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = headers

    # Resource attributes describe the source of telemetry
    trace_attributes = {
        "model_id": "your-project-name",  # Maps to project in Arize AX
        "model_version": "v1",
    }

    endpoint = "https://otlp.arize.com/v1"

    # Set up the tracer provider
    tracer_provider = trace_sdk.TracerProvider(
        resource=Resource(attributes=trace_attributes)
    )
    tracer_provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(endpoint)))
    tracer_provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
    trace_api.set_tracer_provider(tracer_provider=tracer_provider)

    tracer = trace_api.get_tracer(__name__)

    # Auto-instrument
    OpenAIInstrumentor().instrument()
    ```
  </Tab>

  <Tab title="JS/TS">
    ```bash theme={null}
    npm install @arizeai/openinference-instrumentation-openai @opentelemetry/api @opentelemetry/instrumentation @opentelemetry/resources @opentelemetry/sdk-trace-base @opentelemetry/sdk-trace-node @opentelemetry/exporter-trace-otlp-grpc @grpc/grpc-js
    ```

    ```typescript theme={null}
    import { registerInstrumentations } from "@opentelemetry/instrumentation";
    import { OpenAIInstrumentation } from "@arizeai/openinference-instrumentation-openai";
    import { ConsoleSpanExporter } from "@opentelemetry/sdk-trace-base";
    import { NodeTracerProvider, BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
    import { resourceFromAttributes } from "@opentelemetry/resources";
    import { OTLPTraceExporter as GrpcOTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-grpc";
    import { Metadata } from "@grpc/grpc-js";

    const metadata = new Metadata();
    metadata.set("arize-space-id", "your-space-id");
    metadata.set("arize-api-key", "your-api-key");

    const provider = new NodeTracerProvider({
      resource: resourceFromAttributes({
        "model_id": "your-project-name",
        "model_version": "v1",
      }),
      spanProcessors: [
        new BatchSpanProcessor(new ConsoleSpanExporter()),
        new BatchSpanProcessor(
          new GrpcOTLPTraceExporter({
            url: "https://otlp.arize.com/v1",
            metadata,
          })
        ),
      ],
    });

    registerInstrumentations({
      instrumentations: [new OpenAIInstrumentation({})],
    });

    provider.register();
    ```
  </Tab>

  <Tab title="Go">
    `arize-otel-go`'s `arizeotel.Register` (see [Set up your tracer](#set-up-your-tracer)) covers most apps in one call. When you need **multiple exporters** (Arize + a local console for debugging, or Arize + Datadog), drop to raw `sdktrace.NewTracerProvider`:

    ```go theme={null}
    import (
        "context"
        "os"

        "go.opentelemetry.io/otel"
        "go.opentelemetry.io/otel/attribute"
        "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
        "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
        "go.opentelemetry.io/otel/sdk/resource"
        sdktrace "go.opentelemetry.io/otel/sdk/trace"
    )

    ctx := context.Background()

    arizeExporter, _ := otlptracehttp.New(ctx,
        otlptracehttp.WithEndpoint("otlp.arize.com"),
        otlptracehttp.WithHeaders(map[string]string{
            "space_id": os.Getenv("ARIZE_SPACE_ID"),
            "api_key":  os.Getenv("ARIZE_API_KEY"),
        }),
    )
    consoleExporter, _ := stdouttrace.New(stdouttrace.WithPrettyPrint())

    // openinference.project.name is required so the collector can route spans to the right project.
    res, _ := resource.New(ctx, resource.WithAttributes(
        attribute.String("openinference.project.name", "your-project-name"),
        attribute.String("model.version", "v1"),
    ))

    tp := sdktrace.NewTracerProvider(
        sdktrace.WithBatcher(arizeExporter),    // production export to Arize
        sdktrace.WithBatcher(consoleExporter),  // local debugging — drop in production
        sdktrace.WithResource(res),
    )
    otel.SetTracerProvider(tp)
    defer tp.Shutdown(ctx) // flushes batched spans before exit
    ```
  </Tab>
</Tabs>

### Key Concepts

* **Resource attributes** describe the source of telemetry (service, model, environment). Set once on the TracerProvider.
* **Span attributes** describe a single span. Set per-span in your code.
* **Span processors** filter, batch, and perform operations on spans before export.
* **Project name resource attribute.** The canonical OpenInference key is `openinference.project.name` — exposed as `ResourceAttributes.PROJECT_NAME` from `openinference.semconv.resource` in Python, `SEMRESATTRS_PROJECT_NAME` from `@arizeai/openinference-semantic-conventions` in JS/TS, and set automatically by `arize-otel-go`'s `Options.ProjectName` in Go. The Arize collector also accepts `model_id` as a legacy alias (shown in some older Python/JS examples on this page); both route spans to the same project.
* **OTLP auth headers.** The Arize collector accepts both `space_id` / `api_key` (canonical, what `arize-otel-go` sends) and the `arize-space-id` / `arize-api-key` aliases shown in the older Python/JS examples. If you copy the raw-OTel Go snippet below into a stack that already uses the `arize-` prefixed form, pick one and stay consistent.

The most important processor decision for production is which span processor to use:

# Batch vs Simple Span Processor

A **span processor** controls when and how spans are exported. Choose based on your environment:

| Property                | BatchSpanProcessor                         | SimpleSpanProcessor                |
| :---------------------- | :----------------------------------------- | :--------------------------------- |
| **Best for**            | Production & staging                       | Local debugging, demos, CI         |
| **Export behavior**     | Async, in batches                          | Each span immediately (sync)       |
| **Impact on latency**   | Low — work done off the request path       | Higher — export blocks the request |
| **Throughput**          | High, optimized for volume                 | Low, can bottleneck under load     |
| **Reliability on exit** | Requires `force_flush()` / `shutdown()`    | Spans exported immediately         |
| **Visibility speed**    | Slight delay (buffering)                   | Immediate                          |
| **Failure surfacing**   | Export failures logged in background       | Failures raised inline             |
| **Tuning**              | Configurable (batch size, delay, timeouts) | Minimal                            |

<Warning>
  The `SimpleSpanProcessor` is synchronous and blocking. Use `BatchSpanProcessor` for production.
</Warning>

Once your tracer is running, you'll often want to attach more context to the span currently in flight:

# Get the Current Span

Access the current span at any point to enrich it with additional information:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from opentelemetry import trace

    current_span = trace.get_current_span()
    # enrich current_span with attributes, events, etc.
    ```
  </Tab>

  <Tab title="JS/TS">
    ```typescript theme={null}
    import { trace } from "@opentelemetry/api";

    const activeSpan = trace.getActiveSpan();
    // enrich activeSpan with attributes, events, etc.
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    import "go.opentelemetry.io/otel/trace"

    currentSpan := trace.SpanFromContext(ctx)
    // enrich currentSpan with attributes, events, etc.
    ```
  </Tab>
</Tabs>

Running multiple apps from one codebase, or splitting traffic across environments? You can split spans across projects:

# Route Spans to Multiple Projects

To route traces from one application to multiple Arize spaces or projects, use `register_with_routing` from `arize-otel`:

```bash theme={null}
pip install arize-otel
```

```python theme={null}
from arize.otel import register_with_routing, set_routing_context

# Register once with a single API key — routing happens per-context
tracer_provider = register_with_routing(
    api_key="your-api-key",
)

# Route specific operations to a different space + project
with set_routing_context(space_id="other-space-id", project_name="other-project"):
    # Spans created in this block are routed to "other-space-id" / "other-project"
    ...
```

<Info>
  `register_with_routing` uses `ARIZE_API_KEY` from your environment if `api_key` isn't passed. Both `space_id` and `project_name` must be set inside `set_routing_context` — otherwise routing won't be applied.

  **Python-only today.** For JS/TS or Go apps — or more complex routing (e.g., by span attribute) — route at the OTel Collector layer instead. See [OTEL Collector deployment patterns](/ax/instrument/advanced-patterns#otel-collector).
</Info>

If you operate a centralized OpenTelemetry Collector serving many teams or spaces, see the [shared-collector pattern](/ax/instrument/advanced-patterns#alternative-for-centralized-gateway-collectors) that forwards `arize-space-id` from inbound request metadata — avoids redeploying the collector each time a new space is added.

***

## Next step

Keep sensitive data out of your traces with masking and PII redaction:

<Card title="Next: Mask and Redact Data" icon="arrow-right" href="/ax/instrument/mask-and-redact-data" />
