Revert "Merge branch 'spring-projects:main' into main"

This reverts commit ce390b00e1.
pull/30567/head
Almog Tavor 3 years ago
parent c644529e8b
commit 37059a5e92

@ -41,7 +41,7 @@ import org.gradle.api.tasks.TaskAction;
*/
public class DocumentDevtoolsPropertyDefaults extends DefaultTask {
private final Configuration devtools;
private Configuration devtools;
private final RegularFileProperty outputFile;

@ -1,4 +1,4 @@
FROM ubuntu:focal-20220404
FROM ubuntu:focal-20220316
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh

@ -1,4 +1,4 @@
FROM ubuntu:focal-20220404
FROM ubuntu:focal-20220316
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh

@ -4,7 +4,7 @@ org.gradle.caching=true
org.gradle.parallel=true
org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8
kotlinVersion=1.6.20
kotlinVersion=1.6.20-RC2
tomcatVersion=10.0.18
kotlin.stdlib.default.dependency=false

@ -22,7 +22,7 @@ pluginManagement {
}
plugins {
id "com.gradle.enterprise" version "3.9"
id "com.gradle.enterprise" version "3.8.1"
id "io.spring.ge.conventions" version "0.0.9"
}

@ -50,9 +50,7 @@ dependencies {
optional("io.micrometer:micrometer-observation")
optional("io.micrometer:micrometer-core")
optional("io.micrometer:micrometer-tracing-api")
optional("io.micrometer:micrometer-tracing-bridge-brave")
optional("io.micrometer:micrometer-tracing-bridge-otel")
optional("io.micrometer:micrometer-tracing-reporter-wavefront")
optional("io.micrometer:micrometer-binders")
optional("io.micrometer:micrometer-registry-appoptics")
optional("io.micrometer:micrometer-registry-atlas") {
exclude group: "javax.inject", module: "javax.inject"
@ -78,8 +76,6 @@ dependencies {
optional("io.micrometer:micrometer-registry-signalfx")
optional("io.micrometer:micrometer-registry-statsd")
optional("io.micrometer:micrometer-registry-wavefront")
optional("io.zipkin.reporter2:zipkin-sender-urlconnection")
optional("io.opentelemetry:opentelemetry-exporter-zipkin")
optional("io.projectreactor.netty:reactor-netty-http")
optional("io.r2dbc:r2dbc-pool")
optional("io.r2dbc:r2dbc-spi")

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2021 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.
@ -31,7 +31,6 @@ import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryA
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryAuthorizationException.Reason;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.util.Assert;
import org.springframework.web.reactive.function.client.WebClient;
@ -91,7 +90,7 @@ class ReactiveCloudFoundrySecurityService {
private Throwable mapError(Throwable throwable) {
if (throwable instanceof WebClientResponseException) {
HttpStatusCode statusCode = ((WebClientResponseException) throwable).getStatusCode();
HttpStatus statusCode = ((WebClientResponseException) throwable).getStatusCode();
if (statusCode.equals(HttpStatus.FORBIDDEN)) {
return new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, "Access denied");
}

@ -22,7 +22,7 @@ import org.elasticsearch.client.RestClient;
import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestClientHealthIndicator;
import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestHealthIndicator;
import org.springframework.boot.actuate.health.HealthContributor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -34,21 +34,23 @@ import org.springframework.context.annotation.Bean;
/**
* {@link EnableAutoConfiguration Auto-configuration} for
* {@link ElasticsearchRestClientHealthIndicator}.
* {@link ElasticsearchRestHealthIndicator} using the {@link RestClient}.
*
* @author Artsiom Yudovin
* @since 2.1.1
*/
@SuppressWarnings("deprecation")
@AutoConfiguration(after = ElasticsearchRestClientAutoConfiguration.class)
@ConditionalOnClass(RestClient.class)
@ConditionalOnBean(RestClient.class)
@ConditionalOnClass(org.elasticsearch.client.RestHighLevelClient.class)
@ConditionalOnBean(org.elasticsearch.client.RestHighLevelClient.class)
@ConditionalOnEnabledHealthIndicator("elasticsearch")
public class ElasticSearchRestHealthContributorAutoConfiguration
extends CompositeHealthContributorConfiguration<ElasticsearchRestClientHealthIndicator, RestClient> {
public class ElasticSearchRestHealthContributorAutoConfiguration extends
CompositeHealthContributorConfiguration<ElasticsearchRestHealthIndicator, org.elasticsearch.client.RestHighLevelClient> {
@Bean
@ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" })
public HealthContributor elasticsearchHealthContributor(Map<String, RestClient> clients) {
public HealthContributor elasticsearchHealthContributor(
Map<String, org.elasticsearch.client.RestHighLevelClient> clients) {
return createContributor(clients);
}

@ -16,12 +16,12 @@
package org.springframework.boot.actuate.autoconfigure.metrics;
import io.micrometer.binder.jvm.ClassLoaderMetrics;
import io.micrometer.binder.jvm.JvmGcMetrics;
import io.micrometer.binder.jvm.JvmHeapPressureMetrics;
import io.micrometer.binder.jvm.JvmMemoryMetrics;
import io.micrometer.binder.jvm.JvmThreadMetrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmHeapPressureMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;

@ -16,9 +16,9 @@
package org.springframework.boot.actuate.autoconfigure.metrics;
import io.micrometer.binder.kafka.KafkaClientMetrics;
import io.micrometer.binder.kafka.KafkaStreamsMetrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.kafka.KafkaClientMetrics;
import io.micrometer.core.instrument.binder.kafka.KafkaStreamsMetrics;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;

@ -16,8 +16,8 @@
package org.springframework.boot.actuate.autoconfigure.metrics;
import io.micrometer.binder.logging.Log4j2Metrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.logging.Log4j2Metrics;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.spi.LoggerContext;

@ -17,8 +17,8 @@
package org.springframework.boot.actuate.autoconfigure.metrics;
import ch.qos.logback.classic.LoggerContext;
import io.micrometer.binder.logging.LogbackMetrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.logging.LogbackMetrics;
import org.slf4j.ILoggerFactory;
import org.slf4j.LoggerFactory;

@ -19,11 +19,11 @@ package org.springframework.boot.actuate.autoconfigure.metrics;
import java.io.File;
import java.util.List;
import io.micrometer.binder.system.FileDescriptorMetrics;
import io.micrometer.binder.system.ProcessorMetrics;
import io.micrometer.binder.system.UptimeMetrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.binder.system.FileDescriptorMetrics;
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
import io.micrometer.core.instrument.binder.system.UptimeMetrics;
import org.springframework.boot.actuate.metrics.system.DiskSpaceMetricsBinder;
import org.springframework.boot.autoconfigure.AutoConfiguration;

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 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.
@ -72,7 +72,7 @@ class CacheMetricsRegistrarConfiguration {
}
private void bindCacheToRegistry(String beanName, Cache cache) {
Tag cacheManagerTag = Tag.of("cache.manager", getCacheManagerName(beanName));
Tag cacheManagerTag = Tag.of("cacheManager", getCacheManagerName(beanName));
this.cacheMetricsRegistrar.bindCacheToRegistry(cache, cacheManagerTag);
}

@ -168,12 +168,6 @@ public class DynatraceProperties extends StepRegistryProperties {
*/
private String metricKeyPrefix;
/**
* Whether to fall back to the built-in micrometer instruments for Timer and
* DistributionSummary.
*/
private boolean useDynatraceSummaryInstruments = true;
public Map<String, String> getDefaultDimensions() {
return this.defaultDimensions;
}
@ -198,14 +192,6 @@ public class DynatraceProperties extends StepRegistryProperties {
this.metricKeyPrefix = metricKeyPrefix;
}
public boolean isUseDynatraceSummaryInstruments() {
return this.useDynatraceSummaryInstruments;
}
public void setUseDynatraceSummaryInstruments(boolean useDynatraceSummaryInstruments) {
this.useDynatraceSummaryInstruments = useDynatraceSummaryInstruments;
}
}
}

@ -90,11 +90,6 @@ class DynatracePropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapt
return get(v2(V2::isEnrichWithDynatraceMetadata), DynatraceConfig.super::enrichWithDynatraceMetadata);
}
@Override
public boolean useDynatraceSummaryInstruments() {
return get(v2(V2::isUseDynatraceSummaryInstruments), DynatraceConfig.super::useDynatraceSummaryInstruments);
}
private <V> Function<DynatraceProperties, V> v1(Function<V1, V> getter) {
return (properties) -> getter.apply(properties.getV1());
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2019 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.
@ -31,7 +31,7 @@ import org.springframework.util.Assert;
*/
public class PropertiesConfigAdapter<T> {
private final T properties;
private T properties;
/**
* Create a new {@link PropertiesConfigAdapter} instance.

@ -16,7 +16,10 @@
package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront;
import java.time.Duration;
import com.wavefront.sdk.common.WavefrontSender;
import com.wavefront.sdk.common.clients.WavefrontClient.Builder;
import io.micrometer.core.instrument.Clock;
import io.micrometer.wavefront.WavefrontConfig;
import io.micrometer.wavefront.WavefrontMeterRegistry;
@ -25,15 +28,16 @@ import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegi
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.export.ConditionalOnEnabledMetricsExport;
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties;
import org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront.WavefrontProperties.Sender;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.util.unit.DataSize;
/**
* {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Wavefront.
@ -45,17 +49,29 @@ import org.springframework.context.annotation.Bean;
*/
@AutoConfiguration(
before = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },
after = { MetricsAutoConfiguration.class, WavefrontAutoConfiguration.class })
@ConditionalOnBean({ Clock.class, WavefrontSender.class })
after = MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class)
@ConditionalOnClass({ WavefrontMeterRegistry.class, WavefrontSender.class })
@ConditionalOnEnabledMetricsExport("wavefront")
@EnableConfigurationProperties(WavefrontProperties.class)
public class WavefrontMetricsExportAutoConfiguration {
private final WavefrontProperties properties;
public WavefrontMetricsExportAutoConfiguration(WavefrontProperties properties) {
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean
public WavefrontConfig wavefrontConfig() {
return new WavefrontPropertiesConfigAdapter(this.properties);
}
@Bean
@ConditionalOnMissingBean
public WavefrontConfig wavefrontConfig(WavefrontProperties properties) {
return new WavefrontPropertiesConfigAdapter(properties);
public WavefrontSender wavefrontSender(WavefrontConfig wavefrontConfig) {
return createWavefrontSender(wavefrontConfig);
}
@Bean
@ -65,4 +81,14 @@ public class WavefrontMetricsExportAutoConfiguration {
return WavefrontMeterRegistry.builder(wavefrontConfig).clock(clock).wavefrontSender(wavefrontSender).build();
}
private WavefrontSender createWavefrontSender(WavefrontConfig wavefrontConfig) {
Builder builder = WavefrontMeterRegistry.getDefaultSenderBuilder(wavefrontConfig);
PropertyMapper mapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
Sender sender = this.properties.getSender();
mapper.from(sender.getMaxQueueSize()).to(builder::maxQueueSize);
mapper.from(sender.getFlushInterval()).asInt(Duration::getSeconds).to(builder::flushIntervalSeconds);
mapper.from(sender.getMessageSize()).asInt(DataSize::toBytes).to(builder::messageSizeBytes);
return builder.build();
}
}

@ -0,0 +1,132 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront;
import java.net.URI;
import java.time.Duration;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PushRegistryProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.unit.DataSize;
/**
* {@link ConfigurationProperties @ConfigurationProperties} for configuring Wavefront
* metrics export.
*
* @author Jon Schneider
* @author Stephane Nicoll
* @since 2.0.0
*/
@ConfigurationProperties("management.wavefront.metrics.export")
public class WavefrontProperties extends PushRegistryProperties {
/**
* URI to ship metrics to.
*/
private URI uri = URI.create("https://longboard.wavefront.com");
/**
* Unique identifier for the app instance that is the source of metrics being
* published to Wavefront. Defaults to the local host name.
*/
private String source;
/**
* API token used when publishing metrics directly to the Wavefront API host.
*/
private String apiToken;
/**
* Global prefix to separate metrics originating from this app's white box
* instrumentation from those originating from other Wavefront integrations when
* viewed in the Wavefront UI.
*/
private String globalPrefix;
private final Sender sender = new Sender();
public URI getUri() {
return this.uri;
}
public void setUri(URI uri) {
this.uri = uri;
}
public String getSource() {
return this.source;
}
public void setSource(String source) {
this.source = source;
}
public String getApiToken() {
return this.apiToken;
}
public void setApiToken(String apiToken) {
this.apiToken = apiToken;
}
public String getGlobalPrefix() {
return this.globalPrefix;
}
public void setGlobalPrefix(String globalPrefix) {
this.globalPrefix = globalPrefix;
}
public Sender getSender() {
return this.sender;
}
public static class Sender {
private int maxQueueSize = 50000;
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 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;
}
}
}

@ -19,24 +19,18 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront;
import io.micrometer.wavefront.WavefrontConfig;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PushRegistryPropertiesConfigAdapter;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties.Metrics.Export;
/**
* Adapter to convert {@link WavefrontProperties.Metrics} to a {@link WavefrontConfig}.
* Adapter to convert {@link WavefrontProperties} to a {@link WavefrontConfig}.
*
* @author Jon Schneider
* @author Moritz Halbritter
* @since 2.0.0
*/
public class WavefrontPropertiesConfigAdapter
extends PushRegistryPropertiesConfigAdapter<WavefrontProperties.Metrics.Export> implements WavefrontConfig {
private final WavefrontProperties properties;
public class WavefrontPropertiesConfigAdapter extends PushRegistryPropertiesConfigAdapter<WavefrontProperties>
implements WavefrontConfig {
public WavefrontPropertiesConfigAdapter(WavefrontProperties properties) {
super(properties.getMetrics().getExport());
this.properties = properties;
super(properties);
}
@Override
@ -45,28 +39,32 @@ public class WavefrontPropertiesConfigAdapter
}
@Override
public String uri() {
return this.properties.getEffectiveUri().toString();
public String get(String k) {
return null;
}
@Override
public String source() {
return this.properties.getSourceOrDefault();
public String uri() {
return get(this::getUriAsString, WavefrontConfig.DEFAULT_DIRECT::uri);
}
@Override
public int batchSize() {
return this.properties.getSender().getBatchSize();
public String source() {
return get(WavefrontProperties::getSource, WavefrontConfig.super::source);
}
@Override
public String apiToken() {
return this.properties.getApiTokenOrThrow();
return get(WavefrontProperties::getApiToken, WavefrontConfig.super::apiToken);
}
@Override
public String globalPrefix() {
return get(Export::getGlobalPrefix, WavefrontConfig.super::globalPrefix);
return get(WavefrontProperties::getGlobalPrefix, WavefrontConfig.super::globalPrefix);
}
private String getUriAsString(WavefrontProperties properties) {
return (properties.getUri() != null) ? properties.getUri().toString() : null;
}
}

@ -28,11 +28,11 @@ import com.zaxxer.hikari.HikariConfigMXBean;
import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.metrics.micrometer.MicrometerMetricsTrackerFactory;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.MeterBinder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
import org.springframework.boot.actuate.metrics.jdbc.DataSourcePoolMetrics;
@ -43,7 +43,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.jdbc.DataSourceUnwrapper;
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.log.LogMessage;
import org.springframework.util.StringUtils;
@ -67,30 +66,13 @@ public class DataSourcePoolMetricsAutoConfiguration {
private static final String DATASOURCE_SUFFIX = "dataSource";
@Bean
DataSourcePoolMetadataMeterBinder dataSourcePoolMetadataMeterBinder(Map<String, DataSource> dataSources,
@Autowired
void bindDataSourcesToRegistry(Map<String, DataSource> dataSources, MeterRegistry registry,
ObjectProvider<DataSourcePoolMetadataProvider> metadataProviders) {
return new DataSourcePoolMetadataMeterBinder(dataSources, metadataProviders);
}
static class DataSourcePoolMetadataMeterBinder implements MeterBinder {
private final Map<String, DataSource> dataSources;
private final ObjectProvider<DataSourcePoolMetadataProvider> metadataProviders;
DataSourcePoolMetadataMeterBinder(Map<String, DataSource> dataSources,
ObjectProvider<DataSourcePoolMetadataProvider> metadataProviders) {
this.dataSources = dataSources;
this.metadataProviders = metadataProviders;
}
@Override
public void bindTo(MeterRegistry registry) {
List<DataSourcePoolMetadataProvider> metadataProvidersList = this.metadataProviders.stream()
List<DataSourcePoolMetadataProvider> metadataProvidersList = metadataProviders.stream()
.collect(Collectors.toList());
this.dataSources.forEach((name, dataSource) -> bindDataSourceToRegistry(name, dataSource,
metadataProvidersList, registry));
dataSources.forEach(
(name, dataSource) -> bindDataSourceToRegistry(name, dataSource, metadataProvidersList, registry));
}
private void bindDataSourceToRegistry(String beanName, DataSource dataSource,
@ -115,42 +97,33 @@ public class DataSourcePoolMetricsAutoConfiguration {
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HikariDataSource.class)
static class HikariDataSourceMetricsConfiguration {
@Bean
HikariDataSourceMeterBinder hikariDataSourceMeterBinder(ObjectProvider<DataSource> dataSources) {
return new HikariDataSourceMeterBinder(dataSources);
}
static class HikariDataSourceMeterBinder implements MeterBinder {
private static final Log logger = LogFactory.getLog(HikariDataSourceMetricsConfiguration.class);
private static final Log logger = LogFactory.getLog(HikariDataSourceMeterBinder.class);
private final MeterRegistry registry;
private final ObjectProvider<DataSource> dataSources;
HikariDataSourceMeterBinder(ObjectProvider<DataSource> dataSources) {
this.dataSources = dataSources;
HikariDataSourceMetricsConfiguration(MeterRegistry registry) {
this.registry = registry;
}
@Override
public void bindTo(MeterRegistry registry) {
for (DataSource dataSource : this.dataSources) {
@Autowired
void bindMetricsRegistryToHikariDataSources(Collection<DataSource> dataSources) {
for (DataSource dataSource : dataSources) {
HikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(dataSource, HikariConfigMXBean.class,
HikariDataSource.class);
if (hikariDataSource != null) {
bindMetricsRegistryToHikariDataSource(hikariDataSource, registry);
bindMetricsRegistryToHikariDataSource(hikariDataSource);
}
}
}
private void bindMetricsRegistryToHikariDataSource(HikariDataSource hikari, MeterRegistry registry) {
private void bindMetricsRegistryToHikariDataSource(HikariDataSource hikari) {
if (hikari.getMetricRegistry() == null && hikari.getMetricsTrackerFactory() == null) {
try {
hikari.setMetricsTrackerFactory(new MicrometerMetricsTrackerFactory(registry));
hikari.setMetricsTrackerFactory(new MicrometerMetricsTrackerFactory(this.registry));
}
catch (Exception ex) {
logger.warn(LogMessage.format("Failed to bind Hikari metrics: %s", ex.getMessage()));
@ -161,5 +134,3 @@ public class DataSourcePoolMetricsAutoConfiguration {
}
}
}

@ -17,13 +17,13 @@
package org.springframework.boot.actuate.autoconfigure.metrics.mongo;
import com.mongodb.MongoClientSettings;
import io.micrometer.binder.mongodb.DefaultMongoCommandTagsProvider;
import io.micrometer.binder.mongodb.DefaultMongoConnectionPoolTagsProvider;
import io.micrometer.binder.mongodb.MongoCommandTagsProvider;
import io.micrometer.binder.mongodb.MongoConnectionPoolTagsProvider;
import io.micrometer.binder.mongodb.MongoMetricsCommandListener;
import io.micrometer.binder.mongodb.MongoMetricsConnectionPoolListener;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.mongodb.DefaultMongoCommandTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.DefaultMongoConnectionPoolTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.MongoCommandTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.MongoConnectionPoolTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsCommandListener;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsConnectionPoolListener;
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;

@ -21,8 +21,8 @@ import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import io.micrometer.binder.jvm.ExecutorServiceMetrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;

@ -16,10 +16,10 @@
package org.springframework.boot.actuate.autoconfigure.metrics.web.jetty;
import io.micrometer.binder.jetty.JettyConnectionMetrics;
import io.micrometer.binder.jetty.JettyServerThreadPoolMetrics;
import io.micrometer.binder.jetty.JettySslHandshakeMetrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.jetty.JettyConnectionMetrics;
import io.micrometer.core.instrument.binder.jetty.JettyServerThreadPoolMetrics;
import io.micrometer.core.instrument.binder.jetty.JettySslHandshakeMetrics;
import org.eclipse.jetty.server.Server;
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;

@ -16,8 +16,8 @@
package org.springframework.boot.actuate.autoconfigure.metrics.web.tomcat;
import io.micrometer.binder.tomcat.TomcatMetrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.tomcat.TomcatMetrics;
import org.apache.catalina.Manager;
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;

@ -17,7 +17,7 @@
package org.springframework.boot.actuate.autoconfigure.observation;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.observation.Observation.GlobalKeyValuesProvider;
import io.micrometer.observation.Observation.GlobalTagsProvider;
import io.micrometer.observation.ObservationHandler;
import io.micrometer.observation.ObservationPredicate;
import io.micrometer.observation.ObservationRegistry;
@ -48,7 +48,7 @@ public class ObservationAutoConfiguration {
static ObservationRegistryPostProcessor observationRegistryPostProcessor(
ObjectProvider<ObservationRegistryCustomizer<?>> observationRegistryCustomizers,
ObjectProvider<ObservationPredicate> observationPredicates,
ObjectProvider<GlobalKeyValuesProvider<?>> tagProviders,
ObjectProvider<GlobalTagsProvider<?>> tagProviders,
ObjectProvider<ObservationHandler<?>> observationHandlers,
ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping) {
return new ObservationRegistryPostProcessor(observationRegistryCustomizers, observationPredicates, tagProviders,

@ -18,7 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.observation;
import java.util.List;
import io.micrometer.observation.Observation.GlobalKeyValuesProvider;
import io.micrometer.observation.Observation.GlobalTagsProvider;
import io.micrometer.observation.ObservationHandler;
import io.micrometer.observation.ObservationPredicate;
import io.micrometer.observation.ObservationRegistry;
@ -29,7 +29,7 @@ import org.springframework.boot.util.LambdaSafe;
/**
* Configurer to apply {@link ObservationRegistryCustomizer customizers} to
* {@link ObservationRegistry observation registries}. Installs
* {@link ObservationPredicate observation predicates} and {@link GlobalKeyValuesProvider
* {@link ObservationPredicate observation predicates} and {@link GlobalTagsProvider
* global tag providers} into the {@link ObservationRegistry}. Also uses a
* {@link ObservationHandlerGrouping} to group handlers, which are then added to the
* {@link ObservationRegistry}.
@ -42,7 +42,7 @@ class ObservationRegistryConfigurer {
private final ObjectProvider<ObservationPredicate> observationPredicates;
private final ObjectProvider<GlobalKeyValuesProvider<?>> tagProviders;
private final ObjectProvider<GlobalTagsProvider<?>> tagProviders;
private final ObjectProvider<ObservationHandler<?>> observationHandlers;
@ -50,7 +50,7 @@ class ObservationRegistryConfigurer {
ObservationRegistryConfigurer(ObjectProvider<ObservationRegistryCustomizer<?>> customizers,
ObjectProvider<ObservationPredicate> observationPredicates,
ObjectProvider<GlobalKeyValuesProvider<?>> tagProviders,
ObjectProvider<GlobalTagsProvider<?>> tagProviders,
ObjectProvider<ObservationHandler<?>> observationHandlers,
ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping) {
this.customizers = customizers;
@ -79,7 +79,7 @@ class ObservationRegistryConfigurer {
private void registerGlobalTagsProvider(ObservationRegistry registry) {
this.tagProviders.orderedStream()
.forEach((tagProvider) -> registry.observationConfig().keyValuesProvider(tagProvider));
.forEach((tagProvider) -> registry.observationConfig().tagsProvider(tagProvider));
}
@SuppressWarnings("unchecked")

@ -16,7 +16,7 @@
package org.springframework.boot.actuate.autoconfigure.observation;
import io.micrometer.observation.Observation.GlobalKeyValuesProvider;
import io.micrometer.observation.Observation.GlobalTagsProvider;
import io.micrometer.observation.ObservationHandler;
import io.micrometer.observation.ObservationPredicate;
import io.micrometer.observation.ObservationRegistry;
@ -38,7 +38,7 @@ class ObservationRegistryPostProcessor implements BeanPostProcessor {
private final ObjectProvider<ObservationPredicate> observationPredicates;
private final ObjectProvider<GlobalKeyValuesProvider<?>> tagProviders;
private final ObjectProvider<GlobalTagsProvider<?>> tagProviders;
private final ObjectProvider<ObservationHandler<?>> observationHandlers;
@ -48,7 +48,7 @@ class ObservationRegistryPostProcessor implements BeanPostProcessor {
ObservationRegistryPostProcessor(ObjectProvider<ObservationRegistryCustomizer<?>> observationRegistryCustomizers,
ObjectProvider<ObservationPredicate> observationPredicates,
ObjectProvider<GlobalKeyValuesProvider<?>> tagProviders,
ObjectProvider<GlobalTagsProvider<?>> tagProviders,
ObjectProvider<ObservationHandler<?>> observationHandlers,
ObjectProvider<ObservationHandlerGrouping> observationHandlerGrouping) {
this.observationRegistryCustomizers = observationRegistryCustomizers;

@ -1,129 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing;
import java.util.List;
import brave.Tracing;
import brave.Tracing.Builder;
import brave.TracingCustomizer;
import brave.handler.SpanHandler;
import brave.propagation.B3Propagation;
import brave.propagation.CurrentTraceContext;
import brave.propagation.CurrentTraceContext.ScopeDecorator;
import brave.propagation.CurrentTraceContextCustomizer;
import brave.propagation.Propagation.Factory;
import brave.propagation.ThreadLocalCurrentTraceContext;
import brave.sampler.Sampler;
import io.micrometer.tracing.brave.bridge.BraveBaggageManager;
import io.micrometer.tracing.brave.bridge.BraveCurrentTraceContext;
import io.micrometer.tracing.brave.bridge.BraveTracer;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Brave.
*
* @author Moritz Halbritter
* @since 3.0.0
*/
@AutoConfiguration(before = MicrometerTracingAutoConfiguration.class)
@ConditionalOnClass(brave.Tracer.class)
@EnableConfigurationProperties(TracingProperties.class)
public class BraveAutoConfiguration {
/**
* Default value for application name if {@code spring.application.name} is not set.
*/
private static final String DEFAULT_APPLICATION_NAME = "application";
@Bean
@ConditionalOnMissingBean
public Tracing braveTracing(Environment environment, List<SpanHandler> spanHandlers,
List<TracingCustomizer> tracingCustomizers, CurrentTraceContext currentTraceContext,
Factory propagationFactory, Sampler sampler) {
String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
Builder builder = Tracing.newBuilder().currentTraceContext(currentTraceContext)
.propagationFactory(propagationFactory).sampler(sampler).localServiceName(applicationName);
for (SpanHandler spanHandler : spanHandlers) {
builder.addSpanHandler(spanHandler);
}
for (TracingCustomizer tracingCustomizer : tracingCustomizers) {
tracingCustomizer.customize(builder);
}
return builder.build();
}
@Bean
@ConditionalOnMissingBean
public brave.Tracer braveTracer(Tracing tracing) {
return tracing.tracer();
}
@Bean
@ConditionalOnMissingBean
public CurrentTraceContext braveCurrentTraceContext(List<CurrentTraceContext.ScopeDecorator> scopeDecorators,
List<CurrentTraceContextCustomizer> currentTraceContextCustomizers) {
ThreadLocalCurrentTraceContext.Builder builder = ThreadLocalCurrentTraceContext.newBuilder();
for (ScopeDecorator scopeDecorator : scopeDecorators) {
builder.addScopeDecorator(scopeDecorator);
}
for (CurrentTraceContextCustomizer currentTraceContextCustomizer : currentTraceContextCustomizers) {
currentTraceContextCustomizer.customize(builder);
}
return builder.build();
}
@Bean
@ConditionalOnMissingBean
public Factory bravePropagationFactory() {
return B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build();
}
@Bean
@ConditionalOnMissingBean
public Sampler braveSampler(TracingProperties properties) {
return Sampler.create(properties.getSampling().getProbability());
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(BraveTracer.class)
static class BraveMicrometer {
@Bean
@ConditionalOnMissingBean
BraveTracer braveTracerBridge(brave.Tracer tracer, CurrentTraceContext currentTraceContext,
BraveBaggageManager braveBaggageManager) {
return new BraveTracer(tracer, new BraveCurrentTraceContext(currentTraceContext), braveBaggageManager);
}
@Bean
@ConditionalOnMissingBean
BraveBaggageManager braveBaggageManager() {
return new BraveBaggageManager();
}
}
}

@ -1,46 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing;
import io.micrometer.tracing.Tracer;
import io.micrometer.tracing.handler.DefaultTracingObservationHandler;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
/**
* {@link EnableAutoConfiguration Auto-configuration} for the Micrometer Tracing API.
*
* @author Moritz Halbritter
* @since 3.0.0
*/
@AutoConfiguration
@ConditionalOnClass(Tracer.class)
public class MicrometerTracingAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(Tracer.class)
public DefaultTracingObservationHandler defaultTracingObservationHandler(Tracer tracer) {
return new DefaultTracingObservationHandler(tracer);
}
}

@ -1,39 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing;
import org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryConfigurations.MicrometerConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryConfigurations.SdkConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryConfigurations.TracerConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Import;
/**
* {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry.
*
* It uses imports on {@link OpenTelemetryConfigurations} to guarantee the correct
* configuration ordering.
*
* @author Moritz Halbritter
* @since 3.0.0
*/
@AutoConfiguration(before = MicrometerTracingAutoConfiguration.class)
@Import({ SdkConfiguration.class, TracerConfiguration.class, MicrometerConfiguration.class })
public class OpenTelemetryAutoConfiguration {
}

@ -1,151 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing;
import java.util.List;
import java.util.stream.Collectors;
import io.micrometer.tracing.otel.bridge.OtelBaggageManager;
import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
import io.micrometer.tracing.otel.bridge.OtelTracer;
import io.micrometer.tracing.otel.bridge.OtelTracer.EventPublisher;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* Configurations for Open Telemetry. Those are imported by
* {@link OpenTelemetryAutoConfiguration}.
*
* @author Moritz Halbritter
*/
class OpenTelemetryConfigurations {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SdkTracerProvider.class)
@EnableConfigurationProperties(TracingProperties.class)
static class SdkConfiguration {
/**
* Default value for application name if {@code spring.application.name} is not
* set.
*/
private static final String DEFAULT_APPLICATION_NAME = "application";
@Bean
@ConditionalOnMissingBean
OpenTelemetry openTelemetry(SdkTracerProvider sdkTracerProvider, ContextPropagators contextPropagators) {
return OpenTelemetrySdk.builder().setTracerProvider(sdkTracerProvider).setPropagators(contextPropagators)
.build();
}
@Bean
@ConditionalOnMissingBean
SdkTracerProvider otelSdkTracerProvider(Environment environment, List<SpanProcessor> spanProcessors,
Sampler sampler) {
String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
SdkTracerProviderBuilder builder = SdkTracerProvider.builder().setSampler(sampler)
.setResource(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName)));
for (SpanProcessor spanProcessor : spanProcessors) {
builder.addSpanProcessor(spanProcessor);
}
return builder.build();
}
@Bean
@ConditionalOnMissingBean
ContextPropagators otelContextPropagators(List<TextMapPropagator> textMapPropagators) {
return ContextPropagators.create(TextMapPropagator.composite(textMapPropagators));
}
@Bean
@ConditionalOnMissingBean
Sampler otelSampler(TracingProperties properties) {
return Sampler.traceIdRatioBased(properties.getSampling().getProbability());
}
@Bean
@ConditionalOnMissingBean
SpanProcessor otelSpanProcessor(List<SpanExporter> spanExporter) {
return SpanProcessor.composite(spanExporter.stream()
.map((exporter) -> BatchSpanProcessor.builder(exporter).build()).collect(Collectors.toList()));
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Tracer.class)
static class TracerConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(OpenTelemetry.class)
Tracer otelTracer(OpenTelemetry openTelemetry) {
return openTelemetry.getTracer("org.springframework.boot", SpringBootVersion.getVersion());
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OtelTracer.class)
static class MicrometerConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(Tracer.class)
OtelTracer micrometerOtelTracer(Tracer tracer, EventPublisher eventPublisher,
OtelCurrentTraceContext otelCurrentTraceContext) {
return new OtelTracer(tracer, otelCurrentTraceContext, eventPublisher,
new OtelBaggageManager(otelCurrentTraceContext, List.of(), List.of()));
}
@Bean
@ConditionalOnMissingBean
EventPublisher otelTracerEventPublisher() {
return (event) -> {
};
}
@Bean
@ConditionalOnMissingBean
OtelCurrentTraceContext otelCurrentTraceContext() {
return new OtelCurrentTraceContext();
}
}
}

@ -1,56 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration properties for tracing.
*
* @author Moritz Halbritter
* @since 3.0.0
*/
@ConfigurationProperties("management.tracing")
public class TracingProperties {
/**
* Sampling configuration.
*/
private final Sampling sampling = new Sampling();
public Sampling getSampling() {
return this.sampling;
}
public static class Sampling {
/**
* Probability in the range from 0.0 to 1.0 that a trace will be sampled.
*/
private float probability = 0.10f;
public float getProbability() {
return this.probability;
}
public void setProbability(float probability) {
this.probability = probability;
}
}
}

@ -1,20 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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.
*/
/**
* Auto-configuration for Micrometer Tracing.
*/
package org.springframework.boot.actuate.autoconfigure.tracing;

@ -1,73 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.wavefront;
import java.util.concurrent.BlockingQueue;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.tracing.reporter.wavefront.SpanMetrics;
/**
* Bridges {@link SpanMetrics} to a {@link MeterRegistry}.
*
* @author Moritz Halbritter
*/
class MeterRegistrySpanMetrics implements SpanMetrics {
private final Counter spansReceived;
private final Counter spansDropped;
private final Counter reportErrors;
private final MeterRegistry meterRegistry;
MeterRegistrySpanMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.spansReceived = meterRegistry.counter("wavefront.reporter.spans.received");
this.spansDropped = meterRegistry.counter("wavefront.reporter.spans.dropped");
this.reportErrors = meterRegistry.counter("wavefront.reporter.errors");
}
@Override
public void reportDropped() {
this.spansDropped.increment();
}
@Override
public void reportReceived() {
this.spansReceived.increment();
}
@Override
public void reportErrors() {
this.reportErrors.increment();
}
@Override
public void registerQueueSize(BlockingQueue<?> queue) {
this.meterRegistry.gauge("wavefront.reporter.queue.size", queue, (q) -> (double) q.size());
}
@Override
public void registerQueueRemainingCapacity(BlockingQueue<?> queue) {
this.meterRegistry.gauge("wavefront.reporter.queue.remaining_capacity", queue,
(q) -> (double) q.remainingCapacity());
}
}

@ -1,136 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.wavefront;
import java.util.Set;
import brave.handler.SpanHandler;
import com.wavefront.sdk.common.WavefrontSender;
import com.wavefront.sdk.common.application.ApplicationTags;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.tracing.reporter.wavefront.SpanMetrics;
import io.micrometer.tracing.reporter.wavefront.WavefrontBraveSpanHandler;
import io.micrometer.tracing.reporter.wavefront.WavefrontOtelSpanHandler;
import io.micrometer.tracing.reporter.wavefront.WavefrontSpanHandler;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties.Tracing;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Wavefront.
*
* @author Moritz Halbritter
* @since 3.0.0
*/
@AutoConfiguration(after = { MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class,
WavefrontAutoConfiguration.class })
@EnableConfigurationProperties(WavefrontProperties.class)
@ConditionalOnBean(WavefrontSender.class)
public class WavefrontTracingAutoConfiguration {
/**
* Default value for application name if {@code spring.application.name} is not set.
*/
private static final String DEFAULT_APPLICATION_NAME = "application";
@Bean
@ConditionalOnMissingBean
public ApplicationTags applicationTags(Environment environment, WavefrontProperties properties) {
String springApplicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
Tracing tracing = properties.getTracing();
String applicationName = (tracing.getApplicationName() != null) ? tracing.getApplicationName()
: springApplicationName;
String serviceName = (tracing.getServiceName() != null) ? tracing.getServiceName() : springApplicationName;
return new ApplicationTags.Builder(applicationName, serviceName).build();
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(WavefrontSpanHandler.class)
static class WavefrontMicrometer {
@Bean
@ConditionalOnMissingBean
WavefrontSpanHandler wavefrontSpanHandler(WavefrontProperties properties, WavefrontSender wavefrontSender,
SpanMetrics spanMetrics, ApplicationTags applicationTags) {
return new WavefrontSpanHandler(properties.getSender().getMaxQueueSize(), wavefrontSender, spanMetrics,
properties.getSourceOrDefault(), applicationTags, Set.of());
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(MeterRegistry.class)
static class MeterRegistrySpanMetricsConfiguration {
@Bean
@ConditionalOnMissingBean
MeterRegistrySpanMetrics meterRegistrySpanMetrics(MeterRegistry meterRegistry) {
return new MeterRegistrySpanMetrics(meterRegistry);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(MeterRegistry.class)
static class NoopSpanMetricsConfiguration {
@Bean
@ConditionalOnMissingBean
SpanMetrics meterRegistrySpanMetrics() {
return SpanMetrics.NOOP;
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SpanHandler.class)
static class WavefrontBrave {
@Bean
@ConditionalOnMissingBean
WavefrontBraveSpanHandler wavefrontBraveSpanHandler(WavefrontSpanHandler wavefrontSpanHandler) {
return new WavefrontBraveSpanHandler(wavefrontSpanHandler);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SpanExporter.class)
static class WavefrontOpenTelemetry {
@Bean
@ConditionalOnMissingBean
WavefrontOtelSpanHandler wavefrontOtelSpanHandler(WavefrontSpanHandler wavefrontSpanHandler) {
return new WavefrontOtelSpanHandler(wavefrontSpanHandler);
}
}
}
}

@ -1,20 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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.
*/
/**
* Auto-configuration for tracing with Wavefront.
*/
package org.springframework.boot.actuate.autoconfigure.tracing.wavefront;

@ -1,57 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
import zipkin2.Span;
import zipkin2.codec.BytesEncoder;
import zipkin2.codec.SpanBytesEncoder;
import zipkin2.reporter.Sender;
import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.BraveConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.OpenTelemetryConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.ReporterConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.SenderConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Zipkin.
*
* It uses imports on {@link ZipkinConfigurations} to guarantee the correct configuration
* ordering.
*
* @author Moritz Halbritter
* @since 3.0.0
*/
@AutoConfiguration(after = RestTemplateAutoConfiguration.class)
@ConditionalOnClass(Sender.class)
@Import({ SenderConfiguration.class, ReporterConfiguration.class, BraveConfiguration.class,
OpenTelemetryConfiguration.class })
public class ZipkinAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public BytesEncoder<Span> spanBytesEncoder() {
return SpanBytesEncoder.JSON_V2;
}
}

@ -1,109 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
import brave.handler.SpanHandler;
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
import zipkin2.Span;
import zipkin2.codec.BytesEncoder;
import zipkin2.reporter.AsyncReporter;
import zipkin2.reporter.Reporter;
import zipkin2.reporter.Sender;
import zipkin2.reporter.brave.ZipkinSpanHandler;
import zipkin2.reporter.urlconnection.URLConnectionSender;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* Configurations for Zipkin. Those are imported by {@link ZipkinAutoConfiguration}.
*
* @author Moritz Halbritter
*/
class ZipkinConfigurations {
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ZipkinProperties.class)
static class SenderConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(URLConnectionSender.class)
Sender urlConnectionSender(ZipkinProperties properties) {
return URLConnectionSender.newBuilder().connectTimeout((int) properties.getConnectTimeout().getSeconds())
.readTimeout((int) properties.getReadTimeout().getSeconds()).endpoint(properties.getEndpoint())
.build();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(RestTemplateBuilder.class)
@ConditionalOnMissingClass("zipkin2.reporter.urlconnection.URLConnectionSender")
Sender restTemplateSender(ZipkinProperties properties, RestTemplateBuilder restTemplateBuilder) {
RestTemplate restTemplate = restTemplateBuilder.setConnectTimeout(properties.getConnectTimeout())
.setReadTimeout(properties.getReadTimeout()).build();
return new ZipkinRestTemplateSender(properties.getEndpoint(), restTemplate);
}
}
@Configuration(proxyBeanMethods = false)
static class ReporterConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(Sender.class)
Reporter<Span> spanReporter(Sender sender, BytesEncoder<Span> encoder) {
return AsyncReporter.builder(sender).build(encoder);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ZipkinSpanHandler.class)
static class BraveConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(Reporter.class)
SpanHandler zipkinSpanHandler(Reporter<Span> spanReporter) {
return ZipkinSpanHandler.newBuilder(spanReporter).build();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ZipkinSpanExporter.class)
static class OpenTelemetryConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(Sender.class)
ZipkinSpanExporter zipkinSpanExporter(BytesEncoder<Span> encoder, Sender sender) {
return ZipkinSpanExporter.builder().setEncoder(encoder).setSender(sender).build();
}
}
}

@ -1,71 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
import java.time.Duration;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration properties for {@link ZipkinAutoConfiguration}.
*
* @author Moritz Halbritter
* @since 3.0.0
*/
@ConfigurationProperties("management.zipkin.tracing")
public class ZipkinProperties {
/**
* URL to the Zipkin API.
*/
private String endpoint = "http://localhost:9411/api/v2/spans";
/**
* Connection timeout for requests to Zipkin.
*/
private Duration connectTimeout = Duration.ofSeconds(1);
/**
* Read timeout for requests to Zipkin.
*/
private Duration readTimeout = Duration.ofSeconds(10);
public String getEndpoint() {
return this.endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public Duration getConnectTimeout() {
return this.connectTimeout;
}
public void setConnectTimeout(Duration connectTimeout) {
this.connectTimeout = connectTimeout;
}
public Duration getReadTimeout() {
return this.readTimeout;
}
public void setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
}
}

@ -1,170 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.zip.GZIPOutputStream;
import zipkin2.Call;
import zipkin2.Callback;
import zipkin2.CheckResult;
import zipkin2.codec.Encoding;
import zipkin2.reporter.BytesMessageEncoder;
import zipkin2.reporter.ClosedSenderException;
import zipkin2.reporter.Sender;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.util.unit.DataSize;
import org.springframework.web.client.RestTemplate;
/**
* A Zipkin {@link Sender} which uses {@link RestTemplate} for HTTP communication.
* Supports automatic compression with gzip.
*
* @author Moritz Halbritter
*/
class ZipkinRestTemplateSender extends Sender {
private static final DataSize MESSAGE_MAX_BYTES = DataSize.ofKilobytes(512);
private final String endpoint;
private final RestTemplate restTemplate;
private volatile boolean closed;
ZipkinRestTemplateSender(String endpoint, RestTemplate restTemplate) {
this.endpoint = endpoint;
this.restTemplate = restTemplate;
}
@Override
public Encoding encoding() {
return Encoding.JSON;
}
@Override
public int messageMaxBytes() {
return (int) MESSAGE_MAX_BYTES.toBytes();
}
@Override
public int messageSizeInBytes(List<byte[]> encodedSpans) {
return encoding().listSizeInBytes(encodedSpans);
}
@Override
public int messageSizeInBytes(int encodedSizeInBytes) {
return encoding().listSizeInBytes(encodedSizeInBytes);
}
@Override
public Call<Void> sendSpans(List<byte[]> encodedSpans) {
if (this.closed) {
throw new ClosedSenderException();
}
return new HttpCall(this.endpoint, BytesMessageEncoder.JSON.encode(encodedSpans), this.restTemplate);
}
@Override
public CheckResult check() {
try {
sendSpans(List.of()).execute();
return CheckResult.OK;
}
catch (IOException | RuntimeException ex) {
return CheckResult.failed(ex);
}
}
@Override
public void close() throws IOException {
this.closed = true;
}
private static class HttpCall extends Call.Base<Void> {
/**
* Only use gzip compression on data which is bigger than this in bytes.
*/
private static final DataSize COMPRESSION_THRESHOLD = DataSize.ofKilobytes(1);
private final String endpoint;
private final byte[] body;
private final RestTemplate restTemplate;
HttpCall(String endpoint, byte[] body, RestTemplate restTemplate) {
this.endpoint = endpoint;
this.body = body;
this.restTemplate = restTemplate;
}
@Override
protected Void doExecute() throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.set("b3", "0");
headers.set("Content-Type", "application/json");
byte[] body;
if (needsCompression(this.body)) {
headers.set("Content-Encoding", "gzip");
body = compress(this.body);
}
else {
body = this.body;
}
HttpEntity<byte[]> request = new HttpEntity<>(body, headers);
this.restTemplate.exchange(this.endpoint, HttpMethod.POST, request, Void.class);
return null;
}
private boolean needsCompression(byte[] body) {
return body.length > COMPRESSION_THRESHOLD.toBytes();
}
@Override
protected void doEnqueue(Callback<Void> callback) {
try {
doExecute();
callback.onSuccess(null);
}
catch (IOException | RuntimeException ex) {
callback.onError(ex);
}
}
@Override
public Call<Void> clone() {
return new HttpCall(this.endpoint, this.body, this.restTemplate);
}
private byte[] compress(byte[] input) throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(result)) {
gzip.write(input);
}
return result.toByteArray();
}
}
}

@ -1,20 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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.
*/
/**
* Auto-configuration for tracing with Zipkin.
*/
package org.springframework.boot.actuate.autoconfigure.tracing.zipkin;

@ -1,61 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.wavefront;
import java.time.Duration;
import com.wavefront.sdk.common.WavefrontSender;
import com.wavefront.sdk.common.clients.WavefrontClient.Builder;
import org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront.WavefrontMetricsExportAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.wavefront.WavefrontTracingAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.util.unit.DataSize;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Wavefront common infrastructure.
* Metrics are auto-configured in {@link WavefrontMetricsExportAutoConfiguration}, tracing
* is auto-configured in {@link WavefrontTracingAutoConfiguration}.
*
* @author Moritz Halbritter
* @since 3.0.0
*/
@AutoConfiguration
@ConditionalOnClass(WavefrontSender.class)
@EnableConfigurationProperties(WavefrontProperties.class)
public class WavefrontAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public WavefrontSender wavefrontSender(WavefrontProperties properties) {
Builder builder = new Builder(properties.getEffectiveUri().toString(), properties.getApiTokenOrThrow());
PropertyMapper mapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
WavefrontProperties.Sender sender = properties.getSender();
mapper.from(sender.getMaxQueueSize()).to(builder::maxQueueSize);
mapper.from(sender.getFlushInterval()).asInt(Duration::getSeconds).to(builder::flushIntervalSeconds);
mapper.from(sender.getMessageSize()).asInt(DataSize::toBytes).to(builder::messageSizeBytes);
mapper.from(sender.getBatchSize()).to(builder::batchSize);
return builder.build();
}
}

@ -1,290 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.wavefront;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.time.Duration;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PushRegistryProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
import org.springframework.util.unit.DataSize;
/**
* Configuration properties to configure Wavefront.
*
* @author Moritz Halbritter
* @since 3.0.0
*/
@ConfigurationProperties(prefix = "management.wavefront")
public class WavefrontProperties {
/**
* URI to ship metrics and traces to.
*/
private URI uri = URI.create("https://longboard.wavefront.com");
/**
* Unique identifier for the app instance that is the source of metrics being
* published to Wavefront. Defaults to the local host name.
*/
private String source;
/**
* API token used when publishing metrics directly to the Wavefront API host.
*/
private String apiToken;
/**
* Sender configuration.
*/
private final Sender sender = new Sender();
/**
* Metrics configuration.
*/
private final Metrics metrics = new Metrics();
/**
* Tracing configuration.
*/
private final Tracing tracing = new Tracing();
public Sender getSender() {
return this.sender;
}
public Metrics getMetrics() {
return this.metrics;
}
public Tracing getTracing() {
return this.tracing;
}
public URI getUri() {
return this.uri;
}
public void setUri(URI uri) {
this.uri = uri;
}
public String getSource() {
return this.source;
}
public void setSource(String source) {
this.source = source;
}
public String getApiToken() {
return this.apiToken;
}
public void setApiToken(String apiToken) {
this.apiToken = apiToken;
}
/**
* Returns the effective URI of the wavefront instance. This will not be the same URI
* given through {@link #setUri(URI)} when a proxy is used.
* @return the effective URI of the wavefront instance
*/
public URI getEffectiveUri() {
if (usesProxy()) {
// See io.micrometer.wavefront.WavefrontMeterRegistry.getWavefrontReportingUri
return URI.create(this.uri.toString().replace("proxy://", "http://"));
}
return this.uri;
}
/**
* Returns the API token or throws an exception if the API token is mandatory. If a
* proxy is used, the API token is optional.
* @return the API token
*/
public String getApiTokenOrThrow() {
if (this.apiToken == null && !usesProxy()) {
throw new InvalidConfigurationPropertyValueException("management.wavefront.api-token", null,
"This property is mandatory whenever publishing directly to the Wavefront API");
}
return this.apiToken;
}
public String getSourceOrDefault() {
if (this.source != null) {
return this.source;
}
return getSourceDefault();
}
private String getSourceDefault() {
try {
return InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException ex) {
return "unknown";
}
}
private boolean usesProxy() {
return "proxy".equals(this.uri.getScheme());
}
public static class Sender {
/**
* Maximum size of queued messages.
*/
private int maxQueueSize = 50000;
/**
* Flush interval to send queued messages.
*/
private Duration flushInterval = Duration.ofSeconds(1);
/**
* Maximum size of a message.
*/
private DataSize messageSize = DataSize.ofBytes(Integer.MAX_VALUE);
/**
* Number of measurements per request to use for Wavefront. If more measurements
* are found, then multiple requests will be made.
*/
private int batchSize = 10000;
public int getMaxQueueSize() {
return this.maxQueueSize;
}
public void setMaxQueueSize(int maxQueueSize) {
this.maxQueueSize = maxQueueSize;
}
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;
}
public int getBatchSize() {
return this.batchSize;
}
public void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}
}
public static class Metrics {
/**
* Export configuration.
*/
private Export export = new Export();
public Export getExport() {
return this.export;
}
public void setExport(Export export) {
this.export = export;
}
public static class Export extends PushRegistryProperties {
/**
* Global prefix to separate metrics originating from this app's
* instrumentation from those originating from other Wavefront integrations
* when viewed in the Wavefront UI.
*/
private String globalPrefix;
public String getGlobalPrefix() {
return this.globalPrefix;
}
public void setGlobalPrefix(String globalPrefix) {
this.globalPrefix = globalPrefix;
}
/**
* See {@link PushRegistryProperties#getBatchSize()}.
*/
@Override
public Integer getBatchSize() {
throw new UnsupportedOperationException("Use Sender.getBatchSize() instead");
}
/**
* See {@link PushRegistryProperties#setBatchSize(Integer)}.
*/
@Override
public void setBatchSize(Integer batchSize) {
throw new UnsupportedOperationException("Use Sender.setBatchSize(int) instead");
}
}
}
public static class Tracing {
/**
* Application name. Defaults to 'spring.application.name'.
*/
private String applicationName;
/**
* Service name. Defaults to 'spring.application.name'.
*/
private String serviceName;
public String getServiceName() {
return this.serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getApplicationName() {
return this.applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
}
}

@ -1,20 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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.
*/
/**
* Classes shared between Wavefront tracing and metrics.
*/
package org.springframework.boot.actuate.autoconfigure.wavefront;

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2019 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.
@ -28,8 +28,7 @@ import org.springframework.beans.factory.annotation.Value;
* Annotation at the field or method/constructor parameter level that injects the HTTP
* management port that got allocated at runtime. Provides a convenient alternative for
* <code>&#064;Value(&quot;${local.management.port}&quot;)</code>.
* @deprecated since 2.7.0 for removal in 2.9.0 in favor of
* {@code org.springframework.boot.test.web.server.LocalManagementPort}
*
* @author Stephane Nicoll
* @since 2.0.0
*/
@ -37,7 +36,6 @@ import org.springframework.beans.factory.annotation.Value;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Value("${local.management.port}")
@Deprecated
public @interface LocalManagementPort {
}

@ -54,12 +54,6 @@
"sun.java.command"
]
},
{
"name": "management.endpoint.health.probes.add-additional-paths",
"type": "java.lang.Boolean",
"description": "Whether to make the liveness and readiness health groups available on the main server port.",
"defaultValue": false
},
{
"name": "management.endpoint.health.probes.enabled",
"type": "java.lang.Boolean",
@ -1832,7 +1826,7 @@
"type": "java.lang.String",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.api-token"
"replacement": "management.wavefront.metrics.export.api-token"
}
},
{
@ -1840,7 +1834,7 @@
"type": "java.lang.Integer",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.sender.batch-size"
"replacement": "management.wavefront.metrics.export.batch-size"
}
},
{
@ -1885,7 +1879,7 @@
"type": "java.time.Duration",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.sender.flush-interval"
"replacement": "management.wavefront.metrics.export.sender.flush-interval"
}
},
{
@ -1893,7 +1887,7 @@
"type": "java.lang.Integer",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.sender.max-queue-size"
"replacement": "management.wavefront.metrics.export.sender.max-queue-size"
}
},
{
@ -1901,7 +1895,7 @@
"type": "org.springframework.util.unit.DataSize",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.sender.message-size"
"replacement": "management.wavefront.metrics.export.sender.message-size"
}
},
{
@ -1909,7 +1903,7 @@
"type": "java.lang.String",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.source"
"replacement": "management.wavefront.metrics.export.source"
}
},
{
@ -1925,7 +1919,7 @@
"type": "java.net.URI",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.uri"
"replacement": "management.wavefront.metrics.export.uri"
}
},
{

@ -95,12 +95,6 @@ org.springframework.boot.actuate.autoconfigure.startup.StartupEndpointAutoConfig
org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.trace.http.HttpTraceAutoConfiguration
org.springframework.boot.actuate.autoconfigure.trace.http.HttpTraceEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.BraveAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.wavefront.WavefrontTracingAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinAutoConfiguration
org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.mappings.MappingsEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementContextAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2021 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.
@ -20,8 +20,6 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontAutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration;
@ -71,11 +69,10 @@ class SpringApplicationHierarchyTests {
@Configuration
@EnableAutoConfiguration(exclude = { ElasticsearchDataAutoConfiguration.class,
ElasticsearchRepositoriesAutoConfiguration.class, CassandraAutoConfiguration.class,
CassandraDataAutoConfiguration.class, MicrometerTracingAutoConfiguration.class,
MongoDataAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class, Neo4jAutoConfiguration.class,
Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class, RedisAutoConfiguration.class,
RedisRepositoriesAutoConfiguration.class, FlywayAutoConfiguration.class, MetricsAutoConfiguration.class,
WavefrontAutoConfiguration.class })
CassandraDataAutoConfiguration.class, MongoDataAutoConfiguration.class,
MongoReactiveDataAutoConfiguration.class, Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class,
Neo4jRepositoriesAutoConfiguration.class, RedisAutoConfiguration.class,
RedisRepositoriesAutoConfiguration.class, FlywayAutoConfiguration.class, MetricsAutoConfiguration.class })
static class Parent {
}
@ -83,11 +80,10 @@ class SpringApplicationHierarchyTests {
@Configuration
@EnableAutoConfiguration(exclude = { ElasticsearchDataAutoConfiguration.class,
ElasticsearchRepositoriesAutoConfiguration.class, CassandraAutoConfiguration.class,
CassandraDataAutoConfiguration.class, MicrometerTracingAutoConfiguration.class,
MongoDataAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class, Neo4jAutoConfiguration.class,
Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class, RedisAutoConfiguration.class,
RedisRepositoriesAutoConfiguration.class, FlywayAutoConfiguration.class, MetricsAutoConfiguration.class,
WavefrontAutoConfiguration.class })
CassandraDataAutoConfiguration.class, MongoDataAutoConfiguration.class,
MongoReactiveDataAutoConfiguration.class, Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class,
Neo4jRepositoriesAutoConfiguration.class, RedisAutoConfiguration.class,
RedisRepositoriesAutoConfiguration.class, FlywayAutoConfiguration.class, MetricsAutoConfiguration.class })
static class Child {
}

@ -1,110 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.elasticsearch;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestClientHealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ElasticSearchRestHealthContributorAutoConfiguration}.
*
* @author Filip Hrisafov
* @author Andy Wilkinson
*/
class ElasticSearchRestHealthContributorAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
ElasticSearchRestHealthContributorAutoConfiguration.class,
HealthContributorAutoConfiguration.class));
@Test
void runShouldCreateIndicator() {
this.contextRunner.run((context) -> assertThat(context)
.hasSingleBean(ElasticsearchRestClientHealthIndicator.class).hasBean("elasticsearchHealthContributor"));
}
@Test
@SuppressWarnings("deprecation")
void runWithoutRestHighLevelClientAndWithoutRestClientShouldNotCreateIndicator() {
this.contextRunner
.withClassLoader(
new FilteredClassLoader(org.elasticsearch.client.RestHighLevelClient.class, RestClient.class))
.run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class)
.doesNotHaveBean("elasticsearchHealthContributor"));
}
@Test
void runWithoutRestHighLevelClientAndWithRestClientShouldCreateIndicator() {
this.contextRunner.withUserConfiguration(CustomRestClientConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestClientHealthIndicator.class)
.hasBean("elasticsearchHealthContributor"));
}
@Test
void runWithRestHighLevelClientAndWithRestClientShouldCreateIndicator() {
this.contextRunner.withUserConfiguration(CustomRestHighClientConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestClientHealthIndicator.class)
.hasBean("elasticsearchHealthContributor"));
}
@Test
void runWhenDisabledShouldNotCreateIndicator() {
this.contextRunner.withPropertyValues("management.health.elasticsearch.enabled:false")
.run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class)
.doesNotHaveBean("elasticsearchHealthContributor"));
}
@Configuration(proxyBeanMethods = false)
static class CustomRestClientConfiguration {
@Bean
RestClient customRestClient(RestClientBuilder builder) {
return builder.build();
}
}
@Configuration(proxyBeanMethods = false)
@SuppressWarnings("deprecation")
static class CustomRestHighClientConfiguration {
@Bean
org.elasticsearch.client.RestHighLevelClient customRestHighClient(RestClientBuilder builder) {
return new org.elasticsearch.client.RestHighLevelClient(builder);
}
@Bean
RestClient customClient(org.elasticsearch.client.RestHighLevelClient restHighLevelClient) {
return restHighLevelClient.getLowLevelClient();
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 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.
@ -20,7 +20,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
import org.springframework.boot.actuate.elasticsearch.ElasticsearchReactiveHealthIndicator;
import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestClientHealthIndicator;
import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestHealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration;
@ -55,7 +55,7 @@ class ElasticsearchReactiveHealthContributorAutoConfigurationTests {
.withConfiguration(AutoConfigurations.of(ElasticSearchRestHealthContributorAutoConfiguration.class))
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchReactiveHealthIndicator.class)
.hasBean("elasticsearchHealthContributor")
.doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class));
.doesNotHaveBean(ElasticsearchRestHealthIndicator.class));
}
@Test

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2021 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.
@ -31,8 +31,8 @@ import org.springframework.boot.actuate.web.mappings.MappingsEndpoint;
import org.springframework.boot.actuate.web.mappings.reactive.DispatcherHandlersMappingDescriptionProvider;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2021 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.
@ -33,8 +33,8 @@ import org.springframework.boot.actuate.web.mappings.servlet.FiltersMappingDescr
import org.springframework.boot.actuate.web.mappings.servlet.ServletsMappingDescriptionProvider;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@ -16,8 +16,8 @@
package org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation;
import io.micrometer.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.Statistic;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.junit.jupiter.api.Test;

