grpc-ecosystem / grpc-spring

Spring Boot starter module for gRPC framework.
https://grpc-ecosystem.github.io/grpc-spring/
Apache License 2.0
3.54k stars 830 forks source link

GrpcClientMetricAutoConfiguration conflicts with MeterRegistryCustomizer due to eager initialization of MeterRegistry #1141

Open rmitra28 opened 2 months ago

rmitra28 commented 2 months ago

The context

Added a custom MeterRegistryCustomizer to add a default tag (micrometer provided) to all the metrics.

The bug

What's the problem? What's not working? What do you expect to happen. Expect the custom tag to be added to all the metrics captured by the application. However, when adding this library, the custom tags are not added. Excluding certain AutoConfiguration classes (e.g. GrpcClientMetricAutoConfiguration) causes the tags to be added. It seems, these tags are skipped before MeterRegistryPostProcessor is able to post-process the MeterRegistry bean and add MeterRegistryCustomizer logic.

Stacktrace and logs

Is there a stacktrace or a hint in the logs? (very important) Screenshots work as well, but don't screenshot your logs.

"Bean 'metricsClientInterceptor' of type [net.devh.boot.grpc.client.metrics.MetricsClientInterceptor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [grpcClientBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.", "Bean 'net.devh.boot.grpc.client.autoconfigure.GrpcClientMicrometerTraceAutoConfiguration' of type [net.devh.boot.grpc.client.autoconfigure.GrpcClientMicrometerTraceAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [grpcClientBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.", "Bean 'org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration' of type [org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [grpcClientBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.", "Bean 'observationRegistry' of type [io.micrometer.observation.SimpleObservationRegistry] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [grpcClientBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.", "Bean 'globalObservationClientInterceptorConfigurer' of type [io.micrometer.core.instrument.binder.grpc.ObservationGrpcClientInterceptor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [grpcClientBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.", "Bean 'grpcClientConfig' of type [in.dailyhunt.reco.service.interceptor.GrpcClientConfig$$SpringCGLIB$$0] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [grpcClientBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.", "Bean 'customInterceptor' of type [in.dailyhunt.reco.service.interceptor.UserProfileServiceClientInterceptor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [grpcClientBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.", "Bean 'asyncStubFactory' of type [net.devh.boot.grpc.client.stubfactory.AsyncStubFactory] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [grpcClientBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.", "Bean 'blockingStubFactory' of type [net.devh.boot.grpc.client.stubfactory.BlockingStubFactory] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [grpcClientBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.", "Bean 'futureStubFactory' of type [net.devh.boot.grpc.client.stubfactory.FutureStubFactory] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [grpcClientBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies."

Steps to Reproduce

Steps to reproduce the behavior:

  1. Implement a custom MeterRegistryCustomizer @Bean MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() { return registry -> registry.config().commonTags(Tags.of("host", "host-1").and("module", "mymodule")); }
  2. Use the library to implement a GrpcClient implementation.
  3. Start the application with @SpringBootApplication(exclude = {GrpcClientMetricAutoConfiguration.class}) and without. When starting with the auto-configure classes excluded, the tag 'host' and 'module' are added to all metrics. If we do not exclude the autoconfigure classes, the metrics do not carry these tags.

The application's environment

Which versions do you use?

Additional context

nikoncode commented 2 weeks ago

I have same problem.

It happens because GrpcClientBeanPostProcessor initializes beans (like interceptors) eagerly in @PostConstruct, it makes every dependency (including transitive) being unavailable for post processing.

It can prevent exporters like prometheus to be initialized properly, because it's also done via BeanPostProcessor