Skip to content

Kotlin

This guide demonstrates how to instrument a Kotlin application with OpenTelemetry to send traces, metrics, and logs to FusionReactor Cloud.

Beta Status

OpenTelemetry Kotlin is currently in Beta. APIs may change between releases. Suitable for testing and development, but review release notes carefully before production use.

Prerequisites

  • FusionReactor API Key: Obtain this from Account Settings > API Keys in FusionReactor Cloud.
  • Kotlin: Kotlin 1.8+ with JVM target installed on your system.
  • Telemetry Pipeline: You must have either an OpenTelemetry Collector or Grafana Alloy configured and running to receive data from your Kotlin application.

Set up your telemetry pipeline first

Before instrumenting your Kotlin application, ensure you have completed either the Collector setup guide or Grafana Alloy setup guide so your telemetry data has a destination.

Using Java Agent

For JVM-based Kotlin applications, you can use the Java auto-instrumentation agent for zero-code instrumentation.

Step 1: Add dependencies

Add to your build.gradle.kts:

dependencies {
    implementation("io.opentelemetry:opentelemetry-api:1.32.0")
    implementation("io.opentelemetry:opentelemetry-sdk:1.32.0")
    implementation("io.opentelemetry:opentelemetry-exporter-otlp:1.32.0")
    implementation("io.opentelemetry.semconv:opentelemetry-semconv:1.21.0-alpha")
}

Step 2: Create your instrumented application

Create src/main/kotlin/FibonacciApp.kt:

import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.api.common.Attributes
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.exporter.otlp.http.trace.OtlpHttpSpanExporter
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes
import kotlin.system.exitProcess

fun initializeOpenTelemetry(): OpenTelemetry {
    val resource = Resource.getDefault()
        .merge(Resource.create(
            Attributes.of(ResourceAttributes.SERVICE_NAME, "fibonacci-service")
        ))

    val spanExporter = OtlpHttpSpanExporter.builder()
        .setEndpoint("http://localhost:4318/v1/traces")
        .build()

    val sdkTracerProvider = SdkTracerProvider.builder()
        .addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())
        .setResource(resource)
        .build()

    return OpenTelemetrySdk.builder()
        .setTracerProvider(sdkTracerProvider)
        .buildAndRegisterGlobal()
}

fun calculateFibonacci(n: Int, tracer: Tracer) {
    val outerSpan: Span = tracer.spanBuilder("calculate_fibonacci")
        .setAttribute("iterations", n.toLong())
        .startSpan()

    try {
        var prev: Long = 0
        var current: Long = 1

        for (i in 1..n) {
            val span: Span = tracer.spanBuilder("fibonacci_iteration")
                .setAttribute("iteration", i.toLong())
                .setAttribute("value", current)
                .startSpan()

            try {
                println("Iteration $i: $current")

                val next = prev + current
                prev = current
                current = next

                Thread.sleep(100)
            } finally {
                span.end()
            }
        }
        outerSpan.setStatus(StatusCode.OK)
    } catch (e: Exception) {
        outerSpan.setStatus(StatusCode.ERROR, "Error calculating Fibonacci")
        outerSpan.recordException(e)
        throw e
    } finally {
        outerSpan.end()
    }
}

fun main(args: Array<String>) {
    if (args.isEmpty()) {
        println("Usage: kotlin FibonacciApp <iterations>")
        exitProcess(1)
    }

    val iterations = args[0].toIntOrNull() ?: run {
        println("Please provide a valid number")
        exitProcess(1)
    }

    val openTelemetry = initializeOpenTelemetry()
    val tracer = openTelemetry.getTracer("fibonacci-tracer")

    println("Starting Fibonacci calculator")
    println("Fibonacci by Iteration - $iterations rounds")

    calculateFibonacci(iterations, tracer)

    println("Fibonacci complete")

    // Allow time for spans to be exported
    Thread.sleep(2000)
}

How the code works

calculateFibonacci() function: - Creates spans with proper error handling using try-finally blocks - Records exceptions if they occur - Sets span status to indicate success or failure - Uses Kotlin's null-safety features

initializeOpenTelemetry() function: - Configures the OTLP HTTP exporter - Registers the tracer provider globally - Uses Kotlin's builder patterns for clean configuration

Step 3: Run locally

Compile and run your application:

./gradlew run --args="20"

The application will calculate 20 Fibonacci numbers and send telemetry to your local collector at localhost:4318.

Cannot connect to collector?

If you see: Connection errors or export failures Fix: Your collector is not running. Start it first using the Collector setup guide.

Step 4: Verify in FusionReactor Cloud

  1. Log in to FusionReactor Cloud
  2. Navigate to Explore:
  3. Traces: Select Resource Service Name = fibonacci-service

You should see: - Trace spans showing the execution flow - Span attributes with iteration numbers - Error information if exceptions occurred

Next steps

  • Use the Java agent for automatic instrumentation of Kotlin/JVM applications
  • Instrument coroutines with custom spans
  • Add instrumentation to Ktor or Spring Boot applications
  • Create custom dashboards in FusionReactor Cloud


Learn more

OpenTelemetry Java Documentation (applies to Kotlin/JVM)

Need more help?

Contact support in the chat bubble and let us know how we can assist.