@ -16,8 +16,8 @@
package org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation;
import io.micrometer.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.exporter.common.TextFormat;

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2021 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.
@ -20,9 +20,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.BraveAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontAutoConfiguration;
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -83,8 +80,7 @@ class WebEndpointsAutoConfigurationIntegrationTests {
MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class,
RepositoryRestMvcAutoConfiguration.class, HazelcastAutoConfiguration.class,
ElasticsearchDataAutoConfiguration.class, SolrAutoConfiguration.class, RedisAutoConfiguration.class,
RedisRepositoriesAutoConfiguration.class, MetricsAutoConfiguration.class, WavefrontAutoConfiguration.class,
BraveAutoConfiguration.class, OpenTelemetryAutoConfiguration.class })
RedisRepositoriesAutoConfiguration.class, MetricsAutoConfiguration.class })
@SpringBootConfiguration
static class WebEndpointTestApplication {

@ -16,11 +16,11 @@
package org.springframework.boot.actuate.autoconfigure.metrics;
import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmHeapPressureMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
import io.micrometer.binder.jvm.ClassLoaderMetrics;
import io.micrometer.binder.jvm.JvmGcMetrics;
import io.micrometer.binder.jvm.JvmHeapPressureMetrics;
import io.micrometer.binder.jvm.JvmMemoryMetrics;
import io.micrometer.binder.jvm.JvmThreadMetrics;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;

@ -16,7 +16,7 @@
package org.springframework.boot.actuate.autoconfigure.metrics;
import io.micrometer.core.instrument.binder.logging.Log4j2Metrics;
import io.micrometer.binder.logging.Log4j2Metrics;
import org.apache.logging.log4j.LogManager;
import org.junit.jupiter.api.Test;

@ -16,7 +16,7 @@
package org.springframework.boot.actuate.autoconfigure.metrics;
import io.micrometer.core.instrument.binder.logging.Log4j2Metrics;
import io.micrometer.binder.logging.Log4j2Metrics;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.slf4j.SLF4JLoggerContext;
import org.junit.jupiter.api.Test;

@ -16,7 +16,7 @@
package org.springframework.boot.actuate.autoconfigure.metrics;
import io.micrometer.core.instrument.binder.logging.LogbackMetrics;
import io.micrometer.binder.logging.LogbackMetrics;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;

@ -16,7 +16,7 @@
package org.springframework.boot.actuate.autoconfigure.metrics;
import io.micrometer.core.instrument.binder.logging.LogbackMetrics;
import io.micrometer.binder.logging.LogbackMetrics;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;

@ -20,10 +20,10 @@ import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import io.micrometer.binder.system.FileDescriptorMetrics;
import io.micrometer.binder.system.ProcessorMetrics;
import io.micrometer.binder.system.UptimeMetrics;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.binder.system.FileDescriptorMetrics;
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
import io.micrometer.core.instrument.binder.system.UptimeMetrics;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;

@ -44,8 +44,8 @@ class CacheMetricsAutoConfigurationTests {
this.contextRunner.withPropertyValues("spring.cache.type=cache2k", "spring.cache.cache-names=cache1,cache2")
.run((context) -> {
MeterRegistry registry = context.getBean(MeterRegistry.class);
registry.get("cache.gets").tags("name", "cache1").tags("cache.manager", "cacheManager").meter();
registry.get("cache.gets").tags("name", "cache2").tags("cache.manager", "cacheManager").meter();
registry.get("cache.gets").tags("name", "cache1").tags("cacheManager", "cacheManager").meter();
registry.get("cache.gets").tags("name", "cache2").tags("cacheManager", "cacheManager").meter();
});
}
@ -54,8 +54,8 @@ class CacheMetricsAutoConfigurationTests {
this.contextRunner.withPropertyValues("spring.cache.type=caffeine", "spring.cache.cache-names=cache1,cache2")
.run((context) -> {
MeterRegistry registry = context.getBean(MeterRegistry.class);
registry.get("cache.gets").tags("name", "cache1").tags("cache.manager", "cacheManager").meter();
registry.get("cache.gets").tags("name", "cache2").tags("cache.manager", "cacheManager").meter();
registry.get("cache.gets").tags("name", "cache1").tags("cacheManager", "cacheManager").meter();
registry.get("cache.gets").tags("name", "cache2").tags("cacheManager", "cacheManager").meter();
});
}
@ -64,9 +64,9 @@ class CacheMetricsAutoConfigurationTests {
this.contextRunner.withPropertyValues("spring.cache.type=simple", "spring.cache.cache-names=cache1,cache2")
.run((context) -> {
MeterRegistry registry = context.getBean(MeterRegistry.class);
assertThat(registry.find("cache.gets").tags("name", "cache1").tags("cache.manager", "cacheManager")
assertThat(registry.find("cache.gets").tags("name", "cache1").tags("cacheManager", "cacheManager")
.meter()).isNull();
assertThat(registry.find("cache.gets").tags("name", "cache2").tags("cache.manager", "cacheManager")
assertThat(registry.find("cache.gets").tags("name", "cache2").tags("cacheManager", "cacheManager")
.meter()).isNull();
});
}
@ -77,7 +77,7 @@ class CacheMetricsAutoConfigurationTests {
"spring.cache.cache-names=cache1").run((context) -> {
MeterRegistry registry = context.getBean(MeterRegistry.class);
assertThat(registry.find("cache.requests").tags("name", "cache1")
.tags("cache.manager", "cacheManager").meter()).isNull();
.tags("cacheManager", "cacheManager").meter()).isNull();
});
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2021 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.
@ -125,13 +125,6 @@ class DynatracePropertiesConfigAdapterTests {
assertThat(new DynatracePropertiesConfigAdapter(properties).enrichWithDynatraceMetadata()).isTrue();
}
@Test
void whenPropertiesUseDynatraceInstrumentsIsSetAdapterUseDynatraceInstrumentsReturnsIt() {
DynatraceProperties properties = new DynatraceProperties();
properties.getV2().setUseDynatraceSummaryInstruments(false);
assertThat(new DynatracePropertiesConfigAdapter(properties).useDynatraceSummaryInstruments()).isFalse();
}
@Test
void whenPropertiesDefaultDimensionsIsSetAdapterDefaultDimensionsReturnsIt() {
DynatraceProperties properties = new DynatraceProperties();
@ -155,7 +148,6 @@ class DynatracePropertiesConfigAdapterTests {
assertThat(properties.getV2().getMetricKeyPrefix()).isNull();
assertThat(properties.getV2().isEnrichWithDynatraceMetadata()).isTrue();
assertThat(properties.getV2().getDefaultDimensions()).isNull();
assertThat(properties.getV2().isUseDynatraceSummaryInstruments()).isTrue();
assertThat(properties.getDeviceId()).isNull();
assertThat(properties.getTechnologyType()).isEqualTo("java");
assertThat(properties.getGroup()).isNull();

@ -16,8 +16,8 @@
package org.springframework.boot.actuate.autoconfigure.metrics.export.humio;
import io.micrometer.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
import io.micrometer.humio.HumioConfig;
import io.micrometer.humio.HumioMeterRegistry;
import org.junit.jupiter.api.Test;

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 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.
@ -51,7 +51,7 @@ public abstract class PushRegistryPropertiesConfigAdapterTests<P extends PushReg
}
@Test
protected void whenPropertiesBatchSizeIsSetAdapterBatchSizeReturnsIt() {
void whenPropertiesBatchSizeIsSetAdapterBatchSizeReturnsIt() {
P properties = createProperties();
properties.setBatchSize(10042);
assertThat(createConfigAdapter(properties).batchSize()).isEqualTo(10042);

@ -16,12 +16,14 @@
package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront;
import java.util.concurrent.LinkedBlockingQueue;
import com.wavefront.sdk.common.WavefrontSender;
import io.micrometer.core.instrument.Clock;
import io.micrometer.wavefront.WavefrontConfig;
import io.micrometer.wavefront.WavefrontMeterRegistry;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@ -29,6 +31,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@ -48,22 +51,28 @@ class WavefrontMetricsExportAutoConfigurationTests {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(WavefrontMeterRegistry.class));
}
@Test
void failsWithoutAnApiTokenWhenPublishingDirectly() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.run((context) -> assertThat(context).hasFailed());
}
@Test
void autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.withPropertyValues("management.wavefront.api-token=abcde",
.withPropertyValues("management.wavefront.metrics.export.api-token=abcde",
"management.defaults.metrics.export.enabled=false")
.run((context) -> assertThat(context).doesNotHaveBean(WavefrontMeterRegistry.class)
.doesNotHaveBean(WavefrontConfig.class));
.doesNotHaveBean(WavefrontConfig.class).doesNotHaveBean(WavefrontSender.class));
}
@Test
void autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.withPropertyValues("management.wavefront.api-token=abcde",
.withPropertyValues("management.wavefront.metrics.export.api-token=abcde",
"management.wavefront.metrics.export.enabled=false")
.run((context) -> assertThat(context).doesNotHaveBean(WavefrontMeterRegistry.class)
.doesNotHaveBean(WavefrontConfig.class));
.doesNotHaveBean(WavefrontConfig.class).doesNotHaveBean(WavefrontSender.class));
}
@Test
@ -74,10 +83,51 @@ class WavefrontMetricsExportAutoConfigurationTests {
.hasSingleBean(WavefrontSender.class).hasBean("customConfig"));
}
@Test
void defaultWavefrontSenderSettingsAreConsistent() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.withPropertyValues("management.wavefront.metrics.export.api-token=abcde").run((context) -> {
WavefrontProperties properties = new WavefrontProperties();
WavefrontSender sender = context.getBean(WavefrontSender.class);
assertThat(sender)
.extracting("metricsBuffer", as(InstanceOfAssertFactories.type(LinkedBlockingQueue.class)))
.satisfies((queue) -> assertThat(queue.remainingCapacity() + queue.size())
.isEqualTo(properties.getSender().getMaxQueueSize()));
assertThat(sender).hasFieldOrPropertyWithValue("batchSize", properties.getBatchSize());
assertThat(sender).hasFieldOrPropertyWithValue("messageSizeBytes",
(int) properties.getSender().getMessageSize().toBytes());
});
}
@Test
void configureWavefrontSender() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.withPropertyValues("management.wavefront.metrics.export.api-token=abcde",
"management.wavefront.metrics.export.batch-size=50",
"management.wavefront.metrics.export.sender.max-queue-size=100",
"management.wavefront.metrics.export.sender.message-size=1KB")
.run((context) -> {
WavefrontSender sender = context.getBean(WavefrontSender.class);
assertThat(sender).hasFieldOrPropertyWithValue("batchSize", 50);
assertThat(sender)
.extracting("metricsBuffer", as(InstanceOfAssertFactories.type(LinkedBlockingQueue.class)))
.satisfies((queue) -> assertThat(queue.remainingCapacity() + queue.size()).isEqualTo(100));
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
void allowsRegistryToBeCustomized() {
this.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)
.withPropertyValues("management.wavefront.api-token=abcde")
.withPropertyValues("management.wavefront.metrics.export.api-token=abcde")
.run((context) -> assertThat(context).hasSingleBean(Clock.class).hasSingleBean(WavefrontConfig.class)
.hasSingleBean(WavefrontMeterRegistry.class).hasBean("customRegistry"));
}
@ -85,7 +135,7 @@ class WavefrontMetricsExportAutoConfigurationTests {
@Test
void stopsMeterRegistryWhenContextIsClosed() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.withPropertyValues("management.wavefront.api-token=abcde").run((context) -> {
.withPropertyValues("management.wavefront.metrics.export.api-token=abcde").run((context) -> {
WavefrontMeterRegistry registry = context.getBean(WavefrontMeterRegistry.class);
assertThat(registry.isClosed()).isFalse();
context.close();
@ -96,11 +146,6 @@ class WavefrontMetricsExportAutoConfigurationTests {
@Configuration(proxyBeanMethods = false)
static class BaseConfiguration {
@Bean
WavefrontSender customWavefrontSender() {
return Mockito.mock(WavefrontSender.class);
}
@Bean
Clock clock() {
return Clock.SYSTEM;

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2019 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.
@ -16,11 +16,11 @@
package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront;
import java.net.URI;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PushRegistryPropertiesConfigAdapterTests;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties.Metrics.Export;
import static org.assertj.core.api.Assertions.assertThat;
@ -28,35 +28,46 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link WavefrontPropertiesConfigAdapter}.
*
* @author Stephane Nicoll
* @author Moritz Halbritter
*/
class WavefrontPropertiesConfigAdapterTests extends
PushRegistryPropertiesConfigAdapterTests<WavefrontProperties.Metrics.Export, WavefrontPropertiesConfigAdapter> {
class WavefrontPropertiesConfigAdapterTests
extends PushRegistryPropertiesConfigAdapterTests<WavefrontProperties, WavefrontPropertiesConfigAdapter> {
@Override
protected WavefrontProperties.Metrics.Export createProperties() {
return new WavefrontProperties.Metrics.Export();
protected WavefrontProperties createProperties() {
return new WavefrontProperties();
}
@Override
protected WavefrontPropertiesConfigAdapter createConfigAdapter(WavefrontProperties.Metrics.Export export) {
WavefrontProperties properties = new WavefrontProperties();
properties.getMetrics().setExport(export);
protected WavefrontPropertiesConfigAdapter createConfigAdapter(WavefrontProperties properties) {
return new WavefrontPropertiesConfigAdapter(properties);
}
@Test
void whenPropertiesUriIsSetAdapterUriReturnsIt() {
WavefrontProperties properties = createProperties();
properties.setUri(URI.create("https://wavefront.example.com"));
assertThat(createConfigAdapter(properties).uri()).isEqualTo("https://wavefront.example.com");
}
@Test
void whenPropertiesSourceIsSetAdapterSourceReturnsIt() {
WavefrontProperties properties = createProperties();
properties.setSource("test");
assertThat(createConfigAdapter(properties).source()).isEqualTo("test");
}
@Test
void whenPropertiesApiTokenIsSetAdapterApiTokenReturnsIt() {
WavefrontProperties properties = createProperties();
properties.setApiToken("ABC123");
assertThat(createConfigAdapter(properties).apiToken()).isEqualTo("ABC123");
}
@Test
void whenPropertiesGlobalPrefixIsSetAdapterGlobalPrefixReturnsIt() {
Export properties = createProperties();
WavefrontProperties properties = createProperties();
properties.setGlobalPrefix("test");
assertThat(createConfigAdapter(properties).globalPrefix()).isEqualTo("test");
}
@Override
protected void whenPropertiesBatchSizeIsSetAdapterBatchSizeReturnsIt() {
WavefrontProperties properties = new WavefrontProperties();
properties.getSender().setBatchSize(10042);
assertThat(createConfigAdapter(properties.getMetrics().getExport()).batchSize()).isEqualTo(10042);
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 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.
@ -14,31 +14,29 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.wavefront;
package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront;
import io.micrometer.wavefront.WavefrontConfig;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PushRegistryPropertiesTests;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link WavefrontProperties.Metrics.Export}.
* Tests for {@link WavefrontProperties}.
*
* @author Stephane Nicoll
* @author Moritz Halbritter
*/
class WavefrontPropertiesMetricsExportTests {
class WavefrontPropertiesTests extends PushRegistryPropertiesTests {
@Test
@SuppressWarnings("deprecation")
void defaultValuesAreConsistent() {
WavefrontProperties.Metrics.Export properties = new WavefrontProperties.Metrics.Export();
WavefrontProperties properties = new WavefrontProperties();
WavefrontConfig config = WavefrontConfig.DEFAULT_DIRECT;
assertThat(properties.getConnectTimeout()).isEqualTo(config.connectTimeout());
assertStepRegistryDefaultValues(properties, config);
assertThat(properties.getUri().toString()).isEqualTo(config.uri());
assertThat(properties.getGlobalPrefix()).isEqualTo(config.globalPrefix());
assertThat(properties.getReadTimeout()).isEqualTo(config.readTimeout());
assertThat(properties.getStep()).isEqualTo(config.step());
assertThat(properties.isEnabled()).isEqualTo(config.enabled());
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2021 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.
@ -29,7 +29,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.LazyInitializationBeanFactoryPostProcessor;
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@ -91,19 +90,6 @@ class DataSourcePoolMetricsAutoConfigurationTests {
});
}
@Test
void allDataSourcesCanBeInstrumentedWithLazyInitialization() {
this.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class)).withInitializer(
(context) -> context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()))
.withUserConfiguration(TwoDataSourcesConfiguration.class).run((context) -> {
context.getBean("firstDataSource", DataSource.class).getConnection().getMetaData();
context.getBean("secondOne", DataSource.class).getConnection().getMetaData();
MeterRegistry registry = context.getBean(MeterRegistry.class);
registry.get("jdbc.connections.max").tags("name", "first").meter();
registry.get("jdbc.connections.max").tags("name", "secondOne").meter();
});
}
@Test
void autoConfiguredHikariDataSourceIsInstrumented() {
this.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))
@ -181,21 +167,6 @@ class DataSourcePoolMetricsAutoConfigurationTests {
});
}
@Test
void allHikariDataSourcesCanBeInstrumentedWhenUsingLazyInitialization() {
this.contextRunner.withUserConfiguration(TwoHikariDataSourcesConfiguration.class)
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))
.withInitializer((context) -> context
.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()))
.run((context) -> {
context.getBean("firstDataSource", DataSource.class).getConnection();
context.getBean("secondOne", DataSource.class).getConnection();
MeterRegistry registry = context.getBean(MeterRegistry.class);
registry.get("hikaricp.connections").tags("pool", "firstDataSource").meter();
registry.get("hikaricp.connections").tags("pool", "secondOne").meter();
});
}
@Test
void hikariProxiedDataSourceCanBeInstrumented() {
this.contextRunner.withUserConfiguration(ProxiedHikariDataSourcesConfiguration.class)

@ -23,12 +23,12 @@ import com.mongodb.client.MongoClient;
import com.mongodb.client.internal.MongoClientImpl;
import com.mongodb.connection.ConnectionPoolSettings;
import com.mongodb.event.ConnectionPoolListener;
import io.micrometer.core.instrument.binder.mongodb.DefaultMongoCommandTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.DefaultMongoConnectionPoolTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.MongoCommandTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.MongoConnectionPoolTagsProvider;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsCommandListener;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsConnectionPoolListener;
import io.micrometer.binder.mongodb.DefaultMongoCommandTagsProvider;
import io.micrometer.binder.mongodb.DefaultMongoConnectionPoolTagsProvider;
import io.micrometer.binder.mongodb.MongoCommandTagsProvider;
import io.micrometer.binder.mongodb.MongoConnectionPoolTagsProvider;
import io.micrometer.binder.mongodb.MongoMetricsCommandListener;
import io.micrometer.binder.mongodb.MongoMetricsConnectionPoolListener;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;

@ -22,11 +22,11 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.CyclicBarrier;
import io.micrometer.binder.jvm.JvmMemoryMetrics;
import io.micrometer.binder.logging.LogbackMetrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.MockClock;
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.binder.logging.LogbackMetrics;
import io.micrometer.core.instrument.simple.SimpleConfig;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import jakarta.servlet.DispatcherType;

@ -19,8 +19,8 @@ package org.springframework.boot.actuate.autoconfigure.metrics.web.tomcat;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicInteger;
import io.micrometer.binder.tomcat.TomcatMetrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.tomcat.TomcatMetrics;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.apache.tomcat.util.modeler.Registry;
import org.junit.jupiter.api.Test;

@ -19,14 +19,14 @@ package org.springframework.boot.actuate.autoconfigure.observation;
import java.util.ArrayList;
import java.util.List;
import io.micrometer.common.KeyValue;
import io.micrometer.common.KeyValues;
import io.micrometer.common.Tag;
import io.micrometer.common.Tags;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.observation.MeterObservationHandler;
import io.micrometer.core.instrument.search.MeterNotFoundException;
import io.micrometer.observation.Observation;
import io.micrometer.observation.Observation.Context;
import io.micrometer.observation.Observation.GlobalKeyValuesProvider;
import io.micrometer.observation.Observation.GlobalTagsProvider;
import io.micrometer.observation.ObservationHandler;
import io.micrometer.observation.ObservationHandler.AllMatchingCompositeObservationHandler;
import io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler;
@ -104,7 +104,7 @@ class ObservationAutoConfigurationTests {
ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);
Context micrometerContext = new Context();
Observation.start("test-observation", micrometerContext, observationRegistry).stop();
assertThat(micrometerContext.getAllKeyValues()).containsExactly(KeyValue.of("tag1", "value1"));
assertThat(micrometerContext.getAllTags()).containsExactly(Tag.of("tag1", "value1"));
});
}
@ -164,16 +164,16 @@ class ObservationAutoConfigurationTests {
static class GlobalTagsProviders {
@Bean
Observation.GlobalKeyValuesProvider<?> customTagsProvider() {
return new GlobalKeyValuesProvider<>() {
GlobalTagsProvider<?> customTagsProvider() {
return new GlobalTagsProvider<>() {
@Override
public boolean supportsContext(Context context) {
return true;
}
@Override
public KeyValues getLowCardinalityKeyValues(Context context) {
return KeyValues.of("tag1", "value1");
public Tags getLowCardinalityTags(Context context) {
return Tags.of("tag1", "value1");
}
};
}

@ -136,10 +136,10 @@ class ManagementWebSecurityAutoConfigurationTests {
void backOffIfSaml2RelyingPartyAutoConfigurationPresent() {
this.contextRunner.withConfiguration(AutoConfigurations.of(Saml2RelyingPartyAutoConfiguration.class))
.withPropertyValues(
"spring.security.saml2.relyingparty.registration.simplesamlphp.asserting-party.single-sign-on.url=https://simplesaml-for-spring-saml/SSOService.php",
"spring.security.saml2.relyingparty.registration.simplesamlphp.asserting-party.single-sign-on.sign-request=false",
"spring.security.saml2.relyingparty.registration.simplesamlphp.asserting-party.entity-id=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php",
"spring.security.saml2.relyingparty.registration.simplesamlphp.asserting-party.verification.credentials[0].certificate-location=classpath:saml/certificate-location")
"spring.security.saml2.relyingparty.registration.simplesamlphp.identity-provider.single-sign-on.url=https://simplesaml-for-spring-saml/SSOService.php",
"spring.security.saml2.relyingparty.registration.simplesamlphp.identity-provider.single-sign-on.sign-request=false",
"spring.security.saml2.relyingparty.registration.simplesamlphp.identityprovider.entity-id=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php",
"spring.security.saml2.relyingparty.registration.simplesamlphp.identityprovider.verification.credentials[0].certificate-location=classpath:saml/certificate-location")
.run((context) -> assertThat(context).doesNotHaveBean(ManagementWebSecurityAutoConfiguration.class)
.doesNotHaveBean(MANAGEMENT_SECURITY_FILTER_CHAIN_BEAN));
}

@ -1,156 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing;
import brave.Tracer;
import brave.Tracing;
import brave.propagation.CurrentTraceContext;
import brave.propagation.Propagation.Factory;
import brave.sampler.Sampler;
import io.micrometer.tracing.brave.bridge.BraveBaggageManager;
import io.micrometer.tracing.brave.bridge.BraveTracer;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link BraveAutoConfiguration}.
*
* @author Moritz Halbritter
*/
class BraveAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(BraveAutoConfiguration.class));
@Test
void shouldSupplyBraveBeans() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(Tracing.class);
assertThat(context).hasSingleBean(Tracer.class);
assertThat(context).hasSingleBean(CurrentTraceContext.class);
assertThat(context).hasSingleBean(Factory.class);
assertThat(context).hasSingleBean(Sampler.class);
});
}
@Test
void shouldBackOffOnCustomBraveBeans() {
this.contextRunner.withUserConfiguration(CustomBraveConfiguration.class).run((context) -> {
assertThat(context).hasBean("customTracing");
assertThat(context).hasSingleBean(Tracing.class);
assertThat(context).hasBean("customTracer");
assertThat(context).hasSingleBean(Tracer.class);
assertThat(context).hasBean("customCurrentTraceContext");
assertThat(context).hasSingleBean(CurrentTraceContext.class);
assertThat(context).hasBean("customFactory");
assertThat(context).hasSingleBean(Factory.class);
assertThat(context).hasBean("customSampler");
assertThat(context).hasSingleBean(Sampler.class);
});
}
@Test
void shouldSupplyMicrometerBeans() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(BraveTracer.class);
assertThat(context).hasSingleBean(BraveBaggageManager.class);
});
}
@Test
void shouldBackOffOnCustomMicrometerBraveBeans() {
this.contextRunner.withUserConfiguration(CustomMicrometerBraveConfiguration.class).run((context) -> {
assertThat(context).hasBean("customBraveTracer");
assertThat(context).hasSingleBean(BraveTracer.class);
assertThat(context).hasBean("customBraveBaggageManager");
assertThat(context).hasSingleBean(BraveBaggageManager.class);
});
}
@Test
void shouldNotSupplyBraveBeansIfBraveIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("brave")).run((context) -> {
assertThat(context).doesNotHaveBean(Tracing.class);
assertThat(context).doesNotHaveBean(Tracer.class);
assertThat(context).doesNotHaveBean(CurrentTraceContext.class);
assertThat(context).doesNotHaveBean(Factory.class);
assertThat(context).doesNotHaveBean(Sampler.class);
});
}
@Test
void shouldNotSupplyMicrometerBeansIfMicrometerIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("io.micrometer")).run((context) -> {
assertThat(context).doesNotHaveBean(BraveTracer.class);
assertThat(context).doesNotHaveBean(BraveBaggageManager.class);
});
}
@Configuration(proxyBeanMethods = false)
private static class CustomBraveConfiguration {
@Bean
Tracing customTracing() {
return Mockito.mock(Tracing.class);
}
@Bean
Tracer customTracer() {
return Mockito.mock(Tracer.class);
}
@Bean
CurrentTraceContext customCurrentTraceContext() {
return Mockito.mock(CurrentTraceContext.class);
}
@Bean
Factory customFactory() {
return Mockito.mock(Factory.class);
}
@Bean
Sampler customSampler() {
return Mockito.mock(Sampler.class);
}
}
@Configuration(proxyBeanMethods = false)
private static class CustomMicrometerBraveConfiguration {
@Bean
BraveTracer customBraveTracer() {
return Mockito.mock(BraveTracer.class);
}
@Bean
BraveBaggageManager customBraveBaggageManager() {
return Mockito.mock(BraveBaggageManager.class);
}
}
}

