diff --git a/spring-grpc-dependencies/pom.xml b/spring-grpc-dependencies/pom.xml
index dd4275e7..8c39409e 100644
--- a/spring-grpc-dependencies/pom.xml
+++ b/spring-grpc-dependencies/pom.xml
@@ -54,6 +54,7 @@
1.63.2
3.25.5
2.46.0
+ 1.13.6
@@ -112,6 +113,13 @@
proto-google-common-protos
${google-common-protos.version}
+
+ io.micrometer
+ micrometer-bom
+ ${micrometer.version}
+ pom
+ import
+
diff --git a/spring-grpc-spring-boot-autoconfigure/pom.xml b/spring-grpc-spring-boot-autoconfigure/pom.xml
index 35521a06..74f57b2a 100644
--- a/spring-grpc-spring-boot-autoconfigure/pom.xml
+++ b/spring-grpc-spring-boot-autoconfigure/pom.xml
@@ -75,6 +75,16 @@
spring-boot-starter
provided
+
+ io.micrometer
+ micrometer-observation
+ true
+
+
+ io.micrometer
+ micrometer-core
+ true
+
diff --git a/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/server/GrpcServerObservationAutoConfiguration.java b/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/server/GrpcServerObservationAutoConfiguration.java
new file mode 100644
index 00000000..37027ab6
--- /dev/null
+++ b/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/server/GrpcServerObservationAutoConfiguration.java
@@ -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
+ > ServerBuilderCustomizer metricsInterceptor(
+ ServerInterceptor observationGrpcServerInterceptor) {
+ return (serverBuilder) -> serverBuilder.intercept(observationGrpcServerInterceptor);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/GrpcServerObservationAutoConfigurationTests.java b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/GrpcServerObservationAutoConfigurationTests.java
new file mode 100644
index 00000000..2282beb6
--- /dev/null
+++ b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/GrpcServerObservationAutoConfigurationTests.java
@@ -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);
+ });
+ }
+
+}
\ No newline at end of file