Java — manual instrumentation
No auto-instrumentation exists for OpenAI in Java. Manual spans with new semconv.
Before you start
These examples export to a local OpenTelemetry Collector over OTLP/gRPC. Deploy the collector first — see Code examples → Deploy an OpenTelemetry Collector.
Dependencies (pom.xml)
<dependencies>
<dependency>
<groupId>com.openai</groupId>
<artifactId>openai-java</artifactId>
<version>4.35.0</version>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>1.59.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Environment variables
Script
package com.example;
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.*;
// --- OTel imports ---
import io.opentelemetry.api.common.*;
import io.opentelemetry.api.trace.*;
import io.opentelemetry.context.Scope;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
public class GenAiManualInstrumentation {
public static void main(String[] args) {
// --- OTel setup: configure OTLP exporter, resource, and tracer ---
var cxEndpoint = System.getenv().getOrDefault("CX_OTEL_ENDPOINT",
"http://<COLLECTOR_HOST>:4317");
var exporter = OtlpGrpcSpanExporter.builder()
.setEndpoint(cxEndpoint).build();
var resource = Resource.getDefault().merge(Resource.create(
Attributes.builder()
.put("service.name", "java-genai-demo")
.put("cx.application.name", "my-genai-app")
.put("cx.subsystem.name", "my-service").build()));
var tracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(exporter).build())
.setResource(resource).build();
var otel = OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build();
var tracer = otel.getTracer("genai-manual");
// --- Your app logic ---
var openAi = OpenAIOkHttpClient.fromEnv();
var model = "gpt-4o-mini";
var systemMsg = "You are a concise assistant.";
var userMsg = "Explain distributed tracing in one sentence.";
// --- OTel: build gen_ai.input.messages in new semconv format ---
var inputJson = "[" +
"{\"role\":\"system\",\"parts\":[{\"type\":\"text\",\"content\":\"" + systemMsg + "\"}]}," +
"{\"role\":\"user\",\"parts\":[{\"type\":\"text\",\"content\":\"" + userMsg + "\"}]}]";
// OTel: create a GenAI span with required attributes
Span span = tracer.spanBuilder("chat " + model)
.setSpanKind(SpanKind.CLIENT)
.setAttribute("gen_ai.operation.name", "chat")
.setAttribute("gen_ai.provider.name", "openai")
.setAttribute("gen_ai.request.model", model)
.setAttribute("gen_ai.input.messages", inputJson)
.startSpan();
try (Scope ignored = span.makeCurrent()) {
var params = ChatCompletionCreateParams.builder()
.model(ChatModel.GPT_4O_MINI)
.maxCompletionTokens(100)
.addSystemMessage(systemMsg)
.addUserMessage(userMsg).build();
var completion = openAi.chat().completions().create(params);
var text = completion.choices().get(0).message().content().orElse("");
span.setAttribute("gen_ai.response.model", completion.model());
span.setAttribute("gen_ai.response.id", completion.id());
span.setAttribute("gen_ai.usage.input_tokens",
completion.usage().map(u -> u.promptTokens()).orElse(0L));
span.setAttribute("gen_ai.usage.output_tokens",
completion.usage().map(u -> u.completionTokens()).orElse(0L));
span.setAttribute("gen_ai.output.messages",
"[{\"role\":\"assistant\",\"parts\":[{\"type\":\"text\",\"content\":\"" +
text.replace("\"", "\\\"") + "\"}]}]");
System.out.println("Response: " + text);
} catch (Exception e) {
span.setStatus(StatusCode.ERROR, e.getMessage());
span.recordException(e);
} finally {
span.end();
}
tracerProvider.forceFlush();
tracerProvider.shutdown();
}
}
Next steps
Look up which open-source library to use for your provider in Compatibility matrix.
Theme
Light