Skip to content

Commit

Permalink
Improvements to the HttpMeterFilterFactory (#766)
Browse files Browse the repository at this point in the history
* Improvements to the HttpMeterFilterFactory

- Added support for specifying service level objectives (allows the creation of apdex widgets).
- Added support for specifying the expected max duration.
- Added support for specifying the expected min duration.
- Added support for histogram directly on the HttpMeterFilterFactory.
- Removed the redundant HttpHistogramMeterFilterFactory.
- Added tests for validating that the values are set correctly.
  • Loading branch information
lcavadas authored May 27, 2024
1 parent 9bc9f23 commit 67a4086
Show file tree
Hide file tree
Showing 7 changed files with 238 additions and 107 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@
import io.micrometer.core.instrument.config.MeterFilter;
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
import io.micronaut.configuration.metrics.annotation.RequiresMetrics;
import io.micronaut.configuration.metrics.binder.web.config.HttpClientMeterConfig;
import io.micronaut.configuration.metrics.binder.web.config.HttpMeterConfig;
import io.micronaut.configuration.metrics.binder.web.config.HttpServerMeterConfig;
import io.micronaut.context.annotation.Bean;
import io.micronaut.context.annotation.Factory;
import io.micronaut.context.annotation.Requires;
import io.micronaut.context.annotation.Value;
import io.micronaut.core.util.ArrayUtils;
import jakarta.inject.Singleton;

import static io.micronaut.configuration.metrics.binder.web.WebMetricsPublisher.METRIC_HTTP_CLIENT_REQUESTS;
import static io.micronaut.configuration.metrics.binder.web.WebMetricsPublisher.METRIC_HTTP_SERVER_REQUESTS;
import java.util.Arrays;

import static io.micronaut.configuration.metrics.micrometer.MeterRegistryFactory.MICRONAUT_METRICS_BINDERS;
import static io.micronaut.core.util.StringUtils.FALSE;

Expand All @@ -41,41 +42,54 @@
@Requires(property = WebMetricsPublisher.ENABLED, notEquals = FALSE)
public class HttpMeterFilterFactory {

public static final double SECONDS_TO_NANOS = 1_000_000_000d;

/**
* Configure new MeterFilter for http.server.requests metrics.
*
* @param percentiles The percentiles
* @param serverMeterConfig The HttpMeter configuration
* @return A MeterFilter
*/
@Bean
@Singleton
@Requires(property = MICRONAUT_METRICS_BINDERS + ".web.server.percentiles")
MeterFilter addServerPercentileMeterFilter(@Value("${" + MICRONAUT_METRICS_BINDERS + ".web.server.percentiles}") Double[] percentiles) {
return getMeterFilter(percentiles, METRIC_HTTP_SERVER_REQUESTS);
@Requires(property = MICRONAUT_METRICS_BINDERS + ".web.server")
MeterFilter addServerPercentileMeterFilter(HttpServerMeterConfig serverMeterConfig) {
return getMeterFilter(serverMeterConfig, WebMetricsPublisher.METRIC_HTTP_SERVER_REQUESTS);
}

/**
* Configure new MeterFilter for http.client.requests metrics.
*
* @param percentiles The percentiles
* @param clientMeterConfig The HttpMeter configuration
* @return A MeterFilter
*/
@Bean
@Singleton
@Requires(property = MICRONAUT_METRICS_BINDERS + ".web.client.percentiles")
MeterFilter addClientPercentileMeterFilter(@Value("${" + MICRONAUT_METRICS_BINDERS + ".web.client.percentiles}") Double[] percentiles) {
return getMeterFilter(percentiles, METRIC_HTTP_CLIENT_REQUESTS);
@Requires(property = MICRONAUT_METRICS_BINDERS + ".web.client")
MeterFilter addClientPercentileMeterFilter(HttpClientMeterConfig clientMeterConfig) {
return getMeterFilter(clientMeterConfig, WebMetricsPublisher.METRIC_HTTP_CLIENT_REQUESTS);
}

private MeterFilter getMeterFilter(Double[] percentiles, String metricNamePrefix) {
private MeterFilter getMeterFilter(HttpMeterConfig meterConfig, String metricNamePrefix) {
return new MeterFilter() {
@Override
public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) {
if (id.getName().startsWith(metricNamePrefix)) {
return DistributionStatisticConfig.builder()
.percentiles((double[]) ArrayUtils.toPrimitiveArray(percentiles))
.build()
.merge(config);
var builder = DistributionStatisticConfig.builder()
.percentiles()
.percentiles(Arrays.stream(meterConfig.getPercentiles()).mapToDouble(Double::doubleValue).toArray())
.serviceLevelObjectives(Arrays.stream(meterConfig.getSlos()).mapToDouble(d -> d * SECONDS_TO_NANOS).toArray())
.percentilesHistogram(meterConfig.getHistogram());

if (meterConfig.getMin() != null) {
builder.minimumExpectedValue(meterConfig.getMin() * SECONDS_TO_NANOS);
}

if (meterConfig.getMax() != null) {
builder.maximumExpectedValue(meterConfig.getMax() * SECONDS_TO_NANOS);
}

return builder.build().merge(config);
}
return config;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2017-2024 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.configuration.metrics.binder.web.config;

import io.micronaut.context.annotation.ConfigurationProperties;

import static io.micronaut.configuration.metrics.micrometer.MeterRegistryFactory.MICRONAUT_METRICS_BINDERS;

/**
* Http client meter configuration.
* @since 5.6.0
*/
@ConfigurationProperties(MICRONAUT_METRICS_BINDERS + ".web.client")
public class HttpClientMeterConfig extends HttpMeterConfig { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright 2017-2024 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.configuration.metrics.binder.web.config;

/**
* Http meter configuration.
* @since 5.6.0
*/
public abstract class HttpMeterConfig {

private Double[] percentiles = new Double[]{};
private Boolean histogram = false;
private Double min = null;
private Double max = null;
private Double[] slos = new Double[]{};

/**
* Default is empty.
* @return The percentiles. Specify in CSV format, ex: "0.95,0.99".
*/
public Double[] getPercentiles() {
return percentiles;
}

/**
* Default is empty.
* @param percentiles The percentiles. Specify in CSV format, ex: "0.95,0.99".
*/
public void setPercentiles(Double[] percentiles) {
this.percentiles = percentiles;
}

/**
* Default: false.
* @return If a histogram should be published.
*/
public Boolean getHistogram() {
return histogram;
}

/**
* Default: false.
* @param histogram If a histogram should be published.
*/
public void setHistogram(Boolean histogram) {
this.histogram = histogram;
}

/**
* Default: Micrometer default value (0.001).
* @return The minimum time (in s) value expected.
*/
public Double getMin() {
return min;
}

/**
* Default: Micrometer default value (0.001).
* @param min The minimum time (in s) value expected.
*/
public void setMin(Double min) {
this.min = min;
}

/**
* Default: Micrometer default value (30).
* @return The maximum time (in s) value expected.
*/
public Double getMax() {
return max;
}

/**
* Default: Micrometer default value (30).
* @param max The maximum time (in s) value expected.
*/
public void setMax(Double max) {
this.max = max;
}

/**
* Default is empty.
* @return The user-defined service levels objectives (in s) to create. Specify in CSV format, ex: "0.1,0.4".
*/
public Double[] getSlos() {
return slos;
}

/**
* Default is empty.
* @param slos The user-defined service levels objectives (in s) to create. Specify in CSV format, ex: "0.1,0.4".
*/
public void setSlos(Double[] slos) {
this.slos = slos;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2017-2024 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.configuration.metrics.binder.web.config;

import io.micronaut.context.annotation.ConfigurationProperties;

import static io.micronaut.configuration.metrics.micrometer.MeterRegistryFactory.MICRONAUT_METRICS_BINDERS;

/**
* Http server meter configuration.
* @since 5.6.0
*/
@ConfigurationProperties(MICRONAUT_METRICS_BINDERS + ".web.server")
public class HttpServerMeterConfig extends HttpMeterConfig { }
Loading

0 comments on commit 67a4086

Please sign in to comment.