Drop support for Wavefront

Closes gh-45713
This commit is contained in:
Phillip Webb
2025-05-28 12:16:25 -07:00
parent b0a76bca0f
commit 6e67dc652d
25 changed files with 5 additions and 2316 deletions

View File

@@ -33,7 +33,6 @@ dependencies {
optional("io.micrometer:micrometer-tracing")
optional("io.micrometer:micrometer-tracing-bridge-brave")
optional("io.micrometer:micrometer-tracing-bridge-otel")
optional("io.micrometer:micrometer-tracing-reporter-wavefront")
optional("io.micrometer:micrometer-registry-appoptics")
optional("io.micrometer:micrometer-registry-atlas") {
exclude group: "javax.inject", module: "javax.inject"
@@ -55,7 +54,6 @@ dependencies {
}
optional("io.micrometer:micrometer-registry-signalfx")
optional("io.micrometer:micrometer-registry-statsd")
optional("io.micrometer:micrometer-registry-wavefront")
optional("io.zipkin.reporter2:zipkin-reporter-brave")
optional("io.opentelemetry:opentelemetry-exporter-zipkin")
optional("io.opentelemetry:opentelemetry-exporter-otlp")

View File

@@ -1,91 +0,0 @@
/*
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront;
import java.util.Map;
import com.wavefront.sdk.common.WavefrontSender;
import com.wavefront.sdk.common.application.ApplicationTags;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import io.micrometer.wavefront.WavefrontConfig;
import io.micrometer.wavefront.WavefrontMeterRegistry;
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.export.ConditionalOnEnabledMetricsExport;
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontSenderConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
/**
* {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Wavefront.
*
* @author Jon Schneider
* @author Artsiom Yudovin
* @author Stephane Nicoll
* @author Glenn Oppegard
* @since 2.0.0
*/
@AutoConfiguration(
before = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },
after = { MetricsAutoConfiguration.class, WavefrontAutoConfiguration.class })
@ConditionalOnBean(Clock.class)
@ConditionalOnClass({ WavefrontMeterRegistry.class, WavefrontSender.class })
@ConditionalOnEnabledMetricsExport("wavefront")
@EnableConfigurationProperties(WavefrontProperties.class)
@Import(WavefrontSenderConfiguration.class)
public class WavefrontMetricsExportAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public WavefrontConfig wavefrontConfig(WavefrontProperties properties) {
return new WavefrontPropertiesConfigAdapter(properties);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(WavefrontSender.class)
public WavefrontMeterRegistry wavefrontMeterRegistry(WavefrontConfig wavefrontConfig, Clock clock,
WavefrontSender wavefrontSender) {
return WavefrontMeterRegistry.builder(wavefrontConfig).clock(clock).wavefrontSender(wavefrontSender).build();
}
@Bean
@ConditionalOnBean(ApplicationTags.class)
MeterRegistryCustomizer<WavefrontMeterRegistry> wavefrontApplicationTagsCustomizer(
ApplicationTags wavefrontApplicationTags) {
Tags commonTags = Tags.of(wavefrontApplicationTags.toPointTags().entrySet().stream().map(this::asTag).toList());
return (registry) -> registry.config().commonTags(commonTags);
}
private Tag asTag(Map.Entry<String, String> entry) {
return Tag.of(entry.getKey(), entry.getValue());
}
}

View File

@@ -1,93 +0,0 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront;
import com.wavefront.sdk.common.clients.service.token.TokenService.Type;
import io.micrometer.wavefront.WavefrontConfig;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PushRegistryPropertiesConfigAdapter;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties.Metrics.Export;
/**
* Adapter to convert {@link WavefrontProperties} to a {@link WavefrontConfig}.
*
* @author Jon Schneider
* @author Moritz Halbritter
* @since 2.0.0
*/
public class WavefrontPropertiesConfigAdapter
extends PushRegistryPropertiesConfigAdapter<WavefrontProperties.Metrics.Export> implements WavefrontConfig {
private final WavefrontProperties properties;
public WavefrontPropertiesConfigAdapter(WavefrontProperties properties) {
super(properties.getMetrics().getExport());
this.properties = properties;
}
@Override
public String prefix() {
return "management.wavefront.metrics.export";
}
@Override
public String uri() {
return this.properties.getEffectiveUri().toString();
}
@Override
public String source() {
return this.properties.getSourceOrDefault();
}
@Override
public int batchSize() {
return this.properties.getSender().getBatchSize();
}
@Override
public String apiToken() {
return this.properties.getApiTokenOrThrow();
}
@Override
public String globalPrefix() {
return get(Export::getGlobalPrefix, WavefrontConfig.super::globalPrefix);
}
@Override
public boolean reportMinuteDistribution() {
return get(Export::isReportMinuteDistribution, WavefrontConfig.super::reportMinuteDistribution);
}
@Override
public boolean reportHourDistribution() {
return get(Export::isReportHourDistribution, WavefrontConfig.super::reportHourDistribution);
}
@Override
public boolean reportDayDistribution() {
return get(Export::isReportDayDistribution, WavefrontConfig.super::reportDayDistribution);
}
@Override
public Type apiTokenType() {
return this.properties.getWavefrontApiTokenType();
}
}

View File

@@ -1,20 +0,0 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.
*/
/**
* Support for exporting actuator metrics to Wavefront.
*/
package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront;

View File

@@ -1,76 +0,0 @@
/*
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.tracing.wavefront;
import java.util.concurrent.BlockingQueue;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.tracing.reporter.wavefront.SpanMetrics;
/**
* Bridges {@link SpanMetrics} to a {@link MeterRegistry}.
*
* @author Moritz Halbritter
*/
class MeterRegistrySpanMetrics implements SpanMetrics {
private final Counter spansReceived;
private final Counter spansDropped;
private final Counter reportErrors;
private final MeterRegistry meterRegistry;
MeterRegistrySpanMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.spansReceived = meterRegistry.counter("wavefront.reporter.spans.received");
this.spansDropped = meterRegistry.counter("wavefront.reporter.spans.dropped");
this.reportErrors = meterRegistry.counter("wavefront.reporter.errors");
}
@Override
public void reportDropped() {
this.spansDropped.increment();
}
@Override
public void reportReceived() {
this.spansReceived.increment();
}
@Override
public void reportErrors() {
this.reportErrors.increment();
}
@Override
public void registerQueueSize(BlockingQueue<?> queue) {
this.meterRegistry.gauge("wavefront.reporter.queue.size", queue, (q) -> (double) q.size());
}
@Override
public void registerQueueRemainingCapacity(BlockingQueue<?> queue) {
this.meterRegistry.gauge("wavefront.reporter.queue.remaining_capacity", queue, this::remainingCapacity);
}
private double remainingCapacity(BlockingQueue<?> queue) {
return queue.remainingCapacity();
}
}

View File

