TraceAI Java SDK Setup for Future AGI Observability

Set up TraceAI for Java applications. Initialize the tracer, configure credentials, and instrument your LLM clients, vector databases, and frameworks.

📝
TL;DR
  • TraceAI.init() or TraceAI.initFromEnvironment() to start
  • Every integration is a Traced<X> wrapper around your existing client
  • Spans export to FutureAGI via OTLP HTTP, batched every 5 seconds
  • Thread-local context (session, user, tags) applied to spans created through FITracer on the current thread
  • Distributed via JitPack (Maven/Gradle)

How it works

The Java SDK wraps supported client operations with Traced* classes. Initialize TraceAI once, then wrap the client you want to trace. Captured fields depend on the wrapper and operation; token counts require usage data from the provider.

Warning

Content is captured by default. Input/output value flags and structured-message flags are separate. Error details and integration-specific attributes, including Cohere preambles, tool arguments and rerank queries, can still contain sensitive text even with those flags enabled. Do not export sensitive workloads that require complete content suppression. See the configuration reference.

// 1. Initialize once
TraceAI.init(TraceConfig.builder()
    .baseUrl("https://api.futureagi.com")
    .apiKey(System.getenv("FI_API_KEY"))
    .secretKey(System.getenv("FI_SECRET_KEY"))
    .projectName("my-project")
    .build());

// 2. Wrap your client
OpenAIClient client = OpenAIOkHttpClient.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .build();
TracedOpenAIClient traced = new TracedOpenAIClient(client);

// 3. Use it normally - spans are created automatically
ChatCompletion response = traced.createChatCompletion(params);

Open your project in Future AGI to inspect the resulting span.

Installation

The configuration below uses JitPack. main-SNAPSHOT is mutable, so it can change between builds; use an immutable package version compatible with your client SDK for reproducible deployments. Add the JitPack repository to your build:

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>
repositories {
    maven { url 'https://jitpack.io' }
}

Then add the core dependency plus whichever integration you need:

<!-- Core (required) -->
<dependency>
    <groupId>com.github.future-agi.traceAI</groupId>
    <artifactId>traceai-java-core</artifactId>
    <version>main-SNAPSHOT</version>
</dependency>

<!-- Pick your integration, e.g. OpenAI -->
<dependency>
    <groupId>com.github.future-agi.traceAI</groupId>
    <artifactId>traceai-java-openai</artifactId>
    <version>main-SNAPSHOT</version>
</dependency>
// Core (required)
implementation 'com.github.future-agi.traceAI:traceai-java-core:main-SNAPSHOT'

// Pick your integration, e.g. OpenAI
implementation 'com.github.future-agi.traceAI:traceai-java-openai:main-SNAPSHOT'

Requirements: Java 17+


Initialization

From code

import ai.traceai.TraceAI;
import ai.traceai.TraceConfig;

TraceAI.init(TraceConfig.builder()
    .baseUrl("https://api.futureagi.com")
    .apiKey("your-fi-api-key")
    .secretKey("your-fi-secret-key")
    .projectName("my-project")
    .build());

From environment variables

// Reads FI_BASE_URL, FI_API_KEY, FI_SECRET_KEY, FI_PROJECT_NAME
TraceAI.initFromEnvironment();

The builder falls back to environment variables for any field you don’t set explicitly. So you can mix both:

TraceAI.init(TraceConfig.builder()
    .projectName("my-project")          // explicit
    .enableConsoleExporter(true)         // explicit
    // apiKey, secretKey, baseUrl read from env vars
    .build());

Getting the tracer

After initialization, get the FITracer instance to pass to wrappers:

import ai.traceai.FITracer;

FITracer tracer = TraceAI.getTracer();

If you call getTracer() before init(), it throws IllegalStateException.


TraceConfig reference

