Skip to content

Commit d9223b4

Browse files
committed
improve: Make MicrometerMetrics extendable
Signed-off-by: David Sondermann <[email protected]>
1 parent 2bd9c35 commit d9223b4

File tree

9 files changed

+158
-21
lines changed

9 files changed

+158
-21
lines changed

micrometer-support/src/main/java/io/javaoperatorsdk/operator/monitoring/micrometer/MicrometerMetrics.java

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,13 @@ public static MicrometerMetricsBuilder newMicrometerMetricsBuilder(MeterRegistry
9696

9797
/**
9898
* Creates a micrometer-based Metrics implementation that cleans up {@link Meter}s associated with
99-
* deleted resources as specified by the (possibly {@code null}) provided {@link Cleaner}
100-
* instance.
99+
* deleted resources as specified by the provided {@link Cleaner} instance.
101100
*
102101
* @param registry the {@link MeterRegistry} instance to use for metrics recording
103102
* @param cleaner the {@link Cleaner} to use
104103
* @param collectingPerResourceMetrics whether to collect per resource metrics
105104
*/
106-
private MicrometerMetrics(
105+
protected MicrometerMetrics(
107106
MeterRegistry registry, Cleaner cleaner, boolean collectingPerResourceMetrics) {
108107
this.registry = registry;
109108
this.cleaner = cleaner;
@@ -315,11 +314,9 @@ protected Set<Meter.Id> recordedMeterIdsFor(ResourceID resourceID) {
315314
public static class PerResourceCollectingMicrometerMetricsBuilder
316315
extends MicrometerMetricsBuilder {
317316

318-
private int cleaningThreadsNumber;
319-
private int cleanUpDelayInSeconds;
320-
321317
private PerResourceCollectingMicrometerMetricsBuilder(MeterRegistry registry) {
322318
super(registry);
319+
collectingPerResourceMetrics = true;
323320
}
324321

325322
/**
@@ -329,7 +326,7 @@ private PerResourceCollectingMicrometerMetricsBuilder(MeterRegistry registry) {
329326
*/
330327
public PerResourceCollectingMicrometerMetricsBuilder withCleaningThreadNumber(
331328
int cleaningThreadsNumber) {
332-
this.cleaningThreadsNumber = cleaningThreadsNumber <= 0 ? 1 : cleaningThreadsNumber;
329+
cleanerBuilder.withCleaningThreadNumber(cleaningThreadsNumber);
333330
return this;
334331
}
335332

@@ -343,30 +340,24 @@ public PerResourceCollectingMicrometerMetricsBuilder withCleaningThreadNumber(
343340
*/
344341
public PerResourceCollectingMicrometerMetricsBuilder withCleanUpDelayInSeconds(
345342
int cleanUpDelayInSeconds) {
346-
this.cleanUpDelayInSeconds = Math.max(cleanUpDelayInSeconds, 1);
343+
cleanerBuilder.withCleanUpDelayInSeconds(cleanUpDelayInSeconds);
347344
return this;
348345
}
349-
350-
@Override
351-
public MicrometerMetrics build() {
352-
final var cleaner =
353-
new DelayedCleaner(registry, cleanUpDelayInSeconds, cleaningThreadsNumber);
354-
return new MicrometerMetrics(registry, cleaner, true);
355-
}
356346
}
357347

358348
public static class MicrometerMetricsBuilder {
359349
protected final MeterRegistry registry;
360-
private boolean collectingPerResourceMetrics = true;
350+
protected final CleanerBuilder cleanerBuilder;
351+
protected boolean collectingPerResourceMetrics = true;
361352

362353
private MicrometerMetricsBuilder(MeterRegistry registry) {
363354
this.registry = registry;
355+
this.cleanerBuilder = new CleanerBuilder(registry);
364356
}
365357

366358
/** Configures the instance to collect metrics on a per-resource basis. */
367359
@SuppressWarnings("unused")
368360
public PerResourceCollectingMicrometerMetricsBuilder collectingMetricsPerResource() {
369-
collectingPerResourceMetrics = true;
370361
return new PerResourceCollectingMicrometerMetricsBuilder(registry);
371362
}
372363

@@ -381,11 +372,52 @@ public MicrometerMetricsBuilder notCollectingMetricsPerResource() {
381372
}
382373

383374
public MicrometerMetrics build() {
384-
return new MicrometerMetrics(registry, Cleaner.NOOP, collectingPerResourceMetrics);
375+
return new MicrometerMetrics(registry, cleanerBuilder.build(), collectingPerResourceMetrics);
376+
}
377+
}
378+
379+
public static class CleanerBuilder {
380+
381+
private final MeterRegistry registry;
382+
private int cleaningThreadsNumber = 0;
383+
private int cleanUpDelayInSeconds = 0;
384+
385+
public CleanerBuilder(MeterRegistry registry) {
386+
this.registry = registry;
387+
}
388+
389+
/**
390+
* @param cleaningThreadsNumber the maximal number of threads that can be assigned to the
391+
* removal of {@link Meter}s associated with deleted resources, defaults to 1 if not
392+
* specified or if the provided number is lesser or equal to 0
393+
*/
394+
public CleanerBuilder withCleaningThreadNumber(int cleaningThreadsNumber) {
395+
this.cleaningThreadsNumber = cleaningThreadsNumber <= 0 ? 1 : cleaningThreadsNumber;
396+
return this;
397+
}
398+
399+
/**
400+
* @param cleanUpDelayInSeconds the number of seconds to wait before {@link Meter}s are removed
401+
* for deleted resources, defaults to 1 (meaning meters will be removed one second after the
402+
* associated resource is deleted) if not specified or if the provided number is lesser than
403+
* 0. Threading and the general interaction model of interacting with the API server means
404+
* that it's not possible to ensure that meters are immediately deleted in all cases so a
405+
* minimal delay of one second is always enforced
406+
*/
407+
public CleanerBuilder withCleanUpDelayInSeconds(int cleanUpDelayInSeconds) {
408+
this.cleanUpDelayInSeconds = Math.max(cleanUpDelayInSeconds, 1);
409+
return this;
410+
}
411+
412+
public Cleaner build() {
413+
if (cleanUpDelayInSeconds > 0 || cleaningThreadsNumber > 0) {
414+
return new DelayedCleaner(registry, cleanUpDelayInSeconds, cleaningThreadsNumber);
415+
}
416+
return Cleaner.NOOP;
385417
}
386418
}
387419

388-
interface Cleaner {
420+
public interface Cleaner {
389421
Cleaner NOOP = new Cleaner() {};
390422

391423
default void removeMetersFor(ResourceID resourceID) {}
@@ -444,5 +476,10 @@ public void removeMetersFor(ResourceID resourceID) {
444476
metersCleaner.schedule(
445477
() -> super.removeMetersFor(resourceID), cleanUpDelayInSeconds, TimeUnit.SECONDS);
446478
}
479+
480+
// for testing purposes only
481+
int getCleanUpDelayInSeconds() {
482+
return cleanUpDelayInSeconds;
483+
}
447484
}
448485
}

micrometer-support/src/test/java/io/javaoperatorsdk/operator/monitoring/micrometer/AbstractMicrometerMetricsTestFixture.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public DeleteControl cleanup(ConfigMap resource, Context<ConfigMap> context) {
8787
}
8888
}
8989

90-
static class TestSimpleMeterRegistry extends SimpleMeterRegistry {
90+
protected static class TestSimpleMeterRegistry extends SimpleMeterRegistry {
9191
private final Set<Meter.Id> removed = new HashSet<>();
9292

9393
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package io.javaoperatorsdk.operator.monitoring.micrometer;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import io.javaoperatorsdk.operator.monitoring.micrometer.MicrometerMetrics.CleanerBuilder;
6+
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
class CleanerBuilderTest {
11+
12+
private final SimpleMeterRegistry registry = new SimpleMeterRegistry();
13+
14+
@Test
15+
void test_defaultsToNoopCleaner() {
16+
final var cleaner = new CleanerBuilder(registry).build();
17+
assertThat(cleaner).isSameAs(MicrometerMetrics.Cleaner.NOOP);
18+
}
19+
20+
@Test
21+
void test_withCleaningThreadNumber() {
22+
final var cleaner = new CleanerBuilder(registry).withCleaningThreadNumber(42).build();
23+
assertThat(cleaner).isInstanceOf(MicrometerMetrics.DelayedCleaner.class);
24+
if (cleaner instanceof MicrometerMetrics.DelayedCleaner delayedCleaner) {
25+
assertThat(delayedCleaner.getCleanUpDelayInSeconds()).isEqualTo(0);
26+
}
27+
}
28+
29+
@Test
30+
void test_withCleanUpDelayInSeconds() {
31+
final var cleaner = new CleanerBuilder(registry).withCleanUpDelayInSeconds(23).build();
32+
assertThat(cleaner).isInstanceOf(MicrometerMetrics.DelayedCleaner.class);
33+
if (cleaner instanceof MicrometerMetrics.DelayedCleaner delayedCleaner) {
34+
assertThat(delayedCleaner.getCleanUpDelayInSeconds()).isEqualTo(23);
35+
}
36+
}
37+
}

micrometer-support/src/test/java/io/javaoperatorsdk/operator/monitoring/micrometer/DefaultBehaviorIT.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import static org.assertj.core.api.Assertions.assertThat;
1010

1111
public class DefaultBehaviorIT extends AbstractMicrometerMetricsTestFixture {
12+
1213
@Override
1314
protected MicrometerMetrics getMetrics() {
1415
return MicrometerMetrics.newMicrometerMetricsBuilder(registry).build();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.javaoperatorsdk.operator.monitoring.micrometer;
2+
3+
import io.micrometer.core.instrument.MeterRegistry;
4+
5+
public class DefaultBehaviorWithCustomImplementationIT extends DefaultBehaviorIT {
6+
7+
@Override
8+
protected MicrometerMetrics getMetrics() {
9+
return new TestMetrics(registry);
10+
}
11+
12+
private static class TestMetrics extends MicrometerMetrics {
13+
14+
private TestMetrics(MeterRegistry registry) {
15+
super(registry, new CleanerBuilder(registry).build(), true);
16+
}
17+
}
18+
}

micrometer-support/src/test/java/io/javaoperatorsdk/operator/monitoring/micrometer/DelayedMetricsCleaningOnDeleteIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
public class DelayedMetricsCleaningOnDeleteIT extends AbstractMicrometerMetricsTestFixture {
1212

13-
private static final int testDelay = 1;
13+
protected static final int testDelay = 1;
1414

1515
@Override
1616
protected MicrometerMetrics getMetrics() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package io.javaoperatorsdk.operator.monitoring.micrometer;
2+
3+
import io.micrometer.core.instrument.MeterRegistry;
4+
5+
public class DelayedMetricsCleaningOnDeleteWithCustomImplementationIT
6+
extends DelayedMetricsCleaningOnDeleteIT {
7+
8+
@Override
9+
protected MicrometerMetrics getMetrics() {
10+
return new TestMetrics(registry);
11+
}
12+
13+
private static class TestMetrics extends MicrometerMetrics {
14+
15+
private TestMetrics(MeterRegistry registry) {
16+
super(
17+
registry,
18+
new CleanerBuilder(registry)
19+
.withCleanUpDelayInSeconds(testDelay)
20+
.withCleaningThreadNumber(2)
21+
.build(),
22+
true);
23+
}
24+
}
25+
}

micrometer-support/src/test/java/io/javaoperatorsdk/operator/monitoring/micrometer/NoPerResourceCollectionIT.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import static org.assertj.core.api.Assertions.assertThat;
1010

1111
public class NoPerResourceCollectionIT extends AbstractMicrometerMetricsTestFixture {
12+
1213
@Override
1314
protected MicrometerMetrics getMetrics() {
1415
return MicrometerMetrics.withoutPerResourceMetrics(registry);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.javaoperatorsdk.operator.monitoring.micrometer;
2+
3+
import io.micrometer.core.instrument.MeterRegistry;
4+
5+
public class NoPerResourceCollectionWithCustomImplementationIT extends NoPerResourceCollectionIT {
6+
7+
@Override
8+
protected MicrometerMetrics getMetrics() {
9+
return new TestMetrics(registry);
10+
}
11+
12+
private static class TestMetrics extends MicrometerMetrics {
13+
14+
private TestMetrics(MeterRegistry registry) {
15+
super(registry, new CleanerBuilder(registry).build(), false);
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)