-
Notifications
You must be signed in to change notification settings - Fork 4
Open
Labels
questionFurther information is requestedFurther information is requested
Description
We recently ran into an issue with this class:
/** Tracks the number of times a page is routed to in a counter. */
public class PageViewMeter implements VaadinAfterNavigationListener, MeterBinder {
// 2 or more consecutive numbers
private static final Pattern NUMERIC_ID_PATTERN = Pattern.compile("\\d{2,}");
// kubernetes-kit will reinject this field after deserialization
private transient MeterRegistry meterRegistry;
@Override
public void bindTo(@NonNull MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
@Override
public void afterNavigation(AfterNavigationEvent event) {
Counter.builder(PAGE_VIEWS.getName())
.description(PAGE_VIEWS.getDescription())
.withRegistry(meterRegistry)
.withTag("page", sanitize(event.getLocation().getPath()))
.increment();
}
protected String sanitize(String url) {
if (url == null || url.isEmpty()) {
return "/";
}
return NUMERIC_ID_PATTERN.matcher(url).replaceAll("id");
}
}
This meter will work fine, until the moment where the session is deserialized from the session store (redis):
java.lang.NullPointerException: Cannot invoke "io.micrometer.core.instrument.MeterRegistry.counter(io.micrometer.core.instrument.Meter$Id)" because "registry" is null
at io.micrometer.core.instrument.Counter$Builder.register(Counter.java:150)
at io.micrometer.core.instrument.Counter$Builder.lambda$withRegistry$0(Counter.java:134)
at io.micrometer.core.instrument.Meter$MeterProvider.withTag(Meter.java:518)
at ....internal.metrics.PageViewMeter.afterNavigation(PageViewMeter.java:32)
Refactoring the class to use constructor injection fixed the issue:
@Slf4j
public class PageViewMeter implements VaadinAfterNavigationListener {
// vaadin kubernetes-kit will reinject this field after deserialization
private final transient MeterRegistry meterRegistry;
/**
* Constructor injection purposely. If we implement MeterBinder instead, reinjection after
* deserialization does not work
*/
public PageViewMeter(@NonNull MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
@Override
public void afterNavigation(AfterNavigationEvent event) {
if (meterRegistry == null) {
log.warn("MeterRegistry is not set, unable to meter PageViews");
return;
}
final Meter.MeterProvider<Counter> page =
Counter.builder(PAGE_VIEWS.getName())
.description(PAGE_VIEWS.getDescription())
.withRegistry(meterRegistry);
.....
.....
This was not obvious to spot. So my question is how can we write a test for this? So that we know that the mechanism of kubernetes-kit reinjecting spring dependencies after deserialization works.
Metadata
Metadata
Assignees
Labels
questionFurther information is requestedFurther information is requested