☕ Java Integration Guide

Learn how to instrument your Java applications with OpenTelemetry to send distributed traces to TraceKit.

Zero-Code Instrumentation!

Use the OpenTelemetry Java Agent for automatic instrumentation with ZERO code changes. Just add the agent at startup and everything is traced automatically.

📋

Prerequisites

  • • Java 8 or higher (Java 11+ recommended)
  • • An active TraceKit account
  • • A generated API key from the API Keys page

🔍 What Gets Traced Automatically?

With the Java Agent, these operations are traced automatically with ZERO code changes:

ComponentSetupAuto-Traced?
HTTP EndpointsJava Agent (zero code)✓ Yes
JDBC QueriesJava Agent (zero code)✓ Yes
HTTP Client CallsJava Agent (zero code)✓ Yes
Spring BootJava Agent (zero code)✓ Yes
Kafka/RabbitMQJava Agent (zero code)✓ Yes
Custom Business LogicManual spans (optional)Manual

📦 Installation (Java Agent - Recommended)

Download the OpenTelemetry Java Agent - it provides automatic instrumentation with zero code changes:

# Download the latest OpenTelemetry Java Agent
curl -L https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar \
  -o opentelemetry-javaagent.jar

⚙️ Basic Setup (Java Agent)

Simply add the agent when starting your Java application:

java -javaagent:opentelemetry-javaagent.jar \
     -Dotel.service.name=my-java-app \
     -Dotel.exporter.otlp.endpoint={ appURL }/v1/traces \
     -Dotel.exporter.otlp.headers=X-API-Key=your_api_key_here \
     -Dotel.exporter.otlp.protocol=http/protobuf \
     -jar your-application.jar

# That's it! Your app is now fully traced with zero code changes.

That's it!

Your application is now fully instrumented with ZERO code changes!

🚀 Framework Integration

The Java Agent automatically instruments popular frameworks. No code changes needed!

Spring Boot

Your existing Spring Boot app works without changes:

// Your existing Spring Boot application - NO CHANGES NEEDED!
@RestController
@RequestMapping("/api")
public class UserController {

    @GetMapping("/users")
    public List<User> getUsers() {
        // This endpoint is automatically traced!
        return userService.findAll();
    }

    @PostMapping("/users")
    public User createUser(@RequestBody User user) {
        // This endpoint is also automatically traced!
        return userService.save(user);
    }
}

// Just run with the Java Agent and everything is traced!

Quarkus

Quarkus applications are automatically traced:

// Your existing Quarkus application - NO CHANGES NEEDED!
@Path("/api/users")
public class UserResource {

    @Inject
    UserService userService;

    @GET
    public List<User> list() {
        // Automatically traced!
        return userService.listAll();
    }

    @POST
    public User create(User user) {
        // Automatically traced!
        return userService.save(user);
    }
}

Manual SDK Setup (Alternative)

If you prefer programmatic configuration instead of the Java Agent, you can use the SDK directly:

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-sdk</artifactId>
        <version>1.32.0</version>
    </dependency>
    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-exporter-otlp</artifactId>
        <version>1.32.0</version>
    </dependency>
</dependencies>

SDK Initialization

import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;

public class TracingConfig {

    public static OpenTelemetry initializeOpenTelemetry(String serviceName) {
        Resource resource = Resource.getDefault()
            .merge(Resource.create(Attributes.of(
                ResourceAttributes.SERVICE_NAME, serviceName
            )));

        OtlpHttpSpanExporter spanExporter = OtlpHttpSpanExporter.builder()
            .setEndpoint("{ appURL }/v1/traces")
            .addHeader("X-API-Key", System.getenv("TRACEKIT_API_KEY"))
            .build();

        SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
            .addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())
            .setResource(resource)
            .build();

        return OpenTelemetrySdk.builder()
            .setTracerProvider(tracerProvider)
            .buildAndRegisterGlobal();
    }
}

🔧 Manual Instrumentation (Optional)

For custom business logic not automatically traced, you can manually create spans:

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;

public class OrderService {
    private static final Tracer tracer =
        GlobalOpenTelemetry.getTracer("order-service");

    public void processOrder(String orderId) {
        // Start a parent span
        Span span = tracer.spanBuilder("process_order")
            .setAttribute("order.id", orderId)
            .startSpan();

        try (Scope scope = span.makeCurrent()) {
            // Child spans automatically link to parent
            validateOrder(orderId);
            chargePayment(orderId);

            span.setAttribute("order.status", "completed");
        } finally {
            span.end();
        }
    }

    private void validateOrder(String orderId) {
        Span span = tracer.spanBuilder("validate_order")
            .setAttribute("order.id", orderId)
            .startSpan();
        try (Scope scope = span.makeCurrent()) {
            // Validation logic here
        } finally {
            span.end();
        }
    }
}

🔐 Environment Variables

Best practice: Store sensitive configuration in environment variables:

# .env or environment variables
TRACEKIT_API_KEY=ctxio_your_generated_api_key_here
OTEL_SERVICE_NAME=my-java-app
OTEL_EXPORTER_OTLP_ENDPOINT={ appURL }/v1/traces

🏭 Production Configuration

⚠️

Production Checklist

  • • Use HTTPS/TLS for the OTLP endpoint
  • • Store API keys in a secrets manager (AWS Secrets Manager, HashiCorp Vault)
  • • Set appropriate service names and versions
  • • Configure resource attributes (deployment.environment, host.name, etc.)
  • • Adjust sampling rates if needed for high-traffic services
  • • Monitor Java Agent overhead (typically <5%)

🔧 Troubleshooting

Traces Not Appearing?

  1. Verify your API key is correct and not revoked
  2. Check the endpoint URL matches your TraceKit instance
  3. Ensure the Java Agent is loaded (check startup logs)
  4. Verify the -javaagent parameter is before -jar
  5. Check application logs for OpenTelemetry errors

Complete Example

Here's a complete working Spring Boot example:

// Complete Spring Boot example - just run with the Java Agent!

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@RestController
@RequestMapping("/api")
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping("/users")
    public List<User> getUsers() {
        // Automatically traced - no code changes needed!
        return userRepository.findAll();
    }

    @PostMapping("/users")
    public User createUser(@RequestBody User user) {
        // Automatically traced - no code changes needed!
        return userRepository.save(user);
    }
}

// Run with:
// java -javaagent:opentelemetry-javaagent.jar \
//      -Dotel.service.name=spring-api \
//      -Dotel.exporter.otlp.endpoint={ appURL }/v1/traces \
//      -Dotel.exporter.otlp.headers=X-API-Key=$TRACEKIT_API_KEY \
//      -jar target/myapp.jar
🎉

You're all set!

Your Java application is now sending traces to TraceKit. Visit the Dashboard to see your traces.

🚀 Next Steps

  • Explore your traces on the Traces page to identify performance bottlenecks
  • Optionally add custom spans for specific business logic you want to measure
  • Configure sampling for high-traffic services to reduce overhead
  • Set up alert rules to get notified when issues occur