When using buildpacks / bootBuildImage, the Java Buildpack Memory Calculator uses some heuristics to calculate memory parameters.

Those include an assumed number of loaded classes and maximum tread count. We'd like to have alerts, when those values were underestimated, but currently there are no metrics available to write these alerts.

We're currently doing something like the following, but I believe adding this to the actuator-autoconfigure project would be beneficial for other, too.

@AutoConfiguration(after = [MetricsAutoConfiguration::class, CompositeMeterRegistryAutoConfiguration::class])
@ConditionalOnClass(MeterRegistry::class)
@ConditionalOnBean(MeterRegistry::class)
class JvmMemoryCalculatorMetricsAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty("bpl.jvm.thread.count")
    fun jvmMemoryCalculatorMetrics(): JvmMemoryCalculatorMetrics = JvmMemoryCalculatorMetrics()
}

class JvmMemoryCalculatorMetrics : MeterBinder {
    override fun bindTo(registry: MeterRegistry) {
        // These environment variables are always set when running an image build with the Buildpack
        val threadCount = System.getenv("BPL_JVM_THREAD_COUNT")?.toLong()
        val classCount = System.getenv("BPI_JVM_CLASS_COUNT")?.toLong()

        if (threadCount != null) {
            Gauge.builder("jvm.buildpack.memorycalculator.threads") { threadCount }
                .description("Number of threads used by the JVM Memory Calculator as the " +
                    "maximum number of threads")
                .baseUnit(BaseUnits.THREADS)
                .register(registry)
        }

        if (classCount != null) {
            Gauge.builder("jvm.buildpack.memorycalculator.classes") { classCount }
                .description("Number of classes used by the JVM Memory Calculator as the " +
                    "maximum number of loaded classes")
                .baseUnit(BaseUnits.CLASSES)
                .register(registry)
        }
    }
}

Comment From: wilkinsona

Thanks for the suggestion. I wonder if some of this would be better off in Micrometer. For example, Micrometer could provide the MeterBinder implementation that works for any Java application deployed using buildpacks. Spring Boot could then auto-configure it. I'll discuss it with the observability team.

Comment From: michael-arndt-gcx

Good point, wasn't aware there are standard MeterBinders in micrometer.

Please note that my initial assumption was not completely correct. It does work as described above for threads, but for classes the situation is more complicated, as I described in https://github.com/paketo-buildpacks/libjvm/issues/425#issuecomment-2399324759.

In short: the value is not currently not available and it's currently also unclear where other metrics like the maximum number of loaded classes assumed by the memory calculator will come from. Providing a calculated value would clash with the naming-schme of environment variables.

Comment From: wilkinsona

The observability team agree that this could be a standard MeterBinder in Micrometer. Once https://github.com/paketo-buildpacks/libjvm/issues/425 has reached a conclusion, I'd recommend opening a Micrometer issue to add the binder. Once that's happened, please open a new Boot issue to see if we can auto-configure the binder.

/cc @jonatan-ivanov @shakuzen

Comment From: jonatan-ivanov

Thanks Andy for the follow-up. From Micrometer-perspective, I think we will need a stable (no breaking changes in minor or patch versions) mechanism easily available to the JVM to get these values (e.g.: env vars, system properties, property files, etc).

Comment From: michael-arndt-gcx

Thanks Andy for the follow-up. From Micrometer-perspective, I think we will need a stable (no breaking changes in minor or patch versions) mechanism easily available to the JVM to get these values (e.g.: env vars, system properties, property files, etc).

An environment variable is one option currently considered (filesystem also, but with reservations). Number of threads already is available as BPL_JVM_THREAD_COUNT, number of classes not yet.

See https://github.com/paketo-buildpacks/libjvm/issues/425#issuecomment-2399669173