@@ -1,119 +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.wavefront;
import brave.handler.SpanHandler;
import com.wavefront.sdk.common.WavefrontSender;
import com.wavefront.sdk.common.application.ApplicationTags;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.tracing.reporter.wavefront.SpanMetrics;
import io.micrometer.tracing.reporter.wavefront.WavefrontBraveSpanHandler;
import io.micrometer.tracing.reporter.wavefront.WavefrontOtelSpanExporter;
import io.micrometer.tracing.reporter.wavefront.WavefrontSpanHandler;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.ConditionalOnEnabledTracing;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontSenderConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Wavefront tracing.
*
* @author Moritz Halbritter
* @author Glenn Oppegard
* @since 3.0.0
*/
@AutoConfiguration(after = { MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class,
WavefrontAutoConfiguration.class })
@ConditionalOnClass({ WavefrontSender.class, WavefrontSpanHandler.class })
@EnableConfigurationProperties(WavefrontProperties.class)
@Import(WavefrontSenderConfiguration.class)
public class WavefrontTracingAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(WavefrontSender.class)
@ConditionalOnEnabledTracing("wavefront")
WavefrontSpanHandler wavefrontSpanHandler(WavefrontProperties properties, WavefrontSender wavefrontSender,
SpanMetrics spanMetrics, ApplicationTags applicationTags) {
return new WavefrontSpanHandler(properties.getSender().getMaxQueueSize(), wavefrontSender, spanMetrics,
properties.getSourceOrDefault(), applicationTags, properties.getTraceDerivedCustomTagKeys());
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(MeterRegistry.class)
static class MeterRegistrySpanMetricsConfiguration {
@Bean
@ConditionalOnMissingBean
MeterRegistrySpanMetrics meterRegistrySpanMetrics(MeterRegistry meterRegistry) {
return new MeterRegistrySpanMetrics(meterRegistry);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(MeterRegistry.class)
static class NoopSpanMetricsConfiguration {
@Bean
@ConditionalOnMissingBean
SpanMetrics meterRegistrySpanMetrics() {
return SpanMetrics.NOOP;
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SpanHandler.class)
static class WavefrontBrave {
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledTracing("wavefront")
WavefrontBraveSpanHandler wavefrontBraveSpanHandler(WavefrontSpanHandler wavefrontSpanHandler) {
return new WavefrontBraveSpanHandler(wavefrontSpanHandler);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SpanExporter.class)
static class WavefrontOpenTelemetry {
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledTracing("wavefront")
WavefrontOtelSpanExporter wavefrontOtelSpanExporter(WavefrontSpanHandler wavefrontSpanHandler) {
return new WavefrontOtelSpanExporter(wavefrontSpanHandler);
}
}
}

View File

@@ -1,20 +0,0 @@
/*
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Auto-configuration for tracing with Wavefront.
*/
package org.springframework.boot.actuate.autoconfigure.tracing.wavefront;

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.wavefront;
import com.wavefront.sdk.common.WavefrontSender;
import com.wavefront.sdk.common.application.ApplicationTags;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties.Application;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Wavefront common infrastructure.
*
* @author Moritz Halbritter
* @author Glenn Oppegard
* @author Phillip Webb
* @since 3.0.0
*/
@AutoConfiguration
@ConditionalOnClass({ ApplicationTags.class, WavefrontSender.class })
@EnableConfigurationProperties(WavefrontProperties.class)
public class WavefrontAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public ApplicationTags wavefrontApplicationTags(Environment environment, WavefrontProperties properties) {
Application application = properties.getApplication();
String serviceName = application.getServiceName();
serviceName = (StringUtils.hasText(serviceName)) ? serviceName
: environment.getProperty("spring.application.name", "unnamed_service");
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
ApplicationTags.Builder builder = new ApplicationTags.Builder(application.getName(), serviceName);
map.from(application::getClusterName).to(builder::cluster);
map.from(application::getShardName).to(builder::shard);
map.from(application::getCustomTags).to(builder::customTags);
return builder.build();
}
}

View File

@@ -1,446 +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.wavefront;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.time.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.wavefront.sdk.common.clients.service.token.TokenService.Type;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PushRegistryProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
import org.springframework.util.unit.DataSize;
/**
* Configuration properties to configure Wavefront.
*
* @author Moritz Halbritter
* @author Glenn Oppegard
* @since 3.0.0
*/
@ConfigurationProperties("management.wavefront")
public class WavefrontProperties {
/**
* URI to ship metrics and traces to.
*/
private URI uri = URI.create("https://longboard.wavefront.com");
/**
* Unique identifier for the app instance that is the source of metrics and traces
* being published to Wavefront. Defaults to the local host name.
*/
private String source;
/**
* API token used when publishing metrics and traces directly to the Wavefront API
* host.
*/
private String apiToken;
/**
* Type of the API token.
*/
private TokenType apiTokenType;
/**
* Application configuration.
*/
private final Application application = new Application();
/**
* Sender configuration.
*/
private final Sender sender = new Sender();
/**
* Metrics configuration.
*/
private final Metrics metrics = new Metrics();
/**
* Customized span tags for RED metrics.
*/
private Set<String> traceDerivedCustomTagKeys = new HashSet<>();
public Application getApplication() {
return this.application;
}
public Sender getSender() {
return this.sender;
}
public Metrics getMetrics() {
return this.metrics;
}
public URI getUri() {
return this.uri;
}
public void setUri(URI uri) {
this.uri = uri;
}
public String getSource() {
return this.source;
}
public void setSource(String source) {
this.source = source;
}
public String getApiToken() {
return this.apiToken;
}
public void setApiToken(String apiToken) {
this.apiToken = apiToken;
}
/**
* Returns the effective URI of the wavefront instance. This will not be the same URI
* given through {@link #setUri(URI)} when a proxy is used.
* @return the effective URI of the wavefront instance
*/
public URI getEffectiveUri() {
if (usesProxy()) {
// See io.micrometer.wavefront.WavefrontMeterRegistry.getWavefrontReportingUri
return URI.create(this.uri.toString().replace("proxy://", "http://"));
}
return this.uri;
}
/**
* Returns the API token or throws an exception if the API token is mandatory. If a
* proxy is used, the API token is optional.
* @return the API token
*/
public String getApiTokenOrThrow() {
if (this.apiTokenType != TokenType.NO_TOKEN && this.apiToken == null && !usesProxy()) {
throw new InvalidConfigurationPropertyValueException("management.wavefront.api-token", null,
"This property is mandatory whenever publishing directly to the Wavefront API");
}
return this.apiToken;
}
public String getSourceOrDefault() {
if (this.source != null) {
return this.source;
}
return getSourceDefault();
}
private String getSourceDefault() {
try {
return InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException ex) {
return "unknown";
}
}
private boolean usesProxy() {
return "proxy".equals(this.uri.getScheme());
}
public Set<String> getTraceDerivedCustomTagKeys() {
return this.traceDerivedCustomTagKeys;
}
public void setTraceDerivedCustomTagKeys(Set<String> traceDerivedCustomTagKeys) {
this.traceDerivedCustomTagKeys = traceDerivedCustomTagKeys;
}
public TokenType getApiTokenType() {
return this.apiTokenType;
}
public void setApiTokenType(TokenType apiTokenType) {
this.apiTokenType = apiTokenType;
}
/**
* Returns the {@link Type Wavefront token type}.
* @return the Wavefront token type
* @since 3.2.0
*/
public Type getWavefrontApiTokenType() {
if (this.apiTokenType == null) {
return usesProxy() ? Type.NO_TOKEN : Type.WAVEFRONT_API_TOKEN;
}
return switch (this.apiTokenType) {
case NO_TOKEN -> Type.NO_TOKEN;
case WAVEFRONT_API_TOKEN -> Type.WAVEFRONT_API_TOKEN;
case CSP_API_TOKEN -> Type.CSP_API_TOKEN;
case CSP_CLIENT_CREDENTIALS -> Type.CSP_CLIENT_CREDENTIALS;
};
}
public static class Application {
/**
* Wavefront 'Application' name used in ApplicationTags.
*/
private String name = "unnamed_application";
/**
* Wavefront 'Service' name used in ApplicationTags, falling back to
* 'spring.application.name'. If both are unset it defaults to 'unnamed_service'.
*/
private String serviceName;
/**
* Wavefront Cluster name used in ApplicationTags.
*/
private String clusterName;
/**
* Wavefront Shard name used in ApplicationTags.
*/
private String shardName;
/**
* Wavefront custom tags used in ApplicationTags.
*/
private Map<String, String> customTags = new HashMap<>();
public String getServiceName() {
return this.serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getClusterName() {
return this.clusterName;
}
public void setClusterName(String clusterName) {
this.clusterName = clusterName;
}
public String getShardName() {
return this.shardName;
}
public void setShardName(String shardName) {
this.shardName = shardName;
}
public Map<String, String> getCustomTags() {
return this.customTags;
}
public void setCustomTags(Map<String, String> customTags) {
this.customTags = customTags;
}
}
public static class Sender {
/**
* Maximum size of queued messages.
*/
private int maxQueueSize = 50000;
/**
* Flush interval to send queued messages.
*/
private Duration flushInterval = Duration.ofSeconds(1);
/**
* Maximum size of a message.
*/
private DataSize messageSize = DataSize.ofBytes(Integer.MAX_VALUE);
/**
* Number of measurements per request to use for Wavefront. If more measurements
* are found, then multiple requests will be made.
*/
private int batchSize = 10000;
public int getMaxQueueSize() {
return this.maxQueueSize;
}
public void setMaxQueueSize(int maxQueueSize) {
this.maxQueueSize = maxQueueSize;
}
public Duration getFlushInterval() {
return this.flushInterval;
}
public void setFlushInterval(Duration flushInterval) {
this.flushInterval = flushInterval;
}
public DataSize getMessageSize() {
return this.messageSize;
}
public void setMessageSize(DataSize messageSize) {
this.messageSize = messageSize;
}
public int getBatchSize() {
return this.batchSize;
}
public void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}
}
public static class Metrics {
/**
* Export configuration.
*/
private Export export = new Export();
public Export getExport() {
return this.export;
}
public void setExport(Export export) {
this.export = export;
}
public static class Export extends PushRegistryProperties {
/**
* Global prefix to separate metrics originating from this app's
* instrumentation from those originating from other Wavefront integrations
* when viewed in the Wavefront UI.
*/
private String globalPrefix;
/**
* Whether to report histogram distributions aggregated into minute intervals.
*/
private boolean reportMinuteDistribution = true;
/**
* Whether to report histogram distributions aggregated into hour intervals.
*/
private boolean reportHourDistribution;
/**
* Whether to report histogram distributions aggregated into day intervals.
*/
private boolean reportDayDistribution;
public String getGlobalPrefix() {
return this.globalPrefix;
}
public void setGlobalPrefix(String globalPrefix) {
this.globalPrefix = globalPrefix;
}
/**
* See {@link PushRegistryProperties#getBatchSize()}.
*/
@Override
public Integer getBatchSize() {
throw new UnsupportedOperationException("Use Sender.getBatchSize() instead");
}
/**
* See {@link PushRegistryProperties#setBatchSize(Integer)}.
*/
@Override
public void setBatchSize(Integer batchSize) {
throw new UnsupportedOperationException("Use Sender.setBatchSize(int) instead");
}
public boolean isReportMinuteDistribution() {
return this.reportMinuteDistribution;
}
public void setReportMinuteDistribution(boolean reportMinuteDistribution) {
this.reportMinuteDistribution = reportMinuteDistribution;
}
public boolean isReportHourDistribution() {
return this.reportHourDistribution;
}
public void setReportHourDistribution(boolean reportHourDistribution) {
this.reportHourDistribution = reportHourDistribution;
}
public boolean isReportDayDistribution() {
return this.reportDayDistribution;
}
public void setReportDayDistribution(boolean reportDayDistribution) {
this.reportDayDistribution = reportDayDistribution;
}
}
}
/**
* Wavefront token type.
*
* @since 3.2.0
*/
public enum TokenType {
/**
* No token.
*/
NO_TOKEN,
/**
* Wavefront API token.
*/
WAVEFRONT_API_TOKEN,
/**
* CSP API token.
*/
CSP_API_TOKEN,
/**
* CSP client credentials.
*/
CSP_CLIENT_CREDENTIALS
}
}

View File

@@ -1,84 +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.wavefront;
import java.time.Duration;
import com.wavefront.sdk.common.WavefrontSender;
import com.wavefront.sdk.common.clients.WavefrontClient.Builder;
import org.springframework.boot.actuate.autoconfigure.metrics.export.ConditionalOnEnabledMetricsExport;
import org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront.WavefrontMetricsExportAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.ConditionalOnEnabledTracing;
import org.springframework.boot.actuate.autoconfigure.tracing.wavefront.WavefrontTracingAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.unit.DataSize;
/**
* Configuration for {@link WavefrontSender}. This configuration is imported from
* {@link WavefrontMetricsExportAutoConfiguration} and
* {@link WavefrontTracingAutoConfiguration}.
*
* @author Moritz Halbritter
* @since 3.0.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(WavefrontSender.class)
@EnableConfigurationProperties(WavefrontProperties.class)
public class WavefrontSenderConfiguration {
@Bean
@ConditionalOnMissingBean
@Conditional(WavefrontTracingOrMetricsCondition.class)
public WavefrontSender wavefrontSender(WavefrontProperties properties) {
Builder builder = new Builder(properties.getEffectiveUri().toString(), properties.getWavefrontApiTokenType(),
properties.getApiTokenOrThrow());
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
WavefrontProperties.Sender sender = properties.getSender();
map.from(sender.getMaxQueueSize()).to(builder::maxQueueSize);
map.from(sender.getFlushInterval()).asInt(Duration::getSeconds).to(builder::flushIntervalSeconds);
map.from(sender.getMessageSize()).asInt(DataSize::toBytes).to(builder::messageSizeBytes);
map.from(sender.getBatchSize()).to(builder::batchSize);
return builder.build();
}
static final class WavefrontTracingOrMetricsCondition extends AnyNestedCondition {
WavefrontTracingOrMetricsCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnEnabledTracing("wavefront")
static class TracingCondition {
}
@ConditionalOnEnabledMetricsExport("wavefront")
static class MetricsCondition {
}
}
}

View File

@@ -1,20 +0,0 @@
/*
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Classes shared between Wavefront tracing and metrics.
*/
package org.springframework.boot.actuate.autoconfigure.wavefront;

View File

@@ -1823,107 +1823,6 @@
"level": "error"
}
},
{
"name": "management.metrics.export.wavefront.api-token",
"type": "java.lang.String",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.api-token"
}
},
{
"name": "management.metrics.export.wavefront.batch-size",
"type": "java.lang.Integer",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.sender.batch-size"
}
},
{
"name": "management.metrics.export.wavefront.connect-timeout",
"type": "java.time.Duration",
"deprecation": {
"level": "error"
}
},
{
"name": "management.metrics.export.wavefront.enabled",
"type": "java.lang.Boolean",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.metrics.export.enabled"
}
},
{
"name": "management.metrics.export.wavefront.global-prefix",
"type": "java.lang.String",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.metrics.export.global-prefix"
}
},
{
"name": "management.metrics.export.wavefront.num-threads",
"type": "java.lang.Integer",
"deprecation": {
"level": "error"
}
},
{
"name": "management.metrics.export.wavefront.read-timeout",
"type": "java.time.Duration",
"deprecation": {
"level": "error"
}
},
{
"name": "management.metrics.export.wavefront.sender.flush-interval",
"type": "java.time.Duration",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.sender.flush-interval"
}
},
{
"name": "management.metrics.export.wavefront.sender.max-queue-size",
"type": "java.lang.Integer",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.sender.max-queue-size"
}
},
{
"name": "management.metrics.export.wavefront.sender.message-size",
"type": "org.springframework.util.unit.DataSize",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.sender.message-size"
}
},
{
"name": "management.metrics.export.wavefront.source",
"type": "java.lang.String",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.source"
}
},
{
"name": "management.metrics.export.wavefront.step",
"type": "java.time.Duration",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.metrics.export.step"
}
},
{
"name": "management.metrics.export.wavefront.uri",
"type": "java.net.URI",
"deprecation": {
"level": "error",
"replacement": "management.wavefront.uri"
}
},
{
"name": "management.metrics.graphql.autotime.enabled",
"description": "Whether to automatically time web client requests.",
@@ -2146,11 +2045,6 @@
"W3C"
]
},
{
"name": "management.wavefront.tracing.export.enabled",
"type": "java.lang.Boolean",
"description": "Whether auto-configuration of tracing is enabled to export Wavefront traces."
},
{
"name": "management.zipkin.tracing.encoding",
"defaultValue": [

View File

@@ -69,7 +69,6 @@ org.springframework.boot.actuate.autoconfigure.metrics.export.signalfx.SignalFxM
org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration
org.springframework.boot.actuate.autoconfigure.metrics.export.stackdriver.StackdriverMetricsExportAutoConfiguration
org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdMetricsExportAutoConfiguration
org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront.WavefrontMetricsExportAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.batch.BatchObservationAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.graphql.GraphQlObservationAutoConfiguration
org.springframework.boot.actuate.autoconfigure.metrics.integration.IntegrationMetricsAutoConfiguration
@@ -112,9 +111,7 @@ 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.wavefront.WavefrontTracingAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinAutoConfiguration
org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.mappings.MappingsEndpointAutoConfiguration

View File

@@ -1,213 +0,0 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront;
import java.util.Map;
import com.wavefront.sdk.common.WavefrontSender;
import com.wavefront.sdk.common.application.ApplicationTags;
import io.micrometer.core.instrument.Clock;
import io.micrometer.wavefront.WavefrontConfig;
import io.micrometer.wavefront.WavefrontMeterRegistry;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
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.mockito.Mockito.mock;
/**
* Tests for {@link WavefrontMetricsExportAutoConfiguration}.
*
* @author Jon Schneider
* @author Stephane Nicoll
* @author Glenn Oppegard
*/
class WavefrontMetricsExportAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(
AutoConfigurations.of(WavefrontAutoConfiguration.class, WavefrontMetricsExportAutoConfiguration.class));
@Test
void backsOffWithoutAClock() {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(WavefrontMeterRegistry.class));
}
@Test
void autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.withPropertyValues("management.wavefront.api-token=abcde",
"management.defaults.metrics.export.enabled=false")
.run((context) -> assertThat(context).doesNotHaveBean(WavefrontMeterRegistry.class)
.doesNotHaveBean(WavefrontConfig.class));
}
@Test
void autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.withPropertyValues("management.wavefront.api-token=abcde",
"management.wavefront.metrics.export.enabled=false")
.run((context) -> assertThat(context).doesNotHaveBean(WavefrontMeterRegistry.class)
.doesNotHaveBean(WavefrontConfig.class));
}
@Test
void allowsConfigToBeCustomized() {
this.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(Clock.class)
.hasSingleBean(WavefrontMeterRegistry.class)
.hasSingleBean(WavefrontConfig.class)
.hasSingleBean(WavefrontSender.class)
.hasBean("customConfig"));
}
@Test
void allowsRegistryToBeCustomized() {
this.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)
.withPropertyValues("management.wavefront.api-token=abcde")
.run((context) -> assertThat(context).hasSingleBean(Clock.class)
.hasSingleBean(WavefrontConfig.class)
.hasSingleBean(WavefrontMeterRegistry.class)
.hasBean("customRegistry"));
}
@Test
void exportsApplicationTagsInWavefrontRegistryWhenApplicationTagsBean() {
ApplicationTags.Builder builder = new ApplicationTags.Builder("super-application", "super-service");
builder.cluster("super-cluster");
builder.shard("super-shard");
builder.customTags(Map.of("custom-key", "custom-val"));
this.contextRunner.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class))
.withUserConfiguration(BaseConfiguration.class)
.withBean(ApplicationTags.class, builder::build)
.run((context) -> {
WavefrontMeterRegistry registry = context.getBean(WavefrontMeterRegistry.class);
registry.counter("my.counter", "env", "qa");
assertThat(registry.find("my.counter")
.tags("env", "qa")
.tags("application", "super-application")
.tags("service", "super-service")
.tags("cluster", "super-cluster")
.tags("shard", "super-shard")
.tags("custom-key", "custom-val")
.counter()).isNotNull();
});
}
@Test
void exportsApplicationTagsInWavefrontRegistryWhenInProperties() {
this.contextRunner.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class))
.withPropertyValues("management.wavefront.application.service-name=super-service",
"management.wavefront.application.name=super-application",
"management.wavefront.application.cluster-name=super-cluster",
"management.wavefront.application.shard-name=super-shard")
.withUserConfiguration(BaseConfiguration.class)
.run((context) -> {
WavefrontMeterRegistry registry = context.getBean(WavefrontMeterRegistry.class);
registry.counter("my.counter", "env", "qa");
assertThat(registry.find("my.counter")
.tags("env", "qa")
.tags("application", "super-application")
.tags("service", "super-service")
.tags("cluster", "super-cluster")
.tags("shard", "super-shard")
.counter()).isNotNull();
});
}
@Test
void stopsMeterRegistryWhenContextIsClosed() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.withPropertyValues("management.wavefront.api-token=abcde")
.run((context) -> {
WavefrontMeterRegistry registry = context.getBean(WavefrontMeterRegistry.class);
assertThat(registry.isClosed()).isFalse();
context.close();
assertThat(registry.isClosed()).isTrue();
});
}
@Configuration(proxyBeanMethods = false)
static class BaseConfiguration {
@Bean
WavefrontSender customWavefrontSender() {
return mock(WavefrontSender.class);
}
@Bean
Clock clock() {
return Clock.SYSTEM;
}
}
@Configuration(proxyBeanMethods = false)
@Import(BaseConfiguration.class)
static class CustomConfigConfiguration {
@Bean
WavefrontConfig customConfig() {
return new WavefrontConfig() {
@Override
public String get(String key) {
return null;
}
@Override
public String uri() {
return WavefrontConfig.DEFAULT_DIRECT.uri();
}
@Override
public String apiToken() {
return "abc-def";
}
};
}
}
@Configuration(proxyBeanMethods = false)
@Import(BaseConfiguration.class)
static class CustomSenderConfiguration {
@Bean
WavefrontSender customSender() {
return mock(WavefrontSender.class);
}
}
@Configuration(proxyBeanMethods = false)
@Import(BaseConfiguration.class)
static class CustomRegistryConfiguration {
@Bean
WavefrontMeterRegistry customRegistry(WavefrontConfig config, Clock clock) {
return new WavefrontMeterRegistry(config, clock);
}
}
}

