> ## Documentation Index
> Fetch the complete documentation index at: https://arizeai-433a7140-claude-llms-txt-2026-08-12.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Spring AI Tracing

> How to use OpenInference instrumentation with Spring AI and export traces to Arize Phoenix.

## Prerequisites

* Java 11 or higher
* (Optional) Phoenix API key if using auth

### Add Dependencies

#### **1. Gradle**

Add the dependencies to your `build.gradle`:

```groovy expandable theme={null}
dependencies {
	implementation 'org.springframework.ai:spring-ai-starter-model-openai'
	implementation 'io.micrometer:micrometer-tracing-bridge-brave:1.5.1'
	implementation project(path: ':instrumentation:openinference-instrumentation-springAI')

	// OpenTelemetry
	implementation "io.opentelemetry:opentelemetry-sdk"
	implementation "io.opentelemetry:opentelemetry-exporter-otlp"
	implementation "io.opentelemetry:opentelemetry-exporter-logging"

	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
```

## **Setup Phoenix**

<Card>
  <Tabs>
    <Tab title="Self-Host">
      Run Phoenix on your own infrastructure, backed by PostgreSQL so traces persist beyond a single process. This is the option to reach for once Phoenix is shared across a team or environment.

      The [self-hosting guide](/docs/phoenix/self-hosting) covers [Kubernetes](/docs/phoenix/self-hosting/deployment-options/kubernetes), [Helm](/docs/phoenix/self-hosting/deployment-options/kubernetes-helm), [Railway](/docs/phoenix/self-hosting/deployment-options/railway), [AWS CloudFormation](/docs/phoenix/self-hosting/deployment-options/aws-with-cloudformation), [Google Cloud Run](/docs/phoenix/self-hosting/deployment-options/google-cloud-run), [Azure](/docs/phoenix/self-hosting/deployment-options/azure), and [Render](/docs/phoenix/self-hosting/deployment-options/render), plus authentication and configuration.
    </Tab>

    <Tab title="Local">
      ```bash theme={null}
      uvx arize-phoenix serve
      ```

      No [uv](https://docs.astral.sh/uv/)? `pip install arize-phoenix && phoenix serve` does the same thing. See [Terminal setup](/docs/phoenix/environments#terminal) for customization.
    </Tab>

    <Tab title="Container">
      ```bash theme={null}
      docker run -p 6006:6006 -p 4317:4317 arizephoenix/phoenix:latest
      ```

      Images are published to [Docker Hub](https://hub.docker.com/r/arizephoenix/phoenix). See [Docker](/docs/phoenix/self-hosting/deployment-options/docker) for volumes, PostgreSQL, and other options.
    </Tab>
  </Tabs>

  Phoenix serves its UI and OTLP HTTP on port **6006**, and OTLP gRPC on port **4317**. For a local instance that's [http://localhost:6006](http://localhost:6006) — leave it running while you work.
</Card>

<Warning>
  If your Phoenix instance isn't running on localhost, adjust the endpoint in the code below as needed. If it has authentication enabled, also set `PHOENIX_API_KEY` to an API key from its **Settings** page.
</Warning>

## **Configuration for Phoenix Tracing**

```java expandable theme={null}
private static void initializeOpenTelemetry() {
        // Create resource with service name
        Resource resource = Resource.getDefault()
                .merge(Resource.create(Attributes.of(
                        AttributeKey.stringKey("service.name"), "spring-ai",
                        AttributeKey.stringKey(SEMRESATTRS_PROJECT_NAME), "spring-ai-project",
                        AttributeKey.stringKey("service.version"), "0.1.0")));

        String apiKey = System.getenv("PHOENIX_API_KEY");
        OtlpGrpcSpanExporterBuilder otlpExporterBuilder = OtlpGrpcSpanExporter.builder()
                .setEndpoint("http://localhost:4317") // adjust as needed
                .setTimeout(Duration.ofSeconds(2));
        OtlpGrpcSpanExporter otlpExporter = null;
        if (apiKey != null && !apiKey.isEmpty()) {
            otlpExporter = otlpExporterBuilder
                    .setHeaders(() -> Map.of("Authorization", String.format("Bearer %s", apiKey)))
                    .build();
        } else {
            logger.log(Level.WARNING, "Please set PHOENIX_API_KEY environment variable if auth is enabled.");
            otlpExporter = otlpExporterBuilder.build();
        }

        // Create tracer provider with both OTLP (for Phoenix) and console exporters
        tracerProvider = SdkTracerProvider.builder()
                .addSpanProcessor(BatchSpanProcessor.builder(otlpExporter)
                        .setScheduleDelay(Duration.ofSeconds(1))
                        .build())
                .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create()))
                .setResource(resource)
                .build();

        // Build OpenTelemetry SDK
        OpenTelemetrySdk.builder()
                .setTracerProvider(tracerProvider)
                .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
                .buildAndRegisterGlobal();

        System.out.println("OpenTelemetry initialized. Traces will be sent to Phoenix at http://localhost:6006");
    }
}
```

## Run Spring AI

By instrumenting your application, spans will be created whenever it is run and will be sent to the Phoenix server for collection.

```java expandable theme={null}
import com.arize.instrumentation.springAI.SpringAIInstrumentor;
import org.springframework.ai.openai.OpenAiChatModel;

initializeOpenTelemetry();

// 2. Create OITracer + instrumentor
OITracer tracer = new OITracer(tracerProvider.get("com.example.springai"), TraceConfig.getDefault());
ObservationRegistry registry = ObservationRegistry.create();
registry.observationConfig().observationHandler(new SpringAIInstrumentor(tracer));

// 3. Build Spring AI model
String apiKey = System.getenv("OPENAI_API_KEY");
OpenAiApi openAiApi = OpenAiApi.builder().apiKey(apiKey).build();
OpenAiChatOptions options = OpenAiChatOptions.builder().model("gpt-4").build();

OpenAiChatModel model = OpenAiChatModel.builder()
    .openAiApi(openAiApi)
    .defaultOptions(options)
    .observationRegistry(registry)
    .build();

// 4. Use it — traces are automatically created
ChatResponse response = model.call(new Prompt("What is the capital of France?"));
System.out.println("Response: " + response.getResult().getOutput().getContent());
```

<Check>
  Full example: [https://github.com/Arize-ai/openinference/blob/main/java/examples/spring-ai-example/src/main/java/com/arize/openinference/examples/SpringAI.java](https://github.com/Arize-ai/openinference/blob/main/java/examples/spring-ai-example/src/main/java/com/arize/openinference/examples/SpringAI.java)
</Check>

## Observe

Once configured, your OpenInference traces will be automatically sent to Phoenix where you can:

* **Monitor Performance**: Track latency, throughput, and error rates
* **Analyze Usage**: View token usage, model performance, and cost metrics
* **Debug Issues**: Trace request flows and identify bottlenecks
* **Evaluate Quality**: Run evaluations on your LLM outputs

## Resources

<CardGroup>
  <Card title="Full Example" href="https://github.com/Arize-ai/openinference/blob/main/java/examples/spring-ai-example/src/main/java/com/arize/openinference/examples/SpringAI.java" icon="github" horizontal description="Complete tracing example" />

  <Card title="OpenInference package" href="https://central.sonatype.com/artifact/com.arize/openinference-instrumentation-springAI" icon="box" horizontal description="OpenInference Java package" />
</CardGroup>