@ -1,88 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing;
import io.micrometer.tracing.Tracer;
import io.micrometer.tracing.handler.DefaultTracingObservationHandler;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link MicrometerTracingAutoConfiguration}.
*
* @author Moritz Halbritter
*/
class MicrometerTracingAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(MicrometerTracingAutoConfiguration.class));
@Test
void shouldSupplyBeans() {
this.contextRunner.withUserConfiguration(TracerConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class));
}
@Test
void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
assertThat(context).hasBean("customDefaultTracingObservationHandler");
assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class);
});
}
@Test
void shouldNotSupplyBeansIfMicrometerIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("io.micrometer"))
.run((context) -> assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class));
}
@Test
void shouldNotSupplyDefaultTracingObservationHandlerIfTracerIsMissing() {
this.contextRunner
.run((context) -> assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class));
}
@Configuration(proxyBeanMethods = false)
private static class TracerConfiguration {
@Bean
Tracer tracer() {
return Mockito.mock(Tracer.class);
}
}
@Configuration(proxyBeanMethods = false)
private static class CustomConfiguration {
@Bean
DefaultTracingObservationHandler customDefaultTracingObservationHandler() {
return Mockito.mock(DefaultTracingObservationHandler.class);
}
}
}

@ -1,111 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing;
import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
import io.micrometer.tracing.otel.bridge.OtelTracer;
import io.micrometer.tracing.otel.bridge.OtelTracer.EventPublisher;
import io.opentelemetry.api.trace.Tracer;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryConfigurations.MicrometerConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link MicrometerConfiguration}.
*
* @author Moritz Halbritter
*/
class OpenTelemetryConfigurationsMicrometerConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(MicrometerConfiguration.class));
@Test
void shouldSupplyBeans() {
this.contextRunner.withUserConfiguration(TracerConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(OtelTracer.class);
assertThat(context).hasSingleBean(EventPublisher.class);
assertThat(context).hasSingleBean(OtelCurrentTraceContext.class);
});
}
@Test
void shouldNotSupplyBeansIfMicrometerTracingBridgeOtelIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("io.micrometer.tracing.otel"))
.withUserConfiguration(TracerConfiguration.class).run((context) -> {
assertThat(context).doesNotHaveBean(OtelTracer.class);
assertThat(context).doesNotHaveBean(EventPublisher.class);
assertThat(context).doesNotHaveBean(OtelCurrentTraceContext.class);
});
}
@Test
void shouldNotSupplyOtelTracerIfTracerIsMissing() {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(OtelTracer.class));
}
@Test
void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
assertThat(context).hasBean("customOtelTracer");
assertThat(context).hasSingleBean(OtelTracer.class);
assertThat(context).hasBean("customEventPublisher");
assertThat(context).hasSingleBean(EventPublisher.class);
assertThat(context).hasBean("customOtelCurrentTraceContext");
assertThat(context).hasSingleBean(OtelCurrentTraceContext.class);
});
}
@Configuration(proxyBeanMethods = false)
private static class CustomConfiguration {
@Bean
OtelTracer customOtelTracer() {
return Mockito.mock(OtelTracer.class);
}
@Bean
EventPublisher customEventPublisher() {
return Mockito.mock(EventPublisher.class);
}
@Bean
OtelCurrentTraceContext customOtelCurrentTraceContext() {
return Mockito.mock(OtelCurrentTraceContext.class);
}
}
@Configuration(proxyBeanMethods = false)
private static class TracerConfiguration {
@Bean
Tracer tracer() {
return Mockito.mock(Tracer.class);
}
}
}

