Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Export JVM metrics to prometheus. #2129

Merged
merged 5 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions jvb/src/main/kotlin/org/jitsi/videobridge/metrics/JvmMetrics.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright @ 2024 - present 8x8, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.videobridge.metrics

import com.sun.management.UnixOperatingSystemMXBean
import org.jitsi.config.JitsiConfig
import org.jitsi.metaconfig.config
import org.jitsi.utils.logging2.createLogger
import java.lang.management.ManagementFactory
import org.jitsi.videobridge.metrics.VideobridgeMetricsContainer.Companion.instance as metricsContainer

class JvmMetrics private constructor() {
val logger = createLogger()

fun update() {
threadCount.set(ManagementFactory.getThreadMXBean().threadCount.toLong())
ManagementFactory.getGarbageCollectorMXBeans().forEach { gc ->
if (gc.name.lowercase().contains("g1 young")) {
g1YoungTime.set(gc.collectionTime)
g1YoungCount.set(gc.collectionCount)
} else if (gc.name.lowercase().contains("g1 old")) {
g1OldTime.set(gc.collectionTime)
g1OldCount.set(gc.collectionCount)
}
ManagementFactory.getMemoryPoolMXBeans().toSet().forEach { b ->
if (b.name.lowercase().contains("g1 old")) {
logger.info("${b.name} ${b.memoryManagerNames.joinToString { "," }}....${b.usage}")
g1OldUsage.set(b.usage.used)
g1OldCapacity.set(b.usage.max)
}
}
}
(ManagementFactory.getOperatingSystemMXBean() as? UnixOperatingSystemMXBean)?.let {
openFdCount.set(it.openFileDescriptorCount)
}
}

val threadCount = metricsContainer.registerLongGauge(
"thread_count",
"Current number of JVM threads."
)

private val g1YoungCount = metricsContainer.registerLongGauge(
"jvm_g1_young_count",
"Collection count for the G1 young generation."
)

private val g1YoungTime = metricsContainer.registerLongGauge(
"jvm_g1_young_time",
"Collection time for the young G1 generation."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make the order of "G1" and "young" consistent.

)

private val g1OldCount = metricsContainer.registerLongGauge(
"jvm_g1_old_count",
"Collection count for the G1 old generation."
)

private val g1OldTime = metricsContainer.registerLongGauge(
"jvm_g1_old_time",
"Collection time for the G1 old generation."
)

private val g1OldCapacity = metricsContainer.registerLongGauge(
"jvm_g1_old_capacity",
"Capacity of the G1 Old memory pool."
)

private val g1OldUsage = metricsContainer.registerLongGauge(
"jvm_g1_old_usage",
"Usage of the G1 Old memory pool."
)

private val openFdCount = metricsContainer.registerLongGauge(
"jvm_open_fd_count",
"Number of open file descriptors."
)

companion object {
val enable: Boolean by config {
"videobridge.stats.jvm.enabled".from(JitsiConfig.newConfig)
}

val INSTANCE = if (enable) JvmMetrics() else null
fun update() {
INSTANCE?.update()
}
}
}
6 changes: 5 additions & 1 deletion jvb/src/main/kotlin/org/jitsi/videobridge/metrics/Metrics.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ object Metrics {
val lock: Any
get() = metricsUpdater

fun start() = metricsUpdater.addUpdateTask { ThreadsMetric.update() }
fun start() {
if (JvmMetrics.enable) {
metricsUpdater.addUpdateTask { JvmMetrics.update() }
}
}
fun stop() {
metricsUpdater.stop()
executor.shutdown()
Expand Down
29 changes: 0 additions & 29 deletions jvb/src/main/kotlin/org/jitsi/videobridge/metrics/ThreadsMetric.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import org.jitsi.videobridge.EndpointConnectionStatusMonitor
import org.jitsi.videobridge.VersionConfig
import org.jitsi.videobridge.health.JvbHealthChecker
import org.jitsi.videobridge.load_management.JvbLoadManager
import org.jitsi.videobridge.metrics.JvmMetrics
import org.jitsi.videobridge.metrics.Metrics
import org.jitsi.videobridge.metrics.ThreadsMetric
import org.jitsi.videobridge.metrics.VideobridgeMetrics
import org.jitsi.videobridge.metrics.VideobridgePeriodicMetrics
import org.jitsi.videobridge.relay.RelayConfig
Expand Down Expand Up @@ -204,7 +204,9 @@ object VideobridgeStatisticsShim {

put("average_participant_stress", JvbLoadManager.averageParticipantStress)

put(THREADS, ThreadsMetric.threadCount.get())
JvmMetrics.INSTANCE?.threadCount?.let {
put(THREADS, it.get())
}

put(SHUTDOWN_IN_PROGRESS, VideobridgeMetrics.gracefulShutdown.get())
put("shutting_down", VideobridgeMetrics.shuttingDown.get())
Expand Down
4 changes: 4 additions & 0 deletions jvb/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ videobridge {
// /debug/jvb/stats/transit-time
enable-jitter = false
}
jvm {
// Whether to enable collection of JVM metrics (thread count, garbage collection)
enabled = true
}
}
websockets {
enabled = false
Expand Down
Loading