Skip to content

feat: initial PoC for micrometer integration #497

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions operator-framework-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<java.version>11</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<micrometer-core.version>1.7.3</micrometer-core.version>
</properties>

<build>
Expand Down Expand Up @@ -94,5 +95,10 @@
<version>3.20.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<version>${micrometer-core.version}</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package io.javaoperatorsdk.operator;

import io.fabric8.kubernetes.client.CustomResource;
import io.javaoperatorsdk.operator.api.Context;
import io.javaoperatorsdk.operator.api.ResourceController;
import io.javaoperatorsdk.operator.api.UpdateControl;
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
import io.micrometer.core.instrument.*;
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
import io.micrometer.core.instrument.distribution.pause.PauseDetector;
import io.micrometer.core.instrument.noop.*;
import java.util.concurrent.TimeUnit;
import java.util.function.ToDoubleFunction;
import java.util.function.ToLongFunction;

public class Metrics {
public static final Metrics NOOP = new Metrics(new NoopMeterRegistry(Clock.SYSTEM));
private final MeterRegistry registry;

public Metrics(MeterRegistry registry) {
this.registry = registry;
}

public <R extends CustomResource> UpdateControl<R> timeControllerCreateOrUpdate(
ResourceController<R> controller,
ControllerConfiguration<R> configuration,
R resource,
Context<R> context) {
// todo: https://github.com/java-operator-sdk/java-operator-sdk/issues/496 would simplify
// things
final var name = configuration.getName();
final var timer =
registry.timer("operator.sdk.controllers.execution.createOrUpdate", "controller", name);
try {
final var result = timer.record(() -> controller.createOrUpdateResource(resource, context));
String successType = "cr";
if (result.isUpdateStatusSubResource()) {
successType = "status";
}
if (result.isUpdateCustomResourceAndStatusSubResource()) {
successType = "both";
}
registry.counter(
"operator.sdk.controllers.execution.success", "controller", name, "type", successType);
return result;
} catch (Exception e) {
registry.counter(
"operator.sdk.controllers.execution.failure",
"controller",
name,
"exception",
e.getClass().getSimpleName());
throw e;
}
}

private static class NoopMeterRegistry extends MeterRegistry {
protected NoopMeterRegistry(Clock clock) {
super(clock);
}

@Override
protected <T> Gauge newGauge(Meter.Id id, T t, ToDoubleFunction<T> 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<Measurement> iterable) {
return new NoopMeter(id);
}

@Override
protected <T> FunctionTimer newFunctionTimer(
Meter.Id id,
T t,
ToLongFunction<T> toLongFunction,
ToDoubleFunction<T> toDoubleFunction,
TimeUnit timeUnit) {
return new NoopFunctionTimer(id);
}

@Override
protected <T> FunctionCounter newFunctionCounter(
Meter.Id id, T t, ToDoubleFunction<T> toDoubleFunction) {
return new NoopFunctionCounter(id);
}

@Override
protected TimeUnit getBaseTimeUnit() {
return TimeUnit.SECONDS;
}

@Override
protected DistributionStatisticConfig defaultHistogramConfig() {
return DistributionStatisticConfig.NONE;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,25 @@ public class Operator implements AutoCloseable {
private final Object lock;
private final List<ControllerRef> controllers;
private volatile boolean started;
private final Metrics metrics;

public Operator(KubernetesClient k8sClient, ConfigurationService configurationService) {
public Operator(
KubernetesClient k8sClient, ConfigurationService configurationService, Metrics metrics) {
this.k8sClient = k8sClient;
this.configurationService = configurationService;
this.closeables = new ArrayList<>();
this.lock = new Object();
this.controllers = new ArrayList<>();
this.started = false;
this.metrics = metrics;

Runtime.getRuntime().addShutdownHook(new Thread(this::close));
}

public Operator(KubernetesClient k8sClient, ConfigurationService configurationService) {
this(k8sClient, configurationService, Metrics.NOOP);
}

public KubernetesClient getKubernetesClient() {
return k8sClient;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.CustomResource;
import io.javaoperatorsdk.operator.Metrics;
import io.javaoperatorsdk.operator.api.ResourceController;
import java.util.Set;

Expand Down Expand Up @@ -91,4 +92,8 @@ default ObjectMapper getObjectMapper() {
default int getTerminationTimeoutSeconds() {
return DEFAULT_TERMINATION_TIMEOUT_SECONDS;
}

default Metrics getMetrics() {
return Metrics.NOOP;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,11 @@ private PostExecutionControl handleCreateOrUpdate(
getName(resource),
getVersion(resource),
executionScope);
UpdateControl<R> updateControl = controller.createOrUpdateResource(resource, context);
UpdateControl<R> updateControl =
configuration
.getConfigurationService()
.getMetrics()
.timeControllerCreateOrUpdate(controller, configuration, resource, context);
R updatedCustomResource = null;
if (updateControl.isUpdateCustomResourceAndStatusSubResource()) {
updatedCustomResource = updateCustomResource(updateControl.getCustomResource());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@

import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.client.Watcher;
import io.javaoperatorsdk.operator.Metrics;
import io.javaoperatorsdk.operator.TestUtils;
import io.javaoperatorsdk.operator.api.Context;
import io.javaoperatorsdk.operator.api.DeleteControl;
import io.javaoperatorsdk.operator.api.ResourceController;
import io.javaoperatorsdk.operator.api.RetryInfo;
import io.javaoperatorsdk.operator.api.UpdateControl;
import io.javaoperatorsdk.operator.api.config.ConfigurationService;
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
import io.javaoperatorsdk.operator.processing.event.Event;
import io.javaoperatorsdk.operator.processing.event.internal.CustomResourceEvent;
Expand All @@ -40,6 +42,7 @@ class EventDispatcherTest {
private final ResourceController<CustomResource> controller = mock(ResourceController.class);
private ControllerConfiguration<CustomResource> configuration =
mock(ControllerConfiguration.class);
private final ConfigurationService configService = mock(ConfigurationService.class);
private final EventDispatcher.CustomResourceFacade customResourceFacade =
mock(EventDispatcher.CustomResourceFacade.class);

Expand All @@ -51,6 +54,9 @@ void setup() {

when(configuration.getFinalizer()).thenReturn(DEFAULT_FINALIZER);
when(configuration.useFinalizer()).thenCallRealMethod();
when(configuration.getName()).thenReturn("EventDispatcherTestController");
when(configService.getMetrics()).thenReturn(Metrics.NOOP);
when(configuration.getConfigurationService()).thenReturn(configService);
when(controller.createOrUpdateResource(eq(testCustomResource), any()))
.thenReturn(UpdateControl.updateCustomResource(testCustomResource));
when(controller.deleteResource(eq(testCustomResource), any()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public void initialize(KubernetesClient k8sClient, ResourceController controller
namespaces.create(
new NamespaceBuilder().withNewMetadata().withName(TEST_NAMESPACE).endMetadata().build());
}
operator = new Operator(k8sClient, configurationService);
operator = new Operator(k8sClient, configurationService, Metrics.NOOP);
final var overriddenConfig =
ControllerConfigurationOverrider.override(config).settingNamespace(TEST_NAMESPACE);
if (retry != null) {
Expand Down