GH-2302: Remove metrics related components
Resolves https://github.com/spring-cloud/spring-cloud-stream/issues/2302
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2021 the original author or authors.
|
||||
* Copyright 2015-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.
|
||||
@@ -50,7 +50,6 @@ import org.springframework.cloud.stream.binding.InputBindingLifecycle;
|
||||
import org.springframework.cloud.stream.binding.OutputBindingLifecycle;
|
||||
import org.springframework.cloud.stream.config.BindingHandlerAdvise.MappingsProvider;
|
||||
import org.springframework.cloud.stream.function.StreamFunctionProperties;
|
||||
import org.springframework.cloud.stream.micrometer.DestinationPublishingMetricsAutoConfiguration;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -82,8 +81,7 @@ import org.springframework.util.ObjectUtils;
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties({ BindingServiceProperties.class,
|
||||
SpringIntegrationProperties.class, StreamFunctionProperties.class })
|
||||
@Import({ DestinationPublishingMetricsAutoConfiguration.class,
|
||||
SpelExpressionConverterConfiguration.class })
|
||||
@Import({ SpelExpressionConverterConfiguration.class })
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
@ConditionalOnBean(value = BinderTypeRegistry.class, search = SearchStrategy.CURRENT)
|
||||
public class BindingServiceConfiguration {
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2018 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.cloud.stream.micrometer;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
|
||||
/**
|
||||
* @author Vinicius Carvalho
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
@JsonPropertyOrder({ "name", "inteval", "createdTime", "properties", "metrics" })
|
||||
class ApplicationMetrics {
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC")
|
||||
private final Date createdTime;
|
||||
|
||||
private String name;
|
||||
|
||||
private long interval;
|
||||
|
||||
private Collection<Metric<Number>> metrics;
|
||||
|
||||
private Map<String, Object> properties;
|
||||
|
||||
@JsonCreator
|
||||
ApplicationMetrics(@JsonProperty("name") String name,
|
||||
@JsonProperty("metrics") Collection<Metric<Number>> metrics) {
|
||||
this.name = name;
|
||||
this.metrics = metrics;
|
||||
this.createdTime = new Date();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Collection<Metric<Number>> getMetrics() {
|
||||
return this.metrics;
|
||||
}
|
||||
|
||||
public void setMetrics(Collection<Metric<Number>> metrics) {
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
public Date getCreatedTime() {
|
||||
return this.createdTime;
|
||||
}
|
||||
|
||||
public Map<String, Object> getProperties() {
|
||||
return this.properties;
|
||||
}
|
||||
|
||||
public void setProperties(Map<String, Object> properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public long getInterval() {
|
||||
return this.interval;
|
||||
}
|
||||
|
||||
public void setInterval(long interval) {
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2018 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.cloud.stream.micrometer;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanExpressionContext;
|
||||
import org.springframework.beans.factory.config.BeanExpressionResolver;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.bind.BindResult;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
/**
|
||||
* @author Vinicius Carvalho
|
||||
* @author Janne Valkealahti
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
@ConfigurationProperties(prefix = ApplicationMetricsProperties.PREFIX)
|
||||
public class ApplicationMetricsProperties
|
||||
implements EnvironmentAware, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Prefix for Stream application metrics.
|
||||
*/
|
||||
public static final String PREFIX = "spring.cloud.stream.metrics";
|
||||
|
||||
/**
|
||||
* Property for the metrics filter.
|
||||
*/
|
||||
public static final String EXPORT_FILTER = PREFIX + ".filter";
|
||||
|
||||
private static final Bindable<Map<String, String>> STRING_STRING_MAP = Bindable
|
||||
.mapOf(String.class, String.class);
|
||||
|
||||
/**
|
||||
* Pattern to control the 'meters' one wants to capture. By default all 'meters' will
|
||||
* be captured. For example, 'spring.integration.*' will only capture metric
|
||||
* information for meters whose name starts with 'spring.integration'.
|
||||
*/
|
||||
private String meterFilter;
|
||||
|
||||
/**
|
||||
* The name of the metric being emitted. Should be an unique value per application.
|
||||
* Defaults to:
|
||||
* ${spring.application.name:${vcap.application.name:${spring.config.name:application}}}.
|
||||
*/
|
||||
@Value("${spring.application.name:${vcap.application.name:${spring.config.name:application}}}")
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* Application properties that should be added to the metrics payload For example:
|
||||
* `spring.application**`.
|
||||
*/
|
||||
private String[] properties;
|
||||
|
||||
/**
|
||||
* Interval expressed as Duration for scheduling metrics snapshots publishing.
|
||||
* Defaults to 60 seconds
|
||||
*/
|
||||
private Duration scheduleInterval = Duration.ofSeconds(60);
|
||||
|
||||
/**
|
||||
* List of properties that are going to be appended to each message. This gets
|
||||
* populate by onApplicationEvent, once the context refreshes to avoid overhead of
|
||||
* doing per message basis.
|
||||
*/
|
||||
private Map<String, Object> exportProperties;
|
||||
|
||||
private Environment environment;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String[] getProperties() {
|
||||
return this.properties;
|
||||
}
|
||||
|
||||
public void setProperties(String[] properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public Map<String, Object> getExportProperties() {
|
||||
if (this.exportProperties == null) {
|
||||
this.exportProperties = buildExportProperties();
|
||||
}
|
||||
return this.exportProperties;
|
||||
}
|
||||
|
||||
public Duration getScheduleInterval() {
|
||||
return this.scheduleInterval;
|
||||
}
|
||||
|
||||
public void setScheduleInterval(Duration scheduleInterval) {
|
||||
this.scheduleInterval = scheduleInterval;
|
||||
}
|
||||
|
||||
public String getMeterFilter() {
|
||||
return this.meterFilter;
|
||||
}
|
||||
|
||||
public void setMeterFilter(String meterFilter) {
|
||||
this.meterFilter = meterFilter;
|
||||
}
|
||||
|
||||
private boolean isMatch(String name, String[] includes, String[] excludes) {
|
||||
if (ObjectUtils.isEmpty(includes)
|
||||
|| PatternMatchUtils.simpleMatch(includes, name)) {
|
||||
return !PatternMatchUtils.simpleMatch(excludes, name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Map<String, Object> buildExportProperties() {
|
||||
Map<String, Object> props = new HashMap<>();
|
||||
if (!ObjectUtils.isEmpty(this.properties)) {
|
||||
Map<String, String> target = bindProperties();
|
||||
|
||||
BeanExpressionResolver beanExpressionResolver = ((ConfigurableApplicationContext) this.applicationContext)
|
||||
.getBeanFactory().getBeanExpressionResolver();
|
||||
BeanExpressionContext expressionContext = new BeanExpressionContext(
|
||||
((ConfigurableApplicationContext) this.applicationContext)
|
||||
.getBeanFactory(),
|
||||
null);
|
||||
for (Entry<String, String> entry : target.entrySet()) {
|
||||
if (isMatch(entry.getKey(), this.properties, null)) {
|
||||
String stringValue = ObjectUtils.nullSafeToString(entry.getValue());
|
||||
Object exportedValue = null;
|
||||
if (stringValue != null) {
|
||||
exportedValue = stringValue.startsWith("#{")
|
||||
? beanExpressionResolver.evaluate(
|
||||
this.environment.resolvePlaceholders(stringValue),
|
||||
expressionContext)
|
||||
: this.environment.resolvePlaceholders(stringValue);
|
||||
}
|
||||
|
||||
props.put(entry.getKey(), exportedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
private Map<String, String> bindProperties() {
|
||||
Map<String, String> target;
|
||||
BindResult<Map<String, String>> bindResult = Binder.get(this.environment).bind("",
|
||||
STRING_STRING_MAP);
|
||||
if (bindResult.isBound()) {
|
||||
target = bindResult.get();
|
||||
}
|
||||
else {
|
||||
target = new HashMap<>();
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,258 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.stream.micrometer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
import java.util.function.ToLongFunction;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.DistributionSummary;
|
||||
import io.micrometer.core.instrument.FunctionCounter;
|
||||
import io.micrometer.core.instrument.FunctionTimer;
|
||||
import io.micrometer.core.instrument.Gauge;
|
||||
import io.micrometer.core.instrument.LongTaskTimer;
|
||||
import io.micrometer.core.instrument.Measurement;
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.Meter.Id;
|
||||
import io.micrometer.core.instrument.Meter.Type;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Timer;
|
||||
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
|
||||
import io.micrometer.core.instrument.distribution.pause.PauseDetector;
|
||||
import io.micrometer.core.instrument.internal.DefaultGauge;
|
||||
import io.micrometer.core.instrument.internal.DefaultMeter;
|
||||
import io.micrometer.core.instrument.step.StepCounter;
|
||||
import io.micrometer.core.instrument.step.StepDistributionSummary;
|
||||
import io.micrometer.core.instrument.step.StepFunctionCounter;
|
||||
import io.micrometer.core.instrument.step.StepFunctionTimer;
|
||||
import io.micrometer.core.instrument.step.StepTimer;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 2.0
|
||||
*/
|
||||
class DefaultDestinationPublishingMeterRegistry extends MeterRegistry
|
||||
implements SmartLifecycle {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(DefaultDestinationPublishingMeterRegistry.class);
|
||||
|
||||
private final MetricsPublisherConfig metricsPublisherConfig;
|
||||
|
||||
private final Consumer<String> metricsConsumer;
|
||||
|
||||
private final ApplicationMetricsProperties applicationProperties;
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private ScheduledFuture<?> publisher;
|
||||
|
||||
DefaultDestinationPublishingMeterRegistry(
|
||||
ApplicationMetricsProperties applicationProperties,
|
||||
MetersPublisherBinding publisherBinding,
|
||||
MetricsPublisherConfig metricsPublisherConfig, Clock clock) {
|
||||
super(clock);
|
||||
this.metricsPublisherConfig = metricsPublisherConfig;
|
||||
this.metricsConsumer = new MessageChannelPublisher(publisherBinding);
|
||||
this.applicationProperties = applicationProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
start(Executors.defaultThreadFactory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (this.publisher != null) {
|
||||
this.publisher.cancel(false);
|
||||
this.publisher = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return this.publisher != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPhase() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoStartup() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(Runnable callback) {
|
||||
this.stop();
|
||||
callback.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> Gauge newGauge(Meter.Id id, T obj, ToDoubleFunction<T> f) {
|
||||
return new DefaultGauge<>(id, obj, f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Counter newCounter(Meter.Id id) {
|
||||
return new StepCounter(id, this.clock,
|
||||
this.metricsPublisherConfig.step().toMillis());
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected LongTaskTimer newLongTaskTimer(Meter.Id id) {
|
||||
// return new DefaultLongTaskTimer(id, this.clock);
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected TimeUnit getBaseTimeUnit() {
|
||||
return TimeUnit.MILLISECONDS;
|
||||
}
|
||||
|
||||
protected void publish() {
|
||||
List<Metric<Number>> aggregatedMeters = new ArrayList<>();
|
||||
for (Meter meter : this.getMeters()) {
|
||||
if (meter instanceof Timer) {
|
||||
aggregatedMeters.add(toTimerMetric((Timer) meter));
|
||||
}
|
||||
else if (meter instanceof DistributionSummary) {
|
||||
aggregatedMeters.add(toSummaryMetric((DistributionSummary) meter));
|
||||
}
|
||||
}
|
||||
if (!aggregatedMeters.isEmpty()) {
|
||||
ApplicationMetrics metrics = new ApplicationMetrics(
|
||||
this.applicationProperties.getKey(), aggregatedMeters);
|
||||
metrics.setInterval(this.metricsPublisherConfig.step().toMillis());
|
||||
metrics.setProperties(this.applicationProperties.getExportProperties());
|
||||
try {
|
||||
String jsonString = this.objectMapper.writeValueAsString(metrics);
|
||||
this.metricsConsumer.accept(jsonString);
|
||||
}
|
||||
catch (JsonProcessingException e) {
|
||||
logger.warn("Error producing JSON String representation metric data", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Timer newTimer(Id id,
|
||||
DistributionStatisticConfig distributionStatisticConfig,
|
||||
PauseDetector pauseDetector) {
|
||||
return new StepTimer(id, this.clock, distributionStatisticConfig, pauseDetector,
|
||||
getBaseTimeUnit(), this.metricsPublisherConfig.step().toMillis(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> FunctionTimer newFunctionTimer(Id id, T obj,
|
||||
ToLongFunction<T> countFunction, ToDoubleFunction<T> totalTimeFunction,
|
||||
TimeUnit totalTimeFunctionUnits) {
|
||||
return new StepFunctionTimer<T>(id, this.clock,
|
||||
this.metricsPublisherConfig.step().toMillis(), obj, countFunction,
|
||||
totalTimeFunction, totalTimeFunctionUnits, getBaseTimeUnit());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> FunctionCounter newFunctionCounter(Id id, T obj,
|
||||
ToDoubleFunction<T> valueFunction) {
|
||||
return new StepFunctionCounter<T>(id, this.clock,
|
||||
this.metricsPublisherConfig.step().toMillis(), obj, valueFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Meter newMeter(Id id, Type type, Iterable<Measurement> measurements) {
|
||||
return new DefaultMeter(id, type, measurements);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DistributionSummary newDistributionSummary(Id id,
|
||||
DistributionStatisticConfig distributionStatisticConfig, double scale) {
|
||||
return new StepDistributionSummary(id, this.clock, distributionStatisticConfig,
|
||||
scale, this.metricsPublisherConfig.step().toMillis(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DistributionStatisticConfig defaultHistogramConfig() {
|
||||
return DistributionStatisticConfig.builder()
|
||||
.expiry(this.metricsPublisherConfig.step()).build()
|
||||
.merge(DistributionStatisticConfig.DEFAULT);
|
||||
}
|
||||
|
||||
private void start(ThreadFactory threadFactory) {
|
||||
if (this.publisher != null) {
|
||||
stop();
|
||||
}
|
||||
this.publisher = Executors.newSingleThreadScheduledExecutor(threadFactory)
|
||||
.scheduleAtFixedRate(this::publish,
|
||||
this.metricsPublisherConfig.step().toMillis(),
|
||||
this.metricsPublisherConfig.step().toMillis(),
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private Metric<Number> toSummaryMetric(DistributionSummary summary) {
|
||||
return new Metric<Number>(summary.getId(), summary.takeSnapshot());
|
||||
}
|
||||
|
||||
private Metric<Number> toTimerMetric(Timer timer) {
|
||||
return new Metric<Number>(timer.getId(), timer.takeSnapshot());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LongTaskTimer newLongTaskTimer(Id id, DistributionStatisticConfig distributionStatisticConfig) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final class MessageChannelPublisher implements Consumer<String> {
|
||||
|
||||
private final MetersPublisherBinding metersPublisherBinding;
|
||||
|
||||
MessageChannelPublisher(MetersPublisherBinding metersPublisherBinding) {
|
||||
this.metersPublisherBinding = metersPublisherBinding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(String metricData) {
|
||||
logger.trace(metricData);
|
||||
Message<String> message = MessageBuilder.withPayload(metricData)
|
||||
.setHeader("STREAM_CLOUD_STREAM_VERSION", "2.x").build();
|
||||
this.metersPublisherBinding.applicationMetrics().send(message);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.stream.micrometer;
|
||||
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.core.instrument.config.MeterFilter;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.stream.binder.Binder;
|
||||
import org.springframework.cloud.stream.binding.BindableProxyFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 2.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@AutoConfigureBefore(SimpleMetricsExportAutoConfiguration.class)
|
||||
@AutoConfigureAfter(MetricsAutoConfiguration.class)
|
||||
@ConditionalOnClass({ Binder.class, MetricsAutoConfiguration.class })
|
||||
@ConditionalOnProperty("spring.cloud.stream.bindings."
|
||||
+ MetersPublisherBinding.APPLICATION_METRICS + ".destination")
|
||||
@EnableConfigurationProperties(ApplicationMetricsProperties.class)
|
||||
public class DestinationPublishingMetricsAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public MetricsPublisherConfig metricsPublisherConfig(
|
||||
ApplicationMetricsProperties metersPublisherProperties) {
|
||||
return new MetricsPublisherConfig(metersPublisherProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public DefaultDestinationPublishingMeterRegistry defaultDestinationPublishingMeterRegistry(
|
||||
ApplicationMetricsProperties applicationMetricsProperties,
|
||||
MetersPublisherBinding publisherBinding,
|
||||
MetricsPublisherConfig metricsPublisherConfig, Clock clock) {
|
||||
DefaultDestinationPublishingMeterRegistry registry = new DefaultDestinationPublishingMeterRegistry(
|
||||
applicationMetricsProperties, publisherBinding, metricsPublisherConfig,
|
||||
clock);
|
||||
|
||||
if (StringUtils.hasText(applicationMetricsProperties.getMeterFilter())) {
|
||||
registry.config()
|
||||
.meterFilter(MeterFilter.denyUnless(id -> PatternMatchUtils
|
||||
.simpleMatch(applicationMetricsProperties.getMeterFilter(),
|
||||
id.getName())));
|
||||
}
|
||||
return registry;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BeanFactoryPostProcessor metersPublisherBindingRegistrant() {
|
||||
return new BeanFactoryPostProcessor() {
|
||||
@Override
|
||||
public void postProcessBeanFactory(
|
||||
ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
RootBeanDefinition emitterBindingDefinition = new RootBeanDefinition(
|
||||
BindableProxyFactory.class);
|
||||
emitterBindingDefinition.getConstructorArgumentValues()
|
||||
.addGenericArgumentValue(MetersPublisherBinding.class);
|
||||
((DefaultListableBeanFactory) beanFactory).registerBeanDefinition(
|
||||
MetersPublisherBinding.class.getName(), emitterBindingDefinition);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.stream.micrometer;
|
||||
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface MetersPublisherBinding {
|
||||
|
||||
/**
|
||||
* Application metrics channel name.
|
||||
*/
|
||||
String APPLICATION_METRICS = "applicationMetrics";
|
||||
|
||||
/**
|
||||
* @return Channel for application metrics.
|
||||
*/
|
||||
// @Output(APPLICATION_METRICS)
|
||||
MessageChannel applicationMetrics();
|
||||
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.stream.micrometer;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.distribution.HistogramSnapshot;
|
||||
|
||||
/**
|
||||
* Immutable class that wraps the micrometer's {@link HistogramSnapshot}.
|
||||
*
|
||||
* @param <T> the value of type {@link Number}
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
@JsonPropertyOrder({ "id", "timestamp", "sum", "count", "mean", "upper", "total" })
|
||||
class Metric<T extends Number> {
|
||||
|
||||
private final Date timestamp;
|
||||
|
||||
private final Meter.Id id;
|
||||
|
||||
private final Number sum;
|
||||
|
||||
private final Number count;
|
||||
|
||||
private final Number mean;
|
||||
|
||||
private final Number upper;
|
||||
|
||||
private final Number total;
|
||||
|
||||
/**
|
||||
* Create a new {@link Metric} instance.
|
||||
* @param id Meter id
|
||||
* @param snapshot instance of HistogramSnapshot
|
||||
*/
|
||||
Metric(Meter.Id id, HistogramSnapshot snapshot) {
|
||||
this.timestamp = new Date();
|
||||
this.id = id;
|
||||
this.sum = snapshot.total(TimeUnit.MILLISECONDS);
|
||||
this.count = snapshot.count();
|
||||
this.mean = snapshot.mean(TimeUnit.MILLISECONDS);
|
||||
this.upper = snapshot.max(TimeUnit.MILLISECONDS);
|
||||
this.total = snapshot.total(TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public Meter.Id getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC")
|
||||
public Date getTimestamp() {
|
||||
return this.timestamp;
|
||||
}
|
||||
|
||||
public Number getSum() {
|
||||
return this.sum;
|
||||
}
|
||||
|
||||
public Number getCount() {
|
||||
return this.count;
|
||||
}
|
||||
|
||||
public Number getMean() {
|
||||
return this.mean;
|
||||
}
|
||||
|
||||
public Number getUpper() {
|
||||
return this.upper;
|
||||
}
|
||||
|
||||
public Number getTotal() {
|
||||
return this.total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Metric [id=" + this.id + ", sum=" + this.sum + ", count=" + this.count
|
||||
+ ", mean=" + this.mean + ", upper=" + this.upper + ", total="
|
||||
+ this.total + ", timestamp=" + this.timestamp + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.stream.micrometer;
|
||||
|
||||
import io.micrometer.core.instrument.step.StepRegistryConfig;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
class MetricsPublisherConfig implements StepRegistryConfig {
|
||||
|
||||
private final ApplicationMetricsProperties applicationMetricsProperties;
|
||||
|
||||
MetricsPublisherConfig(ApplicationMetricsProperties applicationMetricsProperties) {
|
||||
this.applicationMetricsProperties = applicationMetricsProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prefix() {
|
||||
return ApplicationMetricsProperties.PREFIX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key) {
|
||||
String value = null;
|
||||
if (key.equals(this.prefix() + ".step")) {
|
||||
value = this.applicationMetricsProperties.getScheduleInterval().toString();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user