@ -1,112 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryConfigurations.SdkConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link SdkConfiguration}.
*
* @author Moritz Halbritter
*/
class OpenTelemetryConfigurationsSdkConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(SdkConfiguration.class));
@Test
void shouldSupplyBeans() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(OpenTelemetry.class);
assertThat(context).hasSingleBean(SdkTracerProvider.class);
assertThat(context).hasSingleBean(ContextPropagators.class);
assertThat(context).hasSingleBean(Sampler.class);
assertThat(context).hasSingleBean(SpanProcessor.class);
});
}
@Test
void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(CustomBeans.class).run((context) -> {
assertThat(context).hasBean("customOpenTelemetry");
assertThat(context).hasSingleBean(OpenTelemetry.class);
assertThat(context).hasBean("customSdkTracerProvider");
assertThat(context).hasSingleBean(SdkTracerProvider.class);
assertThat(context).hasBean("customContextPropagators");
assertThat(context).hasSingleBean(ContextPropagators.class);
assertThat(context).hasBean("customSampler");
assertThat(context).hasSingleBean(Sampler.class);
assertThat(context).hasBean("customSpanProcessor");
assertThat(context).hasSingleBean(SpanProcessor.class);
});
}
@Test
void shouldNotSupplyBeansIfSdkIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("io.opentelemetry.sdk")).run((context) -> {
assertThat(context).doesNotHaveBean(OpenTelemetry.class);
assertThat(context).doesNotHaveBean(SdkTracerProvider.class);
assertThat(context).doesNotHaveBean(ContextPropagators.class);
assertThat(context).doesNotHaveBean(Sampler.class);
assertThat(context).doesNotHaveBean(SpanProcessor.class);
});
}
private static class CustomBeans {
@Bean
OpenTelemetry customOpenTelemetry() {
return Mockito.mock(OpenTelemetry.class);
}
@Bean
SdkTracerProvider customSdkTracerProvider() {
return SdkTracerProvider.builder().build();
}
@Bean
ContextPropagators customContextPropagators() {
return Mockito.mock(ContextPropagators.class);
}
@Bean
Sampler customSampler() {
return Mockito.mock(Sampler.class);
}
@Bean
SpanProcessor customSpanProcessor() {
return Mockito.mock(SpanProcessor.class);
}
}
}

