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)