1717import io .micrometer .core .instrument .binder .grpc .MetricCollectingClientInterceptor ;
1818import io .micrometer .core .instrument .binder .grpc .MetricCollectingServerInterceptor ;
1919import java .io .IOException ;
20+ import java .time .Duration ;
21+ import java .time .temporal .ChronoUnit ;
22+ import java .util .ArrayList ;
2023import java .util .Collection ;
2124import java .util .Collections ;
2225import java .util .LinkedList ;
@@ -51,6 +54,13 @@ abstract class GrpcPlatformServiceContainer extends PlatformService {
5154 private final HealthStatusManager healthStatusManager = new HealthStatusManager ();
5255 private InProcessGrpcChannelRegistry grpcChannelRegistry ;
5356 private HealthBlockingStub healthClient ;
57+ private static final String MAX_LATENCY_HISTOGRAM_BUCKET_DURATION =
58+ "metrics.latency.bucket.max.duration" ;
59+ private static final Duration DEFAULT_MAX_LATENCY_HISTOGRAM_BUCKET_DURATION =
60+ Duration .ofSeconds (10 );
61+ private static final Duration DEFAULT_MIN_LATENCY_HISTOGRAM_BUCKET_DURATION =
62+ Duration .ofMillis (10 );
63+ private static final int LATENCY_HISTOGRAM_BUCKET_FACTOR = 5 ;
5464
5565 public GrpcPlatformServiceContainer (ConfigClient configClient ) {
5666 super (configClient );
@@ -68,7 +78,8 @@ protected void doInit() {
6878 new MetricCollectingServerInterceptor (
6979 PlatformMetricsRegistry .getMeterRegistry (),
7080 UnaryOperator .identity (),
71- timerBuilder -> timerBuilder .publishPercentiles (0.5 , 0.75 , 0.90 , 0.95 , 0.99 ),
81+ timerBuilder ->
82+ timerBuilder .serviceLevelObjectives (generateLatencyHistogramBuckets ()),
7283 Status .Code .OK ))
7384 .addService (this .healthStatusManager .getHealthService ());
7485 final GrpcServiceContainerEnvironment serviceContainerEnvironment =
@@ -199,6 +210,20 @@ public boolean healthCheck() {
199210 }
200211 }
201212
213+ private Duration [] generateLatencyHistogramBuckets () {
214+ ArrayList <Duration > histogramBuckets = new ArrayList <>();
215+ Duration currDuration =
216+ getAppConfig ().hasPath (MAX_LATENCY_HISTOGRAM_BUCKET_DURATION )
217+ ? getAppConfig ().getDuration (MAX_LATENCY_HISTOGRAM_BUCKET_DURATION )
218+ : DEFAULT_MAX_LATENCY_HISTOGRAM_BUCKET_DURATION ;
219+ while (currDuration .compareTo (DEFAULT_MIN_LATENCY_HISTOGRAM_BUCKET_DURATION ) > 0 ) {
220+ histogramBuckets .add (currDuration );
221+ currDuration =
222+ currDuration .dividedBy (LATENCY_HISTOGRAM_BUCKET_FACTOR ).truncatedTo (ChronoUnit .MILLIS );
223+ }
224+ return histogramBuckets .toArray (new Duration [histogramBuckets .size ()]);
225+ }
226+
202227 protected InProcessGrpcChannelRegistry buildChannelRegistry () {
203228 return new InProcessGrpcChannelRegistry (
204229 this .getAuthorityInProcessOverrideMap (),
@@ -207,7 +232,8 @@ protected InProcessGrpcChannelRegistry buildChannelRegistry() {
207232 new MetricCollectingClientInterceptor (
208233 PlatformMetricsRegistry .getMeterRegistry (),
209234 UnaryOperator .identity (),
210- timerBuilder -> timerBuilder .publishPercentiles (0.5 , 0.75 , 0.90 , 0.95 , 0.99 ),
235+ timerBuilder ->
236+ timerBuilder .serviceLevelObjectives (generateLatencyHistogramBuckets ()),
211237 Status .Code .OK ))
212238 .build ());
213239 }
@@ -257,7 +283,7 @@ private ServerBuilder<?> initializeBuilder(GrpcPlatformServerDefinition serverDe
257283 new MetricCollectingServerInterceptor (
258284 PlatformMetricsRegistry .getMeterRegistry (),
259285 UnaryOperator .identity (),
260- timerBuilder -> timerBuilder .publishPercentiles ( 0.5 , 0.75 , 0.90 , 0.95 , 0.99 ),
286+ timerBuilder -> timerBuilder .serviceLevelObjectives ( generateLatencyHistogramBuckets () ),
261287 Status .Code .OK ));
262288
263289 serverDefinition .getServerInterceptors ().forEach (builder ::intercept );
0 commit comments