Metrics | Cats Effect IO runtime
Available metrics
CPU Starvation
Platforms: JVM, Scala.js, Scala Native.
These metrics could help identify performance bottlenecks caused by an overloaded compute pool, excessive task scheduling, or lack of CPU resources.
| Name | Description | Unit |
|---|---|---|
| cats.effect.runtime.cpu.starvation.clock.drift.current | The current CPU drift in milliseconds. | ms |
| cats.effect.runtime.cpu.starvation.clock.drift.max | The max CPU drift in milliseconds. | ms |
| cats.effect.runtime.cpu.starvation.count | The number of CPU starvation events. |
Work-stealing thread pool - compute
Platforms: JVM.
Built-in attributes:
pool.id- the id of the work-stealing thread pool
These metrics provide insights about fibers and threads within the compute pool. They help diagnose load distribution, identify bottlenecks, and monitor the pool’s efficiency in handling tasks.
| Name | Description | Unit |
|---|---|---|
| cats.effect.runtime.wstp.compute.fiber.enqueued.count | The total number of fibers enqueued on all local queues. | {fiber} |
| cats.effect.runtime.wstp.compute.fiber.suspended.count | The number of fibers which are currently asynchronously suspended. | {fiber} |
| cats.effect.runtime.wstp.compute.thread.active.count | The number of active worker thread instances currently executing fibers on the compute thread pool. | {thread} |
| cats.effect.runtime.wstp.compute.thread.blocked.count | The number of worker thread instances that can run blocking actions on the compute thread pool. | {thread} |
| cats.effect.runtime.wstp.compute.thread.count | The number of worker thread instances backing the work-stealing thread pool (WSTP). | {thread} |
| cats.effect.runtime.wstp.compute.thread.searching.count | The number of worker thread instances currently searching for fibers to steal from other worker threads. | {thread} |
Work-stealing thread pool - thread
Platforms: JVM.
Built-in attributes:
pool.id- the id of the work-stealing thread pool the worker is used byworker.index- the index of the worker thread-
thread.event- the thread eventparked- a thread is parkedpolled- a thread is polled for I/O eventsblocked- a thread is switched to a blocking thread and been replacedrespawn- a thread is replaced by a newly spawned thread
These metrics provide detailed information about threads state within the compute pool.
| Name | Description | Unit |
|---|---|---|
| cats.effect.runtime.wstp.worker.thread.event.count | The total number of events that happened to this WorkerThread. | {event} |
| cats.effect.runtime.wstp.worker.thread.idle.duration | The total amount of time in nanoseconds that this WorkerThread has been idle. | ns |
Work-stealing thread pool - local queue
Platforms: JVM.
Built-in attributes:
pool.id- the id of the work-stealing thread pool the queue is used byworker.index- the index of the worker thread the queue is used by
These metrics provide a detailed view of fiber distribution within the pool. They help diagnose load imbalances and system inefficiency.
| Name | Description | Unit |
|---|---|---|
| cats.effect.runtime.wstp.worker.localqueue.fiber.count | The total number of fibers enqueued during the lifetime of the local queue. | {fiber} |
| cats.effect.runtime.wstp.worker.localqueue.fiber.enqueued.count | The current number of enqueued fibers. | {fiber} |
| cats.effect.runtime.wstp.worker.localqueue.fiber.spillover.count | The total number of fibers spilt over to the external queue. | {fiber} |
| cats.effect.runtime.wstp.worker.localqueue.fiber.steal_attempt.count | The total number of successful steal attempts by other worker threads. | {fiber} |
| cats.effect.runtime.wstp.worker.localqueue.fiber.stolen.count | The total number of stolen fibers by other worker threads. | {fiber} |
Work-stealing thread pool - timer heap
Platforms: JVM.
Built-in attributes:
pool.id- the id of the work-stealing thread pool the timer heap is used byworker.index- the index of the worker thread the timer heap is used by-
timer.state- the state of the timerexecuted- the successfully executed timerscheduled- the scheduled timercanceled- the canceled timer
These metrics provide a detailed view of timer stats within the pool.
| Name | Description | Unit |
|---|---|---|
| cats.effect.runtime.wstp.worker.timerheap.next.due | Returns the time in nanoseconds till the next due to fire. | ns |
| cats.effect.runtime.wstp.worker.timerheap.outstanding.count | The current number of the outstanding timers, that remain to be executed. | {timer} |
| cats.effect.runtime.wstp.worker.timerheap.packed.count | The total number of times the heap packed itself to remove canceled timers. | {event} |
| cats.effect.runtime.wstp.worker.timerheap.timer.count | The total number of the timers per state. | {timer} |
Work-stealing thread pool - poller
Platforms: JVM.
Built-in attributes:
pool.id- the id of the work-stealing thread pool the poller is used byworker.index- the index of the worker thread the poller is used by-
poller.operation- the operation performed by the polleracceptconnectreadwrite
-
poller.operation.status- the status of the operationsubmitted- the operation has been submittedsucceeded- the operation has errorederrored- the operation has erroredcanceled- the operation has been canceled
These metrics provide a detailed view of poller stats within the pool.
| Name | Description | Unit |
|---|---|---|
| cats.effect.runtime.wstp.worker.poller.operation.count | The total number of the operations per category and outcome. | {operation} |
| cats.effect.runtime.wstp.worker.poller.operation.outstanding.count | The current number of outstanding operations per category. | {operation} |
Getting started
Add the following configuration to the favorite build tool:
Add settings to the build.sbt:
libraryDependencies ++= Seq(
"org.typelevel" %%% "otel4s-instrumentation-metrics" % "0.14.0" // <1>
)
Add directives to the *.scala file:
//> using dep "org.typelevel::otel4s-instrumentation-metrics::0.14.0" // <1>
- Add the
otel4s-instrumentation-metricslibrary
Registering metrics collectors
IORuntimeMetrics.register takes care of the metrics lifecycle management.
import cats.effect._
import org.typelevel.otel4s.instrumentation.ce.IORuntimeMetrics
import org.typelevel.otel4s.metrics.MeterProvider
import org.typelevel.otel4s.trace.TracerProvider
import org.typelevel.otel4s.oteljava.OtelJava
object Main extends IOApp.Simple {
def run: IO[Unit] =
OtelJava.autoConfigured[IO]().use { otel4s =>
implicit val mp: MeterProvider[IO] = otel4s.meterProvider
IORuntimeMetrics
.register[IO](runtime.metrics, IORuntimeMetrics.Config.default)
.surround {
program(otel4s.meterProvider, otel4s.tracerProvider)
}
}
def program(
meterProvider: MeterProvider[IO],
tracerProvider: TracerProvider[IO]
): IO[Unit] = {
val _ = (meterProvider, tracerProvider)
IO.unit
}
}
import cats.effect._
import org.typelevel.otel4s.instrumentation.ce.IORuntimeMetrics
import org.typelevel.otel4s.metrics.MeterProvider
import org.typelevel.otel4s.trace.TracerProvider
import org.typelevel.otel4s.sdk.OpenTelemetrySdk
object Main extends IOApp.Simple {
def run: IO[Unit] =
OpenTelemetrySdk.autoConfigured[IO]().use { autoConfigured =>
val sdk = autoConfigured.sdk
implicit val mp: MeterProvider[IO] = sdk.meterProvider
IORuntimeMetrics
.register[IO](runtime.metrics, IORuntimeMetrics.Config.default)
.surround {
program(sdk.meterProvider, sdk.tracerProvider)
}
}
def program(
meterProvider: MeterProvider[IO],
tracerProvider: TracerProvider[IO]
): IO[Unit] = {
val _ = (meterProvider, tracerProvider)
IO.unit
}
}
Grafana dashboard
You can use a Grafana dashboard to visualize collected metrics.
Customization
The behavior of the IORuntimeMetrics.register can be customized via IORuntimeMetrics.Config.
CPU Starvation
To disable CPU starvation metrics:
val config: IORuntimeMetrics.Config = {
import IORuntimeMetrics.Config._
IORuntimeMetrics.Config(
CpuStarvationConfig.disabled, // disable CPU starvation metrics
WorkStealingThreadPoolConfig.enabled
)
}
IORuntimeMetrics.register[IO](runtime.metrics, config)
To attach attributes to CPU starvation metrics:
val config: IORuntimeMetrics.Config = {
import IORuntimeMetrics.Config._
IORuntimeMetrics.Config(
CpuStarvationConfig.enabled(
Attributes(Attribute("key", "value")) // the attributes
),
WorkStealingThreadPoolConfig.enabled
)
}
IORuntimeMetrics.register[IO](runtime.metrics, config)
Work-stealing thread pool - compute
To disable worker metrics:
val config: IORuntimeMetrics.Config = {
import IORuntimeMetrics.Config._
import WorkStealingThreadPoolConfig._
IORuntimeMetrics.Config(
CpuStarvationConfig.enabled,
WorkStealingThreadPoolConfig(
ComputeConfig.disabled, // disable compute metrics
WorkStealingThreadPoolConfig.WorkerThreadsConfig.enabled
)
)
}
IORuntimeMetrics.register[IO](runtime.metrics, config)
To attach attributes to compute metrics:
val config: IORuntimeMetrics.Config = {
import IORuntimeMetrics.Config._
import WorkStealingThreadPoolConfig._
IORuntimeMetrics.Config(
CpuStarvationConfig.enabled,
WorkStealingThreadPoolConfig(
ComputeConfig.enabled(
Attributes(Attribute("key", "value")) // attributes
),
WorkStealingThreadPoolConfig.WorkerThreadsConfig.enabled
)
)
}
IORuntimeMetrics.register[IO](runtime.metrics, config)
Work-stealing thread pool - thread
To disable thread metrics:
val config: IORuntimeMetrics.Config = {
import IORuntimeMetrics.Config._
import WorkStealingThreadPoolConfig._
IORuntimeMetrics.Config(
CpuStarvationConfig.enabled,
WorkStealingThreadPoolConfig(
ComputeConfig.enabled,
WorkerThreadsConfig(
WorkerThreadsConfig.ThreadConfig.disabled, // disable worker thread metrics
WorkerThreadsConfig.LocalQueueConfig.enabled,
WorkerThreadsConfig.TimerHeapConfig.enabled,
WorkerThreadsConfig.PollerConfig.enabled
)
)
)
}
IORuntimeMetrics.register[IO](runtime.metrics, config)
To attach attributes to thread metrics:
val config: IORuntimeMetrics.Config = {
import IORuntimeMetrics.Config._
import WorkStealingThreadPoolConfig._
IORuntimeMetrics.Config(
CpuStarvationConfig.enabled,
WorkStealingThreadPoolConfig(
ComputeConfig.enabled,
WorkerThreadsConfig(
WorkerThreadsConfig.ThreadConfig.enabled(
Attributes(Attribute("key", "value")) // the attributes
),
WorkerThreadsConfig.LocalQueueConfig.enabled,
WorkerThreadsConfig.TimerHeapConfig.enabled,
WorkerThreadsConfig.PollerConfig.enabled
)
)
)
}
IORuntimeMetrics.register[IO](runtime.metrics, config)
Work-stealing thread pool - local queue
To disable local queue metrics:
val config: IORuntimeMetrics.Config = {
import IORuntimeMetrics.Config._
import WorkStealingThreadPoolConfig._
IORuntimeMetrics.Config(
CpuStarvationConfig.enabled,
WorkStealingThreadPoolConfig(
ComputeConfig.enabled,
WorkerThreadsConfig(
WorkerThreadsConfig.ThreadConfig.enabled,
WorkerThreadsConfig.LocalQueueConfig.disabled, // disable local queue metrics
WorkerThreadsConfig.TimerHeapConfig.enabled,
WorkerThreadsConfig.PollerConfig.enabled
)
)
)
}
IORuntimeMetrics.register[IO](runtime.metrics, config)
To attach attributes to local queue metrics:
val config: IORuntimeMetrics.Config = {
import IORuntimeMetrics.Config._
import WorkStealingThreadPoolConfig._
IORuntimeMetrics.Config(
CpuStarvationConfig.enabled,
WorkStealingThreadPoolConfig(
ComputeConfig.enabled,
WorkerThreadsConfig(
WorkerThreadsConfig.ThreadConfig.enabled,
WorkerThreadsConfig.LocalQueueConfig.enabled(
Attributes(Attribute("key", "value")) // the attributes
),
WorkerThreadsConfig.TimerHeapConfig.enabled,
WorkerThreadsConfig.PollerConfig.enabled
)
)
)
}
IORuntimeMetrics.register[IO](runtime.metrics, config)
Work-stealing thread pool - timer heap
To disable timer heap metrics:
val config: IORuntimeMetrics.Config = {
import IORuntimeMetrics.Config._
import WorkStealingThreadPoolConfig._
IORuntimeMetrics.Config(
CpuStarvationConfig.enabled,
WorkStealingThreadPoolConfig(
ComputeConfig.enabled,
WorkerThreadsConfig(
WorkerThreadsConfig.ThreadConfig.enabled,
WorkerThreadsConfig.LocalQueueConfig.enabled,
WorkerThreadsConfig.TimerHeapConfig.disabled, // disable timer heap metrics
WorkerThreadsConfig.PollerConfig.enabled
)
)
)
}
IORuntimeMetrics.register[IO](runtime.metrics, config)
To attach attributes to timer heap metrics:
val config: IORuntimeMetrics.Config = {
import IORuntimeMetrics.Config._
import WorkStealingThreadPoolConfig._
IORuntimeMetrics.Config(
CpuStarvationConfig.enabled,
WorkStealingThreadPoolConfig(
ComputeConfig.enabled,
WorkerThreadsConfig(
WorkerThreadsConfig.ThreadConfig.enabled,
WorkerThreadsConfig.LocalQueueConfig.enabled,
WorkerThreadsConfig.TimerHeapConfig.enabled(
Attributes(Attribute("key", "value")) // the attributes
),
WorkerThreadsConfig.PollerConfig.enabled
)
)
)
}
IORuntimeMetrics.register[IO](runtime.metrics, config)
Work-stealing thread pool - poller
To disable poller metrics:
val config: IORuntimeMetrics.Config = {
import IORuntimeMetrics.Config._
import WorkStealingThreadPoolConfig._
IORuntimeMetrics.Config(
CpuStarvationConfig.enabled,
WorkStealingThreadPoolConfig(
ComputeConfig.enabled,
WorkerThreadsConfig(
WorkerThreadsConfig.ThreadConfig.enabled,
WorkerThreadsConfig.LocalQueueConfig.enabled,
WorkerThreadsConfig.TimerHeapConfig.enabled,
WorkerThreadsConfig.PollerConfig.disabled // disable poller metrics
)
)
)
}
IORuntimeMetrics.register[IO](runtime.metrics, config)
To attach attributes to poller metrics:
val config: IORuntimeMetrics.Config = {
import IORuntimeMetrics.Config._
import WorkStealingThreadPoolConfig._
IORuntimeMetrics.Config(
CpuStarvationConfig.enabled,
WorkStealingThreadPoolConfig(
ComputeConfig.enabled,
WorkerThreadsConfig(
WorkerThreadsConfig.ThreadConfig.enabled,
WorkerThreadsConfig.LocalQueueConfig.enabled,
WorkerThreadsConfig.TimerHeapConfig.enabled,
WorkerThreadsConfig.PollerConfig.enabled(
Attributes(Attribute("key", "value")) // the attributes
)
)
)
)
}
IORuntimeMetrics.register[IO](runtime.metrics, config)