View File

@@ -1,130 +0,0 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront;
import java.net.URI;
import com.wavefront.sdk.common.clients.service.token.TokenService.Type;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PushRegistryPropertiesConfigAdapterTests;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties.Metrics.Export;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties.TokenType;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link WavefrontPropertiesConfigAdapter}.
*
* @author Stephane Nicoll
* @author Moritz Halbritter
*/
class WavefrontPropertiesConfigAdapterTests extends
PushRegistryPropertiesConfigAdapterTests<WavefrontProperties.Metrics.Export, WavefrontPropertiesConfigAdapter> {
protected WavefrontPropertiesConfigAdapterTests() {
super(WavefrontPropertiesConfigAdapter.class);
}
@Override
protected WavefrontProperties.Metrics.Export createProperties() {
return new WavefrontProperties.Metrics.Export();
}
@Override
protected WavefrontPropertiesConfigAdapter createConfigAdapter(WavefrontProperties.Metrics.Export export) {
WavefrontProperties properties = new WavefrontProperties();
properties.getMetrics().setExport(export);
return new WavefrontPropertiesConfigAdapter(properties);
}
@Test
void whenPropertiesGlobalPrefixIsSetAdapterGlobalPrefixReturnsIt() {
Export properties = createProperties();
properties.setGlobalPrefix("test");
assertThat(createConfigAdapter(properties).globalPrefix()).isEqualTo("test");
}
@Override
protected void whenPropertiesBatchSizeIsSetAdapterBatchSizeReturnsIt() {
WavefrontProperties properties = new WavefrontProperties();
properties.getSender().setBatchSize(10042);
assertThat(new WavefrontPropertiesConfigAdapter(properties).batchSize()).isEqualTo(10042);
}
@Test
void whenPropertiesUriIsSetAdapterUriReturnsIt() {
WavefrontProperties properties = new WavefrontProperties();
properties.setUri(URI.create("https://example.wavefront.com"));
assertThat(new WavefrontPropertiesConfigAdapter(properties).uri()).isEqualTo("https://example.wavefront.com");
}
@Test
void whenPropertiesApiTokenIsSetAdapterApiTokenReturnsIt() {
WavefrontProperties properties = new WavefrontProperties();
properties.setApiToken("my-token");
assertThat(new WavefrontPropertiesConfigAdapter(properties).apiToken()).isEqualTo("my-token");
}
@Test
void whenPropertiesSourceIsSetAdapterSourceReturnsIt() {
WavefrontProperties properties = new WavefrontProperties();
properties.setSource("DESKTOP-GA5");
assertThat(new WavefrontPropertiesConfigAdapter(properties).source()).isEqualTo("DESKTOP-GA5");
}
@Test
void whenPropertiesReportMinuteDistributionIsSetAdapterReportMinuteDistributionReturnsIt() {
Export properties = createProperties();
properties.setReportMinuteDistribution(false);
assertThat(createConfigAdapter(properties).reportMinuteDistribution()).isFalse();
}
@Test
void whenPropertiesReportHourDistributionIsSetAdapterReportHourDistributionReturnsIt() {
Export properties = createProperties();
properties.setReportHourDistribution(true);
assertThat(createConfigAdapter(properties).reportHourDistribution()).isTrue();
}
@Test
void whenPropertiesReportDayDistributionIsSetAdapterReportDayDistributionReturnsIt() {
Export properties = createProperties();
properties.setReportDayDistribution(true);
assertThat(createConfigAdapter(properties).reportDayDistribution()).isTrue();
}
@ParameterizedTest
@CsvSource(textBlock = """
null, WAVEFRONT_API_TOKEN
NO_TOKEN, NO_TOKEN
WAVEFRONT_API_TOKEN, WAVEFRONT_API_TOKEN
CSP_API_TOKEN, CSP_API_TOKEN
CSP_CLIENT_CREDENTIALS, CSP_CLIENT_CREDENTIALS
""")
void whenTokenTypeIsSetAdapterReturnsIt(String property, String wavefront) {
TokenType propertyTokenType = property.equals("null") ? null : TokenType.valueOf(property);
Type wavefrontTokenType = Type.valueOf(wavefront);
WavefrontProperties properties = new WavefrontProperties();
properties.setApiTokenType(propertyTokenType);
assertThat(new WavefrontPropertiesConfigAdapter(properties).apiTokenType()).isEqualTo(wavefrontTokenType);
}
}

