Kotlin Observability: Tracing, Metrics, and Logs in Practice

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Why Observability is a Must-Have for Kotlin Applications

\n\n

Imagine: your Kotlin application is running in production, and suddenly users complain that requests are taking 10 seconds. You check the logs — silence. Metrics show 100% CPU, but don't tell you which specific endpoint is slowing down. Sound familiar?

\n\n

Welcome to the world where observability is not an option, but a necessity. Unlike traditional monitoring, which simply answers "yes/no" to the question "is the system alive," observability allows you to ask questions you didn't even know you had. And Kotlin, with its conciseness and powerful ecosystem, is ideally suited for implementing this culture.

\n\n

In this article, we will break down the three pillars of observability — tracing, metrics, and logs — and show how to integrate them with Kotlin. No fluff, only real code examples.

\n\n

Tracing: A Request's Journey Through Microservices

\n\n

Distributed tracing is like GPS for your request. You can see which services the request passed through, how long each step took, and where the delay occurred. For Kotlin, the best friend for this is OpenTelemetry (OTel).

\n\n

Setting up OpenTelemetry in Kotlin

\n\n

Add dependencies to build.gradle.kts:

\n\n
dependencies {\n    implementation("io.opentelemetry:opentelemetry-api:1.36.0")\n    implementation("io.opentelemetry:opentelemetry-sdk:1.36.0")\n    implementation("io.opentelemetry:opentelemetry-exporter-otlp:1.36.0")\n    implementation("io.opentelemetry:opentelemetry-extension-kotlin:1.36.0")\n}
\n\n

Now let's create a simple tracer:

\n\n
import io.opentelemetry.api.GlobalOpenTelemetry\nimport io.opentelemetry.api.trace.Span\nimport io.opentelemetry.api.trace.Tracer\nimport io.opentelemetry.context.Scope\n\nclass OrderService(private val tracer: Tracer = GlobalOpenTelemetry.getTracer("order-service")) {\n\n    fun processOrder(orderId: String) {\n        val span: Span = tracer.spanBuilder("processOrder")\n            .setAttribute("order.id", orderId)\n            .startSpan()\n\n        span.use { // use() will automatically close the span\n            try {\n                // Simulate work\n                Thread.sleep(100)\n                validateOrder(orderId)\n                chargePayment(orderId)\n            } catch (e: Exception) {\n                span.recordException(e)\n                span.setStatus(StatusCode.ERROR, "Order processing failed")\n                throw e\n            }\n        }\n    }\n\n    private fun validateOrder(orderId: String) {\n        val span: Span = tracer.spanBuilder("validateOrder")\n            .setAttribute("order.id", orderId)\n            .startSpan()\n\n        span.use {\n            Thread.sleep(50) // Simulate validation\n        }\n    }\n\n    private fun chargePayment(orderId: String) {\n        val span: Span = tracer.spanBuilder("chargePayment")\n            .setAttribute("order.id", orderId)\n            .startSpan()\n\n        span.use {\n            Thread.sleep(150) // Simulate payment\n        }\n    }\n}
\n\n

Notice span.use — this is an extension function from opentelemetry-extension-kotlin that automatically closes the span after the block executes. The beauty of Kotlin in action!

\n\n

Context Propagation via Coroutines

\n\n

In Kotlin, we actively use coroutines. OpenTelemetry integrates seamlessly with them through the Context mechanism:

\n\n
import kotlinx.coroutines.withContext\nimport io.opentelemetry.api.trace.Span\nimport io.opentelemetry.context.Context\n\nsuspend fun processOrderAsync(orderId: String) = withContext(Context.current()) {\n    val span = tracer.spanBuilder("processOrderAsync").startSpan()\n    span.use {\n        // Your asynchronous logic\n    }\n}
\n\n

Tracing reveals the full picture: you can see that 80% of the time is spent on paymen

Blogs

Book Recommendations