Auto-configure Micrometer Observations

This commit auto-configures in the Micrometer Observations
API and its Observation server interceptor.

Resolves #1

Signed-off-by: Sunny <hmtang@gmail.com>
This commit is contained in:
Sunny
2024-10-27 20:27:06 +00:00
committed by Chris Bono
parent c56784fd7b
commit 61b1323440
4 changed files with 98 additions and 0 deletions

View File

@@ -54,6 +54,7 @@
<grpc.version>1.63.2</grpc.version>
<protobuf-java.version>3.25.5</protobuf-java.version>
<google-common-protos.version>2.46.0</google-common-protos.version>
<micrometer.version>1.13.6</micrometer.version>
</properties>
<dependencyManagement>
@@ -112,6 +113,13 @@
<artifactId>proto-google-common-protos</artifactId>
<version>${google-common-protos.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-bom</artifactId>
<version>${micrometer.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

View File

@@ -75,6 +75,16 @@
<artifactId>spring-boot-starter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-observation</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<optional>true</optional>
</dependency>
<!-- test dependencies -->
<dependency>

View File

@@ -0,0 +1,32 @@
package org.springframework.grpc.autoconfigure.server;
import io.grpc.ServerBuilder;
import io.grpc.ServerInterceptor;
import io.micrometer.core.instrument.binder.grpc.ObservationGrpcServerInterceptor;
import io.micrometer.observation.ObservationRegistry;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.grpc.server.ServerBuilderCustomizer;
@AutoConfiguration(
afterName = "org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration")
@ConditionalOnClass(value = { ObservationRegistry.class, ObservationGrpcServerInterceptor.class })
@ConditionalOnBean(ObservationRegistry.class)
@ConditionalOnProperty(value = "spring.grpc.server.observation.enabled", matchIfMissing = true)
public class GrpcServerObservationAutoConfiguration {
@Bean
public ServerInterceptor observationGrpcServerInterceptor(ObservationRegistry observationRegistry) {
return new ObservationGrpcServerInterceptor(observationRegistry);
}
@Bean
<T extends ServerBuilder<T>> ServerBuilderCustomizer<T> metricsInterceptor(
ServerInterceptor observationGrpcServerInterceptor) {
return (serverBuilder) -> serverBuilder.intercept(observationGrpcServerInterceptor);
}
}

View File

@@ -0,0 +1,48 @@
package org.springframework.grpc.autoconfigure.server;
import io.grpc.ServerBuilder;
import io.grpc.ServerInterceptor;
import io.micrometer.observation.ObservationRegistry;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.grpc.server.ServerBuilderCustomizer;
import static org.assertj.core.api.Assertions.assertThat;
class GrpcServerObservationAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(GrpcServerObservationAutoConfiguration.class));
@Test
void whenObservationRegistryNotProvided_thenObservationInterceptorNotConfigured() {
this.contextRunner.run(context -> {
assertThat(context).doesNotHaveBean(ServerBuilderCustomizer.class);
});
}
@Test
void whenObservationInterceptorConfigured_thenServerBuilderCustomizerConfigured() {
this.contextRunner.withBean(ObservationRegistry.class, ObservationRegistry::create).run(context -> {
assertThat(context).hasSingleBean(ServerBuilderCustomizer.class);
assertThat(context).hasSingleBean(ServerInterceptor.class);
ServerInterceptor interceptor = context.getBean(ServerInterceptor.class);
ServerBuilderCustomizer customizer = context.getBean(ServerBuilderCustomizer.class);
ServerBuilder<?> builder = org.mockito.Mockito.mock(ServerBuilder.class);
customizer.customize(builder);
org.mockito.Mockito.verify(builder, org.mockito.Mockito.times(1)).intercept(interceptor);
});
}
@Test
void whenObservationPropertyDisabled_thenServerBuilderCustomizerNotConfigured() {
this.contextRunner.withPropertyValues("spring.grpc.server.observation.enabled=false")
.withBean(ObservationRegistry.class, ObservationRegistry::create)
.run(context -> {
assertThat(context).doesNotHaveBean(ServerBuilderCustomizer.class);
assertThat(context).doesNotHaveBean(ServerInterceptor.class);
});
}
}