@ -1,90 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Tracer;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryConfigurations.TracerConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link TracerConfiguration}.
*
* @author Moritz Halbritter
*/
class OpenTelemetryConfigurationsTracerConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(TracerConfiguration.class));
@Test
void shouldSupplyBeans() {
this.contextRunner.withUserConfiguration(OpenTelemetryConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(Tracer.class));
}
@Test
void shouldNotSupplyBeansIfApiIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("io.opentelemetry.api"))
.run((context) -> assertThat(context).doesNotHaveBean(Tracer.class));
}
@Test
void shouldNotSupplyTracerIfOpenTelemetryIsMissing() {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(Tracer.class));
}
@Test
void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(OpenTelemetryConfiguration.class, CustomConfiguration.class)
.run((context) -> {
assertThat(context).hasBean("customTracer");
assertThat(context).hasSingleBean(Tracer.class);
});
}
@Configuration(proxyBeanMethods = false)
private static class OpenTelemetryConfiguration {
@Bean
OpenTelemetry tracer() {
return Mockito.mock(OpenTelemetry.class);
}
}
@Configuration(proxyBeanMethods = false)
private static class CustomConfiguration {
@Bean
Tracer customTracer() {
return Mockito.mock(Tracer.class);
}
}
}

@ -1,101 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.wavefront;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link MeterRegistrySpanMetrics}.
*
* @author Moritz Halbritter
*/
class MeterRegistrySpanMetricsTests {
private SimpleMeterRegistry meterRegistry;
private MeterRegistrySpanMetrics sut;
@BeforeEach
void setUp() {
this.meterRegistry = new SimpleMeterRegistry();
this.sut = new MeterRegistrySpanMetrics(this.meterRegistry);
}
@Test
void reportDroppedShouldIncreaseCounter() {
this.sut.reportDropped();
assertThat(getCounterValue("wavefront.reporter.spans.dropped")).isEqualTo(1);
this.sut.reportDropped();
assertThat(getCounterValue("wavefront.reporter.spans.dropped")).isEqualTo(2);
}
@Test
void reportReceivedShouldIncreaseCounter() {
this.sut.reportReceived();
assertThat(getCounterValue("wavefront.reporter.spans.received")).isEqualTo(1);
this.sut.reportReceived();
assertThat(getCounterValue("wavefront.reporter.spans.received")).isEqualTo(2);
}
@Test
void reportErrorsShouldIncreaseCounter() {
this.sut.reportErrors();
assertThat(getCounterValue("wavefront.reporter.errors")).isEqualTo(1);
this.sut.reportErrors();
assertThat(getCounterValue("wavefront.reporter.errors")).isEqualTo(2);
}
@Test
void registerQueueSizeShouldCreateGauge() {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(2);
this.sut.registerQueueSize(queue);
assertThat(getGaugeValue("wavefront.reporter.queue.size")).isEqualTo(0);
queue.offer(1);
assertThat(getGaugeValue("wavefront.reporter.queue.size")).isEqualTo(1);
}
@Test
void registerQueueRemainingCapacityShouldCreateGauge() {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(2);
this.sut.registerQueueRemainingCapacity(queue);
assertThat(getGaugeValue("wavefront.reporter.queue.remaining_capacity")).isEqualTo(2);
queue.offer(1);
assertThat(getGaugeValue("wavefront.reporter.queue.remaining_capacity")).isEqualTo(1);
}
private double getGaugeValue(String name) {
Gauge gauge = this.meterRegistry.find(name).gauge();
assertThat(gauge).withFailMessage("Gauge '%s' not found", name).isNotNull();
return gauge.value();
}
private double getCounterValue(String name) {
Counter counter = this.meterRegistry.find(name).counter();
assertThat(counter).withFailMessage("Counter '%s' not found", name).isNotNull();
return counter.count();
}
}