View File

@@ -1,101 +0,0 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.tracing.wavefront;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link MeterRegistrySpanMetrics}.
*
* @author Moritz Halbritter
*/
class MeterRegistrySpanMetricsTests {
private SimpleMeterRegistry meterRegistry;
private MeterRegistrySpanMetrics sut;
@BeforeEach
void setUp() {
this.meterRegistry = new SimpleMeterRegistry();
this.sut = new MeterRegistrySpanMetrics(this.meterRegistry);
}
@Test
void reportDroppedShouldIncreaseCounter() {
this.sut.reportDropped();
assertThat(getCounterValue("wavefront.reporter.spans.dropped")).isOne();
this.sut.reportDropped();
assertThat(getCounterValue("wavefront.reporter.spans.dropped")).isEqualTo(2);
}
@Test
void reportReceivedShouldIncreaseCounter() {
this.sut.reportReceived();
assertThat(getCounterValue("wavefront.reporter.spans.received")).isOne();
this.sut.reportReceived();
assertThat(getCounterValue("wavefront.reporter.spans.received")).isEqualTo(2);
}
@Test
void reportErrorsShouldIncreaseCounter() {
this.sut.reportErrors();
assertThat(getCounterValue("wavefront.reporter.errors")).isOne();
this.sut.reportErrors();
assertThat(getCounterValue("wavefront.reporter.errors")).isEqualTo(2);
}
@Test
void registerQueueSizeShouldCreateGauge() {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(2);
this.sut.registerQueueSize(queue);
assertThat(getGaugeValue("wavefront.reporter.queue.size")).isZero();
queue.offer(1);
assertThat(getGaugeValue("wavefront.reporter.queue.size")).isOne();
}
@Test
void registerQueueRemainingCapacityShouldCreateGauge() {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(2);
this.sut.registerQueueRemainingCapacity(queue);
assertThat(getGaugeValue("wavefront.reporter.queue.remaining_capacity")).isEqualTo(2);
queue.offer(1);
assertThat(getGaugeValue("wavefront.reporter.queue.remaining_capacity")).isOne();
}
private double getGaugeValue(String name) {
Gauge gauge = this.meterRegistry.find(name).gauge();
assertThat(gauge).withFailMessage("Gauge '%s' not found", name).isNotNull();
return gauge.value();
}
private double getCounterValue(String name) {
Counter counter = this.meterRegistry.find(name).counter();
assertThat(counter).withFailMessage("Counter '%s' not found", name).isNotNull();
return counter.count();
}
}

