Skip to content

Commit 558e837

Browse files
Add jvm threads states metrics (#1075)
* add jvm threads states metrics * Update instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetrics.scala Co-authored-by: Ivan Topolnjak <[email protected]> * rename timed_waited to timed-waited * remove trailing comma for scala 2.11 compatibility Co-authored-by: Ivan Topolnjak <[email protected]>
1 parent 49aef33 commit 558e837

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetrics.scala

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,9 @@
1717
package kamon.instrumentation.system.jvm
1818

1919
import java.lang.management.ManagementFactory
20-
2120
import kamon.Kamon
2221
import kamon.instrumentation.system.jvm.JvmMetrics.MemoryUsageInstruments.{BufferPoolInstruments, MemoryRegionInstruments}
23-
import kamon.instrumentation.system.jvm.JvmMetricsCollector.{Collector, MemoryPool}
22+
import kamon.instrumentation.system.jvm.JvmMetricsCollector.{Collector, MemoryPool, ThreadState}
2423
import kamon.metric.{Gauge, Histogram, InstrumentGroup, MeasurementUnit}
2524
import kamon.tag.TagSet
2625

@@ -108,6 +107,11 @@ object JvmMetrics {
108107
name = "jvm.threads.daemon",
109108
description = "Tracks the current number of daemon threads on the JVM"
110109
)
110+
111+
val ThreadsStates = Kamon.gauge(
112+
name = "jvm.threads.states",
113+
description = "Tracks the current number of threads on each possible state"
114+
)
111115

112116
val ClassesLoaded = Kamon.gauge(
113117
name = "jvm.class-loading.loaded",
@@ -208,9 +212,18 @@ object JvmMetrics {
208212
}
209213

210214
class ThreadsInstruments extends InstrumentGroup(TagSet.Empty) {
215+
private val _threadsStatesCache = mutable.Map.empty[ThreadState, Gauge]
211216
val total = register(ThreadsTotal)
212217
val peak = register(ThreadsPeak)
213218
val daemon = register(ThreadsDaemon)
219+
220+
def threadState(threadState: ThreadState): Gauge = {
221+
_threadsStatesCache.getOrElseUpdate(threadState, {
222+
val stateTag = TagSet.of("state", threadState.toString)
223+
224+
register(ThreadsStates, stateTag)
225+
})
226+
}
214227
}
215228

216229
object MemoryUsageInstruments {

instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetricsCollector.scala

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import javax.management.{Notification, NotificationEmitter, NotificationListener
2727
import kamon.Kamon
2828
import kamon.instrumentation.system.jvm.JvmMetrics.{ClassLoadingInstruments, GarbageCollectionInstruments, MemoryUsageInstruments, ThreadsInstruments}
2929
import kamon.instrumentation.system.jvm.JvmMetricsCollector.MemoryPool.sanitize
30-
import kamon.instrumentation.system.jvm.JvmMetricsCollector.{Collector, MemoryPool}
30+
import kamon.instrumentation.system.jvm.JvmMetricsCollector.{Collector, MemoryPool, ThreadState}
3131
import kamon.module.{Module, ModuleFactory, ScheduledAction}
3232
import kamon.tag.TagSet
3333

@@ -137,6 +137,15 @@ class JvmMetricsCollector(ec: ExecutionContext) extends ScheduledAction {
137137
threadsInstruments.total.update(threadsMxBen.getThreadCount())
138138
threadsInstruments.peak.update(threadsMxBen.getPeakThreadCount())
139139
threadsInstruments.daemon.update(threadsMxBen.getDaemonThreadCount())
140+
141+
threadsMxBen.getAllThreadIds.map(threadsMxBen.getThreadInfo(_, 0))
142+
.groupBy(_.getThreadState)
143+
.mapValues(_.length)
144+
.foreach {
145+
case (state, count) =>
146+
val threadState = ThreadState.find(state.toString)
147+
threadsInstruments.threadState(threadState).update(count)
148+
}
140149

141150
val currentHeapUsage = ManagementFactory.getMemoryMXBean.getHeapMemoryUsage
142151
val freeHeap = Math.max(0L, currentHeapUsage.getMax - currentHeapUsage.getUsed)
@@ -259,4 +268,27 @@ object JvmMetricsCollector {
259268
def sanitize(name: String): String =
260269
_invalidChars.replaceAllIn(name.toLowerCase, "-")
261270
}
271+
272+
sealed trait ThreadState
273+
object ThreadState {
274+
case object New extends ThreadState { override def toString: String = "new"}
275+
case object Runnable extends ThreadState { override def toString: String = "runnable" }
276+
case object Blocked extends ThreadState { override def toString: String = "blocked" }
277+
case object Waiting extends ThreadState { override def toString: String = "waiting" }
278+
case object TimedWaiting extends ThreadState { override def toString: String = "timed-waiting" }
279+
case object Terminated extends ThreadState { override def toString: String = "terminated" }
280+
case object Unknown extends ThreadState { override def toString: String = "unknown" }
281+
282+
def find(state: String): ThreadState =
283+
_threadStateMapping.getOrElse(state, Unknown)
284+
285+
private val _threadStateMapping: Map[String, ThreadState] = Map(
286+
"NEW" -> New,
287+
"RUNNABLE" -> Runnable,
288+
"BLOCKED" -> Blocked,
289+
"WAITING" -> Waiting,
290+
"TIMED_WAITING" -> TimedWaiting,
291+
"TERMINATED" -> Terminated
292+
)
293+
}
262294
}

0 commit comments

Comments
 (0)