@ -1,192 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.wavefront;
import com.wavefront.sdk.common.WavefrontSender;
import com.wavefront.sdk.common.application.ApplicationTags;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import io.micrometer.tracing.reporter.wavefront.SpanMetrics;
import io.micrometer.tracing.reporter.wavefront.WavefrontBraveSpanHandler;
import io.micrometer.tracing.reporter.wavefront.WavefrontOtelSpanHandler;
import io.micrometer.tracing.reporter.wavefront.WavefrontSpanHandler;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link WavefrontTracingAutoConfiguration}.
*
* @author Moritz Halbritter
*/
class WavefrontTracingAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(WavefrontTracingAutoConfiguration.class));
@Test
void shouldSupplyBeans() {
this.contextRunner.withUserConfiguration(WavefrontSenderConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(ApplicationTags.class);
assertThat(context).hasSingleBean(WavefrontSpanHandler.class);
assertThat(context).hasSingleBean(SpanMetrics.class);
assertThat(context).hasSingleBean(WavefrontBraveSpanHandler.class);
assertThat(context).hasSingleBean(WavefrontOtelSpanHandler.class);
});
}
@Test
void shouldNotSupplyBeansIfWavefrontSenderIsMissing() {
this.contextRunner.run((context) -> {
assertThat(context).doesNotHaveBean(ApplicationTags.class);
assertThat(context).doesNotHaveBean(WavefrontSpanHandler.class);
assertThat(context).doesNotHaveBean(SpanMetrics.class);
assertThat(context).doesNotHaveBean(WavefrontBraveSpanHandler.class);
assertThat(context).doesNotHaveBean(WavefrontOtelSpanHandler.class);
});
}
@Test
void shouldNotSupplyBeansIfMicrometerReporterWavefrontIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("io.micrometer.tracing.reporter.wavefront"))
.withUserConfiguration(WavefrontSenderConfiguration.class).run((context) -> {
assertThat(context).doesNotHaveBean(WavefrontSpanHandler.class);
assertThat(context).doesNotHaveBean(SpanMetrics.class);
assertThat(context).doesNotHaveBean(WavefrontBraveSpanHandler.class);
assertThat(context).doesNotHaveBean(WavefrontOtelSpanHandler.class);
});
}
@Test
void shouldSupplyMeterRegistrySpanMetricsIfMeterRegistryIsAvailable() {
this.contextRunner.withUserConfiguration(WavefrontSenderConfiguration.class, MeterRegistryConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(SpanMetrics.class);
assertThat(context).hasSingleBean(MeterRegistrySpanMetrics.class);
});
}
@Test
void shouldNotSupplyWavefrontBraveSpanHandlerIfBraveIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("brave"))
.withUserConfiguration(WavefrontSenderConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean(WavefrontBraveSpanHandler.class));
}
@Test
void shouldNotSupplyWavefrontOtelSpanHandlerIfOtelIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("io.opentelemetry.sdk.trace"))
.withUserConfiguration(WavefrontSenderConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean(WavefrontOtelSpanHandler.class));
}
@Test
void shouldHaveADefaultApplicationName() {
this.contextRunner.withUserConfiguration(WavefrontSenderConfiguration.class).run((context) -> {
ApplicationTags applicationTags = context.getBean(ApplicationTags.class);
assertThat(applicationTags.getApplication()).isEqualTo("application");
});
}
@Test
void shouldHonorConfigProperties() {
this.contextRunner.withUserConfiguration(WavefrontSenderConfiguration.class)
.withPropertyValues("spring.application.name=super-application",
"management.wavefront.tracing.service-name=super-service")
.run((context) -> {
ApplicationTags applicationTags = context.getBean(ApplicationTags.class);
assertThat(applicationTags.getApplication()).isEqualTo("super-application");
assertThat(applicationTags.getService()).isEqualTo("super-service");
});
}
@Test
void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(WavefrontSenderConfiguration.class, CustomConfiguration.class)
.run((context) -> {
assertThat(context).hasBean("customApplicationTags");
assertThat(context).hasSingleBean(ApplicationTags.class);
assertThat(context).hasBean("customWavefrontSpanHandler");
assertThat(context).hasSingleBean(WavefrontSpanHandler.class);
assertThat(context).hasBean("customSpanMetrics");
assertThat(context).hasSingleBean(SpanMetrics.class);
assertThat(context).hasBean("customWavefrontBraveSpanHandler");
assertThat(context).hasSingleBean(WavefrontBraveSpanHandler.class);
assertThat(context).hasBean("customWavefrontOtelSpanHandler");
assertThat(context).hasSingleBean(WavefrontOtelSpanHandler.class);
});
}
@Configuration(proxyBeanMethods = false)
private static class CustomConfiguration {
@Bean
ApplicationTags customApplicationTags() {
return Mockito.mock(ApplicationTags.class);
}
@Bean
WavefrontSpanHandler customWavefrontSpanHandler() {
return Mockito.mock(WavefrontSpanHandler.class);
}
@Bean
SpanMetrics customSpanMetrics() {
return Mockito.mock(SpanMetrics.class);
}
@Bean
WavefrontBraveSpanHandler customWavefrontBraveSpanHandler() {
return Mockito.mock(WavefrontBraveSpanHandler.class);
}
@Bean
WavefrontOtelSpanHandler customWavefrontOtelSpanHandler() {
return Mockito.mock(WavefrontOtelSpanHandler.class);
}
}
@Configuration(proxyBeanMethods = false)
private static class WavefrontSenderConfiguration {
@Bean
WavefrontSender wavefrontSender() {
return mock(WavefrontSender.class);
}
}
@Configuration(proxyBeanMethods = false)
private static class MeterRegistryConfiguration {
@Bean
MeterRegistry meterRegistry() {
return new SimpleMeterRegistry();
}
}
}

