1
pom.xml
1
pom.xml
@@ -103,7 +103,6 @@
|
||||
<module>spring-cloud-stream-schema</module>
|
||||
<module>spring-cloud-stream-schema-server</module>
|
||||
<module>spring-cloud-stream-tools</module>
|
||||
<!--<module>spring-cloud-stream-metrics</module>-->
|
||||
</modules>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-stream-metrics</artifactId>
|
||||
<description>Emitter module to publish boot metrics</description>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-stream-parent</artifactId>
|
||||
<version>2.0.0.M2</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-stream</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-stream-test-support</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 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
|
||||
*
|
||||
* http://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.metrics;
|
||||
|
||||
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 org.springframework.boot.actuate.metrics.Metric;
|
||||
|
||||
/**
|
||||
* @author Vinicius Carvalho
|
||||
*/
|
||||
public 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 Collection<Metric<?>> metrics;
|
||||
|
||||
private Map<String, Object> properties;
|
||||
|
||||
@JsonCreator
|
||||
public ApplicationMetrics(@JsonProperty("name") String name,
|
||||
@JsonProperty("metrics") Collection<Metric<?>> metrics) {
|
||||
this.name = name;
|
||||
this.metrics = metrics;
|
||||
this.createdTime = new Date();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Collection<Metric<?>> getMetrics() {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
public void setMetrics(Collection<Metric<?>> metrics) {
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
public Date getCreatedTime() {
|
||||
return createdTime;
|
||||
}
|
||||
|
||||
public Map<String, Object> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setProperties(Map<String, Object> properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 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
|
||||
*
|
||||
* http://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.metrics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.MetricsEndpointMetricReader;
|
||||
import org.springframework.boot.actuate.metrics.Metric;
|
||||
import org.springframework.boot.actuate.metrics.export.Exporter;
|
||||
import org.springframework.boot.actuate.metrics.export.MetricCopyExporter;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* Component that sends {@link ApplicationMetrics} from
|
||||
* {@link MetricsEndpointMetricReader} downstream via the configured metrics channel.
|
||||
*
|
||||
* It uses the Spring Boot support for {@link Exporter} to periodically emit messages
|
||||
* polled from the endpoint.
|
||||
*
|
||||
* @author Vinicius Carvalho
|
||||
*/
|
||||
public class ApplicationMetricsExporter implements Exporter {
|
||||
|
||||
private MessageChannel source;
|
||||
|
||||
private ApplicationMetricsProperties properties;
|
||||
|
||||
private MetricsEndpointMetricReader metricsReader;
|
||||
|
||||
public ApplicationMetricsExporter(MetricsEndpoint endpoint, MessageChannel source,
|
||||
ApplicationMetricsProperties properties) {
|
||||
this.source = source;
|
||||
this.properties = properties;
|
||||
this.metricsReader = new MetricsEndpointMetricReader(endpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void export() {
|
||||
ApplicationMetrics appMetrics = new ApplicationMetrics(
|
||||
this.properties.getMetricName(),
|
||||
filter());
|
||||
appMetrics.setProperties(this.properties.getExportProperties());
|
||||
source.send(MessageBuilder.withPayload(appMetrics).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy of similarly named method in {@link MetricCopyExporter}.
|
||||
*/
|
||||
protected Collection<Metric<?>> filter() {
|
||||
Collection<Metric<?>> result = new ArrayList<>();
|
||||
Iterable<Metric<?>> metrics = metricsReader.findAll();
|
||||
for (Metric<?> metric : metrics) {
|
||||
if (isMatch(metric.getName(), this.properties.getTrigger().getIncludes(),
|
||||
this.properties.getTrigger().getExcludes())) {
|
||||
result.add(metric);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy of similarly named method in {@link MetricCopyExporter}.
|
||||
*/
|
||||
private boolean isMatch(String name, String[] includes, String[] excludes) {
|
||||
if (ObjectUtils.isEmpty(includes)
|
||||
|| PatternMatchUtils.simpleMatch(includes, name)) {
|
||||
return !PatternMatchUtils.simpleMatch(excludes, name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 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
|
||||
*
|
||||
* http://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.metrics;
|
||||
|
||||
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.actuate.metrics.export.MetricExportProperties;
|
||||
import org.springframework.boot.actuate.metrics.export.TriggerProperties;
|
||||
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.cloud.stream.metrics.config.BinderMetricsAutoConfiguration;
|
||||
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.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
/**
|
||||
* @author Vinicius Carvalho
|
||||
* @author Janne Valkealahti
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "spring.cloud.stream.metrics")
|
||||
public class ApplicationMetricsProperties
|
||||
implements EnvironmentAware, ApplicationContextAware {
|
||||
|
||||
private static final Bindable<Map<String, String>> STRING_STRING_MAP = Bindable
|
||||
.mapOf(String.class, String.class);
|
||||
|
||||
private final MetricExportProperties metricExportProperties;
|
||||
|
||||
private String prefix = "";
|
||||
|
||||
@Value("${spring.application.name:${vcap.application.name:${spring.config.name:application}}}")
|
||||
private String key;
|
||||
|
||||
private String metricName;
|
||||
|
||||
private String[] properties;
|
||||
|
||||
private Environment environment;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* 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 = null;
|
||||
|
||||
public ApplicationMetricsProperties(MetricExportProperties metricExportProperties) {
|
||||
Assert.notNull(metricExportProperties, "'metricsExportProperties' cannot be null");
|
||||
this.metricExportProperties = metricExportProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public TriggerProperties getTrigger() {
|
||||
return metricExportProperties
|
||||
.findTrigger(BinderMetricsAutoConfiguration.APPLICATION_METRICS_EXPORTER_TRIGGER_NAME);
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix) {
|
||||
if (!prefix.endsWith(".")) {
|
||||
prefix += ".";
|
||||
}
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String[] getProperties() {
|
||||
return 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 String getMetricName() {
|
||||
if (this.metricName == null) {
|
||||
this.metricName = resolveMetricName();
|
||||
}
|
||||
return metricName;
|
||||
}
|
||||
|
||||
private String resolveMetricName() {
|
||||
return this.prefix + this.key;
|
||||
}
|
||||
|
||||
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) applicationContext)
|
||||
.getBeanFactory().getBeanExpressionResolver();
|
||||
BeanExpressionContext expressionContext = new BeanExpressionContext(
|
||||
((ConfigurableApplicationContext) 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(
|
||||
environment.resolvePlaceholders(stringValue), expressionContext)
|
||||
: 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(environment).bind("", STRING_STRING_MAP);
|
||||
if (bindResult.isBound()) {
|
||||
target = bindResult.get();
|
||||
}
|
||||
else {
|
||||
target = new HashMap<>();
|
||||
}
|
||||
return target;
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 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
|
||||
*
|
||||
* http://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.metrics.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.actuate.autoconfigure.MetricExportAutoConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
|
||||
import org.springframework.boot.actuate.metrics.export.Exporter;
|
||||
import org.springframework.boot.actuate.metrics.export.MetricExporters;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.binder.Binder;
|
||||
import org.springframework.cloud.stream.metrics.ApplicationMetricsExporter;
|
||||
import org.springframework.cloud.stream.metrics.ApplicationMetricsProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
||||
/**
|
||||
* Autoconfiguration registering an {@link Exporter} that publishes application metrics
|
||||
* over the {@link Emitter#applicationMetrics()} channel.
|
||||
*
|
||||
* @author Vinicius Carvalho
|
||||
* @author Marius Bogoevici
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(Binder.class)
|
||||
@EnableBinding(Emitter.class)
|
||||
@EnableConfigurationProperties(ApplicationMetricsProperties.class)
|
||||
@AutoConfigureAfter(MetricExportAutoConfiguration.class)
|
||||
@ConditionalOnProperty("spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS
|
||||
+ ".destination")
|
||||
public class BinderMetricsAutoConfiguration {
|
||||
|
||||
public static final String APPLICATION_METRICS_EXPORTER_TRIGGER_NAME = "application";
|
||||
|
||||
public static Log log = LogFactory.getLog(BinderMetricsAutoConfiguration.class);
|
||||
|
||||
/**
|
||||
* Postprocessor for installing the {@link ApplicationMetricsExporter} as an exporter
|
||||
* under the name {@code application}.
|
||||
* @param endpoint the metrics endpoint (lazy reference to prevent early
|
||||
* initialization)
|
||||
* @param emitter the emitter bound interface
|
||||
* @param properties application metrics properties
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public static BeanPostProcessor metricExportersBeanPostProcessor(final @Lazy MetricsEndpoint endpoint,
|
||||
final Emitter emitter, final ApplicationMetricsProperties properties) {
|
||||
return new BeanPostProcessor() {
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String name) throws BeansException {
|
||||
if (bean instanceof MetricExporters) {
|
||||
Map<String, Exporter> exporters = ((MetricExporters) bean).getExporters();
|
||||
if (!exporters.containsKey(APPLICATION_METRICS_EXPORTER_TRIGGER_NAME)) {
|
||||
exporters.put(APPLICATION_METRICS_EXPORTER_TRIGGER_NAME,
|
||||
new ApplicationMetricsExporter(endpoint, emitter.applicationMetrics(), properties));
|
||||
}
|
||||
else {
|
||||
log.warn("Could not register ApplicationMetricExporter: "
|
||||
+ exporters.get(APPLICATION_METRICS_EXPORTER_TRIGGER_NAME)
|
||||
+ " was already registered as " + APPLICATION_METRICS_EXPORTER_TRIGGER_NAME);
|
||||
}
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MetricJsonSerializer metricJsonSerializer() {
|
||||
return new MetricJsonSerializer();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 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
|
||||
*
|
||||
* http://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.metrics.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.env.EnvironmentPostProcessor;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
/**
|
||||
* @author Vinicius Carvalho
|
||||
*/
|
||||
public class BinderMetricsEnvironmentPostProcessor implements EnvironmentPostProcessor {
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||
Map<String, Object> propertiesToAdd = new HashMap<>();
|
||||
propertiesToAdd.put("spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".contentType",
|
||||
"application/json");
|
||||
environment.getPropertySources()
|
||||
.addLast(new MapPropertySource("binderMetricsDefaultProperties", propertiesToAdd));
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 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
|
||||
*
|
||||
* http://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.metrics.config;
|
||||
|
||||
import org.springframework.cloud.stream.annotation.Output;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
|
||||
/**
|
||||
* @author Vinicius Carvalho
|
||||
*/
|
||||
public interface Emitter {
|
||||
|
||||
String APPLICATION_METRICS = "applicationMetrics";
|
||||
|
||||
@Output(APPLICATION_METRICS)
|
||||
MessageChannel applicationMetrics();
|
||||
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 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
|
||||
*
|
||||
* http://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.metrics.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Metric;
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
|
||||
/**
|
||||
* @author Vinicius Carvalho
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
@JsonComponent
|
||||
public class MetricJsonSerializer {
|
||||
|
||||
private static final BlockingQueue<DateFormat> formatters = new LinkedBlockingQueue<DateFormat>();
|
||||
|
||||
private static DateFormat defaultDateFormat() {
|
||||
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
|
||||
df.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
return df;
|
||||
}
|
||||
|
||||
public static class Serializer extends JsonSerializer<Metric<?>> {
|
||||
|
||||
@Override
|
||||
public void serialize(Metric<?> metric, JsonGenerator json,
|
||||
SerializerProvider serializerProvider) throws IOException {
|
||||
json.writeStartObject();
|
||||
json.writeStringField("name", metric.getName());
|
||||
json.writeNumberField("value", metric.getValue().doubleValue());
|
||||
DateFormat df = formatters.poll();
|
||||
if (df == null) {
|
||||
df = defaultDateFormat();
|
||||
}
|
||||
try {
|
||||
json.writeStringField("timestamp", df.format(metric.getTimestamp()));
|
||||
json.writeEndObject();
|
||||
}
|
||||
finally {
|
||||
formatters.offer(df);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Deserializer extends JsonDeserializer<Metric<?>> {
|
||||
|
||||
@Override
|
||||
public Metric<?> deserialize(JsonParser p, DeserializationContext ctxt)
|
||||
throws IOException, JsonProcessingException {
|
||||
JsonNode node = p.getCodec().readTree(p);
|
||||
String name = node.get("name").asText();
|
||||
Number value = node.get("value").asDouble();
|
||||
Date timestamp = null;
|
||||
DateFormat df = formatters.poll();
|
||||
if (df == null) {
|
||||
df = defaultDateFormat();
|
||||
}
|
||||
try {
|
||||
timestamp = df.parse(node.get("timestamp").asText());
|
||||
}
|
||||
catch (ParseException e) {
|
||||
// ignore timestamp parsing errors
|
||||
}
|
||||
finally {
|
||||
formatters.offer(df);
|
||||
}
|
||||
Metric<Number> metric = new Metric<>(name, value, timestamp);
|
||||
return metric;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.stream.metrics.config.BinderMetricsAutoConfiguration
|
||||
org.springframework.boot.env.EnvironmentPostProcessor=\
|
||||
org.springframework.cloud.stream.metrics.config.BinderMetricsEnvironmentPostProcessor
|
||||
@@ -1,321 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 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
|
||||
*
|
||||
* http://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.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.actuate.metrics.Metric;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cloud.stream.metrics.config.Emitter;
|
||||
import org.springframework.cloud.stream.test.binder.MessageCollector;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* @author Vinicius Carvalho
|
||||
* @author Janne Valkealahti
|
||||
*/
|
||||
public class ApplicationMetricsExporterTests {
|
||||
|
||||
@BeforeClass
|
||||
public static void setSystemProps() {
|
||||
System.setProperty("spring.test.env.syntax", "testing");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void unsetSystemProps() {
|
||||
System.clearProperty("spring.test.env.syntax");
|
||||
}
|
||||
|
||||
@Test(expected = NoSuchBeanDefinitionException.class)
|
||||
public void checkDisabledConfiguration() throws Exception {
|
||||
ConfigurableApplicationContext applicationContext = SpringApplication.run(
|
||||
BinderExporterApplication.class, "--server.port=0", "--spring.jmx.enabled=false");
|
||||
try {
|
||||
applicationContext.getBean(Emitter.class);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
applicationContext.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultIncludes() throws Exception {
|
||||
ConfigurableApplicationContext applicationContext = SpringApplication.run(
|
||||
BinderExporterApplication.class, "--server.port=0",
|
||||
"--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
|
||||
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo");
|
||||
Emitter emitterSource = applicationContext.getBean(Emitter.class);
|
||||
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
|
||||
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
|
||||
.poll(10, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(message);
|
||||
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
|
||||
ApplicationMetrics applicationMetrics = mapper
|
||||
.readValue((byte[]) message.getPayload(), ApplicationMetrics.class);
|
||||
Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
|
||||
applicationMetrics.getMetrics()));
|
||||
Assert.assertEquals("application", applicationMetrics.getName());
|
||||
Assert.assertTrue(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
|
||||
applicationContext.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customAppNameAndIndex() throws Exception {
|
||||
ConfigurableApplicationContext applicationContext = SpringApplication.run(
|
||||
BinderExporterApplication.class, "--server.port=0",
|
||||
"--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
|
||||
"--spring.application.name=foo",
|
||||
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo");
|
||||
Emitter emitterSource = applicationContext.getBean(Emitter.class);
|
||||
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
|
||||
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
|
||||
.poll(10, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(message);
|
||||
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
|
||||
ApplicationMetrics applicationMetrics = mapper.readValue((byte[]) message.getPayload(),
|
||||
ApplicationMetrics.class);
|
||||
Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
|
||||
applicationMetrics.getMetrics()));
|
||||
Assert.assertTrue(contains("mem", applicationMetrics.getMetrics()));
|
||||
Assert.assertEquals("foo", applicationMetrics.getName());
|
||||
Assert.assertTrue(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
|
||||
applicationContext.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usingPrefix() throws Exception {
|
||||
ConfigurableApplicationContext applicationContext = SpringApplication.run(
|
||||
BinderExporterApplication.class, "--server.port=0",
|
||||
"--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
|
||||
"--spring.cloud.stream.metrics.prefix=foo",
|
||||
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo");
|
||||
Emitter emitterSource = applicationContext.getBean(Emitter.class);
|
||||
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
|
||||
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
|
||||
.poll(10, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(message);
|
||||
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
|
||||
ApplicationMetrics applicationMetrics = mapper
|
||||
.readValue((byte[]) message.getPayload(), ApplicationMetrics.class);
|
||||
Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
|
||||
applicationMetrics.getMetrics()));
|
||||
Assert.assertTrue(contains("mem", applicationMetrics.getMetrics()));
|
||||
Assert.assertEquals("foo.application", applicationMetrics.getName());
|
||||
Assert.assertTrue(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
|
||||
applicationContext.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void includesExcludesDefaultConfig() throws Exception {
|
||||
ConfigurableApplicationContext applicationContext = SpringApplication.run(
|
||||
BinderExporterApplication.class, "--server.port=0",
|
||||
"--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
|
||||
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo",
|
||||
"--spring.metrics.export.includes=mem**",
|
||||
"--spring.metrics.export.excludes=integration**");
|
||||
Emitter emitterSource = applicationContext.getBean(Emitter.class);
|
||||
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
|
||||
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
|
||||
.poll(10, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(message);
|
||||
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
|
||||
ApplicationMetrics applicationMetrics = mapper
|
||||
.readValue((byte[]) message.getPayload(), ApplicationMetrics.class);
|
||||
Assert.assertFalse(contains("integration.channel.errorChannel.errorRate.mean",
|
||||
applicationMetrics.getMetrics()));
|
||||
Assert.assertTrue(contains("mem", applicationMetrics.getMetrics()));
|
||||
Assert.assertTrue(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
|
||||
applicationContext.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void includesExcludesWithApplicationMetricsConfiguration() throws Exception {
|
||||
ConfigurableApplicationContext applicationContext = SpringApplication.run(
|
||||
BinderExporterApplication.class, "--server.port=0",
|
||||
"--spring.jmx.enabled=false",
|
||||
"--spring.metrics.export.triggers.application.delay-millis=500",
|
||||
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo",
|
||||
"--spring.metrics.export.triggers.application.includes=mem**",
|
||||
"--spring.metrics.export.triggers.application.excludes=integration**");
|
||||
Emitter emitterSource = applicationContext.getBean(Emitter.class);
|
||||
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
|
||||
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
|
||||
.poll(10, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(message);
|
||||
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
|
||||
ApplicationMetrics applicationMetrics = mapper.readValue((byte[]) message.getPayload(),
|
||||
ApplicationMetrics.class);
|
||||
Assert.assertFalse(contains("integration.channel.errorChannel.errorRate.mean",
|
||||
applicationMetrics.getMetrics()));
|
||||
Assert.assertTrue(contains("mem", applicationMetrics.getMetrics()));
|
||||
Assert.assertTrue(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
|
||||
applicationContext.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void includesExcludesWithProperties() throws Exception {
|
||||
ConfigurableApplicationContext applicationContext = SpringApplication.run(
|
||||
BinderExporterApplication.class, "--server.port=0",
|
||||
"--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
|
||||
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo",
|
||||
"--spring.metrics.export.includes=integration**",
|
||||
"--spring.cloud.stream.metrics.properties=java**,spring.test.env**");
|
||||
Emitter emitterSource = applicationContext.getBean(Emitter.class);
|
||||
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
|
||||
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
|
||||
.poll(10, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(message);
|
||||
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
|
||||
ApplicationMetrics applicationMetrics = mapper.readValue((byte[]) message.getPayload(),
|
||||
ApplicationMetrics.class);
|
||||
Assert.assertFalse(contains("mem", applicationMetrics.getMetrics()));
|
||||
Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
|
||||
applicationMetrics.getMetrics()));
|
||||
Assert.assertFalse(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
|
||||
Assert.assertTrue(applicationMetrics.getProperties().get("spring.test.env.syntax")
|
||||
.equals("testing"));
|
||||
applicationContext.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertiesWithPlaceholdersAndExpressions() throws Exception {
|
||||
ConfigurableApplicationContext applicationContext = SpringApplication.run(
|
||||
BinderExporterApplication.class,
|
||||
"--server.port=0",
|
||||
"--spring.jmx.enabled=false",
|
||||
"--PLATFORM_APP_NAME=123-name-foo",
|
||||
"--PLATFORM_APP_ID=123-id-bar",
|
||||
"--spring.cloud.application.guid=${PLATFORM_APP_NAME}.${PLATFORM_APP_ID}",
|
||||
"--spring.cloud.application.guid.expression=#{'${PLATFORM_APP_NAME}' + '..' + '${PLATFORM_APP_ID}'}",
|
||||
"--spring.cloud.application.guid.default.prop=${app.name.not.found:time-source}",
|
||||
"--spring.cloud.application.guid.default.env=${APP_NAME_NOT_FOUND:time-source}",
|
||||
"--spring.metrics.export.delay-millis=500",
|
||||
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo",
|
||||
"--spring.metrics.export.includes=integration**",
|
||||
"--spring.cloud.stream.metrics.properties=spring**");
|
||||
Emitter emitterSource = applicationContext.getBean(Emitter.class);
|
||||
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
|
||||
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
|
||||
.poll(10, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(message);
|
||||
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
|
||||
ApplicationMetrics applicationMetrics = mapper.readValue((byte[]) message.getPayload(),
|
||||
ApplicationMetrics.class);
|
||||
Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
|
||||
applicationMetrics.getMetrics()));
|
||||
Assertions.assertThat(applicationMetrics.getProperties().get("spring.cloud.application.guid"))
|
||||
.isEqualTo("123-name-foo.123-id-bar");
|
||||
Assertions.assertThat(applicationMetrics.getProperties().get("spring.cloud.application.guid.expression"))
|
||||
.isEqualTo("123-name-foo..123-id-bar");
|
||||
Assertions.assertThat(applicationMetrics.getProperties().get("spring.cloud.application.guid.default.prop"))
|
||||
.isEqualTo("time-source");
|
||||
Assertions.assertThat(applicationMetrics.getProperties().get("spring.cloud.application.guid.default.env"))
|
||||
.isEqualTo("time-source");
|
||||
Assert.assertFalse(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
|
||||
Assert.assertTrue(applicationMetrics.getProperties().get("spring.test.env.syntax").equals("testing"));
|
||||
applicationContext.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertiesFromLowerPrioritySourcesOverridden() throws Exception {
|
||||
System.setProperty("spring.cloud.application.guid.test.metrics", "lowPriority");
|
||||
try {
|
||||
ConfigurableApplicationContext applicationContext = SpringApplication.run(
|
||||
BinderExporterApplication.class,
|
||||
"--server.port=0",
|
||||
"--spring.jmx.enabled=false",
|
||||
"--spring.cloud.application.guid.test.metrics=highPriority",
|
||||
"--spring.metrics.export.delay-millis=500",
|
||||
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo",
|
||||
"--spring.metrics.export.includes=integration**",
|
||||
"--spring.cloud.stream.metrics.properties=spring**");
|
||||
Emitter emitterSource = applicationContext.getBean(Emitter.class);
|
||||
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
|
||||
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
|
||||
.poll(10, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(message);
|
||||
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
|
||||
ApplicationMetrics applicationMetrics = mapper.readValue((byte[]) message.getPayload(),
|
||||
ApplicationMetrics.class);
|
||||
Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
|
||||
applicationMetrics.getMetrics()));
|
||||
Assertions.assertThat(applicationMetrics.getProperties().get("spring.cloud.application.guid.test.metrics"))
|
||||
.isEqualTo("highPriority");
|
||||
applicationContext.close();
|
||||
}
|
||||
finally {
|
||||
System.clearProperty("spring.cloud.application.guid.test.metrics");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideAppName() throws Exception {
|
||||
ConfigurableApplicationContext applicationContext = SpringApplication.run(
|
||||
BinderExporterApplication.class, "--server.port=0",
|
||||
"--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
|
||||
"--spring.application.name=foo",
|
||||
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo",
|
||||
"--spring.cloud.stream.metrics.key=foobarfoo");
|
||||
Emitter emitterSource = applicationContext.getBean(Emitter.class);
|
||||
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
|
||||
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
|
||||
.poll(10, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(message);
|
||||
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
|
||||
ApplicationMetrics applicationMetrics = mapper.readValue((byte[]) message.getPayload(),
|
||||
ApplicationMetrics.class);
|
||||
Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
|
||||
applicationMetrics.getMetrics()));
|
||||
Assert.assertTrue(contains("mem", applicationMetrics.getMetrics()));
|
||||
Assert.assertEquals("foobarfoo", applicationMetrics.getName());
|
||||
Assert.assertTrue(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
|
||||
applicationContext.close();
|
||||
}
|
||||
|
||||
private boolean contains(String metric, Collection<Metric<?>> metrics) {
|
||||
boolean contains = false;
|
||||
for (Metric<?> entry : metrics) {
|
||||
contains = entry.getName().equals(metric);
|
||||
if (contains) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return contains;
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
public static class BinderExporterApplication {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 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
|
||||
*
|
||||
* http://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.metrics.config;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.Date;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Metric;
|
||||
import org.springframework.cloud.stream.metrics.config.MetricJsonSerializer.Serializer;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
public class MetricJsonSerializerTests {
|
||||
|
||||
@Test
|
||||
public void validateAlwaysGMTDateAndFormat() throws Exception {
|
||||
Date date = new Date(1493060197188L); // Mon Apr 24 14:56:37 EDT 2017
|
||||
Metric<Number> metric = new Metric<Number>("Hello", 123, date);
|
||||
|
||||
JsonFactory factory = new JsonFactory();
|
||||
StringWriter writer = new StringWriter();
|
||||
JsonGenerator jsonGenerator = factory.createGenerator(writer);
|
||||
Serializer ser = new Serializer();
|
||||
ser.serialize(metric, jsonGenerator, null);
|
||||
jsonGenerator.flush();
|
||||
|
||||
JSONObject json = new JSONObject(writer.toString());
|
||||
String serializedTimestamp = json.getString("timestamp");
|
||||
assertEquals("2017-04-24T18:56:37.188Z", serializedTimestamp);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user