def register()

in util-jvm/src/main/scala/com/twitter/jvm/JvmStats.scala [27:280]


  def register(statsReceiver: StatsReceiver): Unit = {
    val stats = statsReceiver.scope("jvm")

    val mem = ManagementFactory.getMemoryMXBean()

    def heap = mem.getHeapMemoryUsage()
    val heapStats = stats.scope("heap")
    val heapUsedGauge = heapStats.addGauge("used") { heap.getUsed().toFloat }
    gauges.add(heapStats.addGauge("committed") { heap.getCommitted().toFloat })
    gauges.add(heapStats.addGauge("max") { heap.getMax().toFloat })
    gauges.add(heapUsedGauge)

    def nonHeap = mem.getNonHeapMemoryUsage()
    val nonHeapStats = stats.scope("nonheap")
    gauges.add(nonHeapStats.addGauge("committed") { nonHeap.getCommitted().toFloat })
    gauges.add(nonHeapStats.addGauge("max") { nonHeap.getMax().toFloat })
    gauges.add(nonHeapStats.addGauge("used") { nonHeap.getUsed().toFloat })

    val threads = ManagementFactory.getThreadMXBean()
    val threadStats = stats.scope("thread")
    gauges.add(threadStats.addGauge("daemon_count") { threads.getDaemonThreadCount().toFloat })
    gauges.add(threadStats.addGauge("count") { threads.getThreadCount().toFloat })
    gauges.add(threadStats.addGauge("peak_count") { threads.getPeakThreadCount().toFloat })

    val runtime = ManagementFactory.getRuntimeMXBean()
    val uptime = stats.addGauge("uptime") { runtime.getUptime().toFloat }
    gauges.add(uptime)
    gauges.add(stats.addGauge("start_time") { runtime.getStartTime().toFloat })
    gauges.add(stats.addGauge("spec_version") { runtime.getSpecVersion.toFloat })

    val os = ManagementFactory.getOperatingSystemMXBean()
    gauges.add(stats.addGauge("num_cpus") { os.getAvailableProcessors().toFloat })
    os match {
      case unix: com.sun.management.UnixOperatingSystemMXBean =>
        val fileDescriptorCountGauge = stats.addGauge("fd_count") {
          unix.getOpenFileDescriptorCount.toFloat
        }
        gauges.add(fileDescriptorCountGauge)
        gauges.add(stats.addGauge("fd_limit") { unix.getMaxFileDescriptorCount.toFloat })
        // register expression
        stats.registerExpression(
          ExpressionSchema("file_descriptors", Expression(fileDescriptorCountGauge.metadata))
            .withLabel(ExpressionSchema.Role, "jvm")
            .withDescription(
              "Total file descriptors used by the service. If it continuously increasing over time, then potentially files or connections aren't being closed"))
      case _ =>
    }

    val compilerStats = stats.scope("compiler");
    gauges.add(compilerStats.addGauge("graal") {
      System.getProperty("jvmci.Compiler") match {
        case "graal" => 1
        case _ => 0
      }
    })

    ManagementFactory.getCompilationMXBean() match {
      case null =>
      case compilation =>
        val compilationStats = stats.scope("compilation")
        gauges.add(
          compilationStats.addGauge(
            compilationStats.metricBuilder(GaugeType).withCounterishGauge.withName("time_msec")) {
            compilation.getTotalCompilationTime().toFloat
          })
    }

    val classes = ManagementFactory.getClassLoadingMXBean()
    val classLoadingStats = stats.scope("classes")
    gauges.add(
      classLoadingStats.addGauge(
        classLoadingStats.metricBuilder(GaugeType).withCounterishGauge.withName("total_loaded")) {
        classes.getTotalLoadedClassCount().toFloat
      })
    gauges.add(
      classLoadingStats.addGauge(
        classLoadingStats.metricBuilder(GaugeType).withCounterishGauge.withName("total_unloaded")) {
        classes.getUnloadedClassCount().toFloat
      })
    gauges.add(
      classLoadingStats.addGauge("current_loaded") { classes.getLoadedClassCount().toFloat }
    )

    val memPool = ManagementFactory.getMemoryPoolMXBeans.asScala
    val memStats = stats.scope("mem")
    val currentMem = memStats.scope("current")
    val postGCStats = memStats.scope("postGC")
    memPool.foreach { pool =>
      val name = pool.getName.regexSub("""[^\w]""".r) { m => "_" }
      val currentPoolScope = currentMem.hierarchicalScope(name).label("pool", name)
      val postGcPoolScope = postGCStats.hierarchicalScope(name).label("pool", name)
      if (pool.getCollectionUsage != null) {
        def usage = pool.getCollectionUsage // this is a snapshot, we can't reuse the value
        gauges.add(postGcPoolScope.addGauge("used") { usage.getUsed.toFloat })
      }
      if (pool.getUsage != null) {
        def usage = pool.getUsage // this is a snapshot, we can't reuse the value
        val usageGauge = currentPoolScope.addGauge("used") { usage.getUsed.toFloat }
        gauges.add(usageGauge)
        gauges.add(currentPoolScope.addGauge("max") { usage.getMax.toFloat })

        // register memory usage expression
        currentMem.registerExpression(
          ExpressionSchema("memory_pool", Expression(usageGauge.metadata))
            .withLabel(ExpressionSchema.Role, "jvm")
            .withLabel("kind", name)
            .withUnit(Bytes)
            .withDescription(
              s"The current estimate of the amount of space within the $name memory pool holding allocated objects in bytes"))
      }
    }
    gauges.add(postGCStats.addGauge("used") {
      memPool.flatMap(p => Option(p.getCollectionUsage)).map(_.getUsed).sum.toFloat
    })
    gauges.add(currentMem.addGauge("used") {
      memPool.flatMap(p => Option(p.getUsage)).map(_.getUsed).sum.toFloat
    })

    // the Hotspot JVM exposes the full size that the metaspace can grow to
    // which differs from the value exposed by `MemoryUsage.getMax` from above
    val jvm = Jvm()
    jvm.metaspaceUsage.foreach { usage =>
      gauges.add(memStats.scope("metaspace").addGauge("max_capacity") {
        usage.maxCapacity.inBytes.toFloat
      })
    }

    val spStats = stats.scope("safepoint")
    gauges.add(
      spStats.addGauge(
        spStats.metricBuilder(GaugeType).withCounterishGauge.withName("sync_time_millis")) {
        jvm.safepoint.syncTimeMillis.toFloat
      })
    gauges.add(
      spStats.addGauge(
        spStats.metricBuilder(GaugeType).withCounterishGauge.withName("total_time_millis")) {
        jvm.safepoint.totalTimeMillis.toFloat
      })
    gauges.add(
      spStats.addGauge(spStats.metricBuilder(GaugeType).withCounterishGauge.withName("count")) {
        jvm.safepoint.count.toFloat
      })

    ManagementFactory.getPlatformMXBeans(classOf[BufferPoolMXBean]) match {
      case null =>
      case jBufferPool =>
        val bufferPoolStats = memStats.scope("buffer")
        jBufferPool.asScala.foreach { bp =>
          val name = bp.getName
          val bufferPoolScope = bufferPoolStats.hierarchicalScope(name).label("pool", name)
          gauges.add(bufferPoolScope.addGauge("count") { bp.getCount.toFloat })
          gauges.add(bufferPoolScope.addGauge("used") { bp.getMemoryUsed.toFloat })
          gauges.add(bufferPoolScope.addGauge("max") { bp.getTotalCapacity.toFloat })
        }
    }

    val gcPool = ManagementFactory.getGarbageCollectorMXBeans.asScala
    val gcStats = stats.scope("gc")
    gcPool.foreach { gc =>
      val name = gc.getName.regexSub("""[^\w]""".r) { m => "_" }
      val poolScope = gcStats.hierarchicalScope(name).label("jmm", name)
      val poolCycles =
        poolScope.addGauge(
          poolScope.metricBuilder(GaugeType).withCounterishGauge.withName("cycles")) {
          gc.getCollectionCount.toFloat
        }
      val poolMsec = poolScope.addGauge(
        poolScope.metricBuilder(GaugeType).withCounterishGauge.withName("msec")) {
        gc.getCollectionTime.toFloat
      }

      val gcPauseStat = poolScope.stat("pause_msec")
      gc.asInstanceOf[NotificationEmitter].addNotificationListener(
          new NotificationListener {
            override def handleNotification(
              notification: Notification,
              handback: Any
            ): Unit = {
              notification.getType
              if (notification.getType == GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION) {
                gcPauseStat.add(
                  GarbageCollectionNotificationInfo
                    .from(notification.getUserData
                      .asInstanceOf[CompositeData]).getGcInfo.getDuration)
              }
            }
          },
          null,
          null
        )

      gcStats.registerExpression(
        ExpressionSchema(s"gc_cycles", Expression(poolCycles.metadata))
          .withLabel(ExpressionSchema.Role, "jvm")
          .withLabel("gc_pool", name)
          .withDescription(
            s"The total number of collections that have occurred for the $name gc pool"))
      gcStats.registerExpression(ExpressionSchema(s"gc_latency", Expression(poolMsec.metadata))
        .withLabel(ExpressionSchema.Role, "jvm")
        .withLabel("gc_pool", name)
        .withUnit(Milliseconds)
        .withDescription(
          s"The total elapsed time spent doing collections for the $name gc pool in milliseconds"))

      gauges.add(poolCycles)
      gauges.add(poolMsec)
    }

    // note, these could be -1 if the collector doesn't have support for it.
    val cycles =
      gcStats.addGauge(gcStats.metricBuilder(GaugeType).withCounterishGauge.withName("cycles")) {
        gcPool.map(_.getCollectionCount).filter(_ > 0).sum.toFloat
      }
    val msec =
      gcStats.addGauge(gcStats.metricBuilder(GaugeType).withCounterishGauge.withName("msec")) {
        gcPool.map(_.getCollectionTime).filter(_ > 0).sum.toFloat
      }

    gauges.add(cycles)
    gauges.add(msec)
    allocations = new Allocations(gcStats)
    allocations.start()
    if (allocations.trackingEden) {
      val allocationStats = memStats.scope("allocations")
      val eden = allocationStats.hierarchicalScope("eden").label("space", "eden")
      gauges.add(eden.addGauge("bytes") { allocations.eden.toFloat })
    }

    // return ms from ns while retaining precision
    gauges.add(stats.addGauge("application_time_millis") { jvm.applicationTime.toFloat / 1000000 })
    gauges.add(stats.addGauge("tenuring_threshold") { jvm.tenuringThreshold.toFloat })

    // register metric expressions
    stats.registerExpression(
      ExpressionSchema("jvm_uptime", Expression(uptime.metadata))
        .withLabel(ExpressionSchema.Role, "jvm")
        .withUnit(Milliseconds)
        .withDescription("The uptime of the JVM in milliseconds"))
    gcStats.registerExpression(
      ExpressionSchema("gc_cycles", Expression(cycles.metadata))
        .withLabel(ExpressionSchema.Role, "jvm")
        .withDescription("The total number of collections that have occurred"))
    gcStats.registerExpression(
      ExpressionSchema("gc_latency", Expression(msec.metadata))
        .withLabel(ExpressionSchema.Role, "jvm")
        .withUnit(Milliseconds)
        .withDescription("The total elapsed time spent doing collections in milliseconds"))
    heapStats.registerExpression(
      ExpressionSchema("memory_pool", Expression(heapUsedGauge.metadata))
        .withLabel(ExpressionSchema.Role, "jvm")
        .withLabel("kind", "Heap")
        .withUnit(Bytes)
        .withDescription("Heap in use in bytes"))
  }