View File

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

View File

@@ -61,11 +61,9 @@ class ZipkinConfigurationsBraveConfigurationTests {
@Test
void shouldNotSupplyIfZipkinReporterBraveIsNotOnClasspath() {
// Note: Technically, Brave can work without zipkin-reporter. For example,
// WavefrontSpanHandler doesn't require this to operate. If we remove this
// dependency enforcement when WavefrontSpanHandler is in use, we can resolve
// micrometer-metrics/tracing#509. We also need this for any configuration that
// uses senders defined in the Spring Boot source tree, such as HttpSender.
// Note: Technically, Brave can work without zipkin-reporter. We also need this
// for any configuration that uses senders defined in the Spring Boot source tree,
// such as HttpSender.
this.contextRunner.withClassLoader(new FilteredClassLoader("zipkin2.reporter.brave"))
.withUserConfiguration(SenderConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean(AsyncZipkinSpanHandler.class));

View File

@@ -1,100 +0,0 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.wavefront;
import java.util.ArrayList;
import java.util.List;
import com.wavefront.sdk.common.application.ApplicationTags;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link WavefrontAutoConfiguration}.
*
* @author Phillip Webb
*/
class WavefrontAutoConfigurationTests {
ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(WavefrontAutoConfiguration.class));
@Test
void wavefrontApplicationTagsWhenHasUserBeanBacksOff() {
this.contextRunner.withUserConfiguration(TestApplicationTagsConfiguration.class).run((context) -> {
ApplicationTags tags = context.getBean(ApplicationTags.class);
assertThat(tags.getApplication()).isEqualTo("test-application");
assertThat(tags.getService()).isEqualTo("test-service");
});
}
@Test
void wavefrontApplicationTagsMapsProperties() {
List<String> properties = new ArrayList<>();
properties.add("management.wavefront.application.name=test-application");
properties.add("management.wavefront.application.service-name=test-service");
properties.add("management.wavefront.application.cluster-name=test-cluster");
properties.add("management.wavefront.application.shard-name=test-shard");
properties.add("management.wavefront.application.custom-tags.foo=FOO");
properties.add("management.wavefront.application.custom-tags.bar=BAR");
this.contextRunner.withPropertyValues(properties.toArray(String[]::new)).run((context) -> {
ApplicationTags tags = context.getBean(ApplicationTags.class);
assertThat(tags.getApplication()).isEqualTo("test-application");
assertThat(tags.getService()).isEqualTo("test-service");
assertThat(tags.getCluster()).isEqualTo("test-cluster");
assertThat(tags.getShard()).isEqualTo("test-shard");
assertThat(tags.getCustomTags()).hasSize(2).containsEntry("foo", "FOO").containsEntry("bar", "BAR");
});
}
@Test
void wavefrontApplicationTagsWhenNoPropertiesUsesDefaults() {
this.contextRunner.withPropertyValues("spring.application.name=spring-app").run((context) -> {
ApplicationTags tags = context.getBean(ApplicationTags.class);
assertThat(tags.getApplication()).isEqualTo("unnamed_application");
assertThat(tags.getService()).isEqualTo("spring-app");
assertThat(tags.getCluster()).isNull();
assertThat(tags.getShard()).isNull();
assertThat(tags.getCustomTags()).isEmpty();
});
}
@Test
void wavefrontApplicationTagsWhenHasNoServiceNamePropertyAndNoSpringApplicationNameUsesDefault() {
this.contextRunner.run((context) -> {
ApplicationTags tags = context.getBean(ApplicationTags.class);
assertThat(tags.getService()).isEqualTo("unnamed_service");
});
}
@Configuration(proxyBeanMethods = false)
static class TestApplicationTagsConfiguration {
@Bean
ApplicationTags applicationTags() {
return new ApplicationTags.Builder("test-application", "test-service").build();
}
}
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.wavefront;
import io.micrometer.wavefront.WavefrontConfig;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link WavefrontProperties.Metrics.Export}.
*
* @author Stephane Nicoll
* @author Moritz Halbritter
*/
class WavefrontPropertiesMetricsExportTests {
@Test
@SuppressWarnings("deprecation")
void defaultValuesAreConsistent() {
WavefrontProperties.Metrics.Export properties = new WavefrontProperties.Metrics.Export();
WavefrontConfig config = WavefrontConfig.DEFAULT_DIRECT;
assertThat(properties.getConnectTimeout()).isEqualTo(config.connectTimeout());
assertThat(properties.getGlobalPrefix()).isEqualTo(config.globalPrefix());
assertThat(properties.getReadTimeout()).isEqualTo(config.readTimeout());
assertThat(properties.getStep()).isEqualTo(config.step());
assertThat(properties.isEnabled()).isEqualTo(config.enabled());
assertThat(properties.isReportMinuteDistribution()).isEqualTo(config.reportMinuteDistribution());
assertThat(properties.isReportHourDistribution()).isEqualTo(config.reportHourDistribution());
assertThat(properties.isReportDayDistribution()).isEqualTo(config.reportDayDistribution());
}
}

