diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml
new file mode 100644
index 0000000000..f38349c232
--- /dev/null
+++ b/micrometer-support/pom.xml
@@ -0,0 +1,31 @@
+
+
+
+ java-operator-sdk
+ io.javaoperatorsdk
+ 1.9.8-SNAPSHOT
+
+ 4.0.0
+
+ micrometer-support
+ Operator SDK - Micrometer Support
+
+
+ 11
+ 11
+
+
+
+
+ io.micrometer
+ micrometer-core
+
+
+ io.javaoperatorsdk
+ operator-framework-core
+
+
+
+
\ No newline at end of file
diff --git a/micrometer-support/src/main/java/io/javaoperatorsdk/operator/micrometer/MicrometerMetrics.java b/micrometer-support/src/main/java/io/javaoperatorsdk/operator/micrometer/MicrometerMetrics.java
new file mode 100644
index 0000000000..7dd5515173
--- /dev/null
+++ b/micrometer-support/src/main/java/io/javaoperatorsdk/operator/micrometer/MicrometerMetrics.java
@@ -0,0 +1,83 @@
+package io.javaoperatorsdk.operator.micrometer;
+
+import java.util.Collections;
+import java.util.Map;
+
+import io.javaoperatorsdk.operator.Metrics;
+import io.javaoperatorsdk.operator.processing.DefaultEventHandler.EventMonitor;
+import io.javaoperatorsdk.operator.processing.event.Event;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Timer;
+
+public class MicrometerMetrics implements Metrics {
+
+ public static final String PREFIX = "operator.sdk.";
+ private final MeterRegistry registry;
+ private final EventMonitor monitor = new EventMonitor() {
+ @Override
+ public void processedEvent(String uid, Event event) {
+ incrementProcessedEventsNumber();
+ }
+
+ @Override
+ public void failedEvent(String uid, Event event) {
+ incrementControllerRetriesNumber();
+ }
+ };
+
+ public MicrometerMetrics(MeterRegistry registry) {
+ this.registry = registry;
+ }
+
+ public T timeControllerExecution(ControllerExecution execution) {
+ final var name = execution.controllerName();
+ final var execName = PREFIX + "controllers.execution." + execution.name();
+ final var timer =
+ Timer.builder(execName)
+ .tags("controller", name)
+ .publishPercentiles(0.3, 0.5, 0.95)
+ .publishPercentileHistogram()
+ .register(registry);
+ try {
+ final var result = timer.record(execution::execute);
+ final var successType = execution.successTypeName(result);
+ registry
+ .counter(execName + ".success", "controller", name, "type", successType)
+ .increment();
+ return result;
+ } catch (Exception e) {
+ final var exception = e.getClass().getSimpleName();
+ registry
+ .counter(execName + ".failure", "controller", name, "exception", exception)
+ .increment();
+ throw e;
+ }
+ }
+
+ public void incrementControllerRetriesNumber() {
+ registry
+ .counter(
+ PREFIX + "retry.on.exception", "retry", "retryCounter", "type",
+ "retryException")
+ .increment();
+
+ }
+
+ public void incrementProcessedEventsNumber() {
+ registry
+ .counter(
+ PREFIX + "total.events.received", "events", "totalEvents", "type",
+ "eventsReceived")
+ .increment();
+
+ }
+
+ public > T monitorSizeOf(T map, String name) {
+ return registry.gaugeMapSize(PREFIX + name + ".size", Collections.emptyList(), map);
+ }
+
+ @Override
+ public EventMonitor getEventMonitor() {
+ return monitor;
+ }
+}
diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml
index 33ba79521f..0ed9219c18 100644
--- a/operator-framework-core/pom.xml
+++ b/operator-framework-core/pom.xml
@@ -62,10 +62,6 @@
org.slf4j
slf4j-api
-
- io.micrometer
- micrometer-core
-
org.junit.jupiter
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Metrics.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Metrics.java
index 31269b5d41..a3f3ddccb5 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Metrics.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Metrics.java
@@ -1,41 +1,15 @@
package io.javaoperatorsdk.operator;
-import java.util.Collections;
import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.function.ToDoubleFunction;
-import java.util.function.ToLongFunction;
-import io.micrometer.core.instrument.Clock;
-import io.micrometer.core.instrument.Counter;
-import io.micrometer.core.instrument.DistributionSummary;
-import io.micrometer.core.instrument.FunctionCounter;
-import io.micrometer.core.instrument.FunctionTimer;
-import io.micrometer.core.instrument.Gauge;
-import io.micrometer.core.instrument.Measurement;
-import io.micrometer.core.instrument.Meter;
-import io.micrometer.core.instrument.MeterRegistry;
-import io.micrometer.core.instrument.Timer;
-import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
-import io.micrometer.core.instrument.distribution.pause.PauseDetector;
-import io.micrometer.core.instrument.noop.NoopCounter;
-import io.micrometer.core.instrument.noop.NoopDistributionSummary;
-import io.micrometer.core.instrument.noop.NoopFunctionCounter;
-import io.micrometer.core.instrument.noop.NoopFunctionTimer;
-import io.micrometer.core.instrument.noop.NoopGauge;
-import io.micrometer.core.instrument.noop.NoopMeter;
-import io.micrometer.core.instrument.noop.NoopTimer;
+import io.javaoperatorsdk.operator.processing.DefaultEventHandler;
+import io.javaoperatorsdk.operator.processing.DefaultEventHandler.EventMonitor;
-public class Metrics {
- public static final Metrics NOOP = new Metrics(new NoopMeterRegistry(Clock.SYSTEM));
- public static final String PREFIX = "operator.sdk.";
- private final MeterRegistry registry;
+public interface Metrics {
+ Metrics NOOP = new Metrics() {};
- public Metrics(MeterRegistry registry) {
- this.registry = registry;
- }
- public interface ControllerExecution {
+ interface ControllerExecution {
String name();
String controllerName();
@@ -45,111 +19,19 @@ public interface ControllerExecution {
T execute();
}
- public T timeControllerExecution(ControllerExecution execution) {
- final var name = execution.controllerName();
- final var execName = PREFIX + "controllers.execution." + execution.name();
- final var timer =
- Timer.builder(execName)
- .tags("controller", name)
- .publishPercentiles(0.3, 0.5, 0.95)
- .publishPercentileHistogram()
- .register(registry);
- try {
- final var result = timer.record(execution::execute);
- final var successType = execution.successTypeName(result);
- registry
- .counter(execName + ".success", "controller", name, "type", successType)
- .increment();
- return result;
- } catch (Exception e) {
- final var exception = e.getClass().getSimpleName();
- registry
- .counter(execName + ".failure", "controller", name, "exception", exception)
- .increment();
- throw e;
- }
+ default T timeControllerExecution(ControllerExecution execution) {
+ return execution.execute();
}
- public void incrementControllerRetriesNumber() {
- registry
- .counter(
- PREFIX + "retry.on.exception", "retry", "retryCounter", "type",
- "retryException")
- .increment();
-
- }
+ default void incrementControllerRetriesNumber() {}
- public void incrementProcessedEventsNumber() {
- registry
- .counter(
- PREFIX + "total.events.received", "events", "totalEvents", "type",
- "eventsReceived")
- .increment();
+ default void incrementProcessedEventsNumber() {}
+ default > T monitorSizeOf(T map, String name) {
+ return map;
}
- public > T monitorSizeOf(T map, String name) {
- return registry.gaugeMapSize(PREFIX + name + ".size", Collections.emptyList(), map);
- }
-
- public static class NoopMeterRegistry extends MeterRegistry {
- public NoopMeterRegistry(Clock clock) {
- super(clock);
- }
-
- @Override
- protected Gauge newGauge(Meter.Id id, T t, ToDoubleFunction toDoubleFunction) {
- return new NoopGauge(id);
- }
-
- @Override
- protected Counter newCounter(Meter.Id id) {
- return new NoopCounter(id);
- }
-
- @Override
- protected Timer newTimer(
- Meter.Id id,
- DistributionStatisticConfig distributionStatisticConfig,
- PauseDetector pauseDetector) {
- return new NoopTimer(id);
- }
-
- @Override
- protected DistributionSummary newDistributionSummary(
- Meter.Id id, DistributionStatisticConfig distributionStatisticConfig, double v) {
- return new NoopDistributionSummary(id);
- }
-
- @Override
- protected Meter newMeter(Meter.Id id, Meter.Type type, Iterable iterable) {
- return new NoopMeter(id);
- }
-
- @Override
- protected FunctionTimer newFunctionTimer(
- Meter.Id id,
- T t,
- ToLongFunction toLongFunction,
- ToDoubleFunction toDoubleFunction,
- TimeUnit timeUnit) {
- return new NoopFunctionTimer(id);
- }
-
- @Override
- protected FunctionCounter newFunctionCounter(
- Meter.Id id, T t, ToDoubleFunction toDoubleFunction) {
- return new NoopFunctionCounter(id);
- }
-
- @Override
- protected TimeUnit getBaseTimeUnit() {
- return TimeUnit.SECONDS;
- }
-
- @Override
- protected DistributionStatisticConfig defaultHistogramConfig() {
- return DistributionStatisticConfig.NONE;
- }
+ default DefaultEventHandler.EventMonitor getEventMonitor() {
+ return EventMonitor.NOOP;
}
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java
index 834c516c68..c61bcb04b3 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java
@@ -18,9 +18,6 @@
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
import io.javaoperatorsdk.operator.api.config.ExecutorServiceManager;
import io.javaoperatorsdk.operator.processing.ConfiguredController;
-import io.javaoperatorsdk.operator.processing.DefaultEventHandler;
-import io.javaoperatorsdk.operator.processing.DefaultEventHandler.EventMonitor;
-import io.javaoperatorsdk.operator.processing.event.Event;
@SuppressWarnings("rawtypes")
public class Operator implements AutoCloseable {
@@ -32,17 +29,6 @@ public class Operator implements AutoCloseable {
public Operator(KubernetesClient k8sClient, ConfigurationService configurationService) {
this.k8sClient = k8sClient;
this.configurationService = configurationService;
- DefaultEventHandler.setEventMonitor(new EventMonitor() {
- @Override
- public void processedEvent(String uid, Event event) {
- configurationService.getMetrics().incrementProcessedEventsNumber();
- }
-
- @Override
- public void failedEvent(String uid, Event event) {
- configurationService.getMetrics().incrementControllerRetriesNumber();
- }
- });
}
/** Adds a shutdown hook that automatically calls {@link #close()} when the app shuts down. */
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/DefaultEventHandler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/DefaultEventHandler.java
index b44994a018..34201ae2df 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/DefaultEventHandler.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/DefaultEventHandler.java
@@ -14,6 +14,7 @@
import org.slf4j.LoggerFactory;
import io.fabric8.kubernetes.client.CustomResource;
+import io.javaoperatorsdk.operator.Metrics;
import io.javaoperatorsdk.operator.api.RetryInfo;
import io.javaoperatorsdk.operator.api.config.ConfigurationService;
import io.javaoperatorsdk.operator.api.config.ExecutorServiceManager;
@@ -35,13 +36,9 @@
public class DefaultEventHandler> implements EventHandler {
private static final Logger log = LoggerFactory.getLogger(DefaultEventHandler.class);
- private static EventMonitor monitor = new EventMonitor() {
- @Override
- public void processedEvent(String uid, Event event) {}
- @Override
- public void failedEvent(String uid, Event event) {}
- };
+ @Deprecated
+ private static EventMonitor monitor = EventMonitor.NOOP;
private final EventBuffer eventBuffer;
private final Set underProcessing = new HashSet<>();
@@ -51,6 +48,7 @@ public void failedEvent(String uid, Event event) {}
private final ExecutorService executor;
private final String controllerName;
private final ReentrantLock lock = new ReentrantLock();
+ private final EventMonitor eventMonitor;
private volatile boolean running;
private DefaultEventSourceManager eventSourceManager;
@@ -58,16 +56,17 @@ public DefaultEventHandler(ConfiguredController controller) {
this(ExecutorServiceManager.instance().executorService(),
controller.getConfiguration().getName(),
new EventDispatcher<>(controller),
- GenericRetry.fromConfiguration(controller.getConfiguration().getRetryConfiguration()));
+ GenericRetry.fromConfiguration(controller.getConfiguration().getRetryConfiguration()),
+ controller.getConfiguration().getConfigurationService().getMetrics().getEventMonitor());
}
DefaultEventHandler(EventDispatcher eventDispatcher, String relatedControllerName,
Retry retry) {
- this(null, relatedControllerName, eventDispatcher, retry);
+ this(null, relatedControllerName, eventDispatcher, retry, null);
}
private DefaultEventHandler(ExecutorService executor, String relatedControllerName,
- EventDispatcher eventDispatcher, Retry retry) {
+ EventDispatcher eventDispatcher, Retry retry, EventMonitor monitor) {
this.running = true;
this.executor =
executor == null
@@ -78,14 +77,44 @@ private DefaultEventHandler(ExecutorService executor, String relatedControllerNa
this.eventDispatcher = eventDispatcher;
this.retry = retry;
this.eventBuffer = new EventBuffer();
+ this.eventMonitor = monitor != null ? monitor : EventMonitor.NOOP;
+ }
+
+ public void setEventSourceManager(DefaultEventSourceManager eventSourceManager) {
+ this.eventSourceManager = eventSourceManager;
}
+ /**
+ * @deprecated the EventMonitor to be used should now be retrieved from
+ * {@link Metrics#getEventMonitor()}
+ * @param monitor
+ */
+ @Deprecated
public static void setEventMonitor(EventMonitor monitor) {
DefaultEventHandler.monitor = monitor;
}
- public void setEventSourceManager(DefaultEventSourceManager eventSourceManager) {
- this.eventSourceManager = eventSourceManager;
+ /*
+ * TODO: promote this interface to top-level, probably create a `monitoring` package?
+ */
+ public interface EventMonitor {
+ EventMonitor NOOP = new EventMonitor() {
+ @Override
+ public void processedEvent(String uid, Event event) {}
+
+ @Override
+ public void failedEvent(String uid, Event event) {}
+ };
+
+ void processedEvent(String uid, Event event);
+
+ void failedEvent(String uid, Event event);
+ }
+
+ private EventMonitor monitor() {
+ // todo: remove us of static monitor, only here for backwards compatibility
+ return DefaultEventHandler.monitor != EventMonitor.NOOP ? DefaultEventHandler.monitor
+ : eventMonitor;
}
@Override
@@ -102,6 +131,7 @@ public void handleEvent(Event event) {
log.debug("Received event: {}", event);
final Predicate selector = event.getCustomResourcesSelector();
+ final var monitor = monitor();
for (String uid : eventSourceManager.getLatestResourceUids(selector)) {
eventBuffer.addEvent(uid, event);
monitor.processedEvent(uid, event);
@@ -168,6 +198,7 @@ void eventProcessingFinished(
if (retry != null && postExecutionControl.exceptionDuringExecution()) {
handleRetryOnException(executionScope);
+ final var monitor = monitor();
executionScope.getEvents()
.forEach(e -> monitor.failedEvent(executionScope.getCustomResourceUid(), e));
return;
@@ -296,11 +327,6 @@ private void unsetUnderExecution(String customResourceUid) {
underProcessing.remove(customResourceUid);
}
- public interface EventMonitor {
- void processedEvent(String uid, Event event);
-
- void failedEvent(String uid, Event event);
- }
private class ControllerExecution implements Runnable {
private final ExecutionScope executionScope;
diff --git a/pom.xml b/pom.xml
index baa171c9fd..cbc7448686 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,6 +78,7 @@
operator-framework-junit5
operator-framework
samples
+ micrometer-support