@ -1,62 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
import java.util.List;
import zipkin2.Call;
import zipkin2.Callback;
import zipkin2.codec.Encoding;
import zipkin2.reporter.Sender;
class NoopSender extends Sender {
@Override
public Encoding encoding() {
return Encoding.JSON;
}
@Override
public int messageMaxBytes() {
return 1024;
}
@Override
public int messageSizeInBytes(List<byte[]> encodedSpans) {
return encoding().listSizeInBytes(encodedSpans);
}
@Override
public Call<Void> sendSpans(List<byte[]> encodedSpans) {
return new Call.Base<>() {
@Override
public Call<Void> clone() {
return this;
}
@Override
protected Void doExecute() {
return null;
}
@Override
protected void doEnqueue(Callback<Void> callback) {
}
};
}
}

@ -1,71 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
import org.junit.jupiter.api.Test;
import zipkin2.Span;
import zipkin2.codec.BytesEncoder;
import zipkin2.codec.SpanBytesEncoder;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ZipkinAutoConfiguration}.
*
* @author Moritz Halbritter
*/
class ZipkinAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ZipkinAutoConfiguration.class));
@Test
void shouldSupplyBeans() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(BytesEncoder.class));
}
@Test
void shouldNotSupplyBeansIfZipkinReporterIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("zipkin2.reporter"))
.run((context) -> assertThat(context).doesNotHaveBean(BytesEncoder.class));
}
@Test
void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
assertThat(context).hasBean("customBytesEncoder");
assertThat(context).hasSingleBean(BytesEncoder.class);
});
}
@Configuration(proxyBeanMethods = false)
private static class CustomConfiguration {
@Bean
BytesEncoder<Span> customBytesEncoder() {
return SpanBytesEncoder.JSON_V2;
}
}
}

@ -1,92 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
import brave.handler.SpanHandler;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import zipkin2.Span;
import zipkin2.reporter.Reporter;
import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.BraveConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link BraveConfiguration}.
*
* @author Moritz Halbritter
*/
class ZipkinConfigurationsBraveConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(BraveConfiguration.class));
@Test
void shouldSupplyBeans() {
this.contextRunner.withUserConfiguration(ReporterConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(SpanHandler.class));
}
@Test
void shouldNotSupplySpanHandlerIfReporterIsMissing() {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(SpanHandler.class));
}
@Test
void shouldNotSupplyIfZipkinReporterBraveIsNotOnClasspath() {
this.contextRunner.withClassLoader(new FilteredClassLoader("zipkin2.reporter.brave"))
.withUserConfiguration(ReporterConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean(SpanHandler.class));
}
@Test
void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
assertThat(context).hasBean("customSpanHandler");
assertThat(context).hasSingleBean(SpanHandler.class);
});
}
@Configuration(proxyBeanMethods = false)
private static class ReporterConfiguration {
@Bean
@SuppressWarnings("unchecked")
Reporter<Span> reporter() {
return Mockito.mock(Reporter.class);
}
}
@Configuration(proxyBeanMethods = false)
private static class CustomConfiguration {
@Bean
SpanHandler customSpanHandler() {
return Mockito.mock(SpanHandler.class);
}
}
}

@ -1,104 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
import org.junit.jupiter.api.Test;
import zipkin2.Span;
import zipkin2.codec.BytesEncoder;
import zipkin2.codec.SpanBytesEncoder;
import zipkin2.reporter.Sender;
import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.OpenTelemetryConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link OpenTelemetryConfiguration}.
*
* @author Moritz Halbritter
*/
class ZipkinConfigurationsOpenTelemetryConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(BaseConfiguration.class, OpenTelemetryConfiguration.class));
@Test
void shouldSupplyBeans() {
this.contextRunner.withUserConfiguration(SenderConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(ZipkinSpanExporter.class));
}
@Test
void shouldNotSupplyZipkinSpanExporterIfSenderIsMissing() {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ZipkinSpanExporter.class));
}
@Test
void shouldNotSupplyZipkinSpanExporterIfNotOnClasspath() {
this.contextRunner.withClassLoader(new FilteredClassLoader("io.opentelemetry.exporter.zipkin"))
.withUserConfiguration(SenderConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean(ZipkinSpanExporter.class));
}
@Test
void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
assertThat(context).hasBean("customZipkinSpanExporter");
assertThat(context).hasSingleBean(ZipkinSpanExporter.class);
});
}
@Configuration(proxyBeanMethods = false)
private static class SenderConfiguration {
@Bean
Sender sender() {
return new NoopSender();
}
}
@Configuration(proxyBeanMethods = false)
private static class CustomConfiguration {
@Bean
ZipkinSpanExporter customZipkinSpanExporter() {
return ZipkinSpanExporter.builder().build();
}
}
@Configuration(proxyBeanMethods = false)
private static class BaseConfiguration {
@Bean
@ConditionalOnMissingBean
BytesEncoder<Span> spanBytesEncoder() {
return SpanBytesEncoder.JSON_V2;
}
}
}

@ -1,97 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import zipkin2.Span;
import zipkin2.codec.BytesEncoder;
import zipkin2.codec.SpanBytesEncoder;
import zipkin2.reporter.Reporter;
import zipkin2.reporter.Sender;
import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.ReporterConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ReporterConfiguration}.
*
* @author Moritz Halbritter
*/
class ZipkinConfigurationsReporterConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(BaseConfiguration.class, ReporterConfiguration.class));
@Test
void shouldSupplyBeans() {
this.contextRunner.withUserConfiguration(SenderConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(Reporter.class));
}
@Test
void shouldNotSupplyReporterIfSenderIsMissing() {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(Reporter.class));
}
@Test
void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
assertThat(context).hasBean("customReporter");
assertThat(context).hasSingleBean(Reporter.class);
});
}
@Configuration(proxyBeanMethods = false)
private static class SenderConfiguration {
@Bean
Sender sender() {
return new NoopSender();
}
}
@Configuration(proxyBeanMethods = false)
private static class CustomConfiguration {
@Bean
@SuppressWarnings("unchecked")
Reporter<Span> customReporter() {
return Mockito.mock(Reporter.class);
}
}
@Configuration(proxyBeanMethods = false)
private static class BaseConfiguration {
@Bean
@ConditionalOnMissingBean
BytesEncoder<Span> spanBytesEncoder() {
return SpanBytesEncoder.JSON_V2;
}
}
}

@ -1,100 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import zipkin2.reporter.Sender;
import zipkin2.reporter.urlconnection.URLConnectionSender;
import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.SenderConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link SenderConfiguration}.
*
* @author Moritz Halbritter
*/
class ZipkinConfigurationsSenderConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(SenderConfiguration.class));
@Test
void shouldSupplyBeans() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(Sender.class);
assertThat(context).hasSingleBean(URLConnectionSender.class);
assertThat(context).doesNotHaveBean(ZipkinRestTemplateSender.class);
});
}
@Test
void shouldUseRestTemplateSenderIfUrlConnectionSenderIsNotAvailable() {
this.contextRunner.withUserConfiguration(RestTemplateConfiguration.class)
.withClassLoader(new FilteredClassLoader("zipkin2.reporter.urlconnection")).run((context) -> {
assertThat(context).doesNotHaveBean(URLConnectionSender.class);
assertThat(context).hasSingleBean(Sender.class);
assertThat(context).hasSingleBean(ZipkinRestTemplateSender.class);
});
}
@Test
void shouldNotSupplyRestTemplateSenderIfNoBuilderIsAvailable() {
this.contextRunner.run((context) -> {
assertThat(context).doesNotHaveBean(ZipkinRestTemplateSender.class);
assertThat(context).hasSingleBean(Sender.class);
assertThat(context).hasSingleBean(URLConnectionSender.class);
});
}
@Test
void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
assertThat(context).hasBean("customSender");
assertThat(context).hasSingleBean(Sender.class);
});
}
@Configuration(proxyBeanMethods = false)
private static class RestTemplateConfiguration {
@Bean
RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder();
}
}
@Configuration(proxyBeanMethods = false)
private static class CustomConfiguration {
@Bean
Sender customSender() {
return Mockito.mock(Sender.class);
}
}
}

@ -1,122 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import zipkin2.CheckResult;
import zipkin2.reporter.ClosedSenderException;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.header;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
/**
* Tests for {@link ZipkinRestTemplateSender}.
*
* @author Moritz Halbritter
*/
class ZipkinRestTemplateSenderTests {
private static final String ZIPKIN_URL = "http://localhost:9411/api/v2/spans";
private MockRestServiceServer mockServer;
private ZipkinRestTemplateSender sut;
@BeforeEach
void setUp() {
RestTemplate restTemplate = new RestTemplate();
this.mockServer = MockRestServiceServer.createServer(restTemplate);
this.sut = new ZipkinRestTemplateSender(ZIPKIN_URL, restTemplate);
}
@AfterEach
void tearDown() {
this.mockServer.verify();
}
@Test
void checkShouldSendEmptySpanList() {
this.mockServer.expect(requestTo(ZIPKIN_URL)).andExpect(method(HttpMethod.POST))
.andExpect(content().string("[]")).andRespond(withStatus(HttpStatus.ACCEPTED));
assertThat(this.sut.check()).isEqualTo(CheckResult.OK);
}
@Test
void checkShouldNotRaiseException() {
this.mockServer.expect(requestTo(ZIPKIN_URL)).andExpect(method(HttpMethod.POST))
.andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR));
CheckResult result = this.sut.check();
assertThat(result.ok()).isFalse();
assertThat(result.error()).hasMessageContaining("500 Internal Server Error");
}
@Test
void sendSpansShouldSendSpansToZipkin() throws IOException {
this.mockServer.expect(requestTo(ZIPKIN_URL)).andExpect(method(HttpMethod.POST))
.andExpect(content().contentType("application/json")).andExpect(content().string("[span1,span2]"))
.andRespond(withStatus(HttpStatus.ACCEPTED));
this.sut.sendSpans(List.of(toByteArray("span1"), toByteArray("span2"))).execute();
}
@Test
void sendSpansShouldThrowOnHttpFailure() throws IOException {
this.mockServer.expect(requestTo(ZIPKIN_URL)).andExpect(method(HttpMethod.POST))
.andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR));
assertThatThrownBy(() -> this.sut.sendSpans(List.of()).execute())
.hasMessageContaining("500 Internal Server Error");
}
@Test
void sendSpansShouldThrowIfCloseWasCalled() throws IOException {
this.sut.close();
assertThatThrownBy(() -> this.sut.sendSpans(List.of())).isInstanceOf(ClosedSenderException.class);
}
@Test
void sendSpansShouldCompressData() throws IOException {
String uncompressed = "a".repeat(10000);
// This is gzip compressed 10000 times 'a'
byte[] compressed = Base64.getDecoder()
.decode("H4sIAAAAAAAA/+3BMQ0AAAwDIKFLj/k3UR8NcA8AAAAAAAAAAAADUsAZfeASJwAA");
this.mockServer.expect(requestTo(ZIPKIN_URL)).andExpect(method(HttpMethod.POST))
.andExpect(header("Content-Encoding", "gzip")).andExpect(content().contentType("application/json"))
.andExpect(content().bytes(compressed)).andRespond(withStatus(HttpStatus.ACCEPTED));
this.sut.sendSpans(List.of(toByteArray(uncompressed))).execute();
}
private byte[] toByteArray(String input) {
return input.getBytes(StandardCharsets.UTF_8);
}
}

@ -1,101 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.wavefront;
import java.util.concurrent.LinkedBlockingQueue;
import com.wavefront.sdk.common.WavefrontSender;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link WavefrontAutoConfiguration}.
*
* @author Moritz Halbritter
*/
class WavefrontAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(WavefrontAutoConfiguration.class));
@Test
void shouldNotFailIfWavefrontIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("com.wavefront"))
.run(((context) -> assertThat(context).doesNotHaveBean(WavefrontSender.class)));
}
@Test
void failsWithoutAnApiTokenWhenPublishingDirectly() {
this.contextRunner.run((context) -> assertThat(context).hasFailed());
}
@Test
void defaultWavefrontSenderSettingsAreConsistent() {
this.contextRunner.withPropertyValues("management.wavefront.api-token=abcde").run((context) -> {
WavefrontProperties properties = new WavefrontProperties();
WavefrontSender sender = context.getBean(WavefrontSender.class);
assertThat(sender)
.extracting("metricsBuffer", as(InstanceOfAssertFactories.type(LinkedBlockingQueue.class)))
.satisfies((queue) -> assertThat(queue.remainingCapacity() + queue.size())
.isEqualTo(properties.getSender().getMaxQueueSize()));
assertThat(sender).hasFieldOrPropertyWithValue("batchSize", properties.getSender().getBatchSize());
assertThat(sender).hasFieldOrPropertyWithValue("messageSizeBytes",
(int) properties.getSender().getMessageSize().toBytes());
});
}
@Test
void configureWavefrontSender() {
this.contextRunner.withPropertyValues("management.wavefront.api-token=abcde",
"management.wavefront.sender.batch-size=50", "management.wavefront.sender.max-queue-size=100",
"management.wavefront.sender.message-size=1KB").run((context) -> {
WavefrontSender sender = context.getBean(WavefrontSender.class);
assertThat(sender).hasFieldOrPropertyWithValue("batchSize", 50);
assertThat(sender)
.extracting("metricsBuffer", as(InstanceOfAssertFactories.type(LinkedBlockingQueue.class)))
.satisfies((queue) -> assertThat(queue.remainingCapacity() + queue.size()).isEqualTo(100));
assertThat(sender).hasFieldOrPropertyWithValue("messageSizeBytes", 1024);
});
}
@Test
void allowsWavefrontSenderToBeCustomized() {
this.contextRunner.withUserConfiguration(CustomSenderConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(WavefrontSender.class).hasBean("customSender"));
}
@Configuration(proxyBeanMethods = false)
static class CustomSenderConfiguration {
@Bean
WavefrontSender customSender() {
return mock(WavefrontSender.class);
}
}
}

@ -1,54 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.autoconfigure.wavefront;
import java.net.URI;
import org.junit.jupiter.api.Test;
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Tests for {@link WavefrontProperties}.
*
* @author Moritz Halbritter
*/
class WavefrontPropertiesTests {
@Test
void apiTokenIsOptionalWhenUsingProxy() {
WavefrontProperties sut = new WavefrontProperties();
sut.setUri(URI.create("proxy://localhost:2878"));
sut.setApiToken(null);
assertThat(sut.getApiTokenOrThrow()).isNull();
assertThat(sut.getEffectiveUri()).isEqualTo(URI.create("http://localhost:2878"));
}
@Test
void apiTokenIsMandatoryWhenNotUsingProxy() {
WavefrontProperties sut = new WavefrontProperties();
sut.setUri(URI.create("http://localhost:2878"));
sut.setApiToken(null);
assertThat(sut.getEffectiveUri()).isEqualTo(URI.create("http://localhost:2878"));
assertThatThrownBy(sut::getApiTokenOrThrow).isInstanceOf(InvalidConfigurationPropertyValueException.class)
.hasMessageContaining("management.wavefront.api-token");
}
}

@ -24,6 +24,7 @@ dependencies {
optional("io.lettuce:lettuce-core")
optional("io.micrometer:micrometer-observation")
optional("io.micrometer:micrometer-core")
optional("io.micrometer:micrometer-binders")
optional("io.micrometer:micrometer-tracing-api")
optional("io.micrometer:micrometer-registry-prometheus")
optional("io.prometheus:simpleclient_pushgateway") {

@ -26,8 +26,6 @@ import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.Status;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
@ -64,16 +62,12 @@ public class ElasticsearchReactiveHealthIndicator extends AbstractReactiveHealth
}
private Mono<Health> doHealthCheck(Health.Builder builder, ClientResponse response) {
HttpStatusCode httpStatusCode = response.statusCode();
HttpStatus httpStatus = HttpStatus.resolve(httpStatusCode.value());
if (httpStatusCode.is2xxSuccessful()) {
if (response.statusCode().is2xxSuccessful()) {
return response.bodyToMono(STRING_OBJECT_MAP).map((body) -> getHealth(builder, body));
}
builder.down();
builder.withDetail("statusCode", httpStatusCode.value());
if (httpStatus != null) {
builder.withDetail("reasonPhrase", httpStatus.getReasonPhrase());
}
builder.withDetail("statusCode", response.rawStatusCode());
builder.withDetail("reasonPhrase", response.statusCode().getReasonPhrase());
return response.releaseBody().thenReturn(builder.build());
}

@ -1,85 +0,0 @@
/*
* Copyright 2012-2022 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.
* 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 org.springframework.boot.actuate.elasticsearch;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.json.JsonParser;
import org.springframework.boot.json.JsonParserFactory;
import org.springframework.util.StreamUtils;
/**
* {@link HealthIndicator} for an Elasticsearch cluster using a {@link RestClient}.
*
* @author Artsiom Yudovin
* @author Brian Clozel
* @author Filip Hrisafov
* @since 2.7.0
*/
public class ElasticsearchRestClientHealthIndicator extends AbstractHealthIndicator {
private static final String RED_STATUS = "red";
private final RestClient client;
private final JsonParser jsonParser;
public ElasticsearchRestClientHealthIndicator(RestClient client) {
super("Elasticsearch health check failed");
this.client = client;
this.jsonParser = JsonParserFactory.getJsonParser();
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
Response response = this.client.performRequest(new Request("GET", "/_cluster/health/"));
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
builder.down();
builder.withDetail("statusCode", statusLine.getStatusCode());
builder.withDetail("reasonPhrase", statusLine.getReasonPhrase());
return;
}
try (InputStream inputStream = response.getEntity().getContent()) {
doHealthCheck(builder, StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8));
}
}
private void doHealthCheck(Health.Builder builder, String json) {
Map<String, Object> response = this.jsonParser.parseMap(json);
String status = (String) response.get("status");
if (RED_STATUS.equals(status)) {
builder.outOfService();
}
else {
builder.up();
}
builder.withDetails(response);
}
}

@ -16,9 +16,22 @@
package org.springframework.boot.actuate.elasticsearch;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.json.JsonParser;
import org.springframework.boot.json.JsonParserFactory;
import org.springframework.util.StreamUtils;
/**
* {@link HealthIndicator} for an Elasticsearch cluster using a {@link RestClient}.
@ -27,18 +40,51 @@ import org.springframework.boot.actuate.health.HealthIndicator;
* @author Brian Clozel
* @author Filip Hrisafov
* @since 2.1.1
* @deprecated since 2.7.0 for removal in 2.9.0 in favor of
* {@link ElasticsearchRestClientHealthIndicator}
*/
@Deprecated
public class ElasticsearchRestHealthIndicator extends ElasticsearchRestClientHealthIndicator {
public class ElasticsearchRestHealthIndicator extends AbstractHealthIndicator {
private static final String RED_STATUS = "red";
private final RestClient client;
private final JsonParser jsonParser;
@SuppressWarnings("deprecation")
public ElasticsearchRestHealthIndicator(org.elasticsearch.client.RestHighLevelClient client) {
this(client.getLowLevelClient());
}
public ElasticsearchRestHealthIndicator(RestClient client) {
super(client);
super("Elasticsearch health check failed");
this.client = client;
this.jsonParser = JsonParserFactory.getJsonParser();
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
Response response = this.client.performRequest(new Request("GET", "/_cluster/health/"));
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
builder.down();
builder.withDetail("statusCode", statusLine.getStatusCode());
builder.withDetail("reasonPhrase", statusLine.getReasonPhrase());
return;
}
try (InputStream inputStream = response.getEntity().getContent()) {
doHealthCheck(builder, StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8));
}
}
private void doHealthCheck(Health.Builder builder, String json) {
Map<String, Object> response = this.jsonParser.parseMap(json);
String status = (String) response.get("status");
if (RED_STATUS.equals(status)) {
builder.outOfService();
}
else {
builder.up();
}
builder.withDetails(response);
}
}

@ -16,9 +16,9 @@
package org.springframework.boot.actuate.metrics.cache;
import io.micrometer.binder.cache.CaffeineCacheMetrics;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.binder.cache.CaffeineCacheMetrics;
import org.springframework.cache.caffeine.CaffeineCache;

@ -19,9 +19,9 @@ package org.springframework.boot.actuate.metrics.cache;
import java.lang.reflect.Method;
import com.hazelcast.spring.cache.HazelcastCache;
import io.micrometer.binder.cache.HazelcastCacheMetrics;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.binder.cache.HazelcastCacheMetrics;
import org.springframework.util.ReflectionUtils;

@ -16,9 +16,9 @@
package org.springframework.boot.actuate.metrics.cache;
import io.micrometer.binder.cache.JCacheMetrics;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.binder.cache.JCacheMetrics;
import org.springframework.cache.jcache.JCacheCache;

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2021 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.
@ -123,7 +123,7 @@ public class StartupTimeMetricsListener implements SmartApplicationListener {
private Iterable<Tag> createTagsFrom(SpringApplication springApplication) {
Class<?> mainClass = springApplication.getMainApplicationClass();
return (mainClass != null) ? this.tags.and("main.application.class", mainClass.getName()) : this.tags;
return (mainClass != null) ? this.tags.and("main-application-class", mainClass.getName()) : this.tags;
}
}

@ -19,10 +19,10 @@ package org.springframework.boot.actuate.metrics.system;
import java.io.File;
import java.util.List;
import io.micrometer.binder.system.DiskSpaceMetrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.binder.system.DiskSpaceMetrics;
import org.springframework.util.Assert;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save