View File

@@ -1,91 +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.wavefront;
import java.net.URI;
import com.wavefront.sdk.common.clients.service.token.TokenService.Type;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties.TokenType;
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link WavefrontProperties}.
*
* @author Moritz Halbritter
*/
class WavefrontPropertiesTests {
@Test
void apiTokenIsOptionalWhenUsingProxy() {
WavefrontProperties properties = new WavefrontProperties();
properties.setUri(URI.create("proxy://localhost:2878"));
properties.setApiToken(null);
assertThat(properties.getApiTokenOrThrow()).isNull();
assertThat(properties.getEffectiveUri()).isEqualTo(URI.create("http://localhost:2878"));
}
@Test
void apiTokenIsMandatoryWhenNotUsingProxy() {
WavefrontProperties properties = new WavefrontProperties();
properties.setUri(URI.create("http://localhost:2878"));
properties.setApiToken(null);
assertThat(properties.getEffectiveUri()).isEqualTo(URI.create("http://localhost:2878"));
assertThatExceptionOfType(InvalidConfigurationPropertyValueException.class)
.isThrownBy(properties::getApiTokenOrThrow)
.withMessageContaining("management.wavefront.api-token");
}
@Test
void shouldNotFailIfTokenTypeIsSetToNoToken() {
WavefrontProperties properties = new WavefrontProperties();
properties.setUri(URI.create("http://localhost:2878"));
properties.setApiTokenType(TokenType.NO_TOKEN);
properties.setApiToken(null);
assertThat(properties.getApiTokenOrThrow()).isNull();
}
@Test
void wavefrontApiTokenTypeWhenUsingProxy() {
WavefrontProperties properties = new WavefrontProperties();
properties.setUri(URI.create("proxy://localhost:2878"));
assertThat(properties.getWavefrontApiTokenType()).isEqualTo(Type.NO_TOKEN);
}
@Test
void wavefrontApiTokenTypeWhenNotUsingProxy() {
WavefrontProperties properties = new WavefrontProperties();
properties.setUri(URI.create("http://localhost:2878"));
assertThat(properties.getWavefrontApiTokenType()).isEqualTo(Type.WAVEFRONT_API_TOKEN);
}
@ParameterizedTest
@EnumSource
void wavefrontApiTokenMapping(TokenType from) {
WavefrontProperties properties = new WavefrontProperties();
properties.setApiTokenType(from);
Type expected = Type.valueOf(from.name());
assertThat(properties.getWavefrontApiTokenType()).isEqualTo(expected);
}
}

