diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterValue.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterValue.java index c6d5fbcd254..b0dc59d0a26 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterValue.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterValue.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,17 +25,18 @@ import org.springframework.boot.convert.DurationStyle; /** * A meter value that is used when configuring micrometer. Can be a String representation - * of either a {@link Long} (applicable to timers and distribution summaries) or a + * of either a {@link Double} (applicable to timers and distribution summaries) or a * {@link Duration} (applicable to only timers). * * @author Phillip Webb + * @author Stephane Nicoll * @since 2.2.0 */ public final class MeterValue { private final Object value; - MeterValue(long value) { + MeterValue(double value) { this.value = value; } @@ -48,26 +49,29 @@ public final class MeterValue { * @param meterType the meter type * @return the value or {@code null} if the value cannot be applied */ - public Long getValue(Type meterType) { + public Double getValue(Type meterType) { if (meterType == Type.DISTRIBUTION_SUMMARY) { return getDistributionSummaryValue(); } if (meterType == Type.TIMER) { - return getTimerValue(); + Long timerValue = getTimerValue(); + if (timerValue != null) { + return timerValue.doubleValue(); + } } return null; } - private Long getDistributionSummaryValue() { - if (this.value instanceof Long) { - return (Long) this.value; + private Double getDistributionSummaryValue() { + if (this.value instanceof Double) { + return (Double) this.value; } return null; } private Long getTimerValue() { - if (this.value instanceof Long) { - return TimeUnit.MILLISECONDS.toNanos((long) this.value); + if (this.value instanceof Double) { + return TimeUnit.MILLISECONDS.toNanos(((Double) this.value).longValue()); } if (this.value instanceof Duration) { return ((Duration) this.value).toNanos(); @@ -82,8 +86,9 @@ public final class MeterValue { * @return a {@link MeterValue} instance */ public static MeterValue valueOf(String value) { - if (isNumber(value)) { - return new MeterValue(Long.parseLong(value)); + Double number = safeParseDouble(value); + if (number != null) { + return new MeterValue(number); } return new MeterValue(DurationStyle.detectAndParse(value)); } @@ -92,13 +97,29 @@ public final class MeterValue { * Return a new {@link MeterValue} instance for the given long value. * @param value the source value * @return a {@link MeterValue} instance + * @deprecated as of 2.3.0 in favor of {@link #valueOf(double)} */ + @Deprecated public static MeterValue valueOf(long value) { return new MeterValue(value); } - private static boolean isNumber(String value) { - return value.chars().allMatch(Character::isDigit); + /** + * Return a new {@link MeterValue} instance for the given double value. + * @param value the source value + * @return a {@link MeterValue} instance + */ + public static MeterValue valueOf(double value) { + return new MeterValue(value); + } + + private static Double safeParseDouble(String value) { + try { + return Double.parseDouble(value); + } + catch (NumberFormatException nfe) { + return null; + } } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java index bf50bb63cc4..b5bce1a4182 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -91,16 +91,16 @@ public class PropertiesMeterFilter implements MeterFilter { .build().merge(config); } - private long[] convertSla(Meter.Type meterType, ServiceLevelAgreementBoundary[] sla) { + private double[] convertSla(Meter.Type meterType, ServiceLevelAgreementBoundary[] sla) { if (sla == null) { return null; } - long[] converted = Arrays.stream(sla).map((candidate) -> candidate.getValue(meterType)).filter(Objects::nonNull) - .mapToLong(Long::longValue).toArray(); + double[] converted = Arrays.stream(sla).map((candidate) -> candidate.getValue(meterType)) + .filter(Objects::nonNull).mapToDouble(Double::doubleValue).toArray(); return (converted.length != 0) ? converted : null; } - private Long convertMeterValue(Meter.Type meterType, String value) { + private Double convertMeterValue(Meter.Type meterType, String value) { return (value != null) ? MeterValue.valueOf(value).getValue(meterType) : null; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/ServiceLevelAgreementBoundary.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/ServiceLevelAgreementBoundary.java index 9fa875fc188..dd0f80f7706 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/ServiceLevelAgreementBoundary.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/ServiceLevelAgreementBoundary.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,8 @@ import io.micrometer.core.instrument.Meter; /** * A service level agreement boundary for use when configuring Micrometer. Can be - * specified as either a {@link Long} (applicable to timers and distribution summaries) or - * a {@link Duration} (applicable to only timers). + * specified as either a {@link Double} (applicable to timers and distribution summaries) + * or a {@link Duration} (applicable to only timers). * * @author Phillip Webb * @since 2.0.0 @@ -42,17 +42,17 @@ public final class ServiceLevelAgreementBoundary { * @param meterType the meter type * @return the value or {@code null} if the value cannot be applied */ - public Long getValue(Meter.Type meterType) { + public Double getValue(Meter.Type meterType) { return this.value.getValue(meterType); } /** - * Return a new {@link ServiceLevelAgreementBoundary} instance for the given long + * Return a new {@link ServiceLevelAgreementBoundary} instance for the given double * value. * @param value the source value * @return a {@link ServiceLevelAgreementBoundary} instance */ - public static ServiceLevelAgreementBoundary valueOf(long value) { + public static ServiceLevelAgreementBoundary valueOf(double value) { return new ServiceLevelAgreementBoundary(MeterValue.valueOf(value)); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterValueTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterValueTests.java index f63da5faaef..1c1572d1682 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterValueTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterValueTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,17 +30,18 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link MeterValue}. * * @author Phillip Webb + * @author Stephane Nicoll */ class MeterValueTests { @Test - void getValueForDistributionSummaryWhenFromLongShouldReturnLongValue() { - MeterValue meterValue = MeterValue.valueOf(123L); - assertThat(meterValue.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(123); + void getValueForDistributionSummaryWhenFromNumberShouldReturnDoubleValue() { + MeterValue meterValue = MeterValue.valueOf(123.42); + assertThat(meterValue.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(123.42); } @Test - void getValueForDistributionSummaryWhenFromNumberStringShouldReturnLongValue() { + void getValueForDistributionSummaryWhenFromNumberStringShouldReturnDoubleValue() { MeterValue meterValue = MeterValue.valueOf("123"); assertThat(meterValue.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(123); } @@ -52,8 +53,8 @@ class MeterValueTests { } @Test - void getValueForTimerWhenFromLongShouldReturnMsToNanosValue() { - MeterValue meterValue = MeterValue.valueOf(123L); + void getValueForTimerWhenFromNumberShouldReturnMsToNanosValue() { + MeterValue meterValue = MeterValue.valueOf(123d); assertThat(meterValue.getValue(Type.TIMER)).isEqualTo(123000000); } @@ -81,11 +82,11 @@ class MeterValueTests { @Test void valueOfShouldWorkInBinder() { MockEnvironment environment = new MockEnvironment(); - TestPropertyValues.of("duration=10ms", "long=20").applyTo(environment); + TestPropertyValues.of("duration=10ms", "number=20.42").applyTo(environment); assertThat(Binder.get(environment).bind("duration", Bindable.of(MeterValue.class)).get().getValue(Type.TIMER)) .isEqualTo(10000000); - assertThat(Binder.get(environment).bind("long", Bindable.of(MeterValue.class)).get().getValue(Type.TIMER)) - .isEqualTo(20000000); + assertThat(Binder.get(environment).bind("number", Bindable.of(MeterValue.class)).get() + .getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(20.42); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/ServiceLevelAgreementBoundaryTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/ServiceLevelAgreementBoundaryTests.java index d9cb37e7f1d..f3250c13ac8 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/ServiceLevelAgreementBoundaryTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/ServiceLevelAgreementBoundaryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link ServiceLevelAgreementBoundary}. * * @author Phillip Webb + * @author Stephane Nicoll */ class ServiceLevelAgreementBoundaryTests { @@ -46,4 +47,22 @@ class ServiceLevelAgreementBoundaryTests { assertThat(sla.getValue(Type.TIMER)).isEqualTo(123000000); } + @Test + void getValueForDistributionSummaryWhenFromDoubleShouldReturnDoubleValue() { + ServiceLevelAgreementBoundary sla = ServiceLevelAgreementBoundary.valueOf(123.42); + assertThat(sla.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(123.42); + } + + @Test + void getValueForDistributionSummaryWhenFromStringShouldReturnDoubleValue() { + ServiceLevelAgreementBoundary sla = ServiceLevelAgreementBoundary.valueOf("123.42"); + assertThat(sla.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(123.42); + } + + @Test + void getValueForDistributionSummaryWhenFromDurationShouldReturnNull() { + ServiceLevelAgreementBoundary sla = ServiceLevelAgreementBoundary.valueOf("123ms"); + assertThat(sla.getValue(Type.DISTRIBUTION_SUMMARY)).isNull(); + } + }