Builder methodTypeDefaultWhat it does
baseUrl(String)String$FI_BASE_URLFutureAGI OTLP endpoint
apiKey(String)String$FI_API_KEYAPI key for authentication
secretKey(String)String$FI_SECRET_KEYSecret key for authentication
projectName(String)String$FI_PROJECT_NAMEProject name in FutureAGI dashboard
serviceName(String)StringprojectNameOpenTelemetry service.name resource attribute
hideInputs(boolean)booleanfalseSuppress input values and raw inputs set through FITracer
hideOutputs(boolean)booleanfalseSuppress output values and raw outputs set through FITracer
hideInputMessages(boolean)booleanfalseSuppress structured input messages
hideOutputMessages(boolean)booleanfalseSuppress structured output messages
enableConsoleExporter(boolean)booleanfalsePrint spans to console for debugging
batchSize(int)int512Spans per export batch
exportIntervalMs(long)long5000How often to flush spans (ms)

The input and output flags do not suppress structured messages; set the corresponding message flags separately. Integration-specific attributes and error details may also contain data and are not covered by these flags. Review the data your integration exports before tracing sensitive content.


FITracer methods

FITracer is what the Traced* wrappers use internally. You can also use it for custom spans:

import ai.traceai.FISpanKind;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;

FITracer tracer = TraceAI.getTracer();

// Manual span
Span span = tracer.startSpan("my-operation", FISpanKind.CHAIN);
try (Scope scope = span.makeCurrent()) {
    tracer.setInputValue(span, "input text");
    // ... do work ...
    tracer.setOutputValue(span, "output text");
    span.setStatus(io.opentelemetry.api.trace.StatusCode.OK);
} catch (Exception e) {
    tracer.setError(span, e);
    throw e;
} finally {
    span.end();
}

Or use the trace() helper for less boilerplate:

String result = tracer.trace("my-operation", FISpanKind.CHAIN, () -> {
    return doSomething();
});

Available methods

MethodWhat it does
startSpan(name, kind)Creates and starts a new span
startSpan(name, kind, parentContext)Creates a child span under a specific parent
setInputValue(span, value)Sets input.value attribute (respects hideInputs)
setOutputValue(span, value)Sets output.value attribute (respects hideOutputs)
setRawInput(span, object)Sets fi.raw_input as serialized JSON
setRawOutput(span, object)Sets fi.raw_output as serialized JSON
setInputMessages(span, messages)Sets structured input messages (role + content)
setOutputMessages(span, messages)Sets structured output messages (role + content)
setTokenCounts(span, prompt, completion, total)Sets token count attributes
setError(span, throwable)Records exception and sets ERROR status
trace(name, kind, supplier)Executes operation in a span, returns result
trace(name, kind, runnable)Executes void operation in a span
message(role, content)Helper to build message maps

FISpanKind

Every span has a kind that identifies the type of AI operation:

KindUsed for
LLMChat completions, text generation
EMBEDDINGText-to-vector conversions
RETRIEVERVector search, document retrieval
VECTOR_DBVector store writes (upsert, delete)
RERANKERReranking retrieved documents
CHAINSequential pipeline steps
AGENTAutonomous agent operations
TOOLLLM tool/function calls
GUARDRAILSafety and validation checks
WORKFLOWCustom pipeline steps
EVALUATORQuality scoring
CONVERSATIONVoice and conversational AI
UNKNOWNUnspecified

Context attributes

Attach session IDs, user IDs, metadata, and tags to all spans created within a scope using thread-local context:

import ai.traceai.ContextAttributes;

try (var session = ContextAttributes.usingSession("session-123");
     var user = ContextAttributes.usingUser("user-456");
     var meta = ContextAttributes.usingMetadata(Map.of("env", "prod", "version", "2.1"));
     var tags = ContextAttributes.usingTags(List.of("rag", "production"))) {

    // FITracer spans created on this thread receive these context attributes.
    TracedOpenAIClient traced = new TracedOpenAIClient(client);
    traced.createChatCompletion(params);
} catch (Exception e) {
    throw new RuntimeException(e);
}
// Attributes are cleared when the try block exits

These values are thread-local and apply through FITracer. They are not automatically propagated to executor tasks, reactive callbacks or other threads. Establish the context on the thread that creates the spans.


Shutdown

TraceAI registers a JVM shutdown hook that flushes pending spans and shuts down the exporter. For most applications, you don’t need to do anything.

If you need to flush spans before the JVM exits (e.g., in a test or short-lived CLI tool):

TraceAI.shutdown();

This flushes all pending spans (up to 10 second timeout) and resets the tracer. After calling shutdown(), you can call init() again if needed.


Available integrations

Was this page helpful?

Questions & Discussion