> ## Documentation Index
> Fetch the complete documentation index at: https://arize-ax.mintlify.dev/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>

`register()` wires these up for 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">
    For most apps, [`arize-otel-go`](https://github.com/Arize-ai/arize-otel-go) covers tracer setup in a single call. `arizeotel.Options` exposes the knobs you need without dropping to raw OTel:

    ```bash theme={null}
    go get github.com/Arize-ai/arize-otel-go
    ```

    ```go theme={null}
    import (
        "context"
        "log"
        "time"

        arizeotel "github.com/Arize-ai/arize-otel-go"
        "go.opentelemetry.io/otel/attribute"
    )

    func main() {
        ctx := context.Background()

        tp, err := arizeotel.Register(ctx, arizeotel.Options{
            ProjectName: "your-project-name",
            // Endpoint: arizeotel.EndpointArizeEurope, // for EU spaces
            // SimpleProcessor: true,                   // tests / short CLIs
            ExtraResourceAttributes: []attribute.KeyValue{
                attribute.String("deployment.environment", "prod"),
                attribute.String("model.version", "v1"),
            },
        })
        if err != nil {
            log.Printf("register tracer: %v", err)
            return
        }
        defer func() {
            shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
            defer cancel()
            _ = tp.Shutdown(shutdownCtx)
        }()
    }
    ```

    `Register` 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.                       |
    | `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.           |

    **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" />