View File

@@ -1,185 +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.wavefront;
import java.util.concurrent.LinkedBlockingQueue;
import com.wavefront.sdk.common.WavefrontSender;
import com.wavefront.sdk.common.clients.service.token.CSPTokenService;
import com.wavefront.sdk.common.clients.service.token.NoopProxyTokenService;
import com.wavefront.sdk.common.clients.service.token.WavefrontTokenService;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link WavefrontSenderConfiguration}.
*
* @author Moritz Halbritter
*/
class WavefrontSenderConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(WavefrontSenderConfiguration.class));
private final ApplicationContextRunner metricsDisabledContextRunner = this.contextRunner.withPropertyValues(
"management.defaults.metrics.export.enabled=false", "management.simple.metrics.export.enabled=true");
@Test
void shouldNotFailIfWavefrontIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("com.wavefront"))
.run(((context) -> assertThat(context).doesNotHaveBean(WavefrontSender.class)));
}
@Test
void failsWithoutAnApiTokenWhenPublishingDirectly() {
this.contextRunner.run((context) -> assertThat(context).hasFailed());
}
@Test
void defaultWavefrontSenderSettingsAreConsistent() {
this.contextRunner.withPropertyValues("management.wavefront.api-token=abcde").run((context) -> {
WavefrontProperties properties = new WavefrontProperties();
WavefrontSender sender = context.getBean(WavefrontSender.class);
assertThat(sender)
.extracting("metricsBuffer", as(InstanceOfAssertFactories.type(LinkedBlockingQueue.class)))
.satisfies((queue) -> assertThat(queue.remainingCapacity() + queue.size())
.isEqualTo(properties.getSender().getMaxQueueSize()));
assertThat(sender).hasFieldOrPropertyWithValue("batchSize", properties.getSender().getBatchSize());
assertThat(sender).hasFieldOrPropertyWithValue("messageSizeBytes",
(int) properties.getSender().getMessageSize().toBytes());
});
}
@Test
void configureWavefrontSender() {
this.contextRunner
.withPropertyValues("management.wavefront.api-token=abcde", "management.wavefront.sender.batch-size=50",
"management.wavefront.sender.max-queue-size=100", "management.wavefront.sender.message-size=1KB")
.run((context) -> {
WavefrontSender sender = context.getBean(WavefrontSender.class);
assertThat(sender).hasFieldOrPropertyWithValue("batchSize", 50);
assertThat(sender)
.extracting("metricsBuffer", as(InstanceOfAssertFactories.type(LinkedBlockingQueue.class)))
.satisfies((queue) -> assertThat(queue.remainingCapacity() + queue.size()).isEqualTo(100));
assertThat(sender).hasFieldOrPropertyWithValue("messageSizeBytes", 1024);
});
}
@Test
void shouldNotSupplyWavefrontSenderIfMetricsAndGlobalTracingIsDisabled() {
this.metricsDisabledContextRunner
.withPropertyValues("management.tracing.enabled=false", "management.wavefront.api-token=abcde")
.run((context) -> assertThat(context).doesNotHaveBean(WavefrontSender.class));
}
@Test
void shouldNotSupplyWavefrontSenderIfMetricsAndWavefrontTracingIsDisabled() {
this.metricsDisabledContextRunner
.withPropertyValues("management.wavefront.tracing.export.enabled=false",
"management.wavefront.api-token=abcde")
.run((context) -> assertThat(context).doesNotHaveBean(WavefrontSender.class));
}
@Test
void shouldSupplyWavefrontSenderIfOnlyGlobalTracingIsDisabled() {
this.contextRunner
.withPropertyValues("management.tracing.enabled=false", "management.wavefront.api-token=abcde")
.run((context) -> assertThat(context).hasSingleBean(WavefrontSender.class));
}
@Test
void shouldSupplyWavefrontSenderIfOnlyWavefrontTracingIsDisabled() {
this.contextRunner
.withPropertyValues("management.wavefront.tracing.export.enabled=false",
"management.wavefront.api-token=abcde")
.run((context) -> assertThat(context).hasSingleBean(WavefrontSender.class));
}
@Test
void shouldSupplyWavefrontSenderIfOnlyMetricsAreDisabled() {
this.metricsDisabledContextRunner.withPropertyValues("management.wavefront.api-token=abcde")
.run((context) -> assertThat(context).hasSingleBean(WavefrontSender.class));
}
@Test
void allowsWavefrontSenderToBeCustomized() {
this.contextRunner.withUserConfiguration(CustomSenderConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(WavefrontSender.class).hasBean("customSender"));
}
@Test
void shouldApplyTokenTypeWavefrontApiToken() {
this.contextRunner
.withPropertyValues("management.wavefront.api-token-type=WAVEFRONT_API_TOKEN",
"management.wavefront.api-token=abcde")
.run((context) -> {
WavefrontSender sender = context.getBean(WavefrontSender.class);
assertThat(sender).extracting("tokenService").isInstanceOf(WavefrontTokenService.class);
});
}
@Test
void shouldApplyTokenTypeCspApiToken() {
this.contextRunner
.withPropertyValues("management.wavefront.api-token-type=CSP_API_TOKEN",
"management.wavefront.api-token=abcde")
.run((context) -> {
WavefrontSender sender = context.getBean(WavefrontSender.class);
assertThat(sender).extracting("tokenService").isInstanceOf(CSPTokenService.class);
});
}
@Test
void shouldApplyTokenTypeCspClientCredentials() {
this.contextRunner
.withPropertyValues("management.wavefront.api-token-type=CSP_CLIENT_CREDENTIALS",
"management.wavefront.api-token=clientid=cid,clientsecret=csec")
.run((context) -> {
WavefrontSender sender = context.getBean(WavefrontSender.class);
assertThat(sender).extracting("tokenService").isInstanceOf(CSPTokenService.class);
});
}
@Test
void shouldApplyTokenTypeNoToken() {
this.contextRunner.withPropertyValues("management.wavefront.api-token-type=NO_TOKEN").run((context) -> {
WavefrontSender sender = context.getBean(WavefrontSender.class);
assertThat(sender).extracting("tokenService").isInstanceOf(NoopProxyTokenService.class);
});
}
@Configuration(proxyBeanMethods = false)
static class CustomSenderConfiguration {
@Bean
WavefrontSender customSender() {
return mock(WavefrontSender.class);
}
}
}

