Upgrade to Micrometer 1.5 snapshots

pull/20874/head
Stephane Nicoll 5 years ago
commit 5a20403327

@ -101,6 +101,7 @@ dependencies {
optional("org.springframework.data:spring-data-redis") optional("org.springframework.data:spring-data-redis")
optional("org.springframework.data:spring-data-solr") optional("org.springframework.data:spring-data-solr")
optional("org.springframework.integration:spring-integration-core") optional("org.springframework.integration:spring-integration-core")
optional("org.springframework.kafka:spring-kafka")
optional("org.springframework.security:spring-security-config") optional("org.springframework.security:spring-security-config")
optional("org.springframework.security:spring-security-web") optional("org.springframework.security:spring-security-web")
optional("org.springframework.session:spring-session-core") optional("org.springframework.session:spring-session-core")

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,37 +18,37 @@ package org.springframework.boot.actuate.autoconfigure.metrics;
import java.util.Collections; import java.util.Collections;
import javax.management.MBeanServer;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.kafka.KafkaConsumerMetrics; import io.micrometer.core.instrument.binder.kafka.KafkaClientMetrics;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.ProducerFactory;
/** /**
* Auto-configuration for Kafka metrics. * Auto-configuration for Kafka metrics.
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Stephane Nicoll
* @since 2.1.0 * @since 2.1.0
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@AutoConfigureAfter({ MetricsAutoConfiguration.class, JmxAutoConfiguration.class }) @AutoConfigureAfter({ MetricsAutoConfiguration.class, KafkaAutoConfiguration.class })
@ConditionalOnClass({ KafkaConsumerMetrics.class, KafkaConsumer.class }) @ConditionalOnClass({ KafkaClientMetrics.class, ProducerFactory.class })
@ConditionalOnBean(MeterRegistry.class) @ConditionalOnBean(MeterRegistry.class)
public class KafkaMetricsAutoConfiguration { public class KafkaMetricsAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnBean(MBeanServer.class) @ConditionalOnSingleCandidate(ProducerFactory.class)
public KafkaConsumerMetrics kafkaConsumerMetrics(MBeanServer mbeanServer) { public KafkaClientMetrics kafkaClientMetrics(ProducerFactory<?, ?> producerFactory) {
return new KafkaConsumerMetrics(mbeanServer, Collections.emptyList()); return new KafkaClientMetrics(producerFactory.createProducer(), Collections.emptyList());
} }
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 * 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). * {@link Duration} (applicable to only timers).
* *
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll
* @since 2.2.0 * @since 2.2.0
*/ */
public final class MeterValue { public final class MeterValue {
private final Object value; private final Object value;
MeterValue(long value) { MeterValue(double value) {
this.value = value; this.value = value;
} }
@ -48,26 +49,29 @@ public final class MeterValue {
* @param meterType the meter type * @param meterType the meter type
* @return the value or {@code null} if the value cannot be applied * @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) { if (meterType == Type.DISTRIBUTION_SUMMARY) {
return getDistributionSummaryValue(); return getDistributionSummaryValue();
} }
if (meterType == Type.TIMER) { if (meterType == Type.TIMER) {
return getTimerValue(); Long timerValue = getTimerValue();
if (timerValue != null) {
return timerValue.doubleValue();
}
} }
return null; return null;
} }
private Long getDistributionSummaryValue() { private Double getDistributionSummaryValue() {
if (this.value instanceof Long) { if (this.value instanceof Double) {
return (Long) this.value; return (Double) this.value;
} }
return null; return null;
} }
private Long getTimerValue() { private Long getTimerValue() {
if (this.value instanceof Long) { if (this.value instanceof Double) {
return TimeUnit.MILLISECONDS.toNanos((long) this.value); return TimeUnit.MILLISECONDS.toNanos(((Double) this.value).longValue());
} }
if (this.value instanceof Duration) { if (this.value instanceof Duration) {
return ((Duration) this.value).toNanos(); return ((Duration) this.value).toNanos();
@ -82,8 +86,9 @@ public final class MeterValue {
* @return a {@link MeterValue} instance * @return a {@link MeterValue} instance
*/ */
public static MeterValue valueOf(String value) { public static MeterValue valueOf(String value) {
if (isNumber(value)) { Double number = safeParseDouble(value);
return new MeterValue(Long.parseLong(value)); if (number != null) {
return new MeterValue(number);
} }
return new MeterValue(DurationStyle.detectAndParse(value)); 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. * Return a new {@link MeterValue} instance for the given long value.
* @param value the source value * @param value the source value
* @return a {@link MeterValue} instance * @return a {@link MeterValue} instance
* @deprecated as of 2.3.0 in favor of {@link #valueOf(double)}
*/ */
@Deprecated
public static MeterValue valueOf(long value) { public static MeterValue valueOf(long value) {
return new MeterValue(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;
}
} }
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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); .build().merge(config);
} }
private long[] convertSla(Meter.Type meterType, ServiceLevelAgreementBoundary[] sla) { private double[] convertSla(Meter.Type meterType, ServiceLevelAgreementBoundary[] sla) {
if (sla == null) { if (sla == null) {
return null; return null;
} }
long[] converted = Arrays.stream(sla).map((candidate) -> candidate.getValue(meterType)).filter(Objects::nonNull) double[] converted = Arrays.stream(sla).map((candidate) -> candidate.getValue(meterType))
.mapToLong(Long::longValue).toArray(); .filter(Objects::nonNull).mapToDouble(Double::doubleValue).toArray();
return (converted.length != 0) ? converted : null; 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; return (value != null) ? MeterValue.valueOf(value).getValue(meterType) : null;
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 * 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 * specified as either a {@link Double} (applicable to timers and distribution summaries)
* a {@link Duration} (applicable to only timers). * or a {@link Duration} (applicable to only timers).
* *
* @author Phillip Webb * @author Phillip Webb
* @since 2.0.0 * @since 2.0.0
@ -42,17 +42,17 @@ public final class ServiceLevelAgreementBoundary {
* @param meterType the meter type * @param meterType the meter type
* @return the value or {@code null} if the value cannot be applied * @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 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. * value.
* @param value the source value * @param value the source value
* @return a {@link ServiceLevelAgreementBoundary} instance * @return a {@link ServiceLevelAgreementBoundary} instance
*/ */
public static ServiceLevelAgreementBoundary valueOf(long value) { public static ServiceLevelAgreementBoundary valueOf(double value) {
return new ServiceLevelAgreementBoundary(MeterValue.valueOf(value)); return new ServiceLevelAgreementBoundary(MeterValue.valueOf(value));
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -46,6 +46,12 @@ public class AppOpticsProperties extends StepRegistryProperties {
*/ */
private String hostTag = "instance"; private String hostTag = "instance";
/**
* Whether to ship a floored time, useful when sending measurements from multiple
* hosts to align them on a given time boundary.
*/
private boolean floorTimes;
/** /**
* Number of measurements per request to use for this backend. If more measurements * Number of measurements per request to use for this backend. If more measurements
* are found, then multiple requests will be made. * are found, then multiple requests will be made.
@ -81,6 +87,14 @@ public class AppOpticsProperties extends StepRegistryProperties {
this.hostTag = hostTag; this.hostTag = hostTag;
} }
public boolean isFloorTimes() {
return this.floorTimes;
}
public void setFloorTimes(boolean floorTimes) {
this.floorTimes = floorTimes;
}
@Override @Override
public Integer getBatchSize() { public Integer getBatchSize() {
return this.batchSize; return this.batchSize;

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -47,4 +47,9 @@ class AppOpticsPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapt
return get(AppOpticsProperties::getHostTag, AppOpticsConfig.super::hostTag); return get(AppOpticsProperties::getHostTag, AppOpticsConfig.super::hostTag);
} }
@Override
public boolean floorTimes() {
return get(AppOpticsProperties::isFloorTimes, AppOpticsConfig.super::floorTimes);
}
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -56,7 +56,7 @@ public class DatadogProperties extends StepRegistryProperties {
* URI to ship metrics to. If you need to publish metrics to an internal proxy * URI to ship metrics to. If you need to publish metrics to an internal proxy
* en-route to Datadog, you can define the location of the proxy with this. * en-route to Datadog, you can define the location of the proxy with this.
*/ */
private String uri = "https://app.datadoghq.com"; private String uri = "https://api.datadoghq.com";
public String getApiKey() { public String getApiKey() {
return this.apiKey; return this.apiKey;

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -40,11 +40,15 @@ public class ElasticProperties extends StepRegistryProperties {
private String index = "metrics"; private String index = "metrics";
/** /**
* Index date format used for rolling indices. Appended to the index name, preceded by * Index date format used for rolling indices. Appended to the index name.
* a '-'.
*/ */
private String indexDateFormat = "yyyy-MM"; private String indexDateFormat = "yyyy-MM";
/**
* Prefix to separate the index name from the date format used for rolling indices.
*/
private String indexDateSeparator = "-";
/** /**
* Name of the timestamp field. * Name of the timestamp field.
*/ */
@ -65,6 +69,11 @@ public class ElasticProperties extends StepRegistryProperties {
*/ */
private String password = ""; private String password = "";
/**
* Ingest pipeline name. By default, events are not pre-processed.
*/
private String pipeline = "";
public String getHost() { public String getHost() {
return this.host; return this.host;
} }
@ -89,6 +98,14 @@ public class ElasticProperties extends StepRegistryProperties {
this.indexDateFormat = indexDateFormat; this.indexDateFormat = indexDateFormat;
} }
public String getIndexDateSeparator() {
return this.indexDateSeparator;
}
public void setIndexDateSeparator(String indexDateSeparator) {
this.indexDateSeparator = indexDateSeparator;
}
public String getTimestampFieldName() { public String getTimestampFieldName() {
return this.timestampFieldName; return this.timestampFieldName;
} }
@ -121,4 +138,12 @@ public class ElasticProperties extends StepRegistryProperties {
this.password = password; this.password = password;
} }
public String getPipeline() {
return this.pipeline;
}
public void setPipeline(String pipeline) {
this.pipeline = pipeline;
}
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -47,6 +47,11 @@ class ElasticPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter
return get(ElasticProperties::getIndexDateFormat, ElasticConfig.super::indexDateFormat); return get(ElasticProperties::getIndexDateFormat, ElasticConfig.super::indexDateFormat);
} }
@Override
public String indexDateSeparator() {
return get(ElasticProperties::getIndexDateSeparator, ElasticConfig.super::indexDateSeparator);
}
@Override @Override
public String timestampFieldName() { public String timestampFieldName() {
return get(ElasticProperties::getTimestampFieldName, ElasticConfig.super::timestampFieldName); return get(ElasticProperties::getTimestampFieldName, ElasticConfig.super::timestampFieldName);
@ -67,4 +72,9 @@ class ElasticPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter
return get(ElasticProperties::getPassword, ElasticConfig.super::password); return get(ElasticProperties::getPassword, ElasticConfig.super::password);
} }
@Override
public String pipeline() {
return get(ElasticProperties::getPipeline, ElasticConfig.super::pipeline);
}
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -70,8 +70,14 @@ public class GraphiteProperties {
private GraphiteProtocol protocol = GraphiteProtocol.PICKLED; private GraphiteProtocol protocol = GraphiteProtocol.PICKLED;
/** /**
* For the default naming convention, turn the specified tag keys into part of the * Whether Graphite tags should be used, as opposed to a hierarchical naming
* metric prefix. * convention.
*/
private boolean graphiteTagsEnabled = true;
/**
* For the hierarchical naming convention, turn the specified tag keys into part of
* the metric prefix. Ignored if "graphiteTagsEnabled" is true.
*/ */
private String[] tagsAsPrefix = new String[0]; private String[] tagsAsPrefix = new String[0];
@ -131,6 +137,14 @@ public class GraphiteProperties {
this.protocol = protocol; this.protocol = protocol;
} }
public boolean isGraphiteTagsEnabled() {
return this.graphiteTagsEnabled;
}
public void setGraphiteTagsEnabled(boolean graphiteTagsEnabled) {
this.graphiteTagsEnabled = graphiteTagsEnabled;
}
public String[] getTagsAsPrefix() { public String[] getTagsAsPrefix() {
return this.tagsAsPrefix; return this.tagsAsPrefix;
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -76,6 +76,11 @@ class GraphitePropertiesConfigAdapter extends PropertiesConfigAdapter<GraphitePr
return get(GraphiteProperties::getProtocol, GraphiteConfig.super::protocol); return get(GraphiteProperties::getProtocol, GraphiteConfig.super::protocol);
} }
@Override
public boolean graphiteTagsEnabled() {
return get(GraphiteProperties::isGraphiteTagsEnabled, GraphiteConfig.super::graphiteTagsEnabled);
}
@Override @Override
public String[] tagsAsPrefix() { public String[] tagsAsPrefix() {
return get(GraphiteProperties::getTagsAsPrefix, GraphiteConfig.super::tagsAsPrefix); return get(GraphiteProperties::getTagsAsPrefix, GraphiteConfig.super::tagsAsPrefix);

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,6 +20,8 @@ import java.time.Duration;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import io.micrometer.prometheus.HistogramFlavor;
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager.ShutdownOperation; import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager.ShutdownOperation;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
@ -46,6 +48,11 @@ public class PrometheusProperties {
*/ */
private final Pushgateway pushgateway = new Pushgateway(); private final Pushgateway pushgateway = new Pushgateway();
/**
* Histogram type for backing DistributionSummary and Timer.
*/
private HistogramFlavor histogramFlavor = HistogramFlavor.Prometheus;
/** /**
* Step size (i.e. reporting frequency) to use. * Step size (i.e. reporting frequency) to use.
*/ */
@ -59,6 +66,14 @@ public class PrometheusProperties {
this.descriptions = descriptions; this.descriptions = descriptions;
} }
public HistogramFlavor getHistogramFlavor() {
return this.histogramFlavor;
}
public void setHistogramFlavor(HistogramFlavor histogramFlavor) {
this.histogramFlavor = histogramFlavor;
}
public Duration getStep() { public Duration getStep() {
return this.step; return this.step;
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,6 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus
import java.time.Duration; import java.time.Duration;
import io.micrometer.prometheus.HistogramFlavor;
import io.micrometer.prometheus.PrometheusConfig; import io.micrometer.prometheus.PrometheusConfig;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PropertiesConfigAdapter; import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PropertiesConfigAdapter;
@ -45,6 +46,11 @@ class PrometheusPropertiesConfigAdapter extends PropertiesConfigAdapter<Promethe
return get(PrometheusProperties::isDescriptions, PrometheusConfig.super::descriptions); return get(PrometheusProperties::isDescriptions, PrometheusConfig.super::descriptions);
} }
@Override
public HistogramFlavor histogramFlavor() {
return get(PrometheusProperties::getHistogramFlavor, PrometheusConfig.super::histogramFlavor);
}
@Override @Override
public Duration step() { public Duration step() {
return get(PrometheusProperties::getStep, PrometheusConfig.super::step); return get(PrometheusProperties::getStep, PrometheusConfig.super::step);

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,7 +19,6 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.statsd;
import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.Clock;
import io.micrometer.statsd.StatsdConfig; import io.micrometer.statsd.StatsdConfig;
import io.micrometer.statsd.StatsdMeterRegistry; import io.micrometer.statsd.StatsdMeterRegistry;
import io.micrometer.statsd.StatsdMetrics;
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
@ -63,9 +62,4 @@ public class StatsdMetricsExportAutoConfiguration {
return new StatsdMeterRegistry(statsdConfig, clock); return new StatsdMeterRegistry(statsdConfig, clock);
} }
@Bean
public StatsdMetrics statsdMetrics() {
return new StatsdMetrics();
}
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,14 +16,19 @@
package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront; package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront;
import java.time.Duration;
import com.wavefront.sdk.common.WavefrontSender;
import com.wavefront.sdk.direct.ingestion.WavefrontDirectIngestionClient.Builder;
import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.Clock;
import io.micrometer.core.ipc.http.HttpUrlConnectionSender; import io.micrometer.core.instrument.config.MissingRequiredConfigurationException;
import io.micrometer.wavefront.WavefrontConfig; import io.micrometer.wavefront.WavefrontConfig;
import io.micrometer.wavefront.WavefrontMeterRegistry; import io.micrometer.wavefront.WavefrontMeterRegistry;
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront.WavefrontProperties.Sender;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -32,21 +37,25 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.util.unit.DataSize;
/** /**
* {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Wavefront. * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Wavefront.
* *
* @author Jon Schneider * @author Jon Schneider
* @author Artsiom Yudovin * @author Artsiom Yudovin
* @author Stephane Nicoll
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class }) @AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
@AutoConfigureAfter(MetricsAutoConfiguration.class) @AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class) @ConditionalOnBean(Clock.class)
@ConditionalOnClass(WavefrontMeterRegistry.class) @ConditionalOnClass({ WavefrontMeterRegistry.class, WavefrontSender.class })
@ConditionalOnProperty(prefix = "management.metrics.export.wavefront", name = "enabled", havingValue = "true", @ConditionalOnProperty(prefix = "management.metrics.export.wavefront", name = "enabled", havingValue = "true",
matchIfMissing = true) matchIfMissing = true)
@EnableConfigurationProperties(WavefrontProperties.class) @EnableConfigurationProperties(WavefrontProperties.class)
@ -66,10 +75,38 @@ public class WavefrontMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public WavefrontMeterRegistry wavefrontMeterRegistry(WavefrontConfig wavefrontConfig, Clock clock) { public WavefrontSender wavefrontSender(WavefrontConfig wavefrontConfig) {
return WavefrontMeterRegistry.builder(wavefrontConfig).clock(clock).httpClient( if (!StringUtils.hasText(wavefrontConfig.apiToken())) {
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout())) throw new MissingRequiredConfigurationException(
.build(); "apiToken must be set whenever publishing directly to the Wavefront API");
}
return createWavefrontSender(wavefrontConfig);
}
@Bean
@ConditionalOnMissingBean
public WavefrontMeterRegistry wavefrontMeterRegistry(WavefrontConfig wavefrontConfig, Clock clock,
WavefrontSender wavefrontSender) {
return WavefrontMeterRegistry.builder(wavefrontConfig).clock(clock).wavefrontSender(wavefrontSender).build();
}
private WavefrontSender createWavefrontSender(WavefrontConfig wavefrontConfig) {
Builder builder = new Builder(getWavefrontReportingUri(wavefrontConfig.uri()), wavefrontConfig.apiToken());
PropertyMapper mapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
Sender sender = this.properties.getSender();
mapper.from(sender.getMaxQueueSize()).to(builder::maxQueueSize);
mapper.from(sender.getBatchSize()).to(builder::batchSize);
mapper.from(sender.getFlushInterval()).asInt(Duration::getSeconds).to(builder::flushIntervalSeconds);
mapper.from(sender.getMessageSize()).asInt(DataSize::toBytes).to(builder::messageSizeBytes);
return builder.build();
}
private String getWavefrontReportingUri(String uri) {
// proxy reporting is now http reporting on newer wavefront proxies.
if (uri.startsWith("proxy")) {
return "http" + uri.substring(5);
}
return uri;
} }
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,22 +21,19 @@ import java.time.Duration;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PushRegistryProperties; import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PushRegistryProperties;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.unit.DataSize;
/** /**
* {@link ConfigurationProperties @ConfigurationProperties} for configuring Wavefront * {@link ConfigurationProperties @ConfigurationProperties} for configuring Wavefront
* metrics export. * metrics export.
* *
* @author Jon Schneider * @author Jon Schneider
* @author Stephane Nicoll
* @since 2.0.0 * @since 2.0.0
*/ */
@ConfigurationProperties("management.metrics.export.wavefront") @ConfigurationProperties("management.metrics.export.wavefront")
public class WavefrontProperties extends PushRegistryProperties { public class WavefrontProperties extends PushRegistryProperties {
/**
* Step size (i.e. reporting frequency) to use.
*/
private Duration step = Duration.ofSeconds(10);
/** /**
* URI to ship metrics to. * URI to ship metrics to.
*/ */
@ -60,6 +57,8 @@ public class WavefrontProperties extends PushRegistryProperties {
*/ */
private String globalPrefix; private String globalPrefix;
private final Sender sender = new Sender();
public URI getUri() { public URI getUri() {
return this.uri; return this.uri;
} }
@ -68,16 +67,6 @@ public class WavefrontProperties extends PushRegistryProperties {
this.uri = uri; this.uri = uri;
} }
@Override
public Duration getStep() {
return this.step;
}
@Override
public void setStep(Duration step) {
this.step = step;
}
public String getSource() { public String getSource() {
return this.source; return this.source;
} }
@ -102,4 +91,52 @@ public class WavefrontProperties extends PushRegistryProperties {
this.globalPrefix = globalPrefix; this.globalPrefix = globalPrefix;
} }
public Sender getSender() {
return this.sender;
}
public static class Sender {
private int maxQueueSize = 50000;
private int batchSize = 10000;
private Duration flushInterval = Duration.ofSeconds(1);
private DataSize messageSize = DataSize.ofBytes(Integer.MAX_VALUE);
public int getMaxQueueSize() {
return this.maxQueueSize;
}
public void setMaxQueueSize(int maxQueueSize) {
this.maxQueueSize = maxQueueSize;
}
public int getBatchSize() {
return this.batchSize;
}
public void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}
public Duration getFlushInterval() {
return this.flushInterval;
}
public void setFlushInterval(Duration flushInterval) {
this.flushInterval = flushInterval;
}
public DataSize getMessageSize() {
return this.messageSize;
}
public void setMessageSize(DataSize messageSize) {
this.messageSize = messageSize;
}
}
} }

@ -328,6 +328,10 @@
"description": "Whether exporting of metrics to Prometheus is enabled.", "description": "Whether exporting of metrics to Prometheus is enabled.",
"defaultValue": true "defaultValue": true
}, },
{
"name": "management.metrics.export.prometheus.histogram-flavor",
"defaultValue": "prometheus"
},
{ {
"name": "management.metrics.export.signalfx.num-threads", "name": "management.metrics.export.signalfx.num-threads",
"type": "java.lang.Integer", "type": "java.lang.Integer",
@ -376,6 +380,18 @@
"level": "error" "level": "error"
} }
}, },
{
"name": "management.metrics.export.wavefront.connect-timeout",
"deprecation": {
"level": "error"
}
},
{
"name": "management.metrics.export.wavefront.read-timeout",
"deprecation": {
"level": "error"
}
},
{ {
"name": "management.metrics.web.client.request.autotime.enabled", "name": "management.metrics.web.client.request.autotime.enabled",
"description": "Whether to automatically time web client requests.", "description": "Whether to automatically time web client requests.",

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,54 +16,54 @@
package org.springframework.boot.actuate.autoconfigure.metrics; package org.springframework.boot.actuate.autoconfigure.metrics;
import io.micrometer.core.instrument.binder.kafka.KafkaConsumerMetrics; import io.micrometer.core.instrument.binder.kafka.KafkaClientMetrics;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/** /**
* Tests for {@link KafkaMetricsAutoConfiguration}. * Tests for {@link KafkaMetricsAutoConfiguration}.
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Stephane Nicoll
*/ */
class KafkaMetricsAutoConfigurationTests { class KafkaMetricsAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().with(MetricsRun.simple()) private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().with(MetricsRun.simple())
.withPropertyValues("spring.jmx.enabled=true")
.withConfiguration(AutoConfigurations.of(KafkaMetricsAutoConfiguration.class)); .withConfiguration(AutoConfigurations.of(KafkaMetricsAutoConfiguration.class));
@Test @Test
void whenThereIsNoMBeanServerAutoConfigurationBacksOff() { void whenThereIsNoProducerFactoryAutoConfigurationBacksOff() {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(KafkaConsumerMetrics.class)); this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(KafkaClientMetrics.class));
} }
@Test @Test
void whenThereIsAnMBeanServerKafkaConsumerMetricsIsConfigured() { void whenThereIsAnAProducerFactoryKafkaClientMetricsIsConfigured() {
this.contextRunner.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class)) this.contextRunner.withConfiguration(AutoConfigurations.of(KafkaAutoConfiguration.class))
.run((context) -> assertThat(context).hasSingleBean(KafkaConsumerMetrics.class)); .run((context) -> assertThat(context).hasSingleBean(KafkaClientMetrics.class));
} }
@Test @Test
void allowsCustomKafkaConsumerMetricsToBeUsed() { void allowsCustomKafkaClientMetricsToBeUsed() {
this.contextRunner.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class)) this.contextRunner.withConfiguration(AutoConfigurations.of(KafkaAutoConfiguration.class))
.withUserConfiguration(CustomKafkaConsumerMetricsConfiguration.class) .withUserConfiguration(CustomKafkaClientMetricsConfiguration.class).run((context) -> assertThat(context)
.run((context) -> assertThat(context).hasSingleBean(KafkaConsumerMetrics.class) .hasSingleBean(KafkaClientMetrics.class).hasBean("customKafkaClientMetrics"));
.hasBean("customKafkaConsumerMetrics"));
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class CustomKafkaConsumerMetricsConfiguration { static class CustomKafkaClientMetricsConfiguration {
@Bean @Bean
KafkaConsumerMetrics customKafkaConsumerMetrics() { KafkaClientMetrics customKafkaClientMetrics() {
return new KafkaConsumerMetrics(); return mock(KafkaClientMetrics.class);
} }
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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}. * Tests for {@link MeterValue}.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll
*/ */
class MeterValueTests { class MeterValueTests {
@Test @Test
void getValueForDistributionSummaryWhenFromLongShouldReturnLongValue() { void getValueForDistributionSummaryWhenFromNumberShouldReturnDoubleValue() {
MeterValue meterValue = MeterValue.valueOf(123L); MeterValue meterValue = MeterValue.valueOf(123.42);
assertThat(meterValue.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(123); assertThat(meterValue.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(123.42);
} }
@Test @Test
void getValueForDistributionSummaryWhenFromNumberStringShouldReturnLongValue() { void getValueForDistributionSummaryWhenFromNumberStringShouldReturnDoubleValue() {
MeterValue meterValue = MeterValue.valueOf("123"); MeterValue meterValue = MeterValue.valueOf("123");
assertThat(meterValue.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(123); assertThat(meterValue.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(123);
} }
@ -52,8 +53,8 @@ class MeterValueTests {
} }
@Test @Test
void getValueForTimerWhenFromLongShouldReturnMsToNanosValue() { void getValueForTimerWhenFromNumberShouldReturnMsToNanosValue() {
MeterValue meterValue = MeterValue.valueOf(123L); MeterValue meterValue = MeterValue.valueOf(123d);
assertThat(meterValue.getValue(Type.TIMER)).isEqualTo(123000000); assertThat(meterValue.getValue(Type.TIMER)).isEqualTo(123000000);
} }
@ -81,11 +82,11 @@ class MeterValueTests {
@Test @Test
void valueOfShouldWorkInBinder() { void valueOfShouldWorkInBinder() {
MockEnvironment environment = new MockEnvironment(); 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)) assertThat(Binder.get(environment).bind("duration", Bindable.of(MeterValue.class)).get().getValue(Type.TIMER))
.isEqualTo(10000000); .isEqualTo(10000000);
assertThat(Binder.get(environment).bind("long", Bindable.of(MeterValue.class)).get().getValue(Type.TIMER)) assertThat(Binder.get(environment).bind("number", Bindable.of(MeterValue.class)).get()
.isEqualTo(20000000); .getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(20.42);
} }
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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}. * Tests for {@link ServiceLevelAgreementBoundary}.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll
*/ */
class ServiceLevelAgreementBoundaryTests { class ServiceLevelAgreementBoundaryTests {
@ -46,4 +47,22 @@ class ServiceLevelAgreementBoundaryTests {
assertThat(sla.getValue(Type.TIMER)).isEqualTo(123000000); 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();
}
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -61,4 +61,11 @@ class AppOpticsPropertiesConfigAdapterTests
assertThat(createConfigAdapter(properties).hostTag()).isEqualTo("node"); assertThat(createConfigAdapter(properties).hostTag()).isEqualTo("node");
} }
@Test
void whenPropertiesFloorTimesIsSetAdapterHostTagReturnsIt() {
AppOpticsProperties properties = createProperties();
properties.setFloorTimes(true);
assertThat(createConfigAdapter(properties).floorTimes()).isTrue();
}
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -37,6 +37,7 @@ class AppOpticsPropertiesTests extends StepRegistryPropertiesTests {
assertStepRegistryDefaultValues(properties, config); assertStepRegistryDefaultValues(properties, config);
assertThat(properties.getUri()).isEqualToIgnoringWhitespace(config.uri()); assertThat(properties.getUri()).isEqualToIgnoringWhitespace(config.uri());
assertThat(properties.getHostTag()).isEqualToIgnoringWhitespace(config.hostTag()); assertThat(properties.getHostTag()).isEqualToIgnoringWhitespace(config.hostTag());
assertThat(properties.isFloorTimes()).isEqualTo(config.floorTimes());
} }
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -48,6 +48,13 @@ class ElasticPropertiesConfigAdapterTests {
assertThat(new ElasticPropertiesConfigAdapter(properties).indexDateFormat()).isEqualTo("yyyy"); assertThat(new ElasticPropertiesConfigAdapter(properties).indexDateFormat()).isEqualTo("yyyy");
} }
@Test
void whenPropertiesIndexDateSeparatorIsSetAdapterIndexDateFormatReturnsIt() {
ElasticProperties properties = new ElasticProperties();
properties.setIndexDateSeparator("*");
assertThat(new ElasticPropertiesConfigAdapter(properties).indexDateSeparator()).isEqualTo("*");
}
@Test @Test
void whenPropertiesTimestampFieldNameIsSetAdapterTimestampFieldNameReturnsIt() { void whenPropertiesTimestampFieldNameIsSetAdapterTimestampFieldNameReturnsIt() {
ElasticProperties properties = new ElasticProperties(); ElasticProperties properties = new ElasticProperties();
@ -76,4 +83,11 @@ class ElasticPropertiesConfigAdapterTests {
assertThat(new ElasticPropertiesConfigAdapter(properties).password()).isEqualTo("secret"); assertThat(new ElasticPropertiesConfigAdapter(properties).password()).isEqualTo("secret");
} }
@Test
void whenPropertiesPipelineIsSetAdapterPasswordReturnsIt() {
ElasticProperties properties = new ElasticProperties();
properties.setPipeline("testPipeline");
assertThat(new ElasticPropertiesConfigAdapter(properties).pipeline()).isEqualTo("testPipeline");
}
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -38,10 +38,12 @@ class ElasticPropertiesTests extends StepRegistryPropertiesTests {
assertThat(properties.getHost()).isEqualTo(config.host()); assertThat(properties.getHost()).isEqualTo(config.host());
assertThat(properties.getIndex()).isEqualTo(config.index()); assertThat(properties.getIndex()).isEqualTo(config.index());
assertThat(properties.getIndexDateFormat()).isEqualTo(config.indexDateFormat()); assertThat(properties.getIndexDateFormat()).isEqualTo(config.indexDateFormat());
assertThat(properties.getIndexDateSeparator()).isEqualTo(config.indexDateSeparator());
assertThat(properties.getPassword()).isEqualTo(config.password()); assertThat(properties.getPassword()).isEqualTo(config.password());
assertThat(properties.getTimestampFieldName()).isEqualTo(config.timestampFieldName()); assertThat(properties.getTimestampFieldName()).isEqualTo(config.timestampFieldName());
assertThat(properties.getUserName()).isEqualTo(config.userName()); assertThat(properties.getUserName()).isEqualTo(config.userName());
assertThat(properties.isAutoCreateIndex()).isEqualTo(config.autoCreateIndex()); assertThat(properties.isAutoCreateIndex()).isEqualTo(config.autoCreateIndex());
assertThat(properties.getPipeline()).isEqualTo(config.pipeline());
} }
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -46,10 +46,23 @@ class GraphiteMetricsExportAutoConfigurationTests {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(GraphiteMeterRegistry.class)); this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(GraphiteMeterRegistry.class));
} }
@Test
void autoConfiguresUseTagsAsPrefixIsIgnoredByDefault() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.withPropertyValues("management.metrics.export.graphite.tags-as-prefix=ignored").run((context) -> {
assertThat(context).hasSingleBean(GraphiteMeterRegistry.class);
GraphiteMeterRegistry registry = context.getBean(GraphiteMeterRegistry.class);
registry.counter("test.count", Tags.of("app", "myapp"));
assertThat(registry.getDropwizardRegistry().getMeters()).containsOnlyKeys("test.count;app=myapp");
});
}
@Test @Test
void autoConfiguresUseTagsAsPrefix() { void autoConfiguresUseTagsAsPrefix() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class) this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.withPropertyValues("management.metrics.export.graphite.tags-as-prefix=app").run((context) -> { .withPropertyValues("management.metrics.export.graphite.tags-as-prefix=app",
"management.metrics.export.graphite.graphite-tags-enabled=false")
.run((context) -> {
assertThat(context).hasSingleBean(GraphiteMeterRegistry.class); assertThat(context).hasSingleBean(GraphiteMeterRegistry.class);
GraphiteMeterRegistry registry = context.getBean(GraphiteMeterRegistry.class); GraphiteMeterRegistry registry = context.getBean(GraphiteMeterRegistry.class);
registry.counter("test.count", Tags.of("app", "myapp")); registry.counter("test.count", Tags.of("app", "myapp"));

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -39,6 +39,7 @@ class GraphitePropertiesTests {
assertThat(properties.getHost()).isEqualTo(config.host()); assertThat(properties.getHost()).isEqualTo(config.host());
assertThat(properties.getPort()).isEqualTo(config.port()); assertThat(properties.getPort()).isEqualTo(config.port());
assertThat(properties.getProtocol()).isEqualTo(config.protocol()); assertThat(properties.getProtocol()).isEqualTo(config.protocol());
assertThat(properties.isGraphiteTagsEnabled()).isEqualTo(config.graphiteTagsEnabled());
assertThat(properties.getTagsAsPrefix()).isEqualTo(config.tagsAsPrefix()); assertThat(properties.getTagsAsPrefix()).isEqualTo(config.tagsAsPrefix());
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -33,6 +33,7 @@ class PrometheusPropertiesTests {
PrometheusProperties properties = new PrometheusProperties(); PrometheusProperties properties = new PrometheusProperties();
PrometheusConfig config = PrometheusConfig.DEFAULT; PrometheusConfig config = PrometheusConfig.DEFAULT;
assertThat(properties.isDescriptions()).isEqualTo(config.descriptions()); assertThat(properties.isDescriptions()).isEqualTo(config.descriptions());
assertThat(properties.getHistogramFlavor()).isEqualTo(config.histogramFlavor());
assertThat(properties.getStep()).isEqualTo(config.step()); assertThat(properties.getStep()).isEqualTo(config.step());
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,7 +19,6 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.statsd;
import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.Clock;
import io.micrometer.statsd.StatsdConfig; import io.micrometer.statsd.StatsdConfig;
import io.micrometer.statsd.StatsdMeterRegistry; import io.micrometer.statsd.StatsdMeterRegistry;
import io.micrometer.statsd.StatsdMetrics;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
@ -47,9 +46,8 @@ class StatsdMetricsExportAutoConfigurationTests {
@Test @Test
void autoConfiguresItsConfigMeterRegistryAndMetrics() { void autoConfiguresItsConfigMeterRegistryAndMetrics() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class) this.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> assertThat(context)
.run((context) -> assertThat(context).hasSingleBean(StatsdMeterRegistry.class) .hasSingleBean(StatsdMeterRegistry.class).hasSingleBean(StatsdConfig.class));
.hasSingleBean(StatsdConfig.class).hasSingleBean(StatsdMetrics.class));
} }
@Test @Test

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront; package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront;
import com.wavefront.sdk.common.WavefrontSender;
import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.Clock;
import io.micrometer.wavefront.WavefrontConfig; import io.micrometer.wavefront.WavefrontConfig;
import io.micrometer.wavefront.WavefrontMeterRegistry; import io.micrometer.wavefront.WavefrontMeterRegistry;
@ -28,6 +29,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/** /**
* Tests for {@link WavefrontMetricsExportAutoConfiguration}. * Tests for {@link WavefrontMetricsExportAutoConfiguration}.
@ -53,9 +55,10 @@ class WavefrontMetricsExportAutoConfigurationTests {
@Test @Test
void autoConfigurationCanBeDisabled() { void autoConfigurationCanBeDisabled() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class) this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.withPropertyValues("management.metrics.export.wavefront.enabled=false") .withPropertyValues("management.metrics.export.wavefront.api-token=abcde",
"management.metrics.export.wavefront.enabled=false")
.run((context) -> assertThat(context).doesNotHaveBean(WavefrontMeterRegistry.class) .run((context) -> assertThat(context).doesNotHaveBean(WavefrontMeterRegistry.class)
.doesNotHaveBean(WavefrontConfig.class)); .doesNotHaveBean(WavefrontConfig.class).doesNotHaveBean(WavefrontSender.class));
} }
@Test @Test
@ -63,7 +66,30 @@ class WavefrontMetricsExportAutoConfigurationTests {
this.contextRunner.withUserConfiguration(CustomConfigConfiguration.class) this.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(Clock.class) .run((context) -> assertThat(context).hasSingleBean(Clock.class)
.hasSingleBean(WavefrontMeterRegistry.class).hasSingleBean(WavefrontConfig.class) .hasSingleBean(WavefrontMeterRegistry.class).hasSingleBean(WavefrontConfig.class)
.hasBean("customConfig")); .hasSingleBean(WavefrontSender.class).hasBean("customConfig"));
}
@Test
void configureWavefrontSender() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.withPropertyValues("management.metrics.export.wavefront.api-token=abcde",
"management.metrics.export.wavefront.sender.max-queue-size=100",
"management.metrics.export.wavefront.sender.batch-size=200",
"management.metrics.export.wavefront.sender.message-size=1KB")
.run((context) -> {
WavefrontSender sender = context.getBean(WavefrontSender.class);
assertThat(sender).extracting("metricsBuffer").hasFieldOrPropertyWithValue("capacity", 100);
assertThat(sender).hasFieldOrPropertyWithValue("batchSize", 200);
assertThat(sender).hasFieldOrPropertyWithValue("messageSizeBytes", 1024);
});
}
@Test
void allowsWavefrontSenderToBeCustomized() {
this.contextRunner.withUserConfiguration(CustomSenderConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(Clock.class)
.hasSingleBean(WavefrontMeterRegistry.class).hasSingleBean(WavefrontConfig.class)
.hasSingleBean(WavefrontSender.class).hasBean("customSender"));
} }
@Test @Test
@ -109,13 +135,29 @@ class WavefrontMetricsExportAutoConfigurationTests {
@Override @Override
public String uri() { public String uri() {
return WavefrontConfig.DEFAULT_PROXY.uri(); return WavefrontConfig.DEFAULT_DIRECT.uri();
}
@Override
public String apiToken() {
return "abc-def";
} }
}; };
} }
} }
@Configuration(proxyBeanMethods = false)
@Import(BaseConfiguration.class)
static class CustomSenderConfiguration {
@Bean
WavefrontSender customSender() {
return mock(WavefrontSender.class);
}
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@Import(BaseConfiguration.class) @Import(BaseConfiguration.class)
static class CustomRegistryConfiguration { static class CustomRegistryConfiguration {

@ -1182,7 +1182,7 @@ bom {
] ]
} }
} }
library("Micrometer", "1.3.7") { library("Micrometer", "1.5.0-SNAPSHOT") {
group("io.micrometer") { group("io.micrometer") {
modules = [ modules = [
"micrometer-registry-stackdriver" { "micrometer-registry-stackdriver" {

@ -1791,7 +1791,7 @@ Spring Boot registers the following core metrics when applicable:
** Number of classes loaded/unloaded ** Number of classes loaded/unloaded
* CPU metrics * CPU metrics
* File descriptor metrics * File descriptor metrics
* Kafka consumer metrics (<<production-ready-jmx,JMX support>> should be enabled) * Kafka consumer metrics
* Log4j2 metrics: record the number of events logged to Log4j2 at each level * Log4j2 metrics: record the number of events logged to Log4j2 at each level
* Logback metrics: record the number of events logged to Logback at each level * Logback metrics: record the number of events logged to Logback at each level
* Uptime metrics: report a gauge for uptime and a fixed gauge representing the application's absolute start time * Uptime metrics: report a gauge for uptime and a fixed gauge representing the application's absolute start time

Loading…
Cancel
Save