Remove APIs deprecated for removal in 3.5
Closes gh-43788
This commit is contained in:
parent
f301b2a123
commit
2f29a49a1d
|
|
@ -49,7 +49,6 @@ dependencies {
|
|||
optional("io.micrometer:micrometer-registry-new-relic")
|
||||
optional("io.micrometer:micrometer-registry-otlp")
|
||||
optional("io.micrometer:micrometer-registry-prometheus")
|
||||
optional("io.micrometer:micrometer-registry-prometheus-simpleclient")
|
||||
optional("io.micrometer:micrometer-registry-stackdriver") {
|
||||
exclude group: "commons-logging", module: "commons-logging"
|
||||
exclude group: "javax.annotation", module: "javax.annotation-api"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -78,10 +78,8 @@ public class PrometheusMetricsExportAutoConfiguration {
|
|||
@ConditionalOnAvailableEndpoint(PrometheusScrapeEndpoint.class)
|
||||
static class PrometheusScrapeEndpointConfiguration {
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({ PrometheusScrapeEndpoint.class,
|
||||
org.springframework.boot.actuate.metrics.export.prometheus.PrometheusSimpleclientScrapeEndpoint.class })
|
||||
@ConditionalOnMissingBean
|
||||
PrometheusScrapeEndpoint prometheusEndpoint(PrometheusRegistry prometheusRegistry,
|
||||
PrometheusConfig prometheusConfig) {
|
||||
return new PrometheusScrapeEndpoint(prometheusRegistry, prometheusConfig.prometheusProperties());
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -22,7 +22,6 @@ import java.util.Map;
|
|||
|
||||
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager.ShutdownOperation;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
|
||||
|
||||
/**
|
||||
* {@link ConfigurationProperties @ConfigurationProperties} for configuring metrics export
|
||||
|
|
@ -52,13 +51,6 @@ public class PrometheusProperties {
|
|||
*/
|
||||
private final Pushgateway pushgateway = new Pushgateway();
|
||||
|
||||
/**
|
||||
* Histogram type for backing DistributionSummary and Timer.
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0
|
||||
*/
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
private HistogramFlavor histogramFlavor = HistogramFlavor.Prometheus;
|
||||
|
||||
/**
|
||||
* Additional properties to pass to the Prometheus client.
|
||||
*/
|
||||
|
|
@ -77,17 +69,6 @@ public class PrometheusProperties {
|
|||
this.descriptions = descriptions;
|
||||
}
|
||||
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
@DeprecatedConfigurationProperty(since = "3.3.0",
|
||||
reason = "No longer supported. Works only when using the Prometheus simpleclient.")
|
||||
public HistogramFlavor getHistogramFlavor() {
|
||||
return this.histogramFlavor;
|
||||
}
|
||||
|
||||
public void setHistogramFlavor(HistogramFlavor histogramFlavor) {
|
||||
this.histogramFlavor = histogramFlavor;
|
||||
}
|
||||
|
||||
public Duration getStep() {
|
||||
return this.step;
|
||||
}
|
||||
|
|
@ -223,16 +204,4 @@ public class PrometheusProperties {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Prometheus Histogram flavor.
|
||||
*
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0
|
||||
*/
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
public enum HistogramFlavor {
|
||||
|
||||
Prometheus, VictoriaMetrics
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,162 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.prometheus;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.prometheus.client.CollectorRegistry;
|
||||
import io.prometheus.client.exemplars.DefaultExemplarSampler;
|
||||
import io.prometheus.client.exemplars.ExemplarSampler;
|
||||
import io.prometheus.client.exemplars.tracer.common.SpanContextSupplier;
|
||||
import io.prometheus.client.exporter.BasicAuthHttpConnectionFactory;
|
||||
import io.prometheus.client.exporter.PushGateway;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
|
||||
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.metrics.export.prometheus.PrometheusPushGatewayManager;
|
||||
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager.ShutdownOperation;
|
||||
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusScrapeEndpoint;
|
||||
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusSimpleclientScrapeEndpoint;
|
||||
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.ConditionalOnBooleanProperty;
|
||||
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;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Prometheus
|
||||
* with the Prometheus simpleclient.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author David J. M. Karlsen
|
||||
* @author Jonatan Ivanov
|
||||
* @since 2.0.0
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0 in favor of
|
||||
* {@link PrometheusMetricsExportAutoConfiguration}
|
||||
*/
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
@AutoConfiguration(
|
||||
before = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },
|
||||
after = { MetricsAutoConfiguration.class, PrometheusMetricsExportAutoConfiguration.class })
|
||||
@ConditionalOnBean(Clock.class)
|
||||
@ConditionalOnClass(io.micrometer.prometheus.PrometheusMeterRegistry.class)
|
||||
@ConditionalOnEnabledMetricsExport("prometheus")
|
||||
@EnableConfigurationProperties(PrometheusProperties.class)
|
||||
public class PrometheusSimpleclientMetricsExportAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
io.micrometer.prometheus.PrometheusConfig simpleclientPrometheusConfig(PrometheusProperties prometheusProperties) {
|
||||
return new PrometheusSimpleclientPropertiesConfigAdapter(prometheusProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
io.micrometer.prometheus.PrometheusMeterRegistry simpleclientPrometheusMeterRegistry(
|
||||
io.micrometer.prometheus.PrometheusConfig prometheusConfig, CollectorRegistry collectorRegistry,
|
||||
Clock clock, ObjectProvider<ExemplarSampler> exemplarSamplerProvider) {
|
||||
return new io.micrometer.prometheus.PrometheusMeterRegistry(prometheusConfig, collectorRegistry, clock,
|
||||
exemplarSamplerProvider.getIfAvailable());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
CollectorRegistry collectorRegistry() {
|
||||
return new CollectorRegistry(true);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ExemplarSampler.class)
|
||||
@ConditionalOnBean(SpanContextSupplier.class)
|
||||
DefaultExemplarSampler exemplarSampler(SpanContextSupplier spanContextSupplier) {
|
||||
return new DefaultExemplarSampler(spanContextSupplier);
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnAvailableEndpoint(PrometheusSimpleclientScrapeEndpoint.class)
|
||||
static class PrometheusScrapeEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({ PrometheusSimpleclientScrapeEndpoint.class, PrometheusScrapeEndpoint.class })
|
||||
PrometheusSimpleclientScrapeEndpoint prometheusEndpoint(CollectorRegistry collectorRegistry) {
|
||||
return new PrometheusSimpleclientScrapeEndpoint(collectorRegistry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for <a href="https://github.com/prometheus/pushgateway">Prometheus
|
||||
* Pushgateway</a>.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(PushGateway.class)
|
||||
@ConditionalOnBooleanProperty("management.prometheus.metrics.export.pushgateway.enabled")
|
||||
static class PrometheusPushGatewayConfiguration {
|
||||
|
||||
/**
|
||||
* The fallback job name. We use 'spring' since there's a history of Prometheus
|
||||
* spring integration defaulting to that name from when Prometheus integration
|
||||
* didn't exist in Spring itself.
|
||||
*/
|
||||
private static final String FALLBACK_JOB = "spring";
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
PrometheusPushGatewayManager prometheusPushGatewayManager(CollectorRegistry collectorRegistry,
|
||||
PrometheusProperties prometheusProperties, Environment environment) throws MalformedURLException {
|
||||
PrometheusProperties.Pushgateway properties = prometheusProperties.getPushgateway();
|
||||
Duration pushRate = properties.getPushRate();
|
||||
String job = getJob(properties, environment);
|
||||
Map<String, String> groupingKey = properties.getGroupingKey();
|
||||
ShutdownOperation shutdownOperation = properties.getShutdownOperation();
|
||||
PushGateway pushGateway = initializePushGateway(properties.getBaseUrl());
|
||||
if (StringUtils.hasText(properties.getUsername())) {
|
||||
pushGateway.setConnectionFactory(
|
||||
new BasicAuthHttpConnectionFactory(properties.getUsername(), properties.getPassword()));
|
||||
}
|
||||
return new PrometheusPushGatewayManager(pushGateway, collectorRegistry, pushRate, job, groupingKey,
|
||||
shutdownOperation);
|
||||
}
|
||||
|
||||
private PushGateway initializePushGateway(String url) throws MalformedURLException {
|
||||
return new PushGateway(new URL(url));
|
||||
}
|
||||
|
||||
private String getJob(PrometheusProperties.Pushgateway properties, Environment environment) {
|
||||
String job = properties.getJob();
|
||||
job = (job != null) ? job : environment.getProperty("spring.application.name");
|
||||
return (job != null) ? job : FALLBACK_JOB;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.prometheus;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PropertiesConfigAdapter;
|
||||
|
||||
/**
|
||||
* Adapter to convert {@link PrometheusProperties} to a
|
||||
* {@link io.micrometer.prometheus.PrometheusConfig}.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
class PrometheusSimpleclientPropertiesConfigAdapter extends PropertiesConfigAdapter<PrometheusProperties>
|
||||
implements io.micrometer.prometheus.PrometheusConfig {
|
||||
|
||||
PrometheusSimpleclientPropertiesConfigAdapter(PrometheusProperties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prefix() {
|
||||
return "management.prometheus.metrics.export";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean descriptions() {
|
||||
return get(PrometheusProperties::isDescriptions, io.micrometer.prometheus.PrometheusConfig.super::descriptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public io.micrometer.prometheus.HistogramFlavor histogramFlavor() {
|
||||
return get(PrometheusSimpleclientPropertiesConfigAdapter::mapToMicrometerHistogramFlavor,
|
||||
io.micrometer.prometheus.PrometheusConfig.super::histogramFlavor);
|
||||
}
|
||||
|
||||
static io.micrometer.prometheus.HistogramFlavor mapToMicrometerHistogramFlavor(PrometheusProperties properties) {
|
||||
return switch (properties.getHistogramFlavor()) {
|
||||
case Prometheus -> io.micrometer.prometheus.HistogramFlavor.Prometheus;
|
||||
case VictoriaMetrics -> io.micrometer.prometheus.HistogramFlavor.VictoriaMetrics;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration step() {
|
||||
return get(PrometheusProperties::getStep, io.micrometer.prometheus.PrometheusConfig.super::step);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.prometheus;
|
||||
|
||||
import io.micrometer.tracing.Span;
|
||||
import io.micrometer.tracing.Tracer;
|
||||
import io.prometheus.client.exemplars.tracer.common.SpanContextSupplier;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusSimpleclientMetricsExportAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration;
|
||||
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;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Prometheus Exemplars with
|
||||
* Micrometer Tracing.
|
||||
*
|
||||
* @author Jonatan Ivanov
|
||||
* @since 3.0.0
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
@Deprecated(forRemoval = true, since = "3.3.0")
|
||||
@AutoConfiguration(before = PrometheusSimpleclientMetricsExportAutoConfiguration.class,
|
||||
after = MicrometerTracingAutoConfiguration.class)
|
||||
@ConditionalOnBean(Tracer.class)
|
||||
@ConditionalOnClass({ Tracer.class, SpanContextSupplier.class })
|
||||
public class PrometheusSimpleclientExemplarsAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SpanContextSupplier spanContextSupplier(ObjectProvider<Tracer> tracerProvider) {
|
||||
return new LazyTracingSpanContextSupplier(tracerProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Since the MeterRegistry can depend on the {@link Tracer} (Exemplars) and the
|
||||
* {@link Tracer} can depend on the MeterRegistry (recording metrics), this
|
||||
* {@link SpanContextSupplier} breaks the cycle by lazily loading the {@link Tracer}.
|
||||
*/
|
||||
static class LazyTracingSpanContextSupplier implements SpanContextSupplier {
|
||||
|
||||
private final SingletonSupplier<Tracer> tracer;
|
||||
|
||||
LazyTracingSpanContextSupplier(ObjectProvider<Tracer> tracerProvider) {
|
||||
this.tracer = SingletonSupplier.of(tracerProvider::getObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTraceId() {
|
||||
Span currentSpan = currentSpan();
|
||||
return (currentSpan != null) ? currentSpan.context().traceId() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSpanId() {
|
||||
Span currentSpan = currentSpan();
|
||||
return (currentSpan != null) ? currentSpan.context().spanId() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSampled() {
|
||||
Span currentSpan = currentSpan();
|
||||
if (currentSpan == null) {
|
||||
return false;
|
||||
}
|
||||
Boolean sampled = currentSpan.context().sampled();
|
||||
return sampled != null && sampled;
|
||||
}
|
||||
|
||||
private Span currentSpan() {
|
||||
return this.tracer.obtain().currentSpan();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -40,12 +40,9 @@ 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.web.client.RestTemplateBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* Configurations for Zipkin. Those are imported by {@link ZipkinAutoConfiguration}.
|
||||
|
|
@ -57,8 +54,7 @@ import org.springframework.web.reactive.function.client.WebClient;
|
|||
class ZipkinConfigurations {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import({ HttpClientSenderConfiguration.class, WebClientSenderConfiguration.class,
|
||||
RestTemplateSenderConfiguration.class, UrlConnectionSenderConfiguration.class })
|
||||
@Import({ HttpClientSenderConfiguration.class, UrlConnectionSenderConfiguration.class })
|
||||
static class SenderConfiguration {
|
||||
|
||||
}
|
||||
|
|
@ -86,68 +82,6 @@ class ZipkinConfigurations {
|
|||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(WebClient.class)
|
||||
@EnableConfigurationProperties(ZipkinProperties.class)
|
||||
static class WebClientSenderConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(BytesMessageSender.class)
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
ZipkinWebClientSender webClientSender(ZipkinProperties properties, Encoding encoding,
|
||||
ObjectProvider<ZipkinWebClientBuilderCustomizer> customizers,
|
||||
ObjectProvider<ZipkinConnectionDetails> connectionDetailsProvider,
|
||||
ObjectProvider<HttpEndpointSupplier.Factory> endpointSupplierFactoryProvider) {
|
||||
ZipkinConnectionDetails connectionDetails = connectionDetailsProvider
|
||||
.getIfAvailable(() -> new PropertiesZipkinConnectionDetails(properties));
|
||||
HttpEndpointSupplier.Factory endpointSupplierFactory = endpointSupplierFactoryProvider
|
||||
.getIfAvailable(HttpEndpointSuppliers::constantFactory);
|
||||
WebClient.Builder builder = WebClient.builder();
|
||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return new ZipkinWebClientSender(encoding, endpointSupplierFactory, connectionDetails.getSpanEndpoint(),
|
||||
builder.build(), properties.getConnectTimeout().plus(properties.getReadTimeout()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(RestTemplate.class)
|
||||
@EnableConfigurationProperties(ZipkinProperties.class)
|
||||
static class RestTemplateSenderConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(BytesMessageSender.class)
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
ZipkinRestTemplateSender restTemplateSender(ZipkinProperties properties, Encoding encoding,
|
||||
ObjectProvider<ZipkinRestTemplateBuilderCustomizer> customizers,
|
||||
ObjectProvider<ZipkinConnectionDetails> connectionDetailsProvider,
|
||||
ObjectProvider<HttpEndpointSupplier.Factory> endpointSupplierFactoryProvider) {
|
||||
ZipkinConnectionDetails connectionDetails = connectionDetailsProvider
|
||||
.getIfAvailable(() -> new PropertiesZipkinConnectionDetails(properties));
|
||||
HttpEndpointSupplier.Factory endpointSupplierFactory = endpointSupplierFactoryProvider
|
||||
.getIfAvailable(HttpEndpointSuppliers::constantFactory);
|
||||
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder()
|
||||
.setConnectTimeout(properties.getConnectTimeout())
|
||||
.setReadTimeout(properties.getReadTimeout());
|
||||
restTemplateBuilder = applyCustomizers(restTemplateBuilder, customizers);
|
||||
return new ZipkinRestTemplateSender(encoding, endpointSupplierFactory, connectionDetails.getSpanEndpoint(),
|
||||
restTemplateBuilder.build());
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
private RestTemplateBuilder applyCustomizers(RestTemplateBuilder restTemplateBuilder,
|
||||
ObjectProvider<ZipkinRestTemplateBuilderCustomizer> customizers) {
|
||||
Iterable<ZipkinRestTemplateBuilderCustomizer> orderedCustomizers = () -> customizers.orderedStream()
|
||||
.iterator();
|
||||
RestTemplateBuilder currentBuilder = restTemplateBuilder;
|
||||
for (ZipkinRestTemplateBuilderCustomizer customizer : orderedCustomizers) {
|
||||
currentBuilder = customizer.customize(currentBuilder);
|
||||
}
|
||||
return currentBuilder;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(URLConnectionSender.class)
|
||||
@EnableConfigurationProperties(ZipkinProperties.class)
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.springframework.boot.web.client.RestTemplateBuilder;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the
|
||||
* {@link RestTemplateBuilder} used to send spans to Zipkin.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 3.0.0
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0 in favor of
|
||||
* {@link ZipkinHttpClientBuilderCustomizer}
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
public interface ZipkinRestTemplateBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the rest template builder.
|
||||
* @param restTemplateBuilder the {@code RestTemplateBuilder} to customize
|
||||
* @return the customized {@code RestTemplateBuilder}
|
||||
*/
|
||||
RestTemplateBuilder customize(RestTemplateBuilder restTemplateBuilder);
|
||||
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.net.URI;
|
||||
|
||||
import zipkin2.reporter.Encoding;
|
||||
import zipkin2.reporter.HttpEndpointSupplier.Factory;
|
||||
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* An {@link HttpSender} which uses {@link RestTemplate} for HTTP communication.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Stefan Bratanov
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0 in favor of {@link ZipkinHttpClientSender}
|
||||
*/
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
class ZipkinRestTemplateSender extends HttpSender {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
ZipkinRestTemplateSender(Encoding encoding, Factory endpointSupplierFactory, String endpoint,
|
||||
RestTemplate restTemplate) {
|
||||
super(encoding, endpointSupplierFactory, endpoint);
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
void postSpans(URI endpoint, MultiValueMap<String, String> headers, byte[] body) {
|
||||
HttpEntity<byte[]> request = new HttpEntity<>(body, headers);
|
||||
this.restTemplate.exchange(endpoint, HttpMethod.POST, request, Void.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.client.WebClient.Builder;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the
|
||||
* {@link Builder} used to send spans to Zipkin.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 3.0.0
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0 in favor of
|
||||
* {@link ZipkinHttpClientBuilderCustomizer}
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
public interface ZipkinWebClientBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the web client builder.
|
||||
* @param webClientBuilder the {@code WebClient.Builder} to customize
|
||||
*/
|
||||
void customize(WebClient.Builder webClientBuilder);
|
||||
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.net.URI;
|
||||
import java.time.Duration;
|
||||
|
||||
import zipkin2.reporter.Encoding;
|
||||
import zipkin2.reporter.HttpEndpointSupplier.Factory;
|
||||
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* An {@link HttpSender} which uses {@link WebClient} for HTTP communication.
|
||||
*
|
||||
* @author Stefan Bratanov
|
||||
* @author Moritz Halbritter
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0 in favor of {@link ZipkinHttpClientSender}
|
||||
*/
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
class ZipkinWebClientSender extends HttpSender {
|
||||
|
||||
private final WebClient webClient;
|
||||
|
||||
private final Duration timeout;
|
||||
|
||||
ZipkinWebClientSender(Encoding encoding, Factory endpointSupplierFactory, String endpoint, WebClient webClient,
|
||||
Duration timeout) {
|
||||
super(encoding, endpointSupplierFactory, endpoint);
|
||||
this.webClient = webClient;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
void postSpans(URI endpoint, MultiValueMap<String, String> headers, byte[] body) {
|
||||
this.webClient.post()
|
||||
.uri(endpoint)
|
||||
.headers((h) -> h.addAll(headers))
|
||||
.bodyValue(body)
|
||||
.retrieve()
|
||||
.toBodilessEntity()
|
||||
.timeout(this.timeout)
|
||||
.block();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -65,7 +65,6 @@ org.springframework.boot.actuate.autoconfigure.metrics.export.kairos.KairosMetri
|
|||
org.springframework.boot.actuate.autoconfigure.metrics.export.newrelic.NewRelicMetricsExportAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusMetricsExportAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusSimpleclientMetricsExportAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.export.signalfx.SignalFxMetricsExportAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.export.stackdriver.StackdriverMetricsExportAutoConfiguration
|
||||
|
|
@ -112,7 +111,6 @@ org.springframework.boot.actuate.autoconfigure.tracing.NoopTracerAutoConfigurati
|
|||
org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryTracingAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpTracingAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.tracing.prometheus.PrometheusExemplarsAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.tracing.prometheus.PrometheusSimpleclientExemplarsAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.tracing.wavefront.WavefrontTracingAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontAutoConfiguration
|
||||
|
|
|
|||
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.endpoint.web.documentation;
|
||||
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
|
||||
import io.prometheus.client.CollectorRegistry;
|
||||
import io.prometheus.client.exporter.common.TextFormat;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
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.assertThat;
|
||||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.queryParameters;
|
||||
|
||||
/**
|
||||
* Tests for generating documentation describing the
|
||||
* {@link org.springframework.boot.actuate.metrics.export.prometheus.PrometheusSimpleclientScrapeEndpoint}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Johnny Lim
|
||||
*/
|
||||
class PrometheusSimpleclientScrapeEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
void prometheus() {
|
||||
assertThat(this.mvc.get().uri("/actuator/prometheus")).hasStatusOk()
|
||||
.apply(document("prometheus-simpleclient/all"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void prometheusOpenmetrics() {
|
||||
assertThat(this.mvc.get().uri("/actuator/prometheus").accept(TextFormat.CONTENT_TYPE_OPENMETRICS_100))
|
||||
.satisfies((result) -> {
|
||||
assertThat(result).hasStatusOk()
|
||||
.headers()
|
||||
.hasValue("Content-Type", "application/openmetrics-text;version=1.0.0;charset=utf-8");
|
||||
assertThat(result).apply(document("prometheus-simpleclient/openmetrics"));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void filteredPrometheus() {
|
||||
assertThat(this.mvc.get()
|
||||
.uri("/actuator/prometheus")
|
||||
.param("includedNames", "jvm_memory_used_bytes,jvm_memory_committed_bytes"))
|
||||
.hasStatusOk()
|
||||
.apply(document("prometheus-simpleclient/names",
|
||||
queryParameters(parameterWithName("includedNames")
|
||||
.description("Restricts the samples to those that match the names. Optional.")
|
||||
.optional())));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseDocumentationConfiguration.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings({ "removal", "deprecation" })
|
||||
org.springframework.boot.actuate.metrics.export.prometheus.PrometheusSimpleclientScrapeEndpoint endpoint() {
|
||||
CollectorRegistry collectorRegistry = new CollectorRegistry(true);
|
||||
io.micrometer.prometheus.PrometheusMeterRegistry meterRegistry = new io.micrometer.prometheus.PrometheusMeterRegistry(
|
||||
(key) -> null, collectorRegistry, Clock.SYSTEM);
|
||||
new JvmMemoryMetrics().bindTo(meterRegistry);
|
||||
return new org.springframework.boot.actuate.metrics.export.prometheus.PrometheusSimpleclientScrapeEndpoint(
|
||||
collectorRegistry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,411 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.prometheus;
|
||||
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.prometheusmetrics.PrometheusConfig;
|
||||
import io.prometheus.client.CollectorRegistry;
|
||||
import io.prometheus.client.exemplars.ExemplarSampler;
|
||||
import io.prometheus.client.exemplars.tracer.common.SpanContextSupplier;
|
||||
import io.prometheus.client.exporter.BasicAuthHttpConnectionFactory;
|
||||
import io.prometheus.client.exporter.DefaultHttpConnectionFactory;
|
||||
import io.prometheus.client.exporter.HttpConnectionFactory;
|
||||
import io.prometheus.client.exporter.PushGateway;
|
||||
import io.prometheus.metrics.model.registry.PrometheusRegistry;
|
||||
import org.assertj.core.api.ThrowingConsumer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.DualPrometheusMetricsExportAutoConfigurationTests.CustomSecondEndpointConfiguration.SecondPrometheusScrapeEndpoint;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
|
||||
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager;
|
||||
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusScrapeEndpoint;
|
||||
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusSimpleclientScrapeEndpoint;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link PrometheusSimpleclientMetricsExportAutoConfiguration} and
|
||||
* {@link PrometheusMetricsExportAutoConfiguration} with both Prometheus clients on the
|
||||
* classpath.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
* @author Jonatan Ivanov
|
||||
*/
|
||||
@SuppressWarnings({ "removal", "deprecation" })
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
class DualPrometheusMetricsExportAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(PrometheusSimpleclientMetricsExportAutoConfiguration.class,
|
||||
PrometheusMetricsExportAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void backsOffWithoutAClock() {
|
||||
this.contextRunner.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class)
|
||||
.doesNotHaveBean(io.micrometer.prometheus.PrometheusMeterRegistry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfiguresItsConfigPrometheusRegistryAndMeterRegistry() {
|
||||
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(io.micrometer.prometheus.PrometheusMeterRegistry.class)
|
||||
.hasSingleBean(CollectorRegistry.class)
|
||||
.hasSingleBean(io.micrometer.prometheus.PrometheusConfig.class)
|
||||
.hasSingleBean(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class)
|
||||
.hasSingleBean(PrometheusRegistry.class)
|
||||
.hasSingleBean(io.micrometer.prometheusmetrics.PrometheusConfig.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {
|
||||
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
|
||||
.withPropertyValues("management.defaults.metrics.export.enabled=false")
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(io.micrometer.prometheus.PrometheusMeterRegistry.class)
|
||||
.doesNotHaveBean(CollectorRegistry.class)
|
||||
.doesNotHaveBean(io.micrometer.prometheus.PrometheusConfig.class)
|
||||
.doesNotHaveBean(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class)
|
||||
.doesNotHaveBean(PrometheusRegistry.class)
|
||||
.doesNotHaveBean(io.micrometer.prometheusmetrics.PrometheusConfig.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {
|
||||
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
|
||||
.withPropertyValues("management.prometheus.metrics.export.enabled=false")
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(io.micrometer.prometheus.PrometheusMeterRegistry.class)
|
||||
.doesNotHaveBean(CollectorRegistry.class)
|
||||
.doesNotHaveBean(io.micrometer.prometheus.PrometheusConfig.class)
|
||||
.doesNotHaveBean(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class)
|
||||
.doesNotHaveBean(PrometheusRegistry.class)
|
||||
.doesNotHaveBean(io.micrometer.prometheusmetrics.PrometheusConfig.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsCustomConfigToBeUsed() {
|
||||
this.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(io.micrometer.prometheus.PrometheusMeterRegistry.class)
|
||||
.hasSingleBean(CollectorRegistry.class)
|
||||
.hasSingleBean(io.micrometer.prometheus.PrometheusConfig.class)
|
||||
.hasBean("customConfig")
|
||||
.hasSingleBean(PrometheusRegistry.class)
|
||||
.hasSingleBean(io.micrometer.prometheusmetrics.PrometheusConfig.class)
|
||||
.hasBean("otherCustomConfig"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsCustomRegistryToBeUsed() {
|
||||
this.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(io.micrometer.prometheus.PrometheusMeterRegistry.class)
|
||||
.hasBean("customRegistry")
|
||||
.hasSingleBean(CollectorRegistry.class)
|
||||
.hasSingleBean(io.micrometer.prometheus.PrometheusConfig.class)
|
||||
.hasSingleBean(PrometheusRegistry.class)
|
||||
.hasSingleBean(io.micrometer.prometheusmetrics.PrometheusConfig.class)
|
||||
.hasBean("otherCustomRegistry"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsCustomCollectorRegistryToBeUsed() {
|
||||
this.contextRunner.withUserConfiguration(CustomCollectorRegistryConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(io.micrometer.prometheus.PrometheusMeterRegistry.class)
|
||||
.hasBean("customCollectorRegistry")
|
||||
.hasSingleBean(CollectorRegistry.class)
|
||||
.hasSingleBean(io.micrometer.prometheus.PrometheusConfig.class)
|
||||
.hasBean("customPrometheusRegistry")
|
||||
.hasSingleBean(PrometheusRegistry.class)
|
||||
.hasSingleBean(io.micrometer.prometheusmetrics.PrometheusConfig.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfiguresExemplarSamplerIfSpanContextSupplierIsPresent() {
|
||||
this.contextRunner.withUserConfiguration(ExemplarsConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(SpanContextSupplier.class)
|
||||
.hasSingleBean(ExemplarSampler.class)
|
||||
.hasSingleBean(io.micrometer.prometheus.PrometheusMeterRegistry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsCustomExemplarSamplerToBeUsed() {
|
||||
this.contextRunner.withUserConfiguration(ExemplarsConfiguration.class)
|
||||
.withBean("customExemplarSampler", ExemplarSampler.class, () -> mock(ExemplarSampler.class))
|
||||
.run((context) -> assertThat(context).hasSingleBean(ExemplarSampler.class)
|
||||
.getBean(ExemplarSampler.class)
|
||||
.isSameAs(context.getBean("customExemplarSampler")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void exemplarSamplerIsNotAutoConfiguredIfSpanContextSupplierIsMissing() {
|
||||
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(SpanContextSupplier.class)
|
||||
.doesNotHaveBean(ExemplarSampler.class)
|
||||
.hasSingleBean(io.micrometer.prometheus.PrometheusMeterRegistry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void addsScrapeEndpointToManagementContext() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.withPropertyValues("management.endpoints.web.exposure.include=prometheus")
|
||||
.run((context) -> assertThat(context).hasSingleBean(PrometheusScrapeEndpoint.class)
|
||||
.doesNotHaveBean(PrometheusSimpleclientScrapeEndpoint.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void scrapeEndpointNotAddedToManagementContextWhenNotExposed() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(PrometheusSimpleclientScrapeEndpoint.class)
|
||||
.doesNotHaveBean(PrometheusScrapeEndpoint.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void scrapeEndpointCanBeDisabled() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withPropertyValues("management.endpoints.web.exposure.include=prometheus",
|
||||
"management.endpoint.prometheus.enabled=false")
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(PrometheusSimpleclientScrapeEndpoint.class)
|
||||
.doesNotHaveBean(PrometheusScrapeEndpoint.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsCustomScrapeEndpointToBeUsed() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withUserConfiguration(CustomEndpointConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasBean("customEndpoint")
|
||||
.hasSingleBean(PrometheusSimpleclientScrapeEndpoint.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsCustomSecondScrapeEndpointToBeUsed() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withUserConfiguration(CustomSecondEndpointConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasBean("customSecondEndpoint")
|
||||
.hasSingleBean(PrometheusSimpleclientScrapeEndpoint.class)
|
||||
.hasSingleBean(SecondPrometheusScrapeEndpoint.class)
|
||||
.hasSingleBean(PrometheusScrapeEndpoint.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void pushGatewayIsNotConfiguredWhenEnabledFlagIsNotSet() {
|
||||
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(PrometheusPushGatewayManager.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withPushGatewayEnabled(CapturedOutput output) {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withPropertyValues("management.prometheus.metrics.export.pushgateway.enabled=true")
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(output).doesNotContain("Invalid PushGateway base url");
|
||||
hasGatewayURL(context, "http://localhost:9091/metrics/");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void withPushGatewayNoBasicAuth() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withPropertyValues("management.prometheus.metrics.export.pushgateway.enabled=true")
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.run(hasHttpConnectionFactory((httpConnectionFactory) -> assertThat(httpConnectionFactory)
|
||||
.isInstanceOf(DefaultHttpConnectionFactory.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withCustomPushGatewayURL() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withPropertyValues("management.prometheus.metrics.export.pushgateway.enabled=true",
|
||||
"management.prometheus.metrics.export.pushgateway.base-url=https://example.com:8080")
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> hasGatewayURL(context, "https://example.com:8080/metrics/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withPushGatewayBasicAuth() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withPropertyValues("management.prometheus.metrics.export.pushgateway.enabled=true",
|
||||
"management.prometheus.metrics.export.pushgateway.username=admin",
|
||||
"management.prometheus.metrics.export.pushgateway.password=secret")
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.run(hasHttpConnectionFactory((httpConnectionFactory) -> assertThat(httpConnectionFactory)
|
||||
.isInstanceOf(BasicAuthHttpConnectionFactory.class)));
|
||||
}
|
||||
|
||||
private void hasGatewayURL(AssertableApplicationContext context, String url) {
|
||||
assertThat(getPushGateway(context)).hasFieldOrPropertyWithValue("gatewayBaseURL", url);
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableApplicationContext> hasHttpConnectionFactory(
|
||||
ThrowingConsumer<HttpConnectionFactory> httpConnectionFactory) {
|
||||
return (context) -> {
|
||||
PushGateway pushGateway = getPushGateway(context);
|
||||
httpConnectionFactory
|
||||
.accept((HttpConnectionFactory) ReflectionTestUtils.getField(pushGateway, "connectionFactory"));
|
||||
};
|
||||
}
|
||||
|
||||
private PushGateway getPushGateway(AssertableApplicationContext context) {
|
||||
assertThat(context).hasSingleBean(PrometheusPushGatewayManager.class);
|
||||
PrometheusPushGatewayManager gatewayManager = context.getBean(PrometheusPushGatewayManager.class);
|
||||
return (PushGateway) ReflectionTestUtils.getField(gatewayManager, "pushGateway");
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class BaseConfiguration {
|
||||
|
||||
@Bean
|
||||
Clock clock() {
|
||||
return Clock.SYSTEM;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class CustomConfigConfiguration {
|
||||
|
||||
@Bean
|
||||
io.micrometer.prometheus.PrometheusConfig customConfig() {
|
||||
return (key) -> null;
|
||||
}
|
||||
|
||||
@Bean
|
||||
io.micrometer.prometheusmetrics.PrometheusConfig otherCustomConfig() {
|
||||
return (key) -> null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class CustomRegistryConfiguration {
|
||||
|
||||
@Bean
|
||||
io.micrometer.prometheus.PrometheusMeterRegistry customRegistry(
|
||||
io.micrometer.prometheus.PrometheusConfig config, CollectorRegistry collectorRegistry, Clock clock) {
|
||||
return new io.micrometer.prometheus.PrometheusMeterRegistry(config, collectorRegistry, clock);
|
||||
}
|
||||
|
||||
@Bean
|
||||
io.micrometer.prometheusmetrics.PrometheusMeterRegistry otherCustomRegistry(
|
||||
io.micrometer.prometheusmetrics.PrometheusConfig config, PrometheusRegistry prometheusRegistry,
|
||||
Clock clock) {
|
||||
return new io.micrometer.prometheusmetrics.PrometheusMeterRegistry(config, prometheusRegistry, clock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class CustomCollectorRegistryConfiguration {
|
||||
|
||||
@Bean
|
||||
CollectorRegistry customCollectorRegistry() {
|
||||
return new CollectorRegistry();
|
||||
}
|
||||
|
||||
@Bean
|
||||
PrometheusRegistry customPrometheusRegistry() {
|
||||
return new PrometheusRegistry();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class CustomEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
PrometheusSimpleclientScrapeEndpoint customEndpoint(CollectorRegistry collectorRegistry) {
|
||||
return new PrometheusSimpleclientScrapeEndpoint(collectorRegistry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class CustomSecondEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
PrometheusScrapeEndpoint prometheusScrapeEndpoint(PrometheusRegistry prometheusRegistry,
|
||||
PrometheusConfig prometheusConfig) {
|
||||
return new PrometheusScrapeEndpoint(prometheusRegistry, prometheusConfig.prometheusProperties());
|
||||
}
|
||||
|
||||
@Bean
|
||||
SecondPrometheusScrapeEndpoint customSecondEndpoint(CollectorRegistry collectorRegistry) {
|
||||
return new SecondPrometheusScrapeEndpoint(collectorRegistry);
|
||||
}
|
||||
|
||||
@WebEndpoint(id = "prometheussc")
|
||||
static class SecondPrometheusScrapeEndpoint extends PrometheusSimpleclientScrapeEndpoint {
|
||||
|
||||
SecondPrometheusScrapeEndpoint(CollectorRegistry collectorRegistry) {
|
||||
super(collectorRegistry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class ExemplarsConfiguration {
|
||||
|
||||
@Bean
|
||||
SpanContextSupplier spanContextSupplier() {
|
||||
return new SpanContextSupplier() {
|
||||
|
||||
@Override
|
||||
public String getTraceId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSpanId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSampled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -35,15 +35,4 @@ class PrometheusPropertiesTests {
|
|||
assertThat(properties.getStep()).isEqualTo(config.step());
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
void defaultValuesAreConsistentWithSimpleclient() {
|
||||
PrometheusProperties properties = new PrometheusProperties();
|
||||
io.micrometer.prometheus.PrometheusConfig config = io.micrometer.prometheus.PrometheusConfig.DEFAULT;
|
||||
assertThat(properties.isDescriptions()).isEqualTo(config.descriptions());
|
||||
assertThat(PrometheusSimpleclientPropertiesConfigAdapter.mapToMicrometerHistogramFlavor(properties))
|
||||
.isEqualTo(config.histogramFlavor());
|
||||
assertThat(properties.getStep()).isEqualTo(config.step());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,330 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.prometheus;
|
||||
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.prometheus.client.CollectorRegistry;
|
||||
import io.prometheus.client.exemplars.ExemplarSampler;
|
||||
import io.prometheus.client.exemplars.tracer.common.SpanContextSupplier;
|
||||
import io.prometheus.client.exporter.BasicAuthHttpConnectionFactory;
|
||||
import io.prometheus.client.exporter.DefaultHttpConnectionFactory;
|
||||
import io.prometheus.client.exporter.HttpConnectionFactory;
|
||||
import io.prometheus.client.exporter.PushGateway;
|
||||
import org.assertj.core.api.ThrowingConsumer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager;
|
||||
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusSimpleclientScrapeEndpoint;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link PrometheusSimpleclientMetricsExportAutoConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
* @author Jonatan Ivanov
|
||||
*/
|
||||
@SuppressWarnings({ "removal", "deprecation" })
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
class PrometheusSimpleclientMetricsExportAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withClassLoader(new FilteredClassLoader("io.micrometer.prometheusmetrics.", "io.prometheus.metrics"))
|
||||
.withConfiguration(AutoConfigurations.of(PrometheusSimpleclientMetricsExportAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void backsOffWithoutAClock() {
|
||||
this.contextRunner.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(io.micrometer.prometheus.PrometheusMeterRegistry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfiguresItsConfigCollectorRegistryAndMeterRegistry() {
|
||||
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(io.micrometer.prometheus.PrometheusMeterRegistry.class)
|
||||
.hasSingleBean(CollectorRegistry.class)
|
||||
.hasSingleBean(io.micrometer.prometheus.PrometheusConfig.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {
|
||||
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
|
||||
.withPropertyValues("management.defaults.metrics.export.enabled=false")
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(io.micrometer.prometheus.PrometheusMeterRegistry.class)
|
||||
.doesNotHaveBean(CollectorRegistry.class)
|
||||
.doesNotHaveBean(io.micrometer.prometheus.PrometheusConfig.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {
|
||||
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
|
||||
.withPropertyValues("management.prometheus.metrics.export.enabled=false")
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(io.micrometer.prometheus.PrometheusMeterRegistry.class)
|
||||
.doesNotHaveBean(CollectorRegistry.class)
|
||||
.doesNotHaveBean(io.micrometer.prometheus.PrometheusConfig.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsCustomConfigToBeUsed() {
|
||||
this.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(io.micrometer.prometheus.PrometheusMeterRegistry.class)
|
||||
.hasSingleBean(CollectorRegistry.class)
|
||||
.hasSingleBean(io.micrometer.prometheus.PrometheusConfig.class)
|
||||
.hasBean("customConfig"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsCustomRegistryToBeUsed() {
|
||||
this.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(io.micrometer.prometheus.PrometheusMeterRegistry.class)
|
||||
.hasBean("customRegistry")
|
||||
.hasSingleBean(CollectorRegistry.class)
|
||||
.hasSingleBean(io.micrometer.prometheus.PrometheusConfig.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsCustomCollectorRegistryToBeUsed() {
|
||||
this.contextRunner.withUserConfiguration(CustomCollectorRegistryConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(io.micrometer.prometheus.PrometheusMeterRegistry.class)
|
||||
.hasBean("customCollectorRegistry")
|
||||
.hasSingleBean(CollectorRegistry.class)
|
||||
.hasSingleBean(io.micrometer.prometheus.PrometheusConfig.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfiguresExemplarSamplerIfSpanContextSupplierIsPresent() {
|
||||
this.contextRunner.withUserConfiguration(ExemplarsConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(SpanContextSupplier.class)
|
||||
.hasSingleBean(ExemplarSampler.class)
|
||||
.hasSingleBean(io.micrometer.prometheus.PrometheusMeterRegistry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsCustomExemplarSamplerToBeUsed() {
|
||||
this.contextRunner.withUserConfiguration(ExemplarsConfiguration.class)
|
||||
.withBean("customExemplarSampler", ExemplarSampler.class, () -> mock(ExemplarSampler.class))
|
||||
.run((context) -> assertThat(context).hasSingleBean(ExemplarSampler.class)
|
||||
.getBean(ExemplarSampler.class)
|
||||
.isSameAs(context.getBean("customExemplarSampler")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void exemplarSamplerIsNotAutoConfiguredIfSpanContextSupplierIsMissing() {
|
||||
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(SpanContextSupplier.class)
|
||||
.doesNotHaveBean(ExemplarSampler.class)
|
||||
.hasSingleBean(io.micrometer.prometheus.PrometheusMeterRegistry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void addsScrapeEndpointToManagementContext() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.withPropertyValues("management.endpoints.web.exposure.include=prometheus")
|
||||
.run((context) -> assertThat(context).hasSingleBean(PrometheusSimpleclientScrapeEndpoint.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void scrapeEndpointNotAddedToManagementContextWhenNotExposed() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(PrometheusSimpleclientScrapeEndpoint.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void scrapeEndpointCanBeDisabled() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withPropertyValues("management.endpoints.web.exposure.include=prometheus",
|
||||
"management.endpoint.prometheus.enabled=false")
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(PrometheusSimpleclientScrapeEndpoint.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsCustomScrapeEndpointToBeUsed() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withUserConfiguration(CustomEndpointConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasBean("customEndpoint")
|
||||
.hasSingleBean(PrometheusSimpleclientScrapeEndpoint.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void pushGatewayIsNotConfiguredWhenEnabledFlagIsNotSet() {
|
||||
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(PrometheusPushGatewayManager.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withPushGatewayEnabled(CapturedOutput output) {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withPropertyValues("management.prometheus.metrics.export.pushgateway.enabled=true")
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(output).doesNotContain("Invalid PushGateway base url");
|
||||
hasGatewayURL(context, "http://localhost:9091/metrics/");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void withPushGatewayNoBasicAuth() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withPropertyValues("management.prometheus.metrics.export.pushgateway.enabled=true")
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.run(hasHttpConnectionFactory((httpConnectionFactory) -> assertThat(httpConnectionFactory)
|
||||
.isInstanceOf(DefaultHttpConnectionFactory.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withCustomPushGatewayURL() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withPropertyValues("management.prometheus.metrics.export.pushgateway.enabled=true",
|
||||
"management.prometheus.metrics.export.pushgateway.base-url=https://example.com:8080")
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.run((context) -> hasGatewayURL(context, "https://example.com:8080/metrics/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withPushGatewayBasicAuth() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
|
||||
.withPropertyValues("management.prometheus.metrics.export.pushgateway.enabled=true",
|
||||
"management.prometheus.metrics.export.pushgateway.username=admin",
|
||||
"management.prometheus.metrics.export.pushgateway.password=secret")
|
||||
.withUserConfiguration(BaseConfiguration.class)
|
||||
.run(hasHttpConnectionFactory((httpConnectionFactory) -> assertThat(httpConnectionFactory)
|
||||
.isInstanceOf(BasicAuthHttpConnectionFactory.class)));
|
||||
}
|
||||
|
||||
private void hasGatewayURL(AssertableApplicationContext context, String url) {
|
||||
assertThat(getPushGateway(context)).hasFieldOrPropertyWithValue("gatewayBaseURL", url);
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableApplicationContext> hasHttpConnectionFactory(
|
||||
ThrowingConsumer<HttpConnectionFactory> httpConnectionFactory) {
|
||||
return (context) -> {
|
||||
PushGateway pushGateway = getPushGateway(context);
|
||||
httpConnectionFactory
|
||||
.accept((HttpConnectionFactory) ReflectionTestUtils.getField(pushGateway, "connectionFactory"));
|
||||
};
|
||||
}
|
||||
|
||||
private PushGateway getPushGateway(AssertableApplicationContext context) {
|
||||
assertThat(context).hasSingleBean(PrometheusPushGatewayManager.class);
|
||||
PrometheusPushGatewayManager gatewayManager = context.getBean(PrometheusPushGatewayManager.class);
|
||||
return (PushGateway) ReflectionTestUtils.getField(gatewayManager, "pushGateway");
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class BaseConfiguration {
|
||||
|
||||
@Bean
|
||||
Clock clock() {
|
||||
return Clock.SYSTEM;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class CustomConfigConfiguration {
|
||||
|
||||
@Bean
|
||||
io.micrometer.prometheus.PrometheusConfig customConfig() {
|
||||
return (key) -> null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class CustomRegistryConfiguration {
|
||||
|
||||
@Bean
|
||||
io.micrometer.prometheus.PrometheusMeterRegistry customRegistry(
|
||||
io.micrometer.prometheus.PrometheusConfig config, CollectorRegistry collectorRegistry, Clock clock) {
|
||||
return new io.micrometer.prometheus.PrometheusMeterRegistry(config, collectorRegistry, clock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class CustomCollectorRegistryConfiguration {
|
||||
|
||||
@Bean
|
||||
CollectorRegistry customCollectorRegistry() {
|
||||
return new CollectorRegistry();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class CustomEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
PrometheusSimpleclientScrapeEndpoint customEndpoint(CollectorRegistry collectorRegistry) {
|
||||
return new PrometheusSimpleclientScrapeEndpoint(collectorRegistry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class ExemplarsConfiguration {
|
||||
|
||||
@Bean
|
||||
SpanContextSupplier spanContextSupplier() {
|
||||
return new SpanContextSupplier() {
|
||||
|
||||
@Override
|
||||
public String getTraceId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSpanId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSampled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.prometheus;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusProperties.HistogramFlavor;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.AbstractPropertiesConfigAdapterTests;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link PrometheusSimpleclientPropertiesConfigAdapter}.
|
||||
*
|
||||
* @author Mirko Sobeck
|
||||
*/
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
class PrometheusSimpleclientPropertiesConfigAdapterTests extends
|
||||
AbstractPropertiesConfigAdapterTests<PrometheusProperties, PrometheusSimpleclientPropertiesConfigAdapter> {
|
||||
|
||||
PrometheusSimpleclientPropertiesConfigAdapterTests() {
|
||||
super(PrometheusSimpleclientPropertiesConfigAdapter.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenPropertiesDescriptionsIsSetAdapterDescriptionsReturnsIt() {
|
||||
PrometheusProperties properties = new PrometheusProperties();
|
||||
properties.setDescriptions(false);
|
||||
assertThat(new PrometheusSimpleclientPropertiesConfigAdapter(properties).descriptions()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenPropertiesHistogramFlavorIsSetAdapterHistogramFlavorReturnsIt() {
|
||||
PrometheusProperties properties = new PrometheusProperties();
|
||||
properties.setHistogramFlavor(HistogramFlavor.VictoriaMetrics);
|
||||
assertThat(new PrometheusSimpleclientPropertiesConfigAdapter(properties).histogramFlavor())
|
||||
.isEqualTo(io.micrometer.prometheus.HistogramFlavor.VictoriaMetrics);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenPropertiesStepIsSetAdapterStepReturnsIt() {
|
||||
PrometheusProperties properties = new PrometheusProperties();
|
||||
properties.setStep(Duration.ofSeconds(30));
|
||||
assertThat(new PrometheusSimpleclientPropertiesConfigAdapter(properties).step())
|
||||
.isEqualTo(Duration.ofSeconds(30));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.prometheus;
|
||||
|
||||
import io.micrometer.tracing.Span;
|
||||
import io.micrometer.tracing.TraceContext;
|
||||
import io.micrometer.tracing.Tracer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for
|
||||
* {@link org.springframework.boot.actuate.autoconfigure.tracing.prometheus.PrometheusSimpleclientExemplarsAutoConfiguration.LazyTracingSpanContextSupplier}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
class LazyTracingSpanContextSupplierTests {
|
||||
|
||||
private final Tracer tracer = mock(Tracer.class);
|
||||
|
||||
private final ObjectProvider<Tracer> objectProvider = new ObjectProvider<>() {
|
||||
|
||||
@Override
|
||||
public Tracer getObject() throws BeansException {
|
||||
return LazyTracingSpanContextSupplierTests.this.tracer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracer getObject(Object... args) throws BeansException {
|
||||
return LazyTracingSpanContextSupplierTests.this.tracer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracer getIfAvailable() throws BeansException {
|
||||
return LazyTracingSpanContextSupplierTests.this.tracer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracer getIfUnique() throws BeansException {
|
||||
return LazyTracingSpanContextSupplierTests.this.tracer;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private final org.springframework.boot.actuate.autoconfigure.tracing.prometheus.PrometheusSimpleclientExemplarsAutoConfiguration.LazyTracingSpanContextSupplier spanContextSupplier = new org.springframework.boot.actuate.autoconfigure.tracing.prometheus.PrometheusSimpleclientExemplarsAutoConfiguration.LazyTracingSpanContextSupplier(
|
||||
this.objectProvider);
|
||||
|
||||
@Test
|
||||
void whenCurrentSpanIsNullThenSpanIdIsNull() {
|
||||
assertThat(this.spanContextSupplier.getSpanId()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCurrentSpanIsNullThenTraceIdIsNull() {
|
||||
assertThat(this.spanContextSupplier.getTraceId()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCurrentSpanIsNullThenSampledIsFalse() {
|
||||
assertThat(this.spanContextSupplier.isSampled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCurrentSpanHasSpanIdThenSpanIdIsFromSpan() {
|
||||
Span span = mock(Span.class);
|
||||
given(this.tracer.currentSpan()).willReturn(span);
|
||||
TraceContext traceContext = mock(TraceContext.class);
|
||||
given(traceContext.spanId()).willReturn("span-id");
|
||||
given(span.context()).willReturn(traceContext);
|
||||
assertThat(this.spanContextSupplier.getSpanId()).isEqualTo("span-id");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCurrentSpanHasTraceIdThenTraceIdIsFromSpan() {
|
||||
Span span = mock(Span.class);
|
||||
given(this.tracer.currentSpan()).willReturn(span);
|
||||
TraceContext traceContext = mock(TraceContext.class);
|
||||
given(traceContext.traceId()).willReturn("trace-id");
|
||||
given(span.context()).willReturn(traceContext);
|
||||
assertThat(this.spanContextSupplier.getTraceId()).isEqualTo("trace-id");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCurrentSpanHasNoSpanIdThenSpanIdIsNull() {
|
||||
Span span = mock(Span.class);
|
||||
given(this.tracer.currentSpan()).willReturn(span);
|
||||
TraceContext traceContext = mock(TraceContext.class);
|
||||
given(span.context()).willReturn(traceContext);
|
||||
assertThat(this.spanContextSupplier.getSpanId()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCurrentSpanHasNoTraceIdThenTraceIdIsNull() {
|
||||
Span span = mock(Span.class);
|
||||
given(this.tracer.currentSpan()).willReturn(span);
|
||||
TraceContext traceContext = mock(TraceContext.class);
|
||||
given(span.context()).willReturn(traceContext);
|
||||
assertThat(this.spanContextSupplier.getTraceId()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCurrentSpanIsSampledThenSampledIsTrue() {
|
||||
Span span = mock(Span.class);
|
||||
given(this.tracer.currentSpan()).willReturn(span);
|
||||
TraceContext traceContext = mock(TraceContext.class);
|
||||
given(traceContext.sampled()).willReturn(true);
|
||||
given(span.context()).willReturn(traceContext);
|
||||
assertThat(this.spanContextSupplier.isSampled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCurrentSpanIsNotSampledThenSampledIsFalse() {
|
||||
Span span = mock(Span.class);
|
||||
given(this.tracer.currentSpan()).willReturn(span);
|
||||
TraceContext traceContext = mock(TraceContext.class);
|
||||
given(traceContext.sampled()).willReturn(false);
|
||||
given(span.context()).willReturn(traceContext);
|
||||
assertThat(this.spanContextSupplier.isSampled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCurrentSpanHasDeferredSamplingThenSampledIsFalse() {
|
||||
Span span = mock(Span.class);
|
||||
given(this.tracer.currentSpan()).willReturn(span);
|
||||
TraceContext traceContext = mock(TraceContext.class);
|
||||
given(traceContext.sampled()).willReturn(null);
|
||||
given(span.context()).willReturn(traceContext);
|
||||
assertThat(this.spanContextSupplier.isSampled()).isFalse();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.prometheus;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.prometheus.client.exemplars.tracer.common.SpanContextSupplier;
|
||||
import io.prometheus.client.exporter.common.TextFormat;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusSimpleclientMetricsExportAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
|
||||
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.tracing.BraveAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration;
|
||||
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 org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link PrometheusSimpleclientExemplarsAutoConfiguration}.
|
||||
*
|
||||
* @author Jonatan Ivanov
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
class PrometheusSimpleclientExemplarsAutoConfigurationTests {
|
||||
|
||||
private static final Pattern BUCKET_TRACE_INFO_PATTERN = Pattern.compile(
|
||||
"^test_observation_seconds_bucket\\{error=\"none\",le=\".+\"} 1.0 # \\{span_id=\"(\\p{XDigit}+)\",trace_id=\"(\\p{XDigit}+)\"} .+$");
|
||||
|
||||
private static final Pattern COUNTER_TRACE_INFO_PATTERN = Pattern.compile(
|
||||
"^test_observation_seconds_count\\{error=\"none\"} 1.0 # \\{span_id=\"(\\p{XDigit}+)\",trace_id=\"(\\p{XDigit}+)\"} .+$");
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withPropertyValues("management.tracing.sampling.probability=1.0",
|
||||
"management.metrics.distribution.percentiles-histogram.all=true")
|
||||
.with(MetricsRun.limitedTo())
|
||||
.withConfiguration(AutoConfigurations.of(PrometheusSimpleclientMetricsExportAutoConfiguration.class,
|
||||
PrometheusSimpleclientExemplarsAutoConfiguration.class, ObservationAutoConfiguration.class,
|
||||
BraveAutoConfiguration.class, MicrometerTracingAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void shouldNotSupplyBeansIfPrometheusSupportIsMissing() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader("io.prometheus.client.exemplars"))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(SpanContextSupplier.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotSupplyBeansIfMicrometerTracingIsMissing() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader("io.micrometer.tracing"))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(SpanContextSupplier.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupplyCustomBeans() {
|
||||
this.contextRunner.withUserConfiguration(CustomConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(SpanContextSupplier.class)
|
||||
.getBean(SpanContextSupplier.class)
|
||||
.isSameAs(CustomConfiguration.SUPPLIER));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
void prometheusOpenMetricsOutputShouldContainExemplars() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasSingleBean(SpanContextSupplier.class);
|
||||
ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);
|
||||
Observation.start("test.observation", observationRegistry).stop();
|
||||
io.micrometer.prometheus.PrometheusMeterRegistry prometheusMeterRegistry = context
|
||||
.getBean(io.micrometer.prometheus.PrometheusMeterRegistry.class);
|
||||
String openMetricsOutput = prometheusMeterRegistry.scrape(TextFormat.CONTENT_TYPE_OPENMETRICS_100);
|
||||
|
||||
assertThat(openMetricsOutput).contains("test_observation_seconds_bucket");
|
||||
assertThat(openMetricsOutput).containsOnlyOnce("test_observation_seconds_count");
|
||||
assertThat(StringUtils.countOccurrencesOf(openMetricsOutput, "span_id")).isEqualTo(2);
|
||||
assertThat(StringUtils.countOccurrencesOf(openMetricsOutput, "trace_id")).isEqualTo(2);
|
||||
|
||||
Optional<TraceInfo> bucketTraceInfo = openMetricsOutput.lines()
|
||||
.filter((line) -> line.contains("test_observation_seconds_bucket") && line.contains("span_id"))
|
||||
.map(BUCKET_TRACE_INFO_PATTERN::matcher)
|
||||
.flatMap(Matcher::results)
|
||||
.map((matchResult) -> new TraceInfo(matchResult.group(2), matchResult.group(1)))
|
||||
.findFirst();
|
||||
|
||||
Optional<TraceInfo> counterTraceInfo = openMetricsOutput.lines()
|
||||
.filter((line) -> line.contains("test_observation_seconds_count") && line.contains("span_id"))
|
||||
.map(COUNTER_TRACE_INFO_PATTERN::matcher)
|
||||
.flatMap(Matcher::results)
|
||||
.map((matchResult) -> new TraceInfo(matchResult.group(2), matchResult.group(1)))
|
||||
.findFirst();
|
||||
|
||||
assertThat(bucketTraceInfo).isNotEmpty().contains(counterTraceInfo.orElse(null));
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
private static final class CustomConfiguration {
|
||||
|
||||
static final SpanContextSupplier SUPPLIER = mock(SpanContextSupplier.class);
|
||||
|
||||
@Bean
|
||||
SpanContextSupplier customSpanContextSupplier() {
|
||||
return SUPPLIER;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private record TraceInfo(String traceId, String spanId) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,17 +16,9 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import okhttp3.mockwebserver.RecordedRequest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import zipkin2.reporter.BytesMessageSender;
|
||||
import zipkin2.reporter.HttpEndpointSupplier;
|
||||
import zipkin2.reporter.urlconnection.URLConnectionSender;
|
||||
|
|
@ -36,16 +28,10 @@ import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfi
|
|||
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.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
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;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
|
|
@ -60,19 +46,11 @@ class ZipkinConfigurationsSenderConfigurationTests {
|
|||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DefaultEncodingConfiguration.class, SenderConfiguration.class));
|
||||
|
||||
private final ReactiveWebApplicationContextRunner reactiveContextRunner = new ReactiveWebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DefaultEncodingConfiguration.class, SenderConfiguration.class));
|
||||
|
||||
private final WebApplicationContextRunner servletContextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DefaultEncodingConfiguration.class, SenderConfiguration.class));
|
||||
|
||||
@Test
|
||||
void shouldSupplyDefaultHttpClientSenderBeans() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasSingleBean(BytesMessageSender.class);
|
||||
assertThat(context).hasSingleBean(ZipkinHttpClientSender.class);
|
||||
assertThat(context).doesNotHaveBean(ZipkinRestTemplateSender.class);
|
||||
assertThat(context).doesNotHaveBean(ZipkinWebClientSenderTests.class);
|
||||
assertThat(context).doesNotHaveBean(URLConnectionSender.class);
|
||||
});
|
||||
}
|
||||
|
|
@ -80,7 +58,7 @@ class ZipkinConfigurationsSenderConfigurationTests {
|
|||
@Test
|
||||
void shouldUseUrlSenderIfHttpSenderIsNotAvailable() {
|
||||
this.contextRunner.withUserConfiguration(UrlConnectionSenderConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(HttpClient.class, WebClient.class, RestTemplate.class))
|
||||
.withClassLoader(new FilteredClassLoader(HttpClient.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(ZipkinHttpClientSender.class);
|
||||
assertThat(context).hasSingleBean(BytesMessageSender.class);
|
||||
|
|
@ -88,83 +66,6 @@ class ZipkinConfigurationsSenderConfigurationTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPreferWebClientSenderIfWebApplicationIsReactiveAndHttpClientSenderIsNotAvailable() {
|
||||
this.reactiveContextRunner.withUserConfiguration(RestTemplateConfiguration.class, WebClientConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(HttpClient.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(ZipkinHttpClientSender.class);
|
||||
assertThat(context).hasSingleBean(BytesMessageSender.class);
|
||||
assertThat(context).hasSingleBean(ZipkinWebClientSender.class);
|
||||
then(context.getBean(ZipkinWebClientBuilderCustomizer.class)).should()
|
||||
.customize(ArgumentMatchers.any());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPreferWebClientSenderIfWebApplicationIsServletAndHttpClientSenderIsNotAvailable() {
|
||||
this.servletContextRunner.withUserConfiguration(RestTemplateConfiguration.class, WebClientConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(HttpClient.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(ZipkinHttpClientSender.class);
|
||||
assertThat(context).hasSingleBean(BytesMessageSender.class);
|
||||
assertThat(context).hasSingleBean(ZipkinWebClientSender.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPreferWebClientInNonWebApplicationAndHttpClientSenderIsNotAvailable() {
|
||||
this.contextRunner.withUserConfiguration(RestTemplateConfiguration.class, WebClientConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(HttpClient.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(ZipkinHttpClientSender.class);
|
||||
assertThat(context).hasSingleBean(BytesMessageSender.class);
|
||||
assertThat(context).hasSingleBean(ZipkinWebClientSender.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void willUseRestTemplateInNonWebApplicationIfSenderAndWebClientAreNotAvailable() {
|
||||
this.contextRunner.withUserConfiguration(RestTemplateConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(HttpClient.class, WebClient.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(HttpClient.class);
|
||||
assertThat(context).hasSingleBean(BytesMessageSender.class);
|
||||
assertThat(context).hasSingleBean(ZipkinRestTemplateSender.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void willUseRestTemplateInServletWebApplicationIfHttpClientSenderAndWebClientNotAvailable() {
|
||||
this.servletContextRunner.withUserConfiguration(RestTemplateConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(HttpClient.class, WebClient.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(ZipkinHttpClientSender.class);
|
||||
assertThat(context).hasSingleBean(BytesMessageSender.class);
|
||||
assertThat(context).hasSingleBean(ZipkinRestTemplateSender.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void willUseRestTemplateInReactiveWebApplicationIfHttpClientSenderAndWebClientAreNotAvailable() {
|
||||
this.reactiveContextRunner.withUserConfiguration(RestTemplateConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(HttpClient.class, WebClient.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(ZipkinHttpClientSender.class);
|
||||
assertThat(context).hasSingleBean(BytesMessageSender.class);
|
||||
assertThat(context).hasSingleBean(ZipkinRestTemplateSender.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotUseWebClientSenderIfNoBuilderIsAvailable() {
|
||||
this.reactiveContextRunner.run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(ZipkinWebClientSender.class);
|
||||
assertThat(context).hasSingleBean(BytesMessageSender.class);
|
||||
assertThat(context).hasSingleBean(ZipkinHttpClientSender.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBackOffOnCustomBeans() {
|
||||
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
|
||||
|
|
@ -173,74 +74,15 @@ class ZipkinConfigurationsSenderConfigurationTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldApplyZipkinRestTemplateBuilderCustomizers() throws IOException {
|
||||
try (MockWebServer mockWebServer = new MockWebServer()) {
|
||||
mockWebServer.enqueue(new MockResponse().setResponseCode(204));
|
||||
this.reactiveContextRunner
|
||||
.withPropertyValues("management.zipkin.tracing.endpoint=" + mockWebServer.url("/"))
|
||||
.withUserConfiguration(RestTemplateConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(HttpClient.class, WebClient.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(ZipkinRestTemplateSender.class);
|
||||
ZipkinRestTemplateSender sender = context.getBean(ZipkinRestTemplateSender.class);
|
||||
sender.send(List.of("spans".getBytes(StandardCharsets.UTF_8)));
|
||||
RecordedRequest recordedRequest = mockWebServer.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest).isNotNull();
|
||||
assertThat(recordedRequest.getHeaders().get("x-dummy")).isEqualTo("dummy");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUseCustomHttpEndpointSupplierFactory() {
|
||||
this.contextRunner.withUserConfiguration(CustomHttpEndpointSupplierFactoryConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(HttpClient.class, WebClient.class, RestTemplate.class))
|
||||
.withClassLoader(new FilteredClassLoader(HttpClient.class))
|
||||
.run((context) -> assertThat(context.getBean(URLConnectionSender.class))
|
||||
.extracting("delegate.endpointSupplier")
|
||||
.isInstanceOf(CustomHttpEndpointSupplier.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("resource")
|
||||
void shouldUseCustomHttpEndpointSupplierFactoryWhenReactive() {
|
||||
this.reactiveContextRunner.withUserConfiguration(WebClientConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(HttpClient.class))
|
||||
.withUserConfiguration(CustomHttpEndpointSupplierFactoryConfiguration.class)
|
||||
.run((context) -> assertThat(context.getBean(ZipkinWebClientSender.class)).extracting("endpointSupplier")
|
||||
.isInstanceOf(CustomHttpEndpointSupplier.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("resource")
|
||||
void shouldUseCustomHttpEndpointSupplierFactoryWhenRestTemplate() {
|
||||
this.contextRunner.withUserConfiguration(RestTemplateConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(HttpClient.class, WebClient.class))
|
||||
.withUserConfiguration(CustomHttpEndpointSupplierFactoryConfiguration.class)
|
||||
.run((context) -> assertThat(context.getBean(ZipkinRestTemplateSender.class)).extracting("endpointSupplier")
|
||||
.isInstanceOf(CustomHttpEndpointSupplier.class));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
private static final class RestTemplateConfiguration {
|
||||
|
||||
@Bean
|
||||
ZipkinRestTemplateBuilderCustomizer zipkinRestTemplateBuilderCustomizer() {
|
||||
return new DummyZipkinRestTemplateBuilderCustomizer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
private static final class WebClientConfiguration {
|
||||
|
||||
@Bean
|
||||
ZipkinWebClientBuilderCustomizer webClientBuilder() {
|
||||
return mock(ZipkinWebClientBuilderCustomizer.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
private static final class HttpClientConfiguration {
|
||||
|
||||
|
|
@ -261,15 +103,6 @@ class ZipkinConfigurationsSenderConfigurationTests {
|
|||
|
||||
}
|
||||
|
||||
private static final class DummyZipkinRestTemplateBuilderCustomizer implements ZipkinRestTemplateBuilderCustomizer {
|
||||
|
||||
@Override
|
||||
public RestTemplateBuilder customize(RestTemplateBuilder restTemplateBuilder) {
|
||||
return restTemplateBuilder.defaultHeader("x-dummy", "dummy");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
private static final class CustomHttpEndpointSupplierFactoryConfiguration {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import zipkin2.reporter.BytesMessageSender;
|
||||
import zipkin2.reporter.Encoding;
|
||||
import zipkin2.reporter.HttpEndpointSupplier;
|
||||
import zipkin2.reporter.HttpEndpointSuppliers;
|
||||
|
||||
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.assertThatException;
|
||||
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
|
||||
* @author Stefan Bratanov
|
||||
*/
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
class ZipkinRestTemplateSenderTests extends ZipkinHttpSenderTests {
|
||||
|
||||
private static final String ZIPKIN_URL = "http://localhost:9411/api/v2/spans";
|
||||
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
private MockRestServiceServer mockServer;
|
||||
|
||||
@Override
|
||||
BytesMessageSender createSender() {
|
||||
this.restTemplate = new RestTemplate();
|
||||
this.mockServer = MockRestServiceServer.createServer(this.restTemplate);
|
||||
return createSender(Encoding.JSON);
|
||||
}
|
||||
|
||||
BytesMessageSender createSender(Encoding encoding) {
|
||||
return createSender(HttpEndpointSuppliers.constantFactory(), encoding);
|
||||
}
|
||||
|
||||
BytesMessageSender createSender(HttpEndpointSupplier.Factory endpointSupplierFactory, Encoding encoding) {
|
||||
return new ZipkinRestTemplateSender(encoding, endpointSupplierFactory, ZIPKIN_URL, this.restTemplate);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@Override
|
||||
void afterEach() throws IOException {
|
||||
super.afterEach();
|
||||
this.mockServer.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendShouldSendSpansToZipkin() 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.sender.send(List.of(toByteArray("span1"), toByteArray("span2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendShouldSendSpansToZipkinInProto3() throws IOException {
|
||||
this.mockServer.expect(requestTo(ZIPKIN_URL))
|
||||
.andExpect(method(HttpMethod.POST))
|
||||
.andExpect(content().contentType("application/x-protobuf"))
|
||||
.andExpect(content().string("span1span2"))
|
||||
.andRespond(withStatus(HttpStatus.ACCEPTED));
|
||||
try (BytesMessageSender sender = createSender(Encoding.PROTO3)) {
|
||||
sender.send(List.of(toByteArray("span1"), toByteArray("span2")));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendUsesDynamicEndpoint() throws Exception {
|
||||
this.mockServer.expect(requestTo(ZIPKIN_URL + "/1")).andRespond(withStatus(HttpStatus.ACCEPTED));
|
||||
this.mockServer.expect(requestTo(ZIPKIN_URL + "/2")).andRespond(withStatus(HttpStatus.ACCEPTED));
|
||||
try (HttpEndpointSupplier httpEndpointSupplier = new TestHttpEndpointSupplier(ZIPKIN_URL)) {
|
||||
try (BytesMessageSender sender = createSender((endpoint) -> httpEndpointSupplier, Encoding.JSON)) {
|
||||
sender.send(Collections.emptyList());
|
||||
sender.send(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendShouldHandleHttpFailures() {
|
||||
this.mockServer.expect(requestTo(ZIPKIN_URL))
|
||||
.andExpect(method(HttpMethod.POST))
|
||||
.andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR));
|
||||
|
||||
assertThatException().isThrownBy(() -> this.sender.send(Collections.emptyList()))
|
||||
.withMessageContaining("500 Internal Server Error");
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendShouldCompressData() 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.sender.send(List.of(toByteArray(uncompressed)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,204 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.time.Duration;
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import okhttp3.mockwebserver.QueueDispatcher;
|
||||
import okhttp3.mockwebserver.RecordedRequest;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import zipkin2.reporter.BytesMessageSender;
|
||||
import zipkin2.reporter.Encoding;
|
||||
import zipkin2.reporter.HttpEndpointSupplier;
|
||||
import zipkin2.reporter.HttpEndpointSuppliers;
|
||||
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
|
||||
/**
|
||||
* Tests for {@link ZipkinWebClientSender}.
|
||||
*
|
||||
* @author Stefan Bratanov
|
||||
*/
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
class ZipkinWebClientSenderTests extends ZipkinHttpSenderTests {
|
||||
|
||||
private static final Duration TIMEOUT = Duration.ofSeconds(30);
|
||||
|
||||
private static ClearableDispatcher dispatcher;
|
||||
|
||||
private static MockWebServer mockBackEnd;
|
||||
|
||||
private static String ZIPKIN_URL;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws IOException {
|
||||
dispatcher = new ClearableDispatcher();
|
||||
mockBackEnd = new MockWebServer();
|
||||
mockBackEnd.setDispatcher(dispatcher);
|
||||
mockBackEnd.start();
|
||||
ZIPKIN_URL = mockBackEnd.url("/api/v2/spans").toString();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterAll() throws IOException {
|
||||
mockBackEnd.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
super.beforeEach();
|
||||
clearResponses();
|
||||
clearRequests();
|
||||
}
|
||||
|
||||
@Override
|
||||
BytesMessageSender createSender() {
|
||||
return createSender(Encoding.JSON, TIMEOUT);
|
||||
}
|
||||
|
||||
ZipkinWebClientSender createSender(Encoding encoding, Duration timeout) {
|
||||
return createSender(HttpEndpointSuppliers.constantFactory(), encoding, timeout);
|
||||
}
|
||||
|
||||
ZipkinWebClientSender createSender(HttpEndpointSupplier.Factory endpointSupplierFactory, Encoding encoding,
|
||||
Duration timeout) {
|
||||
WebClient webClient = WebClient.builder().build();
|
||||
return new ZipkinWebClientSender(encoding, endpointSupplierFactory, ZIPKIN_URL, webClient, timeout);
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendShouldSendSpansToZipkin() throws IOException, InterruptedException {
|
||||
mockBackEnd.enqueue(new MockResponse());
|
||||
List<byte[]> encodedSpans = List.of(toByteArray("span1"), toByteArray("span2"));
|
||||
this.sender.send(encodedSpans);
|
||||
requestAssertions((request) -> {
|
||||
assertThat(request.getMethod()).isEqualTo("POST");
|
||||
assertThat(request.getHeader("Content-Type")).isEqualTo("application/json");
|
||||
assertThat(request.getBody().readUtf8()).isEqualTo("[span1,span2]");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendShouldSendSpansToZipkinInProto3() throws IOException, InterruptedException {
|
||||
mockBackEnd.enqueue(new MockResponse());
|
||||
List<byte[]> encodedSpans = List.of(toByteArray("span1"), toByteArray("span2"));
|
||||
try (BytesMessageSender sender = createSender(Encoding.PROTO3, TIMEOUT)) {
|
||||
sender.send(encodedSpans);
|
||||
}
|
||||
requestAssertions((request) -> {
|
||||
assertThat(request.getMethod()).isEqualTo("POST");
|
||||
assertThat(request.getHeader("Content-Type")).isEqualTo("application/x-protobuf");
|
||||
assertThat(request.getBody().readUtf8()).isEqualTo("span1span2");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendUsesDynamicEndpoint() throws Exception {
|
||||
mockBackEnd.enqueue(new MockResponse());
|
||||
mockBackEnd.enqueue(new MockResponse());
|
||||
try (HttpEndpointSupplier httpEndpointSupplier = new TestHttpEndpointSupplier(ZIPKIN_URL)) {
|
||||
try (BytesMessageSender sender = createSender((endpoint) -> httpEndpointSupplier, Encoding.JSON, TIMEOUT)) {
|
||||
sender.send(Collections.emptyList());
|
||||
sender.send(Collections.emptyList());
|
||||
}
|
||||
assertThat(mockBackEnd.takeRequest().getPath()).endsWith("/1");
|
||||
assertThat(mockBackEnd.takeRequest().getPath()).endsWith("/2");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendShouldHandleHttpFailures() throws InterruptedException {
|
||||
mockBackEnd.enqueue(new MockResponse().setResponseCode(500));
|
||||
assertThatException().isThrownBy(() -> this.sender.send(Collections.emptyList()))
|
||||
.withMessageContaining("500 Internal Server Error");
|
||||
requestAssertions((request) -> assertThat(request.getMethod()).isEqualTo("POST"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendShouldCompressData() throws IOException, InterruptedException {
|
||||
String uncompressed = "a".repeat(10000);
|
||||
// This is gzip compressed 10000 times 'a'
|
||||
byte[] compressed = Base64.getDecoder()
|
||||
.decode("H4sIAAAAAAAA/+3BMQ0AAAwDIKFLj/k3UR8NcA8AAAAAAAAAAAADUsAZfeASJwAA");
|
||||
mockBackEnd.enqueue(new MockResponse());
|
||||
this.sender.send(List.of(toByteArray(uncompressed)));
|
||||
requestAssertions((request) -> {
|
||||
assertThat(request.getMethod()).isEqualTo("POST");
|
||||
assertThat(request.getHeader("Content-Type")).isEqualTo("application/json");
|
||||
assertThat(request.getHeader("Content-Encoding")).isEqualTo("gzip");
|
||||
assertThat(request.getBody().readByteArray()).isEqualTo(compressed);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTimeout() throws IOException {
|
||||
try (BytesMessageSender sender = createSender(Encoding.JSON, Duration.ofMillis(1))) {
|
||||
MockResponse response = new MockResponse().setResponseCode(200).setHeadersDelay(100, TimeUnit.MILLISECONDS);
|
||||
mockBackEnd.enqueue(response);
|
||||
assertThatException().isThrownBy(() -> sender.send(Collections.emptyList()))
|
||||
.withCauseInstanceOf(TimeoutException.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void requestAssertions(Consumer<RecordedRequest> assertions) throws InterruptedException {
|
||||
RecordedRequest request = mockBackEnd.takeRequest();
|
||||
assertThat(request).satisfies(assertions);
|
||||
}
|
||||
|
||||
private static void clearRequests() {
|
||||
RecordedRequest request;
|
||||
do {
|
||||
try {
|
||||
request = mockBackEnd.takeRequest(0, TimeUnit.SECONDS);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
while (request != null);
|
||||
}
|
||||
|
||||
private static void clearResponses() {
|
||||
dispatcher.clear();
|
||||
}
|
||||
|
||||
private static final class ClearableDispatcher extends QueueDispatcher {
|
||||
|
||||
void clear() {
|
||||
getResponseQueue().clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -53,17 +53,6 @@ public class PrometheusScrapeEndpoint {
|
|||
|
||||
private volatile int nextMetricsScrapeSize = 16;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PrometheusScrapeEndpoint}.
|
||||
* @param prometheusRegistry the Prometheus registry to use
|
||||
* @deprecated since 3.3.1 for removal in 3.5.0 in favor of
|
||||
* {@link #PrometheusScrapeEndpoint(PrometheusRegistry, Properties)}
|
||||
*/
|
||||
@Deprecated(since = "3.3.1", forRemoval = true)
|
||||
public PrometheusScrapeEndpoint(PrometheusRegistry prometheusRegistry) {
|
||||
this(prometheusRegistry, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PrometheusScrapeEndpoint}.
|
||||
* @param prometheusRegistry the Prometheus registry to use
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.metrics.export.prometheus;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Set;
|
||||
|
||||
import io.prometheus.client.Collector.MetricFamilySamples;
|
||||
import io.prometheus.client.CollectorRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link Endpoint @Endpoint} that uses the Prometheus simpleclient to output metrics in a
|
||||
* format that can be scraped by the Prometheus server.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Johnny Lim
|
||||
* @since 2.0.0
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0 in favor of
|
||||
* {@link PrometheusScrapeEndpoint}
|
||||
*/
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
@WebEndpoint(id = "prometheus")
|
||||
public class PrometheusSimpleclientScrapeEndpoint {
|
||||
|
||||
private static final int METRICS_SCRAPE_CHARS_EXTRA = 1024;
|
||||
|
||||
private final CollectorRegistry collectorRegistry;
|
||||
|
||||
private volatile int nextMetricsScrapeSize = 16;
|
||||
|
||||
public PrometheusSimpleclientScrapeEndpoint(CollectorRegistry collectorRegistry) {
|
||||
this.collectorRegistry = collectorRegistry;
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
@ReadOperation(producesFrom = TextOutputFormat.class)
|
||||
public WebEndpointResponse<String> scrape(TextOutputFormat format, @Nullable Set<String> includedNames) {
|
||||
try {
|
||||
Writer writer = new StringWriter(this.nextMetricsScrapeSize);
|
||||
Enumeration<MetricFamilySamples> samples = (includedNames != null)
|
||||
? this.collectorRegistry.filteredMetricFamilySamples(includedNames)
|
||||
: this.collectorRegistry.metricFamilySamples();
|
||||
format.write(writer, samples);
|
||||
String scrapePage = writer.toString();
|
||||
this.nextMetricsScrapeSize = scrapePage.length() + METRICS_SCRAPE_CHARS_EXTRA;
|
||||
return new WebEndpointResponse<>(scrapePage, format);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// This actually never happens since StringWriter doesn't throw an IOException
|
||||
throw new IllegalStateException("Writing metrics failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.metrics.export.prometheus;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import io.prometheus.client.Collector.MetricFamilySamples;
|
||||
import io.prometheus.client.exporter.common.TextFormat;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.Producible;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
|
||||
/**
|
||||
* A {@link Producible} enum for supported Prometheus {@link TextFormat}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.5.0
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0 in favor of {@link PrometheusOutputFormat}
|
||||
*/
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
public enum TextOutputFormat implements Producible<TextOutputFormat> {
|
||||
|
||||
/**
|
||||
* Prometheus text version 0.0.4.
|
||||
*/
|
||||
CONTENT_TYPE_004(TextFormat.CONTENT_TYPE_004) {
|
||||
|
||||
@Override
|
||||
void write(Writer writer, Enumeration<MetricFamilySamples> samples) throws IOException {
|
||||
TextFormat.write004(writer, samples);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* OpenMetrics text version 1.0.0.
|
||||
*/
|
||||
CONTENT_TYPE_OPENMETRICS_100(TextFormat.CONTENT_TYPE_OPENMETRICS_100) {
|
||||
|
||||
@Override
|
||||
void write(Writer writer, Enumeration<MetricFamilySamples> samples) throws IOException {
|
||||
TextFormat.writeOpenMetrics100(writer, samples);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private final MimeType mimeType;
|
||||
|
||||
TextOutputFormat(String mimeType) {
|
||||
this.mimeType = MimeTypeUtils.parseMimeType(mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MimeType getProducedMimeType() {
|
||||
return this.mimeType;
|
||||
}
|
||||
|
||||
abstract void write(Writer writer, Enumeration<MetricFamilySamples> samples) throws IOException;
|
||||
|
||||
}
|
||||
|
|
@ -42,17 +42,6 @@ public class SessionsEndpoint {
|
|||
|
||||
private final FindByIndexNameSessionRepository<? extends Session> indexedSessionRepository;
|
||||
|
||||
/**
|
||||
* Create a new {@link SessionsEndpoint} instance.
|
||||
* @param sessionRepository the session repository
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0 in favor of
|
||||
* {@link #SessionsEndpoint(SessionRepository, FindByIndexNameSessionRepository)}
|
||||
*/
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
public SessionsEndpoint(FindByIndexNameSessionRepository<? extends Session> sessionRepository) {
|
||||
this(sessionRepository, sessionRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link SessionsEndpoint} instance.
|
||||
* @param sessionRepository the session repository
|
||||
|
|
|
|||
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.metrics.export.prometheus;
|
||||
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.prometheus.client.CollectorRegistry;
|
||||
import io.prometheus.client.exporter.common.TextFormat;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link PrometheusSimpleclientScrapeEndpoint}.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Johnny Lim
|
||||
*/
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
class PrometheusSimpleclientScrapeEndpointIntegrationTests {
|
||||
|
||||
@WebEndpointTest
|
||||
void scrapeHasContentTypeText004ByDefault(WebTestClient client) {
|
||||
String expectedContentType = TextFormat.CONTENT_TYPE_004;
|
||||
assertThat(TextFormat.chooseContentType(null)).isEqualTo(expectedContentType);
|
||||
client.get()
|
||||
.uri("/actuator/prometheus")
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(MediaType.parseMediaType(expectedContentType))
|
||||
.expectBody(String.class)
|
||||
.value((body) -> assertThat(body).contains("counter1_total")
|
||||
.contains("counter2_total")
|
||||
.contains("counter3_total"));
|
||||
}
|
||||
|
||||
@WebEndpointTest
|
||||
void scrapeHasContentTypeText004ByDefaultWhenClientAcceptsWildcardWithParameter(WebTestClient client) {
|
||||
String expectedContentType = TextFormat.CONTENT_TYPE_004;
|
||||
String accept = "*/*;q=0.8";
|
||||
assertThat(TextFormat.chooseContentType(accept)).isEqualTo(expectedContentType);
|
||||
client.get()
|
||||
.uri("/actuator/prometheus")
|
||||
.accept(MediaType.parseMediaType(accept))
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(MediaType.parseMediaType(expectedContentType))
|
||||
.expectBody(String.class)
|
||||
.value((body) -> assertThat(body).contains("counter1_total")
|
||||
.contains("counter2_total")
|
||||
.contains("counter3_total"));
|
||||
}
|
||||
|
||||
@WebEndpointTest
|
||||
void scrapeCanProduceOpenMetrics100(WebTestClient client) {
|
||||
MediaType openMetrics = MediaType.parseMediaType(TextFormat.CONTENT_TYPE_OPENMETRICS_100);
|
||||
client.get()
|
||||
.uri("/actuator/prometheus")
|
||||
.accept(openMetrics)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(openMetrics)
|
||||
.expectBody(String.class)
|
||||
.value((body) -> assertThat(body).contains("counter1_total")
|
||||
.contains("counter2_total")
|
||||
.contains("counter3_total"));
|
||||
}
|
||||
|
||||
@WebEndpointTest
|
||||
void scrapePrefersToProduceOpenMetrics100(WebTestClient client) {
|
||||
MediaType openMetrics = MediaType.parseMediaType(TextFormat.CONTENT_TYPE_OPENMETRICS_100);
|
||||
MediaType textPlain = MediaType.parseMediaType(TextFormat.CONTENT_TYPE_004);
|
||||
client.get()
|
||||
.uri("/actuator/prometheus")
|
||||
.accept(openMetrics, textPlain)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(openMetrics);
|
||||
}
|
||||
|
||||
@WebEndpointTest
|
||||
void scrapeWithIncludedNames(WebTestClient client) {
|
||||
client.get()
|
||||
.uri("/actuator/prometheus?includedNames=counter1_total,counter2_total")
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(MediaType.parseMediaType(TextFormat.CONTENT_TYPE_004))
|
||||
.expectBody(String.class)
|
||||
.value((body) -> assertThat(body).contains("counter1_total")
|
||||
.contains("counter2_total")
|
||||
.doesNotContain("counter3_total"));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
PrometheusSimpleclientScrapeEndpoint prometheusScrapeEndpoint(CollectorRegistry collectorRegistry) {
|
||||
return new PrometheusSimpleclientScrapeEndpoint(collectorRegistry);
|
||||
}
|
||||
|
||||
@Bean
|
||||
CollectorRegistry collectorRegistry() {
|
||||
return new CollectorRegistry(true);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("deprecation")
|
||||
MeterRegistry registry(CollectorRegistry registry) {
|
||||
io.micrometer.prometheus.PrometheusMeterRegistry meterRegistry = new io.micrometer.prometheus.PrometheusMeterRegistry(
|
||||
(k) -> null, registry, Clock.SYSTEM);
|
||||
Counter.builder("counter1").register(meterRegistry);
|
||||
Counter.builder("counter2").register(meterRegistry);
|
||||
Counter.builder("counter3").register(meterRegistry);
|
||||
return meterRegistry;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.metrics.export.prometheus;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
import io.micrometer.prometheusmetrics.PrometheusMeterRegistry;
|
||||
import io.prometheus.client.CollectorRegistry;
|
||||
import io.prometheus.metrics.expositionformats.OpenMetricsTextFormatWriter;
|
||||
import io.prometheus.metrics.expositionformats.PrometheusTextFormatWriter;
|
||||
import io.prometheus.metrics.model.registry.PrometheusRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for exposing a {@link PrometheusScrapeEndpoint} and
|
||||
* {@link PrometheusSimpleclientScrapeEndpoint} with different IDs.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Johnny Lim
|
||||
*/
|
||||
class SecondCustomPrometheusScrapeEndpointIntegrationTests {
|
||||
|
||||
@WebEndpointTest
|
||||
void scrapeHasContentTypeText004ByDefault(WebTestClient client) {
|
||||
scrapeHasContentTypeText004ByDefault(client, "/actuator/prometheus");
|
||||
scrapeHasContentTypeText004ByDefault(client, "/actuator/prometheussc");
|
||||
}
|
||||
|
||||
private void scrapeHasContentTypeText004ByDefault(WebTestClient client, String uri) {
|
||||
String expectedContentType = PrometheusTextFormatWriter.CONTENT_TYPE;
|
||||
client.get()
|
||||
.uri(uri)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(MediaType.parseMediaType(expectedContentType))
|
||||
.expectBody(String.class)
|
||||
.value((body) -> assertThat(body).contains("counter1_total")
|
||||
.contains("counter2_total")
|
||||
.contains("counter3_total"));
|
||||
}
|
||||
|
||||
@WebEndpointTest
|
||||
void scrapeHasContentTypeText004ByDefaultWhenClientAcceptsWildcardWithParameter(WebTestClient client) {
|
||||
scrapeHasContentTypeText004ByDefaultWhenClientAcceptsWildcardWithParameter(client, "/actuator/prometheus");
|
||||
scrapeHasContentTypeText004ByDefaultWhenClientAcceptsWildcardWithParameter(client, "/actuator/prometheussc");
|
||||
}
|
||||
|
||||
private void scrapeHasContentTypeText004ByDefaultWhenClientAcceptsWildcardWithParameter(WebTestClient client,
|
||||
String uri) {
|
||||
String expectedContentType = PrometheusTextFormatWriter.CONTENT_TYPE;
|
||||
String accept = "*/*;q=0.8";
|
||||
client.get()
|
||||
.uri(uri)
|
||||
.accept(MediaType.parseMediaType(accept))
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(MediaType.parseMediaType(expectedContentType))
|
||||
.expectBody(String.class)
|
||||
.value((body) -> assertThat(body).contains("counter1_total")
|
||||
.contains("counter2_total")
|
||||
.contains("counter3_total"));
|
||||
}
|
||||
|
||||
@WebEndpointTest
|
||||
void scrapeCanProduceOpenMetrics100(WebTestClient client) {
|
||||
scrapeCanProduceOpenMetrics100(client, "/actuator/prometheus");
|
||||
scrapeCanProduceOpenMetrics100(client, "/actuator/prometheussc");
|
||||
}
|
||||
|
||||
private void scrapeCanProduceOpenMetrics100(WebTestClient client, String uri) {
|
||||
MediaType openMetrics = MediaType.parseMediaType(OpenMetricsTextFormatWriter.CONTENT_TYPE);
|
||||
client.get()
|
||||
.uri(uri)
|
||||
.accept(openMetrics)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(openMetrics)
|
||||
.expectBody(String.class)
|
||||
.value((body) -> assertThat(body).contains("counter1_total")
|
||||
.contains("counter2_total")
|
||||
.contains("counter3_total"));
|
||||
}
|
||||
|
||||
@WebEndpointTest
|
||||
void scrapePrefersToProduceOpenMetrics100(WebTestClient client) {
|
||||
scrapePrefersToProduceOpenMetrics100(client, "/actuator/prometheus");
|
||||
scrapePrefersToProduceOpenMetrics100(client, "/actuator/prometheussc");
|
||||
}
|
||||
|
||||
private void scrapePrefersToProduceOpenMetrics100(WebTestClient client, String uri) {
|
||||
MediaType openMetrics = MediaType.parseMediaType(OpenMetricsTextFormatWriter.CONTENT_TYPE);
|
||||
MediaType textPlain = MediaType.parseMediaType(PrometheusTextFormatWriter.CONTENT_TYPE);
|
||||
client.get()
|
||||
.uri(uri)
|
||||
.accept(openMetrics, textPlain)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(openMetrics);
|
||||
}
|
||||
|
||||
@WebEndpointTest
|
||||
void scrapeWithIncludedNames(WebTestClient client) {
|
||||
scrapeWithIncludedNames(client, "/actuator/prometheus?includedNames=counter1,counter2");
|
||||
scrapeWithIncludedNames(client, "/actuator/prometheussc?includedNames=counter1_total,counter2_total");
|
||||
}
|
||||
|
||||
private void scrapeWithIncludedNames(WebTestClient client, String uri) {
|
||||
client.get()
|
||||
.uri(uri)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(MediaType.parseMediaType(PrometheusTextFormatWriter.CONTENT_TYPE))
|
||||
.expectBody(String.class)
|
||||
.value((body) -> assertThat(body).contains("counter1_total")
|
||||
.contains("counter2_total")
|
||||
.doesNotContain("counter3_total"));
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
PrometheusScrapeEndpoint prometheusScrapeEndpoint(PrometheusRegistry prometheusRegistry) {
|
||||
return new PrometheusScrapeEndpoint(prometheusRegistry, new Properties());
|
||||
}
|
||||
|
||||
@Bean
|
||||
CustomPrometheusScrapeEndpoint customPrometheusScrapeEndpoint(CollectorRegistry collectorRegistry) {
|
||||
return new CustomPrometheusScrapeEndpoint(collectorRegistry);
|
||||
}
|
||||
|
||||
@Bean
|
||||
PrometheusRegistry prometheusRegistry() {
|
||||
return new PrometheusRegistry();
|
||||
}
|
||||
|
||||
@Bean
|
||||
CollectorRegistry collectorRegistry() {
|
||||
return new CollectorRegistry(true);
|
||||
}
|
||||
|
||||
@Bean
|
||||
PrometheusMeterRegistry registry(PrometheusRegistry prometheusRegistry) {
|
||||
return new PrometheusMeterRegistry((k) -> null, prometheusRegistry, Clock.SYSTEM);
|
||||
}
|
||||
|
||||
@Bean
|
||||
io.micrometer.prometheus.PrometheusMeterRegistry oldRegistry(CollectorRegistry collectorRegistry) {
|
||||
return new io.micrometer.prometheus.PrometheusMeterRegistry((k) -> null, collectorRegistry, Clock.SYSTEM);
|
||||
}
|
||||
|
||||
@Bean
|
||||
CompositeMeterRegistry compositeMeterRegistry(PrometheusMeterRegistry prometheusMeterRegistry,
|
||||
io.micrometer.prometheus.PrometheusMeterRegistry prometheusSCMeterRegistry) {
|
||||
CompositeMeterRegistry composite = new CompositeMeterRegistry();
|
||||
composite.add(prometheusMeterRegistry).add(prometheusSCMeterRegistry);
|
||||
Counter.builder("counter1").register(composite);
|
||||
Counter.builder("counter2").register(composite);
|
||||
Counter.builder("counter3").register(composite);
|
||||
return composite;
|
||||
}
|
||||
|
||||
@WebEndpoint(id = "prometheussc")
|
||||
static class CustomPrometheusScrapeEndpoint extends PrometheusSimpleclientScrapeEndpoint {
|
||||
|
||||
CustomPrometheusScrapeEndpoint(CollectorRegistry collectorRegistry) {
|
||||
super(collectorRegistry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.autoconfigure.jooq;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jooq.ExecuteContext;
|
||||
import org.jooq.ExecuteListener;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
/**
|
||||
* Transforms {@link SQLException} into a Spring-specific {@link DataAccessException}.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
* @author Andreas Ahlenstorf
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.5.10
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0 in favor of
|
||||
* {@link ExceptionTranslatorExecuteListener#DEFAULT} or
|
||||
* {@link ExceptionTranslatorExecuteListener#of}
|
||||
*/
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
public class JooqExceptionTranslator implements ExecuteListener {
|
||||
|
||||
private final DefaultExceptionTranslatorExecuteListener delegate = new DefaultExceptionTranslatorExecuteListener(
|
||||
LogFactory.getLog(JooqExceptionTranslator.class));
|
||||
|
||||
@Override
|
||||
public void exception(ExecuteContext context) {
|
||||
this.delegate.exception(context);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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.autoconfigure.jooq;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.ExecuteContext;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.assertArg;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
|
||||
/**
|
||||
* Tests for {@link JooqExceptionTranslator}
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0
|
||||
*/
|
||||
@Deprecated(since = "3.3.0")
|
||||
@SuppressWarnings("removal")
|
||||
class JooqExceptionTranslatorTests {
|
||||
|
||||
private final JooqExceptionTranslator exceptionTranslator = new JooqExceptionTranslator();
|
||||
|
||||
@ParameterizedTest(name = "{0}")
|
||||
@MethodSource
|
||||
void exceptionTranslation(SQLDialect dialect, SQLException sqlException) {
|
||||
ExecuteContext context = mock(ExecuteContext.class);
|
||||
Configuration configuration = mock(Configuration.class);
|
||||
given(context.configuration()).willReturn(configuration);
|
||||
given(configuration.dialect()).willReturn(dialect);
|
||||
given(context.sqlException()).willReturn(sqlException);
|
||||
this.exceptionTranslator.exception(context);
|
||||
then(context).should().exception(assertArg((ex) -> assertThat(ex).isInstanceOf(BadSqlGrammarException.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenExceptionCannotBeTranslatedThenExecuteContextExceptionIsNotCalled() {
|
||||
ExecuteContext context = mock(ExecuteContext.class);
|
||||
Configuration configuration = mock(Configuration.class);
|
||||
given(context.configuration()).willReturn(configuration);
|
||||
given(configuration.dialect()).willReturn(SQLDialect.POSTGRES);
|
||||
given(context.sqlException()).willReturn(new SQLException(null, null, 123456789));
|
||||
this.exceptionTranslator.exception(context);
|
||||
then(context).should(never()).exception(any());
|
||||
}
|
||||
|
||||
static Object[] exceptionTranslation() {
|
||||
return new Object[] { new Object[] { SQLDialect.DERBY, sqlException("42802") },
|
||||
new Object[] { SQLDialect.H2, sqlException(42000) },
|
||||
new Object[] { SQLDialect.HSQLDB, sqlException(-22) },
|
||||
new Object[] { SQLDialect.MARIADB, sqlException(1054) },
|
||||
new Object[] { SQLDialect.MYSQL, sqlException(1054) },
|
||||
new Object[] { SQLDialect.POSTGRES, sqlException("03000") },
|
||||
new Object[] { SQLDialect.SQLITE, sqlException("21000") } };
|
||||
}
|
||||
|
||||
private static SQLException sqlException(String sqlState) {
|
||||
return new SQLException(null, sqlState);
|
||||
}
|
||||
|
||||
private static SQLException sqlException(int vendorCode) {
|
||||
return new SQLException(null, null, vendorCode);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -91,7 +91,7 @@ dependencies {
|
|||
testImplementation("com.h2database:h2")
|
||||
testImplementation("com.unboundid:unboundid-ldapsdk")
|
||||
testImplementation("io.lettuce:lettuce-core")
|
||||
testImplementation("io.micrometer:micrometer-registry-prometheus-simpleclient")
|
||||
testImplementation("io.micrometer:micrometer-registry-prometheus")
|
||||
testImplementation("io.projectreactor.netty:reactor-netty-http")
|
||||
testImplementation("io.projectreactor:reactor-core")
|
||||
testImplementation("io.projectreactor:reactor-test")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -36,14 +36,14 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* @author Moritz Halbritter
|
||||
*/
|
||||
@SpringBootTest
|
||||
@SuppressWarnings("deprecation")
|
||||
class AutoConfigureObservabilityMissingIntegrationTests {
|
||||
|
||||
@Test
|
||||
void customizerRunsAndOnlyEnablesSimpleMeterRegistryWhenNoAnnotationPresent(
|
||||
@Autowired ApplicationContext applicationContext) {
|
||||
assertThat(applicationContext.getBean(MeterRegistry.class)).isInstanceOf(SimpleMeterRegistry.class);
|
||||
assertThat(applicationContext.getBeansOfType(io.micrometer.prometheus.PrometheusMeterRegistry.class)).isEmpty();
|
||||
assertThat(applicationContext.getBeansOfType(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class))
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -35,13 +35,12 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
*/
|
||||
@SpringBootTest
|
||||
@AutoConfigureObservability
|
||||
@SuppressWarnings("deprecation")
|
||||
class AutoConfigureObservabilityPresentIntegrationTests {
|
||||
|
||||
@Test
|
||||
void customizerDoesNotDisableAvailableMeterRegistriesWhenAnnotationPresent(
|
||||
@Autowired ApplicationContext applicationContext) {
|
||||
assertThat(applicationContext.getBeansOfType(io.micrometer.prometheus.PrometheusMeterRegistry.class))
|
||||
assertThat(applicationContext.getBeansOfType(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class))
|
||||
.hasSize(1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ import org.springframework.util.Assert;
|
|||
* @deprecated since 3.4.0 for removal in 3.6.0 in favor of
|
||||
* {@link org.springframework.test.context.bean.override.mockito.MockReset}
|
||||
*/
|
||||
|
||||
@Deprecated(since = "3.4.0", forRemoval = true)
|
||||
public enum MockReset {
|
||||
|
||||
|
|
|
|||
|
|
@ -17,11 +17,8 @@
|
|||
package org.springframework.boot.buildpack.platform.docker;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
|
@ -293,34 +290,6 @@ public class DockerApi {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the layers of an image as paths to layer tar files.
|
||||
* @param reference the reference to export
|
||||
* @param exports a consumer to receive the layer tar file paths (file can only be
|
||||
* accessed during the callback)
|
||||
* @throws IOException on IO error
|
||||
* @since 2.7.10
|
||||
* @deprecated since 3.2.6 for removal in 3.5.0 in favor of
|
||||
* {@link #exportLayers(ImageReference, IOBiConsumer)}
|
||||
*/
|
||||
@Deprecated(since = "3.2.6", forRemoval = true)
|
||||
public void exportLayerFiles(ImageReference reference, IOBiConsumer<String, Path> exports) throws IOException {
|
||||
Assert.notNull(reference, "'reference' must not be null");
|
||||
Assert.notNull(exports, "'exports' must not be null");
|
||||
exportLayers(reference, (name, archive) -> {
|
||||
Path path = Files.createTempFile("docker-export-layer-files-", null);
|
||||
try {
|
||||
try (OutputStream out = Files.newOutputStream(path)) {
|
||||
archive.writeTo(out);
|
||||
exports.accept(name, path);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Files.delete(path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the layers of an image as {@link TarArchive TarArchives}.
|
||||
* @param reference the reference to export
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -78,28 +78,6 @@ public abstract class ProgressUpdateEvent extends UpdateEvent {
|
|||
this.total = total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current progress value.
|
||||
* @return the current progress
|
||||
* @deprecated since 3.3.7 for removal in 3.5.0 in favor of
|
||||
* {@link #asPercentage()}
|
||||
*/
|
||||
@Deprecated(since = "3.3.7", forRemoval = true)
|
||||
public int getCurrent() {
|
||||
return (int) Long.min(this.current, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total progress possible value.
|
||||
* @return the total progress possible
|
||||
* @deprecated since 3.3.7 for removal in 3.5.0 in favor of
|
||||
* {@link #asPercentage()}
|
||||
*/
|
||||
@Deprecated(since = "3.3.7", forRemoval = true)
|
||||
public int getTotal() {
|
||||
return (int) Long.min(this.total, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the progress as a percentage.
|
||||
* @return the progress percentage
|
||||
|
|
@ -110,14 +88,7 @@ public abstract class ProgressUpdateEvent extends UpdateEvent {
|
|||
return (percentage < 0) ? 0 : Math.min(percentage, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the progress detail is considered empty.
|
||||
* @param progressDetail the progress detail to check
|
||||
* @return if the progress detail is empty
|
||||
* @deprecated since 3.3.7 for removal in 3.5.0
|
||||
*/
|
||||
@Deprecated(since = "3.3.7", forRemoval = true)
|
||||
public static boolean isEmpty(ProgressDetail progressDetail) {
|
||||
private static boolean isEmpty(ProgressDetail progressDetail) {
|
||||
return progressDetail == null || progressDetail.current == null || progressDetail.total == null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,10 +23,7 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
|
||||
|
|
@ -392,21 +389,6 @@ class DockerApiTests {
|
|||
assertThat(image.getLayers()).hasSize(46);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void exportLayersWhenReferenceIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.api.exportLayerFiles(null, (name, archive) -> {
|
||||
})).withMessage("'reference' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void exportLayersWhenExportsIsNullThrowsException() {
|
||||
ImageReference reference = ImageReference.of("gcr.io/paketo-buildpacks/builder:base");
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.api.exportLayerFiles(reference, null))
|
||||
.withMessage("'exports' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void exportLayersExportsLayerTars() throws Exception {
|
||||
ImageReference reference = ImageReference.of("gcr.io/paketo-buildpacks/builder:base");
|
||||
|
|
@ -463,29 +445,6 @@ class DockerApiTests {
|
|||
.containsExactly("/cnb/stack.toml");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void exportLayerFilesDeletesTempFiles() throws Exception {
|
||||
ImageReference reference = ImageReference.of("gcr.io/paketo-buildpacks/builder:base");
|
||||
URI exportUri = new URI(IMAGES_URL + "/gcr.io/paketo-buildpacks/builder:base/get");
|
||||
given(DockerApiTests.this.http.get(exportUri)).willReturn(responseOf("export.tar"));
|
||||
List<Path> layerFilePaths = new ArrayList<>();
|
||||
this.api.exportLayerFiles(reference, (name, path) -> layerFilePaths.add(path));
|
||||
layerFilePaths.forEach((path) -> assertThat(path.toFile()).doesNotExist());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void exportLayersWithNoManifestThrowsException() throws Exception {
|
||||
ImageReference reference = ImageReference.of("gcr.io/paketo-buildpacks/builder:base");
|
||||
URI exportUri = new URI(IMAGES_URL + "/gcr.io/paketo-buildpacks/builder:base/get");
|
||||
given(DockerApiTests.this.http.get(exportUri)).willReturn(responseOf("export-no-manifest.tar"));
|
||||
String expectedMessage = "Exported image '%s' does not contain 'index.json' or 'manifest.json'"
|
||||
.formatted(reference);
|
||||
assertThatIllegalStateException().isThrownBy(() -> this.api.exportLayerFiles(reference, (name, archive) -> {
|
||||
})).withMessageContaining(expectedMessage);
|
||||
}
|
||||
|
||||
@Test
|
||||
void tagWhenReferenceIsNullThrowsException() {
|
||||
ImageReference tag = ImageReference.of("localhost:5000/ubuntu");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -39,20 +39,14 @@ abstract class ProgressUpdateEventTests<E extends ProgressUpdateEvent> {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void getProgressDetailsReturnsProgressDetails() {
|
||||
ProgressUpdateEvent event = createEvent();
|
||||
assertThat(event.getProgressDetail().getCurrent()).isOne();
|
||||
assertThat(event.getProgressDetail().getTotal()).isEqualTo(2);
|
||||
assertThat(event.getProgressDetail().asPercentage()).isEqualTo(50);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void getProgressDetailsReturnsProgressDetailsForLongNumbers() {
|
||||
ProgressUpdateEvent event = createEvent("status", new ProgressDetail(4000000000L, 8000000000L), "progress");
|
||||
assertThat(event.getProgressDetail().getCurrent()).isEqualTo(Integer.MAX_VALUE);
|
||||
assertThat(event.getProgressDetail().getTotal()).isEqualTo(Integer.MAX_VALUE);
|
||||
assertThat(event.getProgressDetail().asPercentage()).isEqualTo(50);
|
||||
}
|
||||
|
||||
|
|
@ -62,27 +56,6 @@ abstract class ProgressUpdateEventTests<E extends ProgressUpdateEvent> {
|
|||
assertThat(event.getProgress()).isEqualTo("progress");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void progressDetailIsEmptyWhenCurrentIsNullReturnsTrue() {
|
||||
ProgressDetail detail = new ProgressDetail(null, 2L);
|
||||
assertThat(ProgressDetail.isEmpty(detail)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void progressDetailIsEmptyWhenTotalIsNullReturnsTrue() {
|
||||
ProgressDetail detail = new ProgressDetail(1L, null);
|
||||
assertThat(ProgressDetail.isEmpty(detail)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void progressDetailIsEmptyWhenTotalAndCurrentAreNotNullReturnsFalse() {
|
||||
ProgressDetail detail = new ProgressDetail(1L, 2L);
|
||||
assertThat(ProgressDetail.isEmpty(detail)).isFalse();
|
||||
}
|
||||
|
||||
protected E createEvent() {
|
||||
return createEvent("status", new ProgressDetail(1L, 2L), "progress");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -36,8 +36,6 @@ class PullUpdateEventTests extends AbstractJsonTests {
|
|||
PullImageUpdateEvent.class);
|
||||
assertThat(event.getId()).isEqualTo("4f4fb700ef54");
|
||||
assertThat(event.getStatus()).isEqualTo("Extracting");
|
||||
assertThat(event.getProgressDetail().getCurrent()).isEqualTo(16);
|
||||
assertThat(event.getProgressDetail().getTotal()).isEqualTo(32);
|
||||
assertThat(event.getProgressDetail().asPercentage()).isEqualTo(50);
|
||||
assertThat(event.getProgress()).isEqualTo("[==================================================>] 32B/32B");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -154,10 +154,8 @@ public abstract class BootJar extends Jar implements BootArchive {
|
|||
jarmodeToolsLocation);
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private boolean isIncludeJarmodeTools() {
|
||||
return Boolean.TRUE.equals(this.getIncludeTools().get())
|
||||
&& Boolean.TRUE.equals(this.layered.getIncludeLayerTools().get());
|
||||
return Boolean.TRUE.equals(this.getIncludeTools().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -128,10 +128,8 @@ public abstract class BootWar extends War implements BootArchive {
|
|||
layerResolver, jarmodeToolsLocation);
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private boolean isIncludeJarmodeTools() {
|
||||
return Boolean.TRUE.equals(this.getIncludeTools().get())
|
||||
&& Boolean.TRUE.equals(this.layered.getIncludeLayerTools().get());
|
||||
return Boolean.TRUE.equals(this.getIncludeTools().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -64,20 +64,8 @@ public abstract class LayeredSpec {
|
|||
this.application = objects.newInstance(ApplicationSpec.class);
|
||||
this.dependencies = objects.newInstance(DependenciesSpec.class);
|
||||
getEnabled().convention(true);
|
||||
getIncludeLayerTools().convention(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the layer tools should be included as a dependency in the layered
|
||||
* archive.
|
||||
* @return whether the layer tools should be included
|
||||
* @since 3.0.0
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0 in favor of {@code includeTools}.
|
||||
*/
|
||||
@Input
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
public abstract Property<Boolean> getIncludeLayerTools();
|
||||
|
||||
/**
|
||||
* Returns whether the layers.idx should be included in the archive.
|
||||
* @return whether the layers.idx should be included
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -321,18 +321,6 @@ abstract class AbstractBootArchiveIntegrationTests {
|
|||
.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
void notUpToDateWhenBuiltWithLayerToolsAndThenWithoutLayerTools() {
|
||||
assertThat(this.gradleBuild.scriptProperty("layerTools", "")
|
||||
.build(this.taskName)
|
||||
.task(":" + this.taskName)
|
||||
.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
|
||||
assertThat(this.gradleBuild.scriptProperty("layerTools", "includeLayerTools = false")
|
||||
.build(this.taskName)
|
||||
.task(":" + this.taskName)
|
||||
.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
void notUpToDateWhenBuiltWithToolsAndThenWithoutTools() {
|
||||
assertThat(this.gradleBuild.scriptProperty("includeTools", "")
|
||||
|
|
|
|||
|
|
@ -626,14 +626,6 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
|
|||
assertThat(entryNames).isNotEmpty().contains(this.libPath + JarModeLibrary.TOOLS.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void whenArchiveIsLayeredAndIncludeLayerToolsIsFalseThenLayerToolsAreNotAddedToTheJar() throws IOException {
|
||||
List<String> entryNames = getEntryNames(
|
||||
createLayeredJar((configuration) -> configuration.getIncludeLayerTools().set(false)));
|
||||
assertThat(entryNames).isNotEmpty().doesNotContain(this.libPath + JarModeLibrary.TOOLS.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenIncludeToolsIsFalseThenToolsAreNotAddedToTheJar() throws IOException {
|
||||
this.task.getIncludeTools().set(false);
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '{version}'
|
||||
}
|
||||
|
||||
bootJar {
|
||||
mainClass = 'com.example.Application'
|
||||
layered {
|
||||
{layerTools}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '{version}'
|
||||
id 'war'
|
||||
}
|
||||
|
||||
bootWar {
|
||||
mainClass = 'com.example.Application'
|
||||
layered {
|
||||
{layerTools}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -408,19 +408,6 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests {
|
|||
});
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
void whenJarIsRepackagedWithTheLayersEnabledAndLayerToolsExcluded(MavenBuild mavenBuild) {
|
||||
mavenBuild.project("jar-layered-no-layer-tools").execute((project) -> {
|
||||
File repackaged = new File(project, "jar/target/jar-layered-0.0.1.BUILD-SNAPSHOT.jar");
|
||||
assertThat(jar(repackaged)).hasEntryWithNameStartingWith("BOOT-INF/classes/")
|
||||
.hasEntryWithNameStartingWith("BOOT-INF/lib/jar-release")
|
||||
.hasEntryWithNameStartingWith("BOOT-INF/lib/jar-snapshot")
|
||||
.hasEntryWithNameStartingWith("BOOT-INF/layers.idx")
|
||||
.doesNotHaveEntryWithNameStartingWith(
|
||||
"BOOT-INF/lib/" + JarModeLibrary.TOOLS.getCoordinates().getArtifactId());
|
||||
});
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
void whenJarIsRepackagedWithToolsExclude(MavenBuild mavenBuild) {
|
||||
mavenBuild.project("jar-no-tools").execute((project) -> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -184,19 +184,6 @@ class WarIntegrationTests extends AbstractArchiveIntegrationTests {
|
|||
});
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
void whenWarIsRepackagedWithTheLayersEnabledAndLayerToolsExcluded(MavenBuild mavenBuild) {
|
||||
mavenBuild.project("war-layered-no-layer-tools").execute((project) -> {
|
||||
File repackaged = new File(project, "war/target/war-layered-0.0.1.BUILD-SNAPSHOT.war");
|
||||
assertThat(jar(repackaged)).hasEntryWithNameStartingWith("WEB-INF/classes/")
|
||||
.hasEntryWithNameStartingWith("WEB-INF/lib/jar-release")
|
||||
.hasEntryWithNameStartingWith("WEB-INF/lib/jar-snapshot")
|
||||
.hasEntryWithNameStartingWith("WEB-INF/layers.idx")
|
||||
.doesNotHaveEntryWithNameStartingWith(
|
||||
"WEB-INF/lib/" + JarModeLibrary.TOOLS.getCoordinates().getArtifactId());
|
||||
});
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
void whenWarIsRepackagedWithToolsExclude(MavenBuild mavenBuild) {
|
||||
mavenBuild.project("war-no-tools").execute((project) -> {
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>jar-release</artifactId>
|
||||
<version>0.0.1.RELEASE</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>jar</name>
|
||||
<description>Release Jar dependency</description>
|
||||
</project>
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>jar-snapshot</artifactId>
|
||||
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>jar</name>
|
||||
<description>Snapshot Jar dependency</description>
|
||||
</project>
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>jar-layered</artifactId>
|
||||
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>@java.version@</maven.compiler.source>
|
||||
<maven.compiler.target>@java.version@</maven.compiler.target>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>@project.groupId@</groupId>
|
||||
<artifactId>@project.artifactId@</artifactId>
|
||||
<version>@project.version@</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<layers>
|
||||
<includeLayerTools>false</includeLayerTools>
|
||||
</layers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>jar-snapshot</artifactId>
|
||||
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>jar-release</artifactId>
|
||||
<version>0.0.1.RELEASE</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
* 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.test;
|
||||
|
||||
public class SampleApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>aggregator</artifactId>
|
||||
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>@java.version@</maven.compiler.source>
|
||||
<maven.compiler.target>@java.version@</maven.compiler.target>
|
||||
</properties>
|
||||
<modules>
|
||||
<module>jar-snapshot</module>
|
||||
<module>jar-release</module>
|
||||
<module>jar</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>jar-release</artifactId>
|
||||
<version>0.0.1.RELEASE</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>jar</name>
|
||||
<description>Release Jar dependency</description>
|
||||
</project>
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>jar-snapshot</artifactId>
|
||||
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>jar</name>
|
||||
<description>Snapshot Jar dependency</description>
|
||||
</project>
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>aggregator</artifactId>
|
||||
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>@java.version@</maven.compiler.source>
|
||||
<maven.compiler.target>@java.version@</maven.compiler.target>
|
||||
</properties>
|
||||
<modules>
|
||||
<module>jar-snapshot</module>
|
||||
<module>jar-release</module>
|
||||
<module>war</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>aggregator</artifactId>
|
||||
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>war-layered</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>war</name>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>@project.groupId@</groupId>
|
||||
<artifactId>@project.artifactId@</artifactId>
|
||||
<version>@project.version@</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<layers>
|
||||
<includeLayerTools>false</includeLayerTools>
|
||||
</layers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>@maven-war-plugin.version@</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Not-Used>Foo</Not-Used>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>@spring-framework.version@</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<version>@jakarta-servlet.version@</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>jar-snapshot</artifactId>
|
||||
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>jar-release</artifactId>
|
||||
<version>0.0.1.RELEASE</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
* 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.test;
|
||||
|
||||
public class SampleApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
<html></html>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -180,12 +180,8 @@ public abstract class AbstractPackagerMojo extends AbstractDependencyFilterMojo
|
|||
return packager;
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private boolean getIncludeRelevantJarModeJars() {
|
||||
if (!this.includeTools) {
|
||||
return false;
|
||||
}
|
||||
return this.layers.isIncludeLayerTools();
|
||||
return this.includeTools;
|
||||
}
|
||||
|
||||
private CustomLayers getCustomLayers(File configuration) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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,9 +28,6 @@ public class Layers {
|
|||
|
||||
private boolean enabled = true;
|
||||
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
private boolean includeLayerTools = true;
|
||||
|
||||
private File configuration;
|
||||
|
||||
/**
|
||||
|
|
@ -41,16 +38,6 @@ public class Layers {
|
|||
return this.enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to include the layer tools jar.
|
||||
* @return true if layer tools should be included
|
||||
* @deprecated since 3.3.0 for removal in 3.5.0 in favor of {@code includeTools}.
|
||||
*/
|
||||
@Deprecated(since = "3.3.0", forRemoval = true)
|
||||
public boolean isIncludeLayerTools() {
|
||||
return this.includeLayerTools;
|
||||
}
|
||||
|
||||
/**
|
||||
* The location of the layers configuration file. If no file is provided, a default
|
||||
* configuration is used with four layers: {@code application}, {@code resources},
|
||||
|
|
|
|||
Loading…
Reference in New Issue