Fix bug in SslMeterBinder when binding without registered bundles

Before this commit the meter registries were derived from the created
gauges. If the SslMeterBinder has been bound to a MeterRegistry without
any bundles, then no gauges are created. If a SslBundle is then
dynamically added, onBundleChange is called with the new bundle, but the
list of meter registries is empty (because we have no gauges). The
effect is that the newly registered bundle has no metrics.

Closes gh-48180
This commit is contained in:
Moritz Halbritter
2025-11-19 15:06:09 +01:00
parent 0b92b8177c
commit 0addec6b68
2 changed files with 12 additions and 23 deletions
@@ -21,9 +21,7 @@ import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -58,6 +56,8 @@ class SslMeterBinder implements MeterBinder {
private final BundleMetrics bundleMetrics = new BundleMetrics();
private final Set<MeterRegistry> boundMeterRegistries = ConcurrentHashMap.newKeySet();
SslMeterBinder(SslInfo sslInfo, SslBundles sslBundles) {
this(sslInfo, sslBundles, Clock.systemDefaultZone());
}
@@ -77,13 +77,14 @@ class SslMeterBinder implements MeterBinder {
private void onBundleChange(String bundleName) {
BundleInfo bundle = this.sslInfo.getBundle(bundleName);
this.bundleMetrics.updateBundle(bundle);
for (MeterRegistry meterRegistry : this.bundleMetrics.getMeterRegistries()) {
for (MeterRegistry meterRegistry : this.boundMeterRegistries) {
createOrUpdateBundleMetrics(meterRegistry, bundle);
}
}
@Override
public void bindTo(MeterRegistry meterRegistry) {
this.boundMeterRegistries.add(meterRegistry);
for (BundleInfo bundle : this.sslInfo.getBundles()) {
createOrUpdateBundleMetrics(meterRegistry, bundle);
}
@@ -138,18 +139,6 @@ class SslMeterBinder implements MeterBinder {
return gauges.getGauge(meterRegistry);
}
/**
* Returns all meter registries.
* @return all meter registries
*/
Collection<MeterRegistry> getMeterRegistries() {
Set<MeterRegistry> result = new HashSet<>();
for (Gauges metrics : this.gauges.values()) {
result.addAll(metrics.getMeterRegistries());
}
return result;
}
/**
* Updates the given bundle.
* @param bundle the updated bundle
@@ -184,14 +173,6 @@ class SslMeterBinder implements MeterBinder {
return new Gauges(bundle, this.multiGauges);
}
/**
* Returns all meter registries.
* @return all meter registries
*/
Set<MeterRegistry> getMeterRegistries() {
return this.multiGauges.keySet();
}
private MultiGauge createGauge(MeterRegistry meterRegistry) {
return MultiGauge.builder(CHAIN_EXPIRY_METRIC_NAME)
.baseUnit("seconds")
@@ -88,6 +88,14 @@ class SslMeterBinderTests {
.hasDays(36889);
}
@Test
void shouldRegisterMetricsIfNoBundleExistsAtBindTime() {
DefaultSslBundleRegistry sslBundleRegistry = new DefaultSslBundleRegistry();
MeterRegistry meterRegistry = bindToRegistry(sslBundleRegistry);
sslBundleRegistry.registerBundle("dummy", SslBundle.of(createSslStoreBundle("classpath:test.p12")));
assertThat(meterRegistry.getMeters()).isNotEmpty();
}
private long findExpiryGauge(MeterRegistry meterRegistry, String chain, String certificateSerialNumber) {
return (long) meterRegistry.get("ssl.chain.expiry")
.tag("bundle", "test-0")