View File

@@ -1140,8 +1140,6 @@
* xref:reference:actuator/metrics.adoc#actuator.metrics.export.stackdriver[#production-ready-metrics-export-stackdriver]
* xref:reference:actuator/metrics.adoc#actuator.metrics.export.statsd[#actuator.metrics.export.statsd]
* xref:reference:actuator/metrics.adoc#actuator.metrics.export.statsd[#production-ready-metrics-export-statsd]
* xref:reference:actuator/metrics.adoc#actuator.metrics.export.wavefront[#actuator.metrics.export.wavefront]
* xref:reference:actuator/metrics.adoc#actuator.metrics.export.wavefront[#production-ready-metrics-export-wavefront]
* xref:reference:actuator/metrics.adoc#actuator.metrics.export[#actuator.metrics.export]
* xref:reference:actuator/metrics.adoc#actuator.metrics.export[#production-ready-metrics-export]
* xref:reference:actuator/metrics.adoc#actuator.metrics.getting-started[#actuator.metrics.getting-started]
@@ -1228,10 +1226,8 @@
* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.micrometer-observation[#actuator.micrometer-tracing.micrometer-observation]
* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.propagating-traces[#actuator.micrometer-tracing.propagating-traces]
* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tests[#actuator.micrometer-tracing.tests]
* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations.brave-wavefront[#actuator.micrometer-tracing.tracer-implementations.brave-wavefront]
* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations.brave-zipkin[#actuator.micrometer-tracing.tracer-implementations.brave-zipkin]
* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations.otel-otlp[#actuator.micrometer-tracing.tracer-implementations.otel-otlp]
* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations.otel-wavefront[#actuator.micrometer-tracing.tracer-implementations.otel-wavefront]
* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations.otel-zipkin[#actuator.micrometer-tracing.tracer-implementations.otel-zipkin]
* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations[#actuator.micrometer-tracing.tracer-implementations]
* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracers[#actuator.micrometer-tracing.tracers]

View File

@@ -20,7 +20,6 @@ Spring Boot Actuator provides dependency management and auto-configuration for {
- xref:actuator/metrics.adoc#actuator.metrics.export.simple[] (in-memory)
- xref:actuator/metrics.adoc#actuator.metrics.export.stackdriver[]
- xref:actuator/metrics.adoc#actuator.metrics.export.statsd[]
- xref:actuator/metrics.adoc#actuator.metrics.export.wavefront[]
TIP: To learn more about Micrometer's capabilities, see its {url-micrometer-docs}[reference documentation], in particular the {url-micrometer-docs-concepts}[concepts section].
@@ -650,43 +649,6 @@ management:
[[actuator.metrics.export.wavefront]]
=== Wavefront
The Wavefront registry periodically pushes metrics to {url-micrometer-docs-implementations}/wavefront[Wavefront].
If you are exporting metrics to https://www.wavefront.com/[Wavefront] directly, you must provide your API token:
[configprops,yaml]
----
management:
wavefront:
api-token: "YOUR_API_TOKEN"
----
Alternatively, you can use a Wavefront sidecar or an internal proxy in your environment to forward metrics data to the Wavefront API host:
[configprops,yaml]
----
management:
wavefront:
uri: "proxy://localhost:2878"
----
NOTE: If you publish metrics to a Wavefront proxy (as described in https://docs.wavefront.com/proxies_installing.html[the Wavefront documentation]), the host must be in the `proxy://HOST:PORT` format.
You can also change the interval at which metrics are sent to Wavefront:
[configprops,yaml]
----
management:
wavefront:
metrics:
export:
step: "30s"
----
[[actuator.metrics.supported]]
== Supported Metrics and Meters

View File

@@ -12,8 +12,8 @@ TIP: To learn more about Micrometer Tracing capabilities, see its {url-micromete
Spring Boot ships auto-configuration for the following tracers:
* https://opentelemetry.io/[OpenTelemetry] with https://zipkin.io/[Zipkin], https://docs.wavefront.com/[Wavefront], or https://opentelemetry.io/docs/reference/specification/protocol/[OTLP]
* https://github.com/openzipkin/brave[OpenZipkin Brave] with https://zipkin.io/[Zipkin] or https://docs.wavefront.com/[Wavefront]
* https://opentelemetry.io/[OpenTelemetry] with https://zipkin.io/[Zipkin] or https://opentelemetry.io/docs/reference/specification/protocol/[OTLP].
* https://github.com/openzipkin/brave[OpenZipkin Brave] with https://zipkin.io/[Zipkin].
@@ -128,18 +128,6 @@ Use the `management.zipkin.tracing.*` configuration properties to configure repo
[[actuator.micrometer-tracing.tracer-implementations.otel-wavefront]]
=== OpenTelemetry With Wavefront
Tracing with OpenTelemetry and reporting to Wavefront requires the following dependencies:
* `io.micrometer:micrometer-tracing-bridge-otel` - bridges the Micrometer Observation API to OpenTelemetry.
* `io.micrometer:micrometer-tracing-reporter-wavefront` - reports traces to Wavefront.
Use the `management.wavefront.*` configuration properties to configure reporting to Wavefront.
[[actuator.micrometer-tracing.tracer-implementations.otel-otlp]]
=== OpenTelemetry With OTLP
@@ -168,18 +156,6 @@ Use the `management.zipkin.tracing.*` configuration properties to configure repo
[[actuator.micrometer-tracing.tracer-implementations.brave-wavefront]]
=== OpenZipkin Brave With Wavefront
Tracing with OpenZipkin Brave and reporting to Wavefront requires the following dependencies:
* `io.micrometer:micrometer-tracing-bridge-brave` - bridges the Micrometer Observation API to Brave.
* `io.micrometer:micrometer-tracing-reporter-wavefront` - reports traces to Wavefront.
Use the `management.wavefront.*` configuration properties to configure reporting to Wavefront.
[[actuator.micrometer-tracing.micrometer-observation]]
== Integration with Micrometer Observation