Skip to content

Commit

Permalink
Polish micrometer-registry-health module (#2441)
Browse files Browse the repository at this point in the history
  • Loading branch information
izeye committed Feb 16, 2021
1 parent 20cffda commit 9c3c9f4
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 88 deletions.
Expand Up @@ -21,6 +21,12 @@

import static io.micrometer.core.instrument.config.validate.PropertyValidator.getDuration;

/**
* {@link MeterRegistryConfig} for {@link HealthMeterRegistry}.
*
* @author Jon Schneider
* @since 1.6.0
*/
public interface HealthConfig extends MeterRegistryConfig {
HealthConfig DEFAULT = key -> null;

Expand Down
Expand Up @@ -17,24 +17,23 @@

import java.util.function.BinaryOperator;

/**
* Utilities for queries.
*
* @author Jon Schneider
*/
class QueryUtils {
public static final BinaryOperator<Double> SUM_OR_NAN = (v1, v2) -> {
static final BinaryOperator<Double> SUM_OR_NAN = (v1, v2) -> {
if (Double.isNaN(v1)) {
if (Double.isNaN(v2)) {
return Double.NaN;
}
return v2;
} else if (Double.isNaN(v2)) {
return v1;
}
return v1 + v2;
};

public static final BinaryOperator<Double> MAX_OR_NAN = (v1, v2) -> {
static final BinaryOperator<Double> MAX_OR_NAN = (v1, v2) -> {
if (Double.isNaN(v1)) {
if (Double.isNaN(v2)) {
return Double.NaN;
}
return v2;
} else if (Double.isNaN(v2)) {
return v1;
Expand Down
Expand Up @@ -20,6 +20,7 @@
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
import io.micrometer.core.instrument.config.MeterFilter;
import io.micrometer.core.instrument.distribution.HistogramSupport;
import io.micrometer.core.instrument.distribution.ValueAtPercentile;
import io.micrometer.core.instrument.search.Search;
import io.micrometer.core.lang.Nullable;
Expand Down Expand Up @@ -64,11 +65,14 @@ public abstract class ServiceLevelObjective {
@Nullable
private final String failedMessage;

private final Meter.Id id;

protected ServiceLevelObjective(String name, Tags tags, @Nullable String baseUnit, @Nullable String failedMessage) {
this.name = name;
this.tags = tags;
this.baseUnit = baseUnit;
this.failedMessage = failedMessage;
this.id = new Meter.Id(name, tags, baseUnit, failedMessage, Meter.Type.GAUGE);
}

public String getName() {
Expand All @@ -85,7 +89,7 @@ public String getBaseUnit() {
}

public Meter.Id getId() {
return new Meter.Id(name, tags, baseUnit, failedMessage, Meter.Type.GAUGE);
return id;
}

@Nullable
Expand Down Expand Up @@ -125,7 +129,7 @@ protected SingleIndicator(NumericQuery query, String testDescription, Predicate<

@Override
public boolean healthy(MeterRegistry registry) {
Double v = query.getValue(registry);
Double v = getValue(registry);
return v.isNaN() || test.test(v);
}

Expand Down Expand Up @@ -181,8 +185,7 @@ public static class Builder {
private final Collection<MeterBinder> requires;

Builder(String name) {
this.name = name;
this.requires = new ArrayList<>();
this(name, null, new ArrayList<>());
}

Builder(String name, @Nullable String failedMessage, Collection<MeterBinder> requires) {
Expand Down Expand Up @@ -215,7 +218,7 @@ public final Builder tags(String... tags) {
}

/**
* @param tags Tags to add to the eventual timer.
* @param tags Tags to add to the single indicator.
* @return The builder with added tags.
*/
public final Builder tags(Iterable<Tag> tags) {
Expand All @@ -226,7 +229,7 @@ public final Builder tags(Iterable<Tag> tags) {
/**
* @param key The tag key.
* @param value The tag value.
* @return The timer builder with a single added tag.
* @return The single indicator builder with a single added tag.
*/
public final Builder tag(String key, String value) {
this.tags = tags.and(key, value);
Expand Down Expand Up @@ -278,15 +281,11 @@ public final NumericQuery total(Function<Search, Search> search) {
public final NumericQuery maxPercentile(Function<Search, Search> search, double percentile) {
return new Instant(name, tags, baseUnit, failedMessage, requires, search, s -> s.meters().stream()
.map(m -> {
ValueAtPercentile[] valueAtPercentiles = new ValueAtPercentile[0];
if (m instanceof DistributionSummary) {
valueAtPercentiles = ((DistributionSummary) m).takeSnapshot().percentileValues();
} else if (m instanceof Timer) {
valueAtPercentiles = ((Timer) m).takeSnapshot().percentileValues();
} else if (m instanceof LongTaskTimer) {
valueAtPercentiles = ((LongTaskTimer) m).takeSnapshot().percentileValues();
if (!(m instanceof HistogramSupport)) {
return Double.NaN;
}

ValueAtPercentile[] valueAtPercentiles = ((HistogramSupport) m).takeSnapshot().percentileValues();
return Arrays.stream(valueAtPercentiles)
.filter(vap -> vap.percentile() == percentile)
.map(ValueAtPercentile::value)
Expand Down Expand Up @@ -653,7 +652,7 @@ public Builder tags(String... tags) {
}

/**
* @param tags Tags to add to the eventual timer.
* @param tags Tags to add to the multiple indicator.
* @return The builder with added tags.
*/
public Builder tags(Iterable<Tag> tags) {
Expand Down
Expand Up @@ -23,6 +23,8 @@
import java.time.Duration;

/**
* {@link ServiceLevelObjective ServiceLevelObjectives} for Java Virtual Machine.
*
* @author Jon Schneider
* @since 1.6.0
*/
Expand All @@ -31,7 +33,7 @@ public class JvmServiceLevelObjectives {
* A series of high-level heap monitors originally defined in
* <a href="https://www.jetbrains.com/help/teamcity/teamcity-memory-monitor.html">Team City's memory monitor</a>.
*/
public static final ServiceLevelObjective[] MEMORY = new ServiceLevelObjective[]{
public static final ServiceLevelObjective[] MEMORY = new ServiceLevelObjective[] {
ServiceLevelObjective
.build("jvm.pool.memory")
.failedMessage("Memory usage in a single memory pool exceeds 90% after garbage collection.")
Expand All @@ -44,6 +46,7 @@ public class JvmServiceLevelObjectives {
.build("jvm.gc.load")
.failedMessage("Memory cleaning is taking more than 50% of CPU resources on average. " +
"This usually means really serious problems with memory resulting in high performance degradation.")
.requires(new JvmHeapPressureMetrics())
.baseUnit("percent CPU time spent")
.value(s -> s.name("jvm.gc.overhead"))
.isLessThan(0.5),
Expand Down Expand Up @@ -72,7 +75,7 @@ public class JvmServiceLevelObjectives {
.and()
};

public static final ServiceLevelObjective[] ALLOCATIONS = new ServiceLevelObjective[]{
public static final ServiceLevelObjective[] ALLOCATIONS = new ServiceLevelObjective[] {
ServiceLevelObjective
.build("jvm.allocations.g1.humongous")
.failedMessage("A single object was allocated that exceeded 50% of the total size of the eden space.")
Expand Down
Expand Up @@ -19,11 +19,13 @@
import io.micrometer.health.ServiceLevelObjective;

/**
* {@link ServiceLevelObjective ServiceLevelObjectives} for Operating System.
*
* @author Jon Schneider
* @since 1.6.0
*/
public class OperatingSystemServiceLevelObjectives {
public static final ServiceLevelObjective[] DISK = new ServiceLevelObjective[]{
public static final ServiceLevelObjective[] DISK = new ServiceLevelObjective[] {
ServiceLevelObjective.build("os.file.descriptors")
.failedMessage("Too many file descriptors are open. When the max is reached, " +
"further attempts to retrieve a file descriptor will block indefinitely.")
Expand Down
Expand Up @@ -13,6 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* SLO-based health meter registry.
*/
@NonNullApi
@NonNullFields
package io.micrometer.health;
Expand Down
Expand Up @@ -29,6 +29,11 @@
import static io.micrometer.core.instrument.MockClock.clock;
import static org.assertj.core.api.Assertions.assertThat;

/**
* Tests for {@link HealthMeterRegistry}.
*
* @author Jon Schneider
*/
class HealthMeterRegistryTest {
@Test
void healthFromServiceLevelObjective() {
Expand Down Expand Up @@ -123,8 +128,7 @@ void applyRequiredBinders() {
.build();

assertThat(registry.getMeters().stream().map(m -> m.getId().getName()))
.containsOnly("jvm.memory.used")
.isNotEmpty();
.containsOnly("jvm.memory.used");
}

@Test
Expand All @@ -143,7 +147,6 @@ public Meter.Id map(Meter.Id id) {

assertThat(registry.getServiceLevelObjectives().stream().map(ServiceLevelObjective::getName))
.contains("jvm.collection.load")
.doesNotContain("jvm.pool.memory")
.isNotEmpty();
.doesNotContain("jvm.pool.memory");
}
}
Expand Up @@ -156,15 +156,15 @@ void isLessThan() {
.count(s -> s.name("my.timer"))
.isLessThan(4)
.healthy(registry)
).isEqualTo(true);
).isTrue();

assertThat(
ServiceLevelObjective
.build("sum")
.total(s -> s.name("my.timer"))
.isLessThan(Duration.ofSeconds(6))
.healthy(registry)
).isEqualTo(true);
).isTrue();
}

@Test
Expand All @@ -175,14 +175,14 @@ void isLessThanOrEqualTo() {
.count(s -> s.name("my.timer"))
.isLessThanOrEqualTo(3)
.healthy(registry)
).isEqualTo(true);
).isTrue();

assertThat(ServiceLevelObjective
.build("sum")
.total(s -> s.name("my.timer"))
.isLessThanOrEqualTo(Duration.ofSeconds(5))
.healthy(registry)
).isEqualTo(true);
).isTrue();
}

@Test
Expand All @@ -193,15 +193,15 @@ void isGreaterThan() {
.count(s -> s.name("my.timer"))
.isGreaterThan(2)
.healthy(registry)
).isEqualTo(true);
).isTrue();

assertThat(
ServiceLevelObjective
.build("sum")
.total(s -> s.name("my.timer"))
.isGreaterThan(Duration.ofSeconds(4))
.healthy(registry)
).isEqualTo(true);
).isTrue();
}

@Test
Expand All @@ -212,15 +212,15 @@ void isGreaterThanOrEqualTo() {
.count(s -> s.name("my.timer"))
.isGreaterThanOrEqualTo(3)
.healthy(registry)
).isEqualTo(true);
).isTrue();

assertThat(
ServiceLevelObjective
.build("sum")
.total(s -> s.name("my.timer"))
.isGreaterThanOrEqualTo(Duration.ofSeconds(5))
.healthy(registry)
).isEqualTo(true);
).isTrue();
}

@Test
Expand All @@ -231,14 +231,14 @@ void isEqualTo() {
.count(s -> s.name("my.timer"))
.isEqualTo(3)
.healthy(registry)
).isEqualTo(true);
).isTrue();

assertThat(
ServiceLevelObjective
.build("sum")
.total(s -> s.name("my.timer"))
.isEqualTo(Duration.ofSeconds(5))
.healthy(registry)
).isEqualTo(true);
).isTrue();
}
}

0 comments on commit 9c3c9f4

Please sign in to comment.