247 changed files with 4857 additions and 15223 deletions
@ -1,150 +0,0 @@
@@ -1,150 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.cache; |
||||
|
||||
import javax.cache.Caching; |
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine; |
||||
import com.hazelcast.core.IMap; |
||||
import com.hazelcast.spring.cache.HazelcastCache; |
||||
import net.sf.ehcache.Ehcache; |
||||
import net.sf.ehcache.statistics.StatisticsGateway; |
||||
import org.infinispan.spring.provider.SpringCache; |
||||
|
||||
import org.springframework.boot.actuate.cache.CacheStatistics; |
||||
import org.springframework.boot.actuate.cache.CacheStatisticsProvider; |
||||
import org.springframework.boot.actuate.cache.CaffeineCacheStatisticsProvider; |
||||
import org.springframework.boot.actuate.cache.ConcurrentMapCacheStatisticsProvider; |
||||
import org.springframework.boot.actuate.cache.DefaultCacheStatistics; |
||||
import org.springframework.boot.actuate.cache.EhCacheStatisticsProvider; |
||||
import org.springframework.boot.actuate.cache.HazelcastCacheStatisticsProvider; |
||||
import org.springframework.boot.actuate.cache.InfinispanCacheStatisticsProvider; |
||||
import org.springframework.boot.actuate.cache.JCacheCacheStatisticsProvider; |
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
||||
import org.springframework.cache.Cache; |
||||
import org.springframework.cache.CacheManager; |
||||
import org.springframework.cache.caffeine.CaffeineCacheManager; |
||||
import org.springframework.cache.concurrent.ConcurrentMapCache; |
||||
import org.springframework.cache.ehcache.EhCacheCache; |
||||
import org.springframework.cache.jcache.JCacheCache; |
||||
import org.springframework.cache.support.NoOpCacheManager; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
/** |
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link CacheStatisticsProvider} |
||||
* beans. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @author Phillip Webb |
||||
* @author Eddú Meléndez |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@AutoConfigureAfter(CacheAutoConfiguration.class) |
||||
@ConditionalOnBean(CacheManager.class) |
||||
public class CacheStatisticsAutoConfiguration { |
||||
|
||||
@Configuration |
||||
@ConditionalOnClass({ Caching.class, JCacheCache.class }) |
||||
static class JCacheCacheStatisticsProviderConfiguration { |
||||
|
||||
@Bean |
||||
public JCacheCacheStatisticsProvider jCacheCacheStatisticsProvider() { |
||||
return new JCacheCacheStatisticsProvider(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnClass({ EhCacheCache.class, Ehcache.class, StatisticsGateway.class }) |
||||
static class EhCacheCacheStatisticsProviderConfiguration { |
||||
|
||||
@Bean |
||||
public EhCacheStatisticsProvider ehCacheCacheStatisticsProvider() { |
||||
return new EhCacheStatisticsProvider(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnClass({ IMap.class, HazelcastCache.class }) |
||||
static class HazelcastCacheStatisticsConfiguration { |
||||
|
||||
@Bean |
||||
public HazelcastCacheStatisticsProvider hazelcastCacheStatisticsProvider() { |
||||
return new HazelcastCacheStatisticsProvider(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnClass({ SpringCache.class }) |
||||
static class InfinispanCacheStatisticsProviderConfiguration { |
||||
|
||||
@Bean |
||||
public InfinispanCacheStatisticsProvider infinispanCacheStatisticsProvider() { |
||||
return new InfinispanCacheStatisticsProvider(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnClass({ Caffeine.class, CaffeineCacheManager.class }) |
||||
static class CaffeineCacheStatisticsProviderConfiguration { |
||||
|
||||
@Bean |
||||
public CaffeineCacheStatisticsProvider caffeineCacheStatisticsProvider() { |
||||
return new CaffeineCacheStatisticsProvider(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnClass(ConcurrentMapCache.class) |
||||
static class ConcurrentMapCacheStatisticsConfiguration { |
||||
|
||||
@Bean |
||||
public ConcurrentMapCacheStatisticsProvider concurrentMapCacheStatisticsProvider() { |
||||
return new ConcurrentMapCacheStatisticsProvider(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnClass(NoOpCacheManager.class) |
||||
static class NoOpCacheStatisticsConfiguration { |
||||
|
||||
private static final CacheStatistics NO_OP_STATS = new DefaultCacheStatistics(); |
||||
|
||||
@Bean |
||||
public CacheStatisticsProvider<Cache> noOpCacheStatisticsProvider() { |
||||
return (cacheManager, cache) -> { |
||||
if (cacheManager instanceof NoOpCacheManager) { |
||||
return NO_OP_STATS; |
||||
} |
||||
return null; |
||||
}; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,20 +0,0 @@
@@ -1,20 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
*/ |
||||
|
||||
/** |
||||
* Auto-configuration for actuator cache concerns. |
||||
*/ |
||||
package org.springframework.boot.actuate.autoconfigure.cache; |
||||
@ -1,43 +0,0 @@
@@ -1,43 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Inherited; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier; |
||||
|
||||
/** |
||||
* Qualifier annotation for a metric repository that is used by the actuator (to |
||||
* distinguish it from others that might be installed by the user). |
||||
* |
||||
* @author Dave Syer |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Qualifier |
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, |
||||
ElementType.ANNOTATION_TYPE }) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Inherited |
||||
@Documented |
||||
public @interface ActuatorMetricWriter { |
||||
|
||||
} |
||||
@ -1,43 +0,0 @@
@@ -1,43 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Inherited; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier; |
||||
|
||||
/** |
||||
* Qualifier annotation for a metric reader that can be exported (to distinguish it from |
||||
* others that might be installed by the user for other purposes). |
||||
* |
||||
* @author Dave Syer |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Qualifier |
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, |
||||
ElementType.ANNOTATION_TYPE }) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Inherited |
||||
@Documented |
||||
public @interface ExportMetricReader { |
||||
|
||||
} |
||||
@ -1,43 +0,0 @@
@@ -1,43 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Inherited; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier; |
||||
|
||||
/** |
||||
* Qualifier annotation for a metric repository that is to be used to export metrics from |
||||
* the {@link ExportMetricReader} readers. |
||||
* |
||||
* @author Dave Syer |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Qualifier |
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, |
||||
ElementType.ANNOTATION_TYPE }) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Inherited |
||||
@Documented |
||||
public @interface ExportMetricWriter { |
||||
|
||||
} |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import io.micrometer.core.instrument.binder.JvmMemoryMetrics; |
||||
import io.micrometer.core.instrument.binder.LogbackMetrics; |
||||
import io.micrometer.core.instrument.binder.MeterBinder; |
||||
import io.micrometer.core.instrument.binder.UptimeMetrics; |
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
/** |
||||
* Configuration for various {@link MeterBinder MeterBinders}. |
||||
* |
||||
* @author Jon Schneider |
||||
*/ |
||||
@Configuration |
||||
class MeterBindersConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(JvmMemoryMetrics.class) |
||||
public JvmMemoryMetrics jvmMemoryMetrics() { |
||||
return new JvmMemoryMetrics(); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(LogbackMetrics.class) |
||||
@ConditionalOnClass(name = "ch.qos.logback.classic.Logger") |
||||
public LogbackMetrics logbackMetrics() { |
||||
return new LogbackMetrics(); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(UptimeMetrics.class) |
||||
public UptimeMetrics uptimeMetrics() { |
||||
return new UptimeMetrics(); |
||||
} |
||||
|
||||
} |
||||
@ -1,147 +0,0 @@
@@ -1,147 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.beans.factory.ObjectProvider; |
||||
import org.springframework.beans.factory.annotation.Value; |
||||
import org.springframework.boot.actuate.metrics.export.Exporter; |
||||
import org.springframework.boot.actuate.metrics.export.MetricExportProperties; |
||||
import org.springframework.boot.actuate.metrics.export.MetricExporters; |
||||
import org.springframework.boot.actuate.metrics.reader.CompositeMetricReader; |
||||
import org.springframework.boot.actuate.metrics.reader.MetricReader; |
||||
import org.springframework.boot.actuate.metrics.reader.MetricsEndpointMetricReader; |
||||
import org.springframework.boot.actuate.metrics.statsd.StatsdMetricWriter; |
||||
import org.springframework.boot.actuate.metrics.writer.GaugeWriter; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.scheduling.annotation.EnableScheduling; |
||||
import org.springframework.scheduling.annotation.SchedulingConfigurer; |
||||
import org.springframework.scheduling.config.ScheduledTaskRegistrar; |
||||
import org.springframework.util.CollectionUtils; |
||||
|
||||
/** |
||||
* {@link EnableAutoConfiguration Auto-configuration} for metrics export. |
||||
* |
||||
* @author Dave Syer |
||||
* @author Simon Buettner |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@EnableScheduling |
||||
@ConditionalOnProperty(value = "spring.metrics.export.enabled", matchIfMissing = true) |
||||
@EnableConfigurationProperties |
||||
public class MetricExportAutoConfiguration { |
||||
|
||||
private final MetricsEndpointMetricReader endpointReader; |
||||
|
||||
private final List<MetricReader> readers; |
||||
|
||||
private final Map<String, GaugeWriter> writers; |
||||
|
||||
private final Map<String, Exporter> exporters; |
||||
|
||||
public MetricExportAutoConfiguration(MetricExportProperties properties, |
||||
ObjectProvider<MetricsEndpointMetricReader> endpointReader, |
||||
@ExportMetricReader ObjectProvider<List<MetricReader>> readers, |
||||
@ExportMetricWriter ObjectProvider<Map<String, GaugeWriter>> writers, |
||||
ObjectProvider<Map<String, Exporter>> exporters) { |
||||
this.endpointReader = endpointReader.getIfAvailable(); |
||||
this.readers = readers.getIfAvailable(); |
||||
this.writers = writers.getIfAvailable(); |
||||
this.exporters = exporters.getIfAvailable(); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(name = "metricWritersMetricExporter") |
||||
public SchedulingConfigurer metricWritersMetricExporter( |
||||
MetricExportProperties properties) { |
||||
Map<String, GaugeWriter> writers = new HashMap<>(); |
||||
MetricReader reader = this.endpointReader; |
||||
if (reader == null && !CollectionUtils.isEmpty(this.readers)) { |
||||
reader = new CompositeMetricReader( |
||||
this.readers.toArray(new MetricReader[this.readers.size()])); |
||||
} |
||||
if (reader == null && CollectionUtils.isEmpty(this.exporters)) { |
||||
return new NoOpSchedulingConfigurer(); |
||||
} |
||||
MetricExporters exporters = new MetricExporters(properties); |
||||
if (reader != null) { |
||||
if (!CollectionUtils.isEmpty(this.writers)) { |
||||
writers.putAll(this.writers); |
||||
} |
||||
exporters.setReader(reader); |
||||
exporters.setWriters(writers); |
||||
} |
||||
exporters.setExporters(this.exporters == null |
||||
? Collections.<String, Exporter>emptyMap() : this.exporters); |
||||
return exporters; |
||||
} |
||||
|
||||
@Configuration |
||||
static class StatsdConfiguration { |
||||
|
||||
@Bean |
||||
@ExportMetricWriter |
||||
@ConditionalOnMissingBean |
||||
@ConditionalOnProperty(prefix = "spring.metrics.export.statsd", name = "host") |
||||
public StatsdMetricWriter statsdMetricWriter(MetricExportProperties properties) { |
||||
MetricExportProperties.Statsd statsdProperties = properties.getStatsd(); |
||||
return new StatsdMetricWriter(statsdProperties.getPrefix(), |
||||
statsdProperties.getHost(), statsdProperties.getPort()); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
protected static class MetricExportPropertiesConfiguration { |
||||
|
||||
@Value("${spring.application.name:application}.${random.value:0000}") |
||||
private String prefix = ""; |
||||
|
||||
private String aggregateKeyPattern = "k.d"; |
||||
|
||||
@Bean(name = "spring.metrics.export-org.springframework.boot.actuate.metrics.export.MetricExportProperties") |
||||
@ConditionalOnMissingBean |
||||
public MetricExportProperties metricExportProperties() { |
||||
MetricExportProperties export = new MetricExportProperties(); |
||||
export.getRedis().setPrefix("spring.metrics" |
||||
+ (this.prefix.length() > 0 ? "." : "") + this.prefix); |
||||
export.getAggregate().setPrefix(this.prefix); |
||||
export.getAggregate().setKeyPattern(this.aggregateKeyPattern); |
||||
return export; |
||||
} |
||||
|
||||
} |
||||
|
||||
private static class NoOpSchedulingConfigurer implements SchedulingConfigurer { |
||||
|
||||
@Override |
||||
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,75 +0,0 @@
@@ -1,75 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import javax.servlet.Servlet; |
||||
import javax.servlet.ServletRegistration; |
||||
|
||||
import org.springframework.boot.actuate.metrics.CounterService; |
||||
import org.springframework.boot.actuate.metrics.GaugeService; |
||||
import org.springframework.boot.actuate.metrics.web.servlet.MetricsFilter; |
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter; |
||||
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.ConditionalOnProperty; |
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.web.filter.OncePerRequestFilter; |
||||
import org.springframework.web.servlet.HandlerMapping; |
||||
|
||||
/** |
||||
* {@link EnableAutoConfiguration Auto-configuration} that records Servlet interactions |
||||
* with a {@link CounterService} and {@link GaugeService}. |
||||
* |
||||
* @author Dave Syer |
||||
* @author Phillip Webb |
||||
* @author Andy Wilkinson |
||||
* @author Sebastian Kirsch |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnBean({ CounterService.class, GaugeService.class }) |
||||
@ConditionalOnClass({ Servlet.class, ServletRegistration.class, |
||||
OncePerRequestFilter.class, HandlerMapping.class }) |
||||
@AutoConfigureAfter(MetricRepositoryAutoConfiguration.class) |
||||
@ConditionalOnProperty(prefix = "management.metrics.filter", name = "enabled", matchIfMissing = true) |
||||
@EnableConfigurationProperties({ MetricFilterProperties.class }) |
||||
public class MetricFilterAutoConfiguration { |
||||
|
||||
private final CounterService counterService; |
||||
|
||||
private final GaugeService gaugeService; |
||||
|
||||
private final MetricFilterProperties properties; |
||||
|
||||
public MetricFilterAutoConfiguration(CounterService counterService, |
||||
GaugeService gaugeService, MetricFilterProperties properties) { |
||||
this.counterService = counterService; |
||||
this.gaugeService = gaugeService; |
||||
this.properties = properties; |
||||
} |
||||
|
||||
@Bean |
||||
public MetricsFilter metricsFilter() { |
||||
return new MetricsFilter(this.counterService, this.gaugeService, |
||||
this.properties.getCounterSubmissions(), |
||||
this.properties.getGaugeSubmissions()); |
||||
} |
||||
|
||||
} |
||||
@ -1,69 +0,0 @@
@@ -1,69 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import java.util.EnumSet; |
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
|
||||
import org.springframework.boot.actuate.metrics.web.servlet.MetricsFilter; |
||||
import org.springframework.boot.actuate.metrics.web.servlet.MetricsFilterSubmission; |
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* Configuration properties for the {@link MetricsFilter}. |
||||
* |
||||
* @author Sebastian Kirsch |
||||
* @author Phillip Webb |
||||
* @since 2.0.0 |
||||
*/ |
||||
@ConfigurationProperties(prefix = "management.metrics.filter") |
||||
public class MetricFilterProperties { |
||||
|
||||
/** |
||||
* Submissions that should be made to the gauge. |
||||
*/ |
||||
private Set<MetricsFilterSubmission> gaugeSubmissions; |
||||
|
||||
/** |
||||
* Submissions that should be made to the counter. |
||||
*/ |
||||
private Set<MetricsFilterSubmission> counterSubmissions; |
||||
|
||||
public MetricFilterProperties() { |
||||
this.gaugeSubmissions = new HashSet<>(EnumSet.of(MetricsFilterSubmission.MERGED)); |
||||
this.counterSubmissions = new HashSet<>( |
||||
EnumSet.of(MetricsFilterSubmission.MERGED)); |
||||
} |
||||
|
||||
public Set<MetricsFilterSubmission> getGaugeSubmissions() { |
||||
return this.gaugeSubmissions; |
||||
} |
||||
|
||||
public void setGaugeSubmissions(Set<MetricsFilterSubmission> gaugeSubmissions) { |
||||
this.gaugeSubmissions = gaugeSubmissions; |
||||
} |
||||
|
||||
public Set<MetricsFilterSubmission> getCounterSubmissions() { |
||||
return this.counterSubmissions; |
||||
} |
||||
|
||||
public void setCounterSubmissions(Set<MetricsFilterSubmission> counterSubmissions) { |
||||
this.counterSubmissions = counterSubmissions; |
||||
} |
||||
|
||||
} |
||||
@ -1,114 +0,0 @@
@@ -1,114 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import com.codahale.metrics.MetricRegistry; |
||||
|
||||
import org.springframework.boot.actuate.metrics.CounterService; |
||||
import org.springframework.boot.actuate.metrics.GaugeService; |
||||
import org.springframework.boot.actuate.metrics.buffer.BufferCounterService; |
||||
import org.springframework.boot.actuate.metrics.buffer.BufferGaugeService; |
||||
import org.springframework.boot.actuate.metrics.buffer.BufferMetricReader; |
||||
import org.springframework.boot.actuate.metrics.buffer.CounterBuffers; |
||||
import org.springframework.boot.actuate.metrics.buffer.GaugeBuffers; |
||||
import org.springframework.boot.actuate.metrics.export.Exporter; |
||||
import org.springframework.boot.actuate.metrics.export.MetricCopyExporter; |
||||
import org.springframework.boot.actuate.metrics.repository.InMemoryMetricRepository; |
||||
import org.springframework.boot.actuate.metrics.writer.MetricWriter; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.messaging.MessageChannel; |
||||
|
||||
/** |
||||
* {@link EnableAutoConfiguration Auto-configuration} for metrics services. Creates |
||||
* user-facing {@link GaugeService} and {@link CounterService} instances, and also back |
||||
* end repositories to catch the data pumped into them. |
||||
* <p> |
||||
* In general, even if metric data needs to be stored and analysed remotely, it is |
||||
* recommended to use in-memory storage to buffer metric updates locally as is done by the |
||||
* default {@link CounterBuffers} and {@link GaugeBuffers}. The values can be exported |
||||
* (e.g. on a periodic basis) using an {@link Exporter}, most implementations of which |
||||
* have optimizations for sending data to remote repositories. |
||||
* <p> |
||||
* If Spring Messaging is on the classpath and a {@link MessageChannel} called |
||||
* "metricsChannel" is also available, all metric update events are published additionally |
||||
* as messages on that channel. Additional analysis or actions can be taken by clients |
||||
* subscribing to that channel. |
||||
* <p> |
||||
* In addition if Dropwizard's metrics library is on the classpath a |
||||
* {@link MetricRegistry} will be created and the default counter and gauge services will |
||||
* switch to using it instead of the default repository. Users can create "special" |
||||
* Dropwizard metrics by prefixing their metric names with the appropriate type (e.g. |
||||
* "histogram.*", "meter.*". "timer.*") and sending them to the {@code GaugeService} or |
||||
* {@code CounterService}. |
||||
* <p> |
||||
* By default all metric updates go to all {@link MetricWriter} instances in the |
||||
* application context via a {@link MetricCopyExporter} firing every 5 seconds (disable |
||||
* this by setting {@code spring.metrics.export.enabled=false}). |
||||
* |
||||
* @see GaugeService |
||||
* @see CounterService |
||||
* @see MetricWriter |
||||
* @see InMemoryMetricRepository |
||||
* @see Exporter |
||||
* @author Dave Syer |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
public class MetricRepositoryAutoConfiguration { |
||||
|
||||
@Configuration |
||||
@ConditionalOnMissingBean(GaugeService.class) |
||||
static class FastMetricServicesConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public CounterBuffers counterBuffers() { |
||||
return new CounterBuffers(); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public GaugeBuffers gaugeBuffers() { |
||||
return new GaugeBuffers(); |
||||
} |
||||
|
||||
@Bean |
||||
@ExportMetricReader |
||||
@ConditionalOnMissingBean |
||||
public BufferMetricReader actuatorMetricReader(CounterBuffers counters, |
||||
GaugeBuffers gauges) { |
||||
return new BufferMetricReader(counters, gauges); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(CounterService.class) |
||||
public BufferCounterService counterService(CounterBuffers writer) { |
||||
return new BufferCounterService(writer); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(GaugeService.class) |
||||
public BufferGaugeService gaugeService(GaugeBuffers writer) { |
||||
return new BufferGaugeService(writer); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,128 @@
@@ -0,0 +1,128 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
|
||||
import io.micrometer.core.annotation.Timed; |
||||
import io.micrometer.core.instrument.MeterRegistry; |
||||
import io.micrometer.core.instrument.Metrics; |
||||
import io.micrometer.core.instrument.binder.MeterBinder; |
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry; |
||||
|
||||
import org.springframework.beans.factory.ObjectProvider; |
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.atlas.AtlasExportConfiguration; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.datadog.DatadogExportConfiguration; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.ganglia.GangliaExportConfiguration; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.graphite.GraphiteExportConfiguration; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.influx.InfluxExportConfiguration; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.jmx.JmxExportConfiguration; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusExportConfiguration; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleExportConfiguration; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.reactive.server.WebFluxMetricsConfiguration; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsConfiguration; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsConfiguration; |
||||
import org.springframework.boot.actuate.metrics.MetricsEndpoint; |
||||
import org.springframework.boot.actuate.metrics.integration.SpringIntegrationMetrics; |
||||
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.autoconfigure.condition.SearchStrategy; |
||||
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; |
||||
import org.springframework.integration.config.EnableIntegrationManagement; |
||||
import org.springframework.integration.support.management.IntegrationManagementConfigurer; |
||||
|
||||
/** |
||||
* {@link EnableAutoConfiguration Auto-configuration} for Micrometer-based metrics. |
||||
* |
||||
* @since 2.0.0 |
||||
* @author Jon Schneider |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnClass(Timed.class) |
||||
@EnableConfigurationProperties(MetricsProperties.class) |
||||
@Import({ MeterBindersConfiguration.class, WebMvcMetricsConfiguration.class, |
||||
WebFluxMetricsConfiguration.class, RestTemplateMetricsConfiguration.class, |
||||
AtlasExportConfiguration.class, DatadogExportConfiguration.class, |
||||
GangliaExportConfiguration.class, GraphiteExportConfiguration.class, |
||||
InfluxExportConfiguration.class, JmxExportConfiguration.class, |
||||
PrometheusExportConfiguration.class, SimpleExportConfiguration.class }) |
||||
public class MetricsAutoConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(MeterRegistry.class) |
||||
public CompositeMeterRegistry compositeMeterRegistry( |
||||
ObjectProvider<Collection<MetricsExporter>> exporters) { |
||||
CompositeMeterRegistry composite = new CompositeMeterRegistry(); |
||||
exporters.getIfAvailable(Collections::emptyList).stream() |
||||
.map(MetricsExporter::registry).forEach(composite::add); |
||||
return composite; |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnBean(MeterRegistry.class) |
||||
@ConditionalOnMissingBean |
||||
@ConditionalOnEnabledEndpoint |
||||
public MetricsEndpoint metricsEndpoint(MeterRegistry registry) { |
||||
return new MetricsEndpoint(registry); |
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnClass(EnableIntegrationManagement.class) |
||||
static class MetricsIntegrationConfiguration { |
||||
|
||||
@Bean(name = IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME) |
||||
@ConditionalOnMissingBean(value = IntegrationManagementConfigurer.class, name = IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME, search = SearchStrategy.CURRENT) |
||||
public IntegrationManagementConfigurer integrationManagementConfigurer() { |
||||
IntegrationManagementConfigurer configurer = new IntegrationManagementConfigurer(); |
||||
configurer.setDefaultCountsEnabled(true); |
||||
configurer.setDefaultStatsEnabled(true); |
||||
return configurer; |
||||
} |
||||
|
||||
@Bean |
||||
public SpringIntegrationMetrics springIntegrationMetrics( |
||||
IntegrationManagementConfigurer configurer) { |
||||
return new SpringIntegrationMetrics(configurer); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class MeterRegistryConfigurationSupport { |
||||
|
||||
MeterRegistryConfigurationSupport(MeterRegistry registry, |
||||
ObjectProvider<Collection<MeterRegistryConfigurer>> configurers, |
||||
MetricsProperties config, Collection<MeterBinder> binders) { |
||||
configurers.getIfAvailable(Collections::emptyList) |
||||
.forEach((configurer) -> configurer.configureRegistry(registry)); |
||||
binders.forEach((binder) -> binder.bindTo(registry)); |
||||
if (config.isUseGlobalRegistry()) { |
||||
Metrics.addRegistry(registry); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,80 +0,0 @@
@@ -1,80 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import com.codahale.metrics.MetricRegistry; |
||||
|
||||
import org.springframework.beans.factory.ObjectProvider; |
||||
import org.springframework.boot.actuate.metrics.CounterService; |
||||
import org.springframework.boot.actuate.metrics.GaugeService; |
||||
import org.springframework.boot.actuate.metrics.dropwizard.DropwizardMetricServices; |
||||
import org.springframework.boot.actuate.metrics.dropwizard.ReservoirFactory; |
||||
import org.springframework.boot.actuate.metrics.reader.MetricReaderPublicMetrics; |
||||
import org.springframework.boot.actuate.metrics.reader.MetricRegistryMetricReader; |
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
/** |
||||
* {@link EnableAutoConfiguration Auto-configuration} for Dropwizard-based metrics. |
||||
* |
||||
* @author Dave Syer |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnClass(MetricRegistry.class) |
||||
@AutoConfigureBefore(MetricRepositoryAutoConfiguration.class) |
||||
public class MetricsDropwizardAutoConfiguration { |
||||
|
||||
private final ReservoirFactory reservoirFactory; |
||||
|
||||
public MetricsDropwizardAutoConfiguration( |
||||
ObjectProvider<ReservoirFactory> reservoirFactory) { |
||||
this.reservoirFactory = reservoirFactory.getIfAvailable(); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public MetricRegistry metricRegistry() { |
||||
return new MetricRegistry(); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean({ DropwizardMetricServices.class, CounterService.class, |
||||
GaugeService.class }) |
||||
public DropwizardMetricServices dropwizardMetricServices( |
||||
MetricRegistry metricRegistry) { |
||||
if (this.reservoirFactory == null) { |
||||
return new DropwizardMetricServices(metricRegistry); |
||||
} |
||||
else { |
||||
return new DropwizardMetricServices(metricRegistry, this.reservoirFactory); |
||||
} |
||||
} |
||||
|
||||
@Bean |
||||
public MetricReaderPublicMetrics dropwizardPublicMetrics( |
||||
MetricRegistry metricRegistry) { |
||||
MetricRegistryMetricReader reader = new MetricRegistryMetricReader( |
||||
metricRegistry); |
||||
return new MetricReaderPublicMetrics(reader); |
||||
} |
||||
|
||||
} |
||||
@ -1,62 +0,0 @@
@@ -1,62 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
import org.springframework.beans.factory.ObjectProvider; |
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; |
||||
import org.springframework.boot.actuate.metrics.MetricsEndpoint; |
||||
import org.springframework.boot.actuate.metrics.PublicMetrics; |
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator; |
||||
|
||||
/** |
||||
* {@link EnableAutoConfiguration Auto-configuration} for the {@link MetricsEndpoint}. |
||||
* |
||||
* @author Phillip Webb |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@AutoConfigureAfter(PublicMetricsAutoConfiguration.class) |
||||
public class MetricsEndpointAutoConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
@ConditionalOnEnabledEndpoint |
||||
public MetricsEndpoint metricsEndpoint( |
||||
ObjectProvider<List<PublicMetrics>> publicMetrics) { |
||||
return metricsEndpoint(publicMetrics.getIfAvailable(Collections::emptyList)); |
||||
} |
||||
|
||||
private MetricsEndpoint metricsEndpoint(List<PublicMetrics> publicMetrics) { |
||||
return new MetricsEndpoint(sort(publicMetrics)); |
||||
} |
||||
|
||||
private List<PublicMetrics> sort(List<PublicMetrics> publicMetrics) { |
||||
List<PublicMetrics> sorted = new ArrayList<>(publicMetrics); |
||||
Collections.sort(sorted, AnnotationAwareOrderComparator.INSTANCE); |
||||
return sorted; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,154 @@
@@ -0,0 +1,154 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* {@link ConfigurationProperties} for configuring Micrometer-based metrics. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
*/ |
||||
@ConfigurationProperties("spring.metrics") |
||||
public class MetricsProperties { |
||||
|
||||
private Web web = new Web(); |
||||
|
||||
/** |
||||
* Whether or not auto-configured MeterRegistry implementations should be bound to the |
||||
* global static registry on Metrics. For testing, set this to 'false' to maximize |
||||
* test independence. |
||||
*/ |
||||
private boolean useGlobalRegistry = true; |
||||
|
||||
public boolean isUseGlobalRegistry() { |
||||
return this.useGlobalRegistry; |
||||
} |
||||
|
||||
public void setUseGlobalRegistry(boolean useGlobalRegistry) { |
||||
this.useGlobalRegistry = useGlobalRegistry; |
||||
} |
||||
|
||||
public Web getWeb() { |
||||
return this.web; |
||||
} |
||||
|
||||
public static class Web { |
||||
|
||||
private Client client = new Client(); |
||||
|
||||
private Server server = new Server(); |
||||
|
||||
public Client getClient() { |
||||
return this.client; |
||||
} |
||||
|
||||
public void setClient(Client client) { |
||||
this.client = client; |
||||
} |
||||
|
||||
public Server getServer() { |
||||
return this.server; |
||||
} |
||||
|
||||
public void setServer(Server server) { |
||||
this.server = server; |
||||
} |
||||
|
||||
public static class Client { |
||||
|
||||
/** |
||||
* Whether or not instrumented requests record percentiles histogram buckets |
||||
* by default. |
||||
*/ |
||||
private boolean recordRequestPercentiles; |
||||
|
||||
/** |
||||
* Name of the metric for sent requests. |
||||
*/ |
||||
private String requestsMetricName = "http.client.requests"; |
||||
|
||||
public boolean isRecordRequestPercentiles() { |
||||
return this.recordRequestPercentiles; |
||||
} |
||||
|
||||
public void setRecordRequestPercentiles(boolean recordRequestPercentiles) { |
||||
this.recordRequestPercentiles = recordRequestPercentiles; |
||||
} |
||||
|
||||
public String getRequestsMetricName() { |
||||
return this.requestsMetricName; |
||||
} |
||||
|
||||
public void setRequestsMetricName(String requestsMetricName) { |
||||
this.requestsMetricName = requestsMetricName; |
||||
} |
||||
|
||||
} |
||||
|
||||
public static class Server { |
||||
|
||||
/** |
||||
* Whether or not requests handled by Spring MVC or WebFlux should be |
||||
* automatically timed. If the number of time series emitted grows too large |
||||
* on account of request mapping timings, disable this and use 'Timed' on a |
||||
* per request mapping basis as needed. |
||||
*/ |
||||
private boolean autoTimeRequests = true; |
||||
|
||||
/** |
||||
* Whether or not instrumented requests record percentiles histogram buckets |
||||
* by default. Can be overridden by adding '@Timed' to a request endpoint and |
||||
* setting 'percentiles' to true. |
||||
*/ |
||||
private boolean recordRequestPercentiles; |
||||
|
||||
/** |
||||
* Name of the metric for received requests. |
||||
*/ |
||||
private String requestsMetricName = "http.server.requests"; |
||||
|
||||
public boolean isAutoTimeRequests() { |
||||
return this.autoTimeRequests; |
||||
} |
||||
|
||||
public void setAutoTimeRequests(boolean autoTimeRequests) { |
||||
this.autoTimeRequests = autoTimeRequests; |
||||
} |
||||
|
||||
public boolean isRecordRequestPercentiles() { |
||||
return this.recordRequestPercentiles; |
||||
} |
||||
|
||||
public void setRecordRequestPercentiles(boolean recordRequestPercentiles) { |
||||
this.recordRequestPercentiles = recordRequestPercentiles; |
||||
} |
||||
|
||||
public String getRequestsMetricName() { |
||||
return this.requestsMetricName; |
||||
} |
||||
|
||||
public void setRequestsMetricName(String requestsMetricName) { |
||||
this.requestsMetricName = requestsMetricName; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,167 +0,0 @@
@@ -1,167 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import javax.servlet.Servlet; |
||||
import javax.sql.DataSource; |
||||
|
||||
import org.apache.catalina.startup.Tomcat; |
||||
|
||||
import org.springframework.beans.factory.ObjectProvider; |
||||
import org.springframework.boot.actuate.autoconfigure.cache.CacheStatisticsAutoConfiguration; |
||||
import org.springframework.boot.actuate.cache.CachePublicMetrics; |
||||
import org.springframework.boot.actuate.cache.CacheStatisticsProvider; |
||||
import org.springframework.boot.actuate.metrics.DataSourcePublicMetrics; |
||||
import org.springframework.boot.actuate.metrics.PublicMetrics; |
||||
import org.springframework.boot.actuate.metrics.SystemPublicMetrics; |
||||
import org.springframework.boot.actuate.metrics.TomcatPublicMetrics; |
||||
import org.springframework.boot.actuate.metrics.integration.SpringIntegrationMetricReader; |
||||
import org.springframework.boot.actuate.metrics.reader.CompositeMetricReader; |
||||
import org.springframework.boot.actuate.metrics.reader.MetricReader; |
||||
import org.springframework.boot.actuate.metrics.reader.MetricReaderPublicMetrics; |
||||
import org.springframework.boot.actuate.metrics.rich.RichGaugeReader; |
||||
import org.springframework.boot.actuate.metrics.rich.RichGaugeReaderPublicMetrics; |
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; |
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy; |
||||
import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; |
||||
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider; |
||||
import org.springframework.cache.CacheManager; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.integration.config.EnableIntegrationManagement; |
||||
import org.springframework.integration.support.management.IntegrationManagementConfigurer; |
||||
|
||||
/** |
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link PublicMetrics}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @author Phillip Webb |
||||
* @author Johannes Edmeier |
||||
* @author Artem Bilan |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, CacheAutoConfiguration.class, |
||||
MetricRepositoryAutoConfiguration.class, CacheStatisticsAutoConfiguration.class, |
||||
IntegrationAutoConfiguration.class }) |
||||
public class PublicMetricsAutoConfiguration { |
||||
|
||||
private final List<MetricReader> metricReaders; |
||||
|
||||
public PublicMetricsAutoConfiguration( |
||||
@ExportMetricReader ObjectProvider<List<MetricReader>> metricReaders) { |
||||
this.metricReaders = metricReaders.getIfAvailable(); |
||||
} |
||||
|
||||
@Bean |
||||
public SystemPublicMetrics systemPublicMetrics() { |
||||
return new SystemPublicMetrics(); |
||||
} |
||||
|
||||
@Bean |
||||
public MetricReaderPublicMetrics metricReaderPublicMetrics() { |
||||
return new MetricReaderPublicMetrics( |
||||
new CompositeMetricReader(this.metricReaders == null ? new MetricReader[0] |
||||
: this.metricReaders |
||||
.toArray(new MetricReader[this.metricReaders.size()]))); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnBean(RichGaugeReader.class) |
||||
public RichGaugeReaderPublicMetrics richGaugePublicMetrics( |
||||
RichGaugeReader richGaugeReader) { |
||||
return new RichGaugeReaderPublicMetrics(richGaugeReader); |
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnClass(DataSource.class) |
||||
@ConditionalOnBean(DataSource.class) |
||||
static class DataSourceMetricsConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
@ConditionalOnBean(DataSourcePoolMetadataProvider.class) |
||||
public DataSourcePublicMetrics dataSourcePublicMetrics() { |
||||
return new DataSourcePublicMetrics(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnClass({ Servlet.class, Tomcat.class }) |
||||
@ConditionalOnWebApplication |
||||
static class TomcatMetricsConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public TomcatPublicMetrics tomcatPublicMetrics() { |
||||
return new TomcatPublicMetrics(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnClass(CacheManager.class) |
||||
@ConditionalOnBean(CacheManager.class) |
||||
static class CacheStatisticsConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
@ConditionalOnBean(CacheStatisticsProvider.class) |
||||
public CachePublicMetrics cachePublicMetrics( |
||||
Map<String, CacheManager> cacheManagers, |
||||
Collection<CacheStatisticsProvider<?>> statisticsProviders) { |
||||
return new CachePublicMetrics(cacheManagers, statisticsProviders); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
@ConditionalOnClass(EnableIntegrationManagement.class) |
||||
static class IntegrationMetricsConfiguration { |
||||
|
||||
@Bean(name = IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME) |
||||
@ConditionalOnMissingBean(value = IntegrationManagementConfigurer.class, name = IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME, search = SearchStrategy.CURRENT) |
||||
public IntegrationManagementConfigurer managementConfigurer() { |
||||
IntegrationManagementConfigurer configurer = new IntegrationManagementConfigurer(); |
||||
configurer.setDefaultCountsEnabled(true); |
||||
configurer.setDefaultStatsEnabled(true); |
||||
return configurer; |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(name = "springIntegrationPublicMetrics") |
||||
public MetricReaderPublicMetrics springIntegrationPublicMetrics( |
||||
IntegrationManagementConfigurer managementConfigurer) { |
||||
return new MetricReaderPublicMetrics( |
||||
new SpringIntegrationMetricReader(managementConfigurer)); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export; |
||||
|
||||
import java.time.Duration; |
||||
|
||||
import io.micrometer.core.instrument.spectator.step.StepRegistryConfig; |
||||
|
||||
/** |
||||
* Specialization of {@link RegistryProperties} for configuring a metrics registry that |
||||
* pushes aggregated metrics on a regular interval. |
||||
* |
||||
* @author Jon Schneider |
||||
* @author Andy Wilkinson |
||||
* @since 2.0.0 |
||||
*/ |
||||
public abstract class StepRegistryProperties extends RegistryProperties |
||||
implements StepRegistryConfig { |
||||
|
||||
public void setStep(Duration step) { |
||||
set("step", step); |
||||
} |
||||
|
||||
public void setEnabled(Boolean enabled) { |
||||
set("enabled", enabled); |
||||
} |
||||
|
||||
public void setBatchSize(Integer batchSize) { |
||||
set("batchSize", batchSize); |
||||
} |
||||
|
||||
public void setConnectTimeout(Duration connectTimeout) { |
||||
set("connectTimeout", connectTimeout); |
||||
} |
||||
|
||||
public void setReadTimeout(Duration readTimeout) { |
||||
set("readTimeout", readTimeout); |
||||
} |
||||
|
||||
public void setNumThreads(Integer numThreads) { |
||||
set("numThreads", numThreads); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.atlas; |
||||
|
||||
import com.netflix.spectator.atlas.AtlasConfig; |
||||
import io.micrometer.atlas.AtlasMeterRegistry; |
||||
import io.micrometer.core.instrument.Clock; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.StringToDurationConverter; |
||||
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.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Import; |
||||
|
||||
/** |
||||
* Configuration for exporting metrics to Atlas. |
||||
* |
||||
* @author Jon Schneider |
||||
* @author Andy Wilkinson |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnClass(AtlasMeterRegistry.class) |
||||
@Import(StringToDurationConverter.class) |
||||
@EnableConfigurationProperties(AtlasProperties.class) |
||||
public class AtlasExportConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnProperty(value = "metrics.atlas.enabled", matchIfMissing = true) |
||||
public MetricsExporter atlasExporter(AtlasConfig config, Clock clock) { |
||||
return () -> new AtlasMeterRegistry(config, clock); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public Clock clock() { |
||||
return Clock.SYSTEM; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.atlas; |
||||
|
||||
import java.time.Duration; |
||||
|
||||
import com.netflix.spectator.atlas.AtlasConfig; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.RegistryProperties; |
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* {@link ConfigurationProperties} for configuring Atlas metrics export. |
||||
* |
||||
* @since 2.0.0 |
||||
* @author Jon Schneider |
||||
*/ |
||||
@ConfigurationProperties(prefix = "metrics.atlas") |
||||
public class AtlasProperties extends RegistryProperties implements AtlasConfig { |
||||
|
||||
@Override |
||||
protected String prefix() { |
||||
return "atlas"; |
||||
} |
||||
|
||||
public void setStep(Duration step) { |
||||
set("step", step); |
||||
} |
||||
|
||||
public void setMeterTTL(Duration meterTTL) { |
||||
set("meterTTL", meterTTL); |
||||
} |
||||
|
||||
public void setEnabled(Boolean enabled) { |
||||
set("enabled", enabled); |
||||
} |
||||
|
||||
public void setNumThreads(Integer numThreads) { |
||||
set("numThreads", numThreads); |
||||
} |
||||
|
||||
public void setUri(String uri) { |
||||
set("uri", uri); |
||||
} |
||||
|
||||
public void setLwcEnabled(boolean lwcEnabled) { |
||||
set("lwcEnabled", lwcEnabled); |
||||
} |
||||
|
||||
public void setConfigRefreshFrequency(Duration configRefreshFrequency) { |
||||
set("configRefreshFrequency", configRefreshFrequency); |
||||
} |
||||
|
||||
public void setConfigTTL(Duration configTTL) { |
||||
set("configTTL", configTTL); |
||||
} |
||||
|
||||
public void setConfigUri(String configUri) { |
||||
set("configUri", configUri); |
||||
} |
||||
|
||||
public void setEvalUri(String evalUri) { |
||||
set("evalUri", evalUri); |
||||
} |
||||
|
||||
public void setConnectTimeout(Duration connectTimeout) { |
||||
set("connectTimeout", connectTimeout); |
||||
} |
||||
|
||||
public void setReadTimeout(Duration readTimeout) { |
||||
set("readTimeout", readTimeout); |
||||
} |
||||
|
||||
public void setBatchSize(Integer batchSize) { |
||||
set("batchSize", batchSize); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.datadog; |
||||
|
||||
import io.micrometer.core.instrument.Clock; |
||||
import io.micrometer.datadog.DatadogConfig; |
||||
import io.micrometer.datadog.DatadogMeterRegistry; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.StringToDurationConverter; |
||||
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.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Import; |
||||
|
||||
/** |
||||
* Configuration for exporting metrics to Datadog. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnClass(DatadogMeterRegistry.class) |
||||
@Import(StringToDurationConverter.class) |
||||
@EnableConfigurationProperties(DatadogProperties.class) |
||||
public class DatadogExportConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnProperty(value = "metrics.datadog.enabled", matchIfMissing = true) |
||||
public MetricsExporter datadogExporter(DatadogConfig config, Clock clock) { |
||||
return () -> new DatadogMeterRegistry(config, clock); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public Clock clock() { |
||||
return Clock.SYSTEM; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.datadog; |
||||
|
||||
import io.micrometer.datadog.DatadogConfig; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.StepRegistryProperties; |
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* {@link ConfigurationProperties} for configuring Datadog metrics export. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
*/ |
||||
@ConfigurationProperties(prefix = "metrics.datadog") |
||||
public class DatadogProperties extends StepRegistryProperties implements DatadogConfig { |
||||
|
||||
@Override |
||||
public String prefix() { |
||||
return "metrics.datadog"; |
||||
} |
||||
|
||||
public DatadogProperties() { |
||||
set("apiKey", "dummyKey"); // FIXME otherwise tests fail
|
||||
} |
||||
|
||||
public void setApiKey(String apiKey) { |
||||
set("apiKey", apiKey); |
||||
} |
||||
|
||||
public void setHostTag(String hostTag) { |
||||
set("hostTag", hostTag); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,65 @@
@@ -0,0 +1,65 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.ganglia; |
||||
|
||||
import io.micrometer.core.instrument.Clock; |
||||
import io.micrometer.core.instrument.util.HierarchicalNameMapper; |
||||
import io.micrometer.ganglia.GangliaConfig; |
||||
import io.micrometer.ganglia.GangliaMeterRegistry; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.StringToDurationConverter; |
||||
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.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Import; |
||||
|
||||
/** |
||||
* Configuration for exporting metrics to Ganglia. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnClass(GangliaMeterRegistry.class) |
||||
@Import(StringToDurationConverter.class) |
||||
@EnableConfigurationProperties(GangliaProperties.class) |
||||
public class GangliaExportConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnProperty(value = "metrics.ganglia.enabled", matchIfMissing = true) |
||||
public MetricsExporter gangliaExporter(GangliaConfig config, |
||||
HierarchicalNameMapper nameMapper, Clock clock) { |
||||
return () -> new GangliaMeterRegistry(config, nameMapper, clock); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public Clock clock() { |
||||
return Clock.SYSTEM; |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public HierarchicalNameMapper hierarchicalNameMapper() { |
||||
return HierarchicalNameMapper.DEFAULT; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,78 @@
@@ -0,0 +1,78 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.ganglia; |
||||
|
||||
import java.time.Duration; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
import info.ganglia.gmetric4j.gmetric.GMetric; |
||||
import io.micrometer.ganglia.GangliaConfig; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.RegistryProperties; |
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* {@link ConfigurationProperties} for configuring Ganglia metrics export. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
*/ |
||||
@ConfigurationProperties(prefix = "metrics.ganglia") |
||||
public class GangliaProperties extends RegistryProperties implements GangliaConfig { |
||||
|
||||
@Override |
||||
public String prefix() { |
||||
return "metrics.ganglia"; |
||||
} |
||||
|
||||
public void setStep(Duration step) { |
||||
set("step", step); |
||||
} |
||||
|
||||
public void setRateUnits(TimeUnit rateUnits) { |
||||
set("rateUnits", rateUnits); |
||||
} |
||||
|
||||
public void setDurationUnits(TimeUnit durationUnits) { |
||||
set("durationUnits", durationUnits); |
||||
} |
||||
|
||||
public void setProtocolVersion(String protocolVersion) { |
||||
set("protocolVersion", protocolVersion); |
||||
} |
||||
|
||||
public void setAddressingMode(GMetric.UDPAddressingMode addressingMode) { |
||||
set("addressingMode", addressingMode); |
||||
} |
||||
|
||||
public void setTtl(Integer ttl) { |
||||
set("ttl", ttl); |
||||
} |
||||
|
||||
public void setHost(String host) { |
||||
set("host", host); |
||||
} |
||||
|
||||
public void setPort(Integer port) { |
||||
set("port", port); |
||||
} |
||||
|
||||
public void setEnabled(Boolean enabled) { |
||||
set("enabled", enabled); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,65 @@
@@ -0,0 +1,65 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.graphite; |
||||
|
||||
import io.micrometer.core.instrument.Clock; |
||||
import io.micrometer.core.instrument.util.HierarchicalNameMapper; |
||||
import io.micrometer.graphite.GraphiteConfig; |
||||
import io.micrometer.graphite.GraphiteMeterRegistry; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.StringToDurationConverter; |
||||
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.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Import; |
||||
|
||||
/** |
||||
* Configuration for exporting metrics to Graphite. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnClass(GraphiteMeterRegistry.class) |
||||
@Import(StringToDurationConverter.class) |
||||
@EnableConfigurationProperties(GraphiteProperties.class) |
||||
public class GraphiteExportConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnProperty(value = "metrics.graphite.enabled", matchIfMissing = true) |
||||
public MetricsExporter graphiteExporter(GraphiteConfig config, |
||||
HierarchicalNameMapper nameMapper, Clock clock) { |
||||
return () -> new GraphiteMeterRegistry(config, nameMapper, clock); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public Clock clock() { |
||||
return Clock.SYSTEM; |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public HierarchicalNameMapper hierarchicalNameMapper() { |
||||
return HierarchicalNameMapper.DEFAULT; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,65 @@
@@ -0,0 +1,65 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.graphite; |
||||
|
||||
import java.time.Duration; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
import io.micrometer.graphite.GraphiteConfig; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.RegistryProperties; |
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* {@link ConfigurationProperties} for configuring Graphite metrics export. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
*/ |
||||
@ConfigurationProperties(prefix = "metrics.graphite") |
||||
public class GraphiteProperties extends RegistryProperties implements GraphiteConfig { |
||||
|
||||
@Override |
||||
public String prefix() { |
||||
return "metrics.graphite"; |
||||
} |
||||
|
||||
public void setStep(Duration step) { |
||||
set("step", step); |
||||
} |
||||
|
||||
public void setRateUnits(TimeUnit rateUnits) { |
||||
set("rateUnits", rateUnits); |
||||
} |
||||
|
||||
public void setDurationUnits(TimeUnit durationUnits) { |
||||
set("durationUnits", durationUnits); |
||||
} |
||||
|
||||
public void setHost(String host) { |
||||
set("host", host); |
||||
} |
||||
|
||||
public void setPort(Integer port) { |
||||
set("port", port); |
||||
} |
||||
|
||||
public void setEnabled(Boolean enabled) { |
||||
set("enabled", enabled); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.influx; |
||||
|
||||
import io.micrometer.core.instrument.Clock; |
||||
import io.micrometer.influx.InfluxConfig; |
||||
import io.micrometer.influx.InfluxMeterRegistry; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.StringToDurationConverter; |
||||
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.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Import; |
||||
|
||||
/** |
||||
* Configuration for exporting metrics to Influx. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnClass(InfluxMeterRegistry.class) |
||||
@Import(StringToDurationConverter.class) |
||||
@EnableConfigurationProperties(InfluxProperties.class) |
||||
public class InfluxExportConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnProperty(value = "metrics.influx.enabled", matchIfMissing = true) |
||||
public MetricsExporter influxExporter(InfluxConfig config, Clock clock) { |
||||
return () -> new InfluxMeterRegistry(config, clock); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public Clock clock() { |
||||
return Clock.SYSTEM; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,67 @@
@@ -0,0 +1,67 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.influx; |
||||
|
||||
import io.micrometer.influx.InfluxConfig; |
||||
import io.micrometer.influx.InfluxConsistency; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.StepRegistryProperties; |
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* {@link ConfigurationProperties} for configuring Influx metrics export. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
*/ |
||||
@ConfigurationProperties(prefix = "metrics.influx") |
||||
public class InfluxProperties extends StepRegistryProperties implements InfluxConfig { |
||||
|
||||
@Override |
||||
public String prefix() { |
||||
return "metrics.influx"; |
||||
} |
||||
|
||||
public void setDb(String db) { |
||||
set("db", db); |
||||
} |
||||
|
||||
public void setConsistency(InfluxConsistency consistency) { |
||||
set("consistency", consistency); |
||||
} |
||||
|
||||
public void setUserName(String userName) { |
||||
set("userName", userName); |
||||
} |
||||
|
||||
public void setPassword(String password) { |
||||
set("password", password); |
||||
} |
||||
|
||||
public void setRetentionPolicy(String retentionPolicy) { |
||||
set("retentionPolicy", retentionPolicy); |
||||
} |
||||
|
||||
public void setUri(String uri) { |
||||
set("uri", uri); |
||||
} |
||||
|
||||
public void setCompressed(Boolean compressed) { |
||||
set("compressed", compressed); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,75 @@
@@ -0,0 +1,75 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.prometheus; |
||||
|
||||
import io.micrometer.core.instrument.Clock; |
||||
import io.micrometer.prometheus.PrometheusConfig; |
||||
import io.micrometer.prometheus.PrometheusMeterRegistry; |
||||
import io.prometheus.client.CollectorRegistry; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter; |
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration; |
||||
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusScrapeEndpoint; |
||||
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.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
/** |
||||
* Configuration for exporting metrics to Prometheus. |
||||
* |
||||
* @since 2.0.0 |
||||
* @author Jon Schneider |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnClass(PrometheusMeterRegistry.class) |
||||
@EnableConfigurationProperties(PrometheusProperties.class) |
||||
public class PrometheusExportConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnProperty(value = "metrics.prometheus.enabled", matchIfMissing = true) |
||||
public MetricsExporter prometheusExporter(PrometheusConfig config, |
||||
CollectorRegistry collectorRegistry, Clock clock) { |
||||
return () -> new PrometheusMeterRegistry(config, collectorRegistry, clock); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public CollectorRegistry collectorRegistry() { |
||||
return new CollectorRegistry(true); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public Clock clock() { |
||||
return Clock.SYSTEM; |
||||
} |
||||
|
||||
@ManagementContextConfiguration |
||||
public static class PrometheusScrapeEndpointConfiguration { |
||||
|
||||
@Bean |
||||
public PrometheusScrapeEndpoint prometheusEndpoint( |
||||
CollectorRegistry collectorRegistry) { |
||||
return new PrometheusScrapeEndpoint(collectorRegistry); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.prometheus; |
||||
|
||||
import io.micrometer.prometheus.PrometheusConfig; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.RegistryProperties; |
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* {@link ConfigurationProperties} for configuring metrics export to Prometheus. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
*/ |
||||
@ConfigurationProperties(prefix = "metrics.prometheus") |
||||
public class PrometheusProperties extends RegistryProperties implements PrometheusConfig { |
||||
|
||||
private boolean enabled = true; |
||||
|
||||
public boolean isEnabled() { |
||||
return this.enabled; |
||||
} |
||||
|
||||
public void setEnabled(boolean enabled) { |
||||
this.enabled = enabled; |
||||
} |
||||
|
||||
public void setDescriptions(Boolean descriptions) { |
||||
set("descriptions", descriptions); |
||||
} |
||||
|
||||
@Override |
||||
public String prefix() { |
||||
return "metrics.prometheus"; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.simple; |
||||
|
||||
import io.micrometer.core.instrument.Clock; |
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
/** |
||||
* Configuration for exporting metrics to a {@link SimpleMeterRegistry}. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@EnableConfigurationProperties(SimpleProperties.class) |
||||
public class SimpleExportConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnProperty(value = "metrics.simple.enabled", matchIfMissing = true) |
||||
@ConditionalOnMissingBean(MetricsExporter.class) |
||||
public MetricsExporter simpleExporter(Clock clock) { |
||||
return () -> new SimpleMeterRegistry(clock); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public Clock clock() { |
||||
return Clock.SYSTEM; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.reactive.server; |
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; |
||||
import org.springframework.boot.actuate.metrics.web.reactive.server.DefaultWebFluxTagsProvider; |
||||
import org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter; |
||||
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsProvider; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
/** |
||||
* Configures instrumentation of Spring Webflux MVC annotation-based programming model |
||||
* request mappings. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
*/ |
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) |
||||
@Configuration |
||||
public class WebFluxMetricsConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(WebFluxTagsProvider.class) |
||||
public DefaultWebFluxTagsProvider webfluxTagConfigurer() { |
||||
return new DefaultWebFluxTagsProvider(); |
||||
} |
||||
|
||||
@Bean |
||||
public MetricsWebFilter webfluxMetrics(MeterRegistry registry, |
||||
WebFluxTagsProvider tagConfigurer, MetricsProperties properties) { |
||||
return new MetricsWebFilter(registry, tagConfigurer, |
||||
properties.getWeb().getServer().getRequestsMetricName()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,103 @@
@@ -0,0 +1,103 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.web.client; |
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry; |
||||
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; |
||||
import org.springframework.boot.actuate.metrics.web.client.DefaultRestTemplateExchangeTagsProvider; |
||||
import org.springframework.boot.actuate.metrics.web.client.MetricsRestTemplateCustomizer; |
||||
import org.springframework.boot.actuate.metrics.web.client.RestTemplateExchangeTagsProvider; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.web.client.RestTemplate; |
||||
|
||||
/** |
||||
* Configuration for {@link RestTemplate}-related metrics. |
||||
* |
||||
* @author Jon Schneider |
||||
* @author Phillip Webb |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnClass(name = "org.springframework.web.client.RestTemplate") |
||||
public class RestTemplateMetricsConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(RestTemplateExchangeTagsProvider.class) |
||||
public DefaultRestTemplateExchangeTagsProvider restTemplateTagConfigurer() { |
||||
return new DefaultRestTemplateExchangeTagsProvider(); |
||||
} |
||||
|
||||
@Bean |
||||
public MetricsRestTemplateCustomizer metricsRestTemplateCustomizer( |
||||
MeterRegistry meterRegistry, |
||||
RestTemplateExchangeTagsProvider restTemplateTagConfigurer, |
||||
MetricsProperties properties) { |
||||
return new MetricsRestTemplateCustomizer(meterRegistry, restTemplateTagConfigurer, |
||||
properties.getWeb().getClient().getRequestsMetricName(), |
||||
properties.getWeb().getClient().isRecordRequestPercentiles()); |
||||
} |
||||
|
||||
@Bean |
||||
public static BeanPostProcessor restTemplateInterceptorPostProcessor( |
||||
ApplicationContext applicationContext) { |
||||
return new MetricsInterceptorPostProcessor(applicationContext); |
||||
} |
||||
|
||||
/** |
||||
* {@link BeanPostProcessor} to apply {@link MetricsRestTemplateCustomizer} to any |
||||
* directly registered {@link RestTemplate} beans. |
||||
*/ |
||||
private static class MetricsInterceptorPostProcessor implements BeanPostProcessor { |
||||
|
||||
private final ApplicationContext applicationContext; |
||||
|
||||
private MetricsRestTemplateCustomizer customizer; |
||||
|
||||
MetricsInterceptorPostProcessor(ApplicationContext applicationContext) { |
||||
this.applicationContext = applicationContext; |
||||
} |
||||
|
||||
@Override |
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) { |
||||
return bean; |
||||
} |
||||
|
||||
@Override |
||||
public Object postProcessAfterInitialization(Object bean, String beanName) { |
||||
if (bean instanceof RestTemplate) { |
||||
geCustomizer().customize((RestTemplate) bean); |
||||
} |
||||
return bean; |
||||
} |
||||
|
||||
private MetricsRestTemplateCustomizer geCustomizer() { |
||||
if (this.customizer == null) { |
||||
this.customizer = this.applicationContext |
||||
.getBean(MetricsRestTemplateCustomizer.class); |
||||
} |
||||
return this.customizer; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,87 @@
@@ -0,0 +1,87 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.web.servlet; |
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; |
||||
import org.springframework.boot.actuate.metrics.web.servlet.DefaultWebMvcTagsProvider; |
||||
import org.springframework.boot.actuate.metrics.web.servlet.MetricsHandlerInterceptor; |
||||
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetrics; |
||||
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsProvider; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; |
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.web.servlet.DispatcherServlet; |
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; |
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
||||
|
||||
/** |
||||
* Configures instrumentation of Spring Web MVC servlet-based request mappings. |
||||
* |
||||
* @author Jon Schneider |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Configuration |
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) |
||||
@ConditionalOnClass(DispatcherServlet.class) |
||||
@EnableConfigurationProperties(MetricsProperties.class) |
||||
public class WebMvcMetricsConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(WebMvcTagsProvider.class) |
||||
public DefaultWebMvcTagsProvider webmvcTagConfigurer() { |
||||
return new DefaultWebMvcTagsProvider(); |
||||
} |
||||
|
||||
@Bean |
||||
public WebMvcMetrics controllerMetrics(MeterRegistry registry, |
||||
MetricsProperties properties, WebMvcTagsProvider configurer) { |
||||
return new WebMvcMetrics(registry, configurer, |
||||
properties.getWeb().getServer().getRequestsMetricName(), |
||||
properties.getWeb().getServer().isAutoTimeRequests(), |
||||
properties.getWeb().getServer().isRecordRequestPercentiles()); |
||||
} |
||||
|
||||
@Bean |
||||
public MetricsHandlerInterceptor webMetricsInterceptor( |
||||
WebMvcMetrics controllerMetrics) { |
||||
return new MetricsHandlerInterceptor(controllerMetrics); |
||||
} |
||||
|
||||
@Configuration |
||||
public class MetricsServletRequestInterceptorConfiguration |
||||
implements WebMvcConfigurer { |
||||
|
||||
private final MetricsHandlerInterceptor handlerInterceptor; |
||||
|
||||
public MetricsServletRequestInterceptorConfiguration( |
||||
MetricsHandlerInterceptor handlerInterceptor) { |
||||
this.handlerInterceptor = handlerInterceptor; |
||||
} |
||||
|
||||
@Override |
||||
public void addInterceptors(InterceptorRegistry registry) { |
||||
registry.addInterceptor(this.handlerInterceptor); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,314 +0,0 @@
@@ -1,314 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.cache; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.util.Arrays; |
||||
|
||||
import javax.cache.Caching; |
||||
import javax.cache.configuration.MutableConfiguration; |
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine; |
||||
import com.hazelcast.cache.HazelcastCachingProvider; |
||||
import com.hazelcast.config.Config; |
||||
import com.hazelcast.config.XmlConfigBuilder; |
||||
import com.hazelcast.core.Hazelcast; |
||||
import com.hazelcast.core.HazelcastInstance; |
||||
import com.hazelcast.spring.cache.HazelcastCacheManager; |
||||
import org.infinispan.manager.DefaultCacheManager; |
||||
import org.infinispan.manager.EmbeddedCacheManager; |
||||
import org.infinispan.spring.provider.SpringEmbeddedCacheManager; |
||||
import org.junit.After; |
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.boot.actuate.cache.CacheStatistics; |
||||
import org.springframework.boot.actuate.cache.CacheStatisticsProvider; |
||||
import org.springframework.cache.Cache; |
||||
import org.springframework.cache.CacheManager; |
||||
import org.springframework.cache.caffeine.CaffeineCacheManager; |
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheManager; |
||||
import org.springframework.cache.ehcache.EhCacheCacheManager; |
||||
import org.springframework.cache.ehcache.EhCacheManagerUtils; |
||||
import org.springframework.cache.jcache.JCacheCacheManager; |
||||
import org.springframework.cache.support.NoOpCacheManager; |
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.core.io.ClassPathResource; |
||||
import org.springframework.core.io.Resource; |
||||
import org.springframework.util.Assert; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.offset; |
||||
|
||||
/** |
||||
* Tests for {@link CacheStatisticsAutoConfiguration}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @author Eddú Meléndez |
||||
* @author Raja Kolli |
||||
*/ |
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) |
||||
public class CacheStatisticsAutoConfigurationTests { |
||||
|
||||
private AnnotationConfigApplicationContext context; |
||||
|
||||
private CacheManager cacheManager; |
||||
|
||||
@After |
||||
public void after() { |
||||
if (this.context != null) { |
||||
this.context.close(); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void basicJCacheCacheStatistics() { |
||||
load(JCacheCacheConfig.class); |
||||
CacheStatisticsProvider provider = this.context |
||||
.getBean("jCacheCacheStatisticsProvider", CacheStatisticsProvider.class); |
||||
doTestCoreStatistics(provider, false); |
||||
} |
||||
|
||||
@Test |
||||
public void basicEhCacheCacheStatistics() { |
||||
load(EhCacheConfig.class); |
||||
CacheStatisticsProvider provider = this.context |
||||
.getBean("ehCacheCacheStatisticsProvider", CacheStatisticsProvider.class); |
||||
doTestCoreStatistics(provider, true); |
||||
} |
||||
|
||||
@Test |
||||
public void basicHazelcastCacheStatistics() { |
||||
load(HazelcastConfig.class); |
||||
CacheStatisticsProvider provider = this.context.getBean( |
||||
"hazelcastCacheStatisticsProvider", CacheStatisticsProvider.class); |
||||
doTestCoreStatistics(provider, true); |
||||
} |
||||
|
||||
@Test |
||||
public void basicInfinispanCacheStatistics() { |
||||
load(InfinispanConfig.class); |
||||
CacheStatisticsProvider provider = this.context.getBean( |
||||
"infinispanCacheStatisticsProvider", CacheStatisticsProvider.class); |
||||
doTestCoreStatistics(provider, true); |
||||
} |
||||
|
||||
@Test |
||||
public void baseCaffeineCacheStatistics() { |
||||
load(CaffeineCacheConfig.class); |
||||
CacheStatisticsProvider provider = this.context.getBean( |
||||
"caffeineCacheStatisticsProvider", CacheStatisticsProvider.class); |
||||
doTestCoreStatistics(provider, true); |
||||
} |
||||
|
||||
@Test |
||||
public void concurrentMapCacheStatistics() { |
||||
load(ConcurrentMapConfig.class); |
||||
CacheStatisticsProvider provider = this.context.getBean( |
||||
"concurrentMapCacheStatisticsProvider", CacheStatisticsProvider.class); |
||||
Cache books = getCache("books"); |
||||
CacheStatistics cacheStatistics = provider.getCacheStatistics(this.cacheManager, |
||||
books); |
||||
assertCoreStatistics(cacheStatistics, 0L, null, null); |
||||
getOrCreate(books, "a", "b", "b", "a", "a"); |
||||
CacheStatistics updatedCacheStatistics = provider |
||||
.getCacheStatistics(this.cacheManager, books); |
||||
assertCoreStatistics(updatedCacheStatistics, 2L, null, null); |
||||
} |
||||
|
||||
@Test |
||||
public void noOpCacheStatistics() { |
||||
load(NoOpCacheConfig.class); |
||||
CacheStatisticsProvider provider = this.context |
||||
.getBean("noOpCacheStatisticsProvider", CacheStatisticsProvider.class); |
||||
Cache books = getCache("books"); |
||||
CacheStatistics cacheStatistics = provider.getCacheStatistics(this.cacheManager, |
||||
books); |
||||
assertCoreStatistics(cacheStatistics, null, null, null); |
||||
getOrCreate(books, "a", "b", "b", "a", "a"); |
||||
CacheStatistics updatedCacheStatistics = provider |
||||
.getCacheStatistics(this.cacheManager, books); |
||||
assertCoreStatistics(updatedCacheStatistics, null, null, null); |
||||
} |
||||
|
||||
private void doTestCoreStatistics(CacheStatisticsProvider provider, |
||||
boolean supportSize) { |
||||
Cache books = getCache("books"); |
||||
CacheStatistics cacheStatistics = provider.getCacheStatistics(this.cacheManager, |
||||
books); |
||||
assertCoreStatistics(cacheStatistics, (supportSize ? 0L : null), null, null); |
||||
getOrCreate(books, "a", "b", "b", "a", "a", "a"); |
||||
CacheStatistics updatedCacheStatistics = provider |
||||
.getCacheStatistics(this.cacheManager, books); |
||||
assertCoreStatistics(updatedCacheStatistics, (supportSize ? 2L : null), 0.66D, |
||||
0.33D); |
||||
} |
||||
|
||||
private void assertCoreStatistics(CacheStatistics metrics, Long size, Double hitRatio, |
||||
Double missRatio) { |
||||
assertThat(metrics).isNotNull(); |
||||
assertThat(metrics.getSize()).isEqualTo(size); |
||||
checkRatio("Wrong hit ratio for metrics " + metrics, hitRatio, |
||||
metrics.getHitRatio()); |
||||
checkRatio("Wrong miss ratio for metrics " + metrics, missRatio, |
||||
metrics.getMissRatio()); |
||||
} |
||||
|
||||
private void checkRatio(String message, Double expected, Double actual) { |
||||
if (expected == null || actual == null) { |
||||
assertThat(actual).as(message).isEqualTo(expected); |
||||
} |
||||
else { |
||||
assertThat(actual).as(message).isEqualTo(expected, offset(0.01D)); |
||||
} |
||||
} |
||||
|
||||
private void getOrCreate(Cache cache, String... ids) { |
||||
for (String id : ids) { |
||||
Cache.ValueWrapper wrapper = cache.get(id); |
||||
if (wrapper == null) { |
||||
cache.put(id, id); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private Cache getCache(String cacheName) { |
||||
Cache cache = this.cacheManager.getCache(cacheName); |
||||
Assert.notNull(cache, "No cache with name '" + cacheName + "' found."); |
||||
return cache; |
||||
} |
||||
|
||||
private void load(Class<?>... config) { |
||||
this.context = new AnnotationConfigApplicationContext(); |
||||
if (config.length > 0) { |
||||
this.context.register(config); |
||||
} |
||||
this.context.register(CacheStatisticsAutoConfiguration.class); |
||||
this.context.refresh(); |
||||
this.cacheManager = this.context.getBean(CacheManager.class); |
||||
} |
||||
|
||||
@Configuration |
||||
static class JCacheCacheConfig { |
||||
|
||||
@Bean |
||||
public JCacheCacheManager cacheManager() { |
||||
javax.cache.CacheManager cacheManager = jCacheCacheManager(); |
||||
return new JCacheCacheManager(cacheManager); |
||||
} |
||||
|
||||
@Bean |
||||
public javax.cache.CacheManager jCacheCacheManager() { |
||||
javax.cache.CacheManager cacheManager = Caching |
||||
.getCachingProvider(HazelcastCachingProvider.class.getName()) |
||||
.getCacheManager(); |
||||
MutableConfiguration<Object, Object> config = new MutableConfiguration<>(); |
||||
config.setStatisticsEnabled(true); |
||||
cacheManager.createCache("books", config); |
||||
cacheManager.createCache("speakers", config); |
||||
return cacheManager; |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class EhCacheConfig { |
||||
|
||||
@Bean |
||||
public EhCacheCacheManager cacheManager() { |
||||
return new EhCacheCacheManager(ehCacheCacheManager()); |
||||
} |
||||
|
||||
@Bean |
||||
public net.sf.ehcache.CacheManager ehCacheCacheManager() { |
||||
return EhCacheManagerUtils |
||||
.buildCacheManager(new ClassPathResource("cache/test-ehcache.xml")); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class HazelcastConfig { |
||||
|
||||
@Bean |
||||
public HazelcastCacheManager cacheManager() throws IOException { |
||||
return new HazelcastCacheManager(hazelcastInstance()); |
||||
} |
||||
|
||||
@Bean |
||||
public HazelcastInstance hazelcastInstance() throws IOException { |
||||
Resource resource = new ClassPathResource("cache/test-hazelcast.xml"); |
||||
Config cfg = new XmlConfigBuilder(resource.getURL()).build(); |
||||
return Hazelcast.newHazelcastInstance(cfg); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class InfinispanConfig { |
||||
|
||||
@Bean |
||||
public SpringEmbeddedCacheManager cacheManager() throws IOException { |
||||
return new SpringEmbeddedCacheManager(embeddedCacheManager()); |
||||
} |
||||
|
||||
@Bean |
||||
public EmbeddedCacheManager embeddedCacheManager() throws IOException { |
||||
Resource resource = new ClassPathResource("cache/test-infinispan.xml"); |
||||
try (InputStream in = resource.getInputStream()) { |
||||
return new DefaultCacheManager(in); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class ConcurrentMapConfig { |
||||
|
||||
@Bean |
||||
public ConcurrentMapCacheManager cacheManager() { |
||||
return new ConcurrentMapCacheManager("books", "speakers"); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class NoOpCacheConfig { |
||||
|
||||
@Bean |
||||
public NoOpCacheManager cacheManager() { |
||||
return new NoOpCacheManager(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class CaffeineCacheConfig { |
||||
|
||||
@Bean |
||||
public CaffeineCacheManager cacheManager() { |
||||
CaffeineCacheManager cacheManager = new CaffeineCacheManager(); |
||||
cacheManager.setCaffeine(Caffeine.newBuilder().recordStats()); |
||||
cacheManager.setCacheNames(Arrays.asList("books", "speaker")); |
||||
return cacheManager; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry; |
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations; |
||||
import org.springframework.boot.context.annotation.UserConfigurations; |
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner; |
||||
import org.springframework.context.annotation.Bean; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for applying {@link MeterRegistryConfigurer MeterRegistryConfigurers}. |
||||
* |
||||
* @author Jon Schneider |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
public class MeterRegistryConfigurerTests { |
||||
|
||||
@Test |
||||
public void commonTagsAreAppliedToAutoConfiguredBinders() { |
||||
new ApplicationContextRunner() |
||||
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class)) |
||||
.withConfiguration( |
||||
UserConfigurations.of(MeterRegistryConfigurerConfiguration.class)) |
||||
.withPropertyValues("metrics.use-global-registry=false") |
||||
.run((context) -> assertThat(context.getBean(MeterRegistry.class) |
||||
.find("jvm.memory.used").tags("region", "us-east-1").gauge()) |
||||
.isPresent()); |
||||
} |
||||
|
||||
static class MeterRegistryConfigurerConfiguration { |
||||
|
||||
@Bean |
||||
public MeterRegistryConfigurer registryConfigurer() { |
||||
return (registry) -> registry.config().commonTags("region", "us-east-1"); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,197 +0,0 @@
@@ -1,197 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import java.util.Map; |
||||
|
||||
import org.junit.After; |
||||
import org.junit.Rule; |
||||
import org.junit.Test; |
||||
import org.junit.rules.ExpectedException; |
||||
import org.mockito.Mockito; |
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException; |
||||
import org.springframework.boot.actuate.metrics.GaugeService; |
||||
import org.springframework.boot.actuate.metrics.Metric; |
||||
import org.springframework.boot.actuate.metrics.export.MetricCopyExporter; |
||||
import org.springframework.boot.actuate.metrics.export.MetricExporters; |
||||
import org.springframework.boot.actuate.metrics.reader.MetricsEndpointMetricReader; |
||||
import org.springframework.boot.actuate.metrics.statsd.StatsdMetricWriter; |
||||
import org.springframework.boot.actuate.metrics.writer.GaugeWriter; |
||||
import org.springframework.boot.actuate.metrics.writer.MetricWriter; |
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; |
||||
import org.springframework.boot.test.util.TestPropertyValues; |
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.integration.channel.FixedSubscriberChannel; |
||||
import org.springframework.messaging.SubscribableChannel; |
||||
import org.springframework.scheduling.annotation.SchedulingConfigurer; |
||||
import org.springframework.test.util.ReflectionTestUtils; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.ArgumentMatchers.any; |
||||
import static org.mockito.Mockito.atLeastOnce; |
||||
import static org.mockito.Mockito.verify; |
||||
|
||||
/** |
||||
* Tests for {@link MetricExportAutoConfiguration}. |
||||
* |
||||
* @author Phillip Webb |
||||
* @author Dave Syer |
||||
* @author Simon Buettner |
||||
*/ |
||||
public class MetricExportAutoConfigurationTests { |
||||
|
||||
@Rule |
||||
public ExpectedException thrown = ExpectedException.none(); |
||||
|
||||
private AnnotationConfigApplicationContext context; |
||||
|
||||
@After |
||||
public void after() { |
||||
if (this.context != null) { |
||||
this.context.close(); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void metricsFlushAutomatically() throws Exception { |
||||
this.context = new AnnotationConfigApplicationContext(WriterConfig.class, |
||||
MetricRepositoryAutoConfiguration.class, |
||||
MetricExportAutoConfiguration.class, |
||||
PropertyPlaceholderAutoConfiguration.class); |
||||
GaugeService gaugeService = this.context.getBean(GaugeService.class); |
||||
assertThat(gaugeService).isNotNull(); |
||||
gaugeService.submit("foo", 2.7); |
||||
MetricExporters flusher = this.context.getBean(MetricExporters.class); |
||||
flusher.close(); // this will be called by Spring on shutdown
|
||||
MetricWriter writer = this.context.getBean("writer", MetricWriter.class); |
||||
verify(writer, atLeastOnce()).set(any(Metric.class)); |
||||
} |
||||
|
||||
@Test |
||||
public void defaultExporterWhenMessageChannelAvailable() throws Exception { |
||||
this.context = new AnnotationConfigApplicationContext( |
||||
MessageChannelConfiguration.class, |
||||
MetricRepositoryAutoConfiguration.class, |
||||
MetricsChannelAutoConfiguration.class, |
||||
MetricExportAutoConfiguration.class, |
||||
PropertyPlaceholderAutoConfiguration.class); |
||||
MetricExporters exporter = this.context.getBean(MetricExporters.class); |
||||
assertThat(exporter).isNotNull(); |
||||
assertThat(exporter.getExporters()).containsKey("messageChannelMetricWriter"); |
||||
} |
||||
|
||||
@Test |
||||
public void provideAdditionalWriter() { |
||||
this.context = new AnnotationConfigApplicationContext(WriterConfig.class, |
||||
MetricRepositoryAutoConfiguration.class, |
||||
MetricExportAutoConfiguration.class, |
||||
PropertyPlaceholderAutoConfiguration.class); |
||||
GaugeService gaugeService = this.context.getBean(GaugeService.class); |
||||
assertThat(gaugeService).isNotNull(); |
||||
gaugeService.submit("foo", 2.7); |
||||
MetricExporters exporters = this.context.getBean(MetricExporters.class); |
||||
MetricCopyExporter exporter = (MetricCopyExporter) exporters.getExporters() |
||||
.get("writer"); |
||||
exporter.setIgnoreTimestamps(true); |
||||
exporter.export(); |
||||
MetricWriter writer = this.context.getBean("writer", MetricWriter.class); |
||||
Mockito.verify(writer, Mockito.atLeastOnce()).set(any(Metric.class)); |
||||
} |
||||
|
||||
@Test |
||||
public void exportMetricsEndpoint() { |
||||
this.context = new AnnotationConfigApplicationContext(WriterConfig.class, |
||||
MetricEndpointConfiguration.class, MetricExportAutoConfiguration.class, |
||||
PropertyPlaceholderAutoConfiguration.class); |
||||
MetricExporters exporters = this.context.getBean(MetricExporters.class); |
||||
MetricCopyExporter exporter = (MetricCopyExporter) exporters.getExporters() |
||||
.get("writer"); |
||||
exporter.setIgnoreTimestamps(true); |
||||
exporter.export(); |
||||
MetricsEndpointMetricReader reader = this.context.getBean("endpointReader", |
||||
MetricsEndpointMetricReader.class); |
||||
Mockito.verify(reader, Mockito.atLeastOnce()).findAll(); |
||||
} |
||||
|
||||
@Test |
||||
public void statsdMissingHost() throws Exception { |
||||
this.context = new AnnotationConfigApplicationContext(); |
||||
this.context.register(WriterConfig.class, MetricEndpointConfiguration.class, |
||||
MetricExportAutoConfiguration.class, |
||||
PropertyPlaceholderAutoConfiguration.class); |
||||
this.context.refresh(); |
||||
this.thrown.expect(NoSuchBeanDefinitionException.class); |
||||
this.context.getBean(StatsdMetricWriter.class); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
@Test |
||||
public void statsdWithHost() throws Exception { |
||||
this.context = new AnnotationConfigApplicationContext(); |
||||
TestPropertyValues.of("spring.metrics.export.statsd.host=localhost") |
||||
.applyTo(this.context); |
||||
this.context.register(MetricEndpointConfiguration.class, |
||||
MetricExportAutoConfiguration.class, |
||||
PropertyPlaceholderAutoConfiguration.class); |
||||
this.context.refresh(); |
||||
StatsdMetricWriter statsdWriter = this.context.getBean(StatsdMetricWriter.class); |
||||
assertThat(statsdWriter).isNotNull(); |
||||
SchedulingConfigurer schedulingConfigurer = this.context |
||||
.getBean(SchedulingConfigurer.class); |
||||
Map<String, GaugeWriter> exporters = (Map<String, GaugeWriter>) ReflectionTestUtils |
||||
.getField(schedulingConfigurer, "writers"); |
||||
assertThat(exporters).containsValue(statsdWriter); |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
public static class MessageChannelConfiguration { |
||||
|
||||
@Bean |
||||
public SubscribableChannel metricsChannel() { |
||||
return new FixedSubscriberChannel((message) -> { |
||||
}); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
public static class WriterConfig { |
||||
|
||||
@Bean |
||||
@ExportMetricWriter |
||||
public MetricWriter writer() { |
||||
return Mockito.mock(MetricWriter.class); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
public static class MetricEndpointConfiguration { |
||||
|
||||
@Bean |
||||
@ExportMetricReader |
||||
public MetricsEndpointMetricReader endpointReader() { |
||||
return Mockito.mock(MetricsEndpointMetricReader.class); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,561 +0,0 @@
@@ -1,561 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.concurrent.CountDownLatch; |
||||
|
||||
import javax.servlet.Filter; |
||||
import javax.servlet.FilterChain; |
||||
import javax.servlet.ServletException; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.boot.actuate.metrics.CounterService; |
||||
import org.springframework.boot.actuate.metrics.GaugeService; |
||||
import org.springframework.boot.actuate.metrics.web.servlet.MetricsFilter; |
||||
import org.springframework.boot.actuate.metrics.web.servlet.MetricsFilterSubmission; |
||||
import org.springframework.boot.test.util.TestPropertyValues; |
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.core.annotation.Order; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.ResponseEntity; |
||||
import org.springframework.mock.web.MockHttpServletRequest; |
||||
import org.springframework.mock.web.MockHttpServletResponse; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.test.web.servlet.MockMvc; |
||||
import org.springframework.test.web.servlet.MvcResult; |
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders; |
||||
import org.springframework.web.bind.annotation.PathVariable; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.ResponseBody; |
||||
import org.springframework.web.bind.annotation.ResponseStatus; |
||||
import org.springframework.web.bind.annotation.RestController; |
||||
import org.springframework.web.context.request.async.DeferredResult; |
||||
import org.springframework.web.filter.OncePerRequestFilter; |
||||
import org.springframework.web.util.NestedServletException; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.hamcrest.Matchers.is; |
||||
import static org.hamcrest.Matchers.notNullValue; |
||||
import static org.hamcrest.Matchers.nullValue; |
||||
import static org.junit.Assert.fail; |
||||
import static org.mockito.ArgumentMatchers.anyDouble; |
||||
import static org.mockito.ArgumentMatchers.anyString; |
||||
import static org.mockito.ArgumentMatchers.eq; |
||||
import static org.mockito.BDDMockito.willAnswer; |
||||
import static org.mockito.BDDMockito.willThrow; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.never; |
||||
import static org.mockito.Mockito.times; |
||||
import static org.mockito.Mockito.verify; |
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch; |
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; |
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; |
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request; |
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
||||
|
||||
/** |
||||
* Tests for {@link MetricFilterAutoConfiguration}. |
||||
* |
||||
* @author Phillip Webb |
||||
* @author Andy Wilkinson |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
public class MetricFilterAutoConfigurationTests { |
||||
|
||||
@Test |
||||
public void defaultMetricFilterAutoConfigurationProperties() { |
||||
MetricFilterProperties properties = new MetricFilterProperties(); |
||||
assertThat(properties.getGaugeSubmissions()) |
||||
.containsExactly(MetricsFilterSubmission.MERGED); |
||||
assertThat(properties.getCounterSubmissions()) |
||||
.containsExactly(MetricsFilterSubmission.MERGED); |
||||
} |
||||
|
||||
@Test |
||||
public void recordsHttpInteractions() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
Config.class, MetricFilterAutoConfiguration.class); |
||||
try { |
||||
Filter filter = context.getBean(Filter.class); |
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", |
||||
"/test/path"); |
||||
MockHttpServletResponse response = new MockHttpServletResponse(); |
||||
FilterChain chain = mock(FilterChain.class); |
||||
willAnswer((invocation) -> { |
||||
response.setStatus(200); |
||||
return null; |
||||
}).given(chain).doFilter(request, response); |
||||
filter.doFilter(request, response, chain); |
||||
verify(context.getBean(CounterService.class)) |
||||
.increment("status.200.test.path"); |
||||
verify(context.getBean(GaugeService.class)).submit(eq("response.test.path"), |
||||
anyDouble()); |
||||
} |
||||
finally { |
||||
context.close(); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void recordsHttpInteractionsWithTemplateVariable() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
Config.class, MetricFilterAutoConfiguration.class); |
||||
Filter filter = context.getBean(Filter.class); |
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(new MetricFilterTestController()) |
||||
.addFilter(filter).build(); |
||||
mvc.perform(get("/templateVarTest/foo")).andExpect(status().isOk()); |
||||
verify(context.getBean(CounterService.class)) |
||||
.increment("status.200.templateVarTest.someVariable"); |
||||
verify(context.getBean(GaugeService.class)) |
||||
.submit(eq("response.templateVarTest.someVariable"), anyDouble()); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void recordsHttpInteractionsWithRegexTemplateVariable() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
Config.class, MetricFilterAutoConfiguration.class); |
||||
Filter filter = context.getBean(Filter.class); |
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(new MetricFilterTestController()) |
||||
.addFilter(filter).build(); |
||||
mvc.perform(get("/templateVarRegexTest/foo")).andExpect(status().isOk()); |
||||
verify(context.getBean(CounterService.class)) |
||||
.increment("status.200.templateVarRegexTest.someVariable"); |
||||
verify(context.getBean(GaugeService.class)) |
||||
.submit(eq("response.templateVarRegexTest.someVariable"), anyDouble()); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void recordsHttpInteractionsWithWildcardMapping() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
Config.class, MetricFilterAutoConfiguration.class); |
||||
Filter filter = context.getBean(Filter.class); |
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(new MetricFilterTestController()) |
||||
.addFilter(filter).build(); |
||||
mvc.perform(get("/wildcardMapping/foo")).andExpect(status().isOk()); |
||||
verify(context.getBean(CounterService.class)) |
||||
.increment("status.200.wildcardMapping.star"); |
||||
verify(context.getBean(GaugeService.class)) |
||||
.submit(eq("response.wildcardMapping.star"), anyDouble()); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void recordsHttpInteractionsWithDoubleWildcardMapping() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
Config.class, MetricFilterAutoConfiguration.class); |
||||
Filter filter = context.getBean(Filter.class); |
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(new MetricFilterTestController()) |
||||
.addFilter(filter).build(); |
||||
mvc.perform(get("/doubleWildcardMapping/foo/bar/baz")).andExpect(status().isOk()); |
||||
verify(context.getBean(CounterService.class)) |
||||
.increment("status.200.doubleWildcardMapping.star-star.baz"); |
||||
verify(context.getBean(GaugeService.class)) |
||||
.submit(eq("response.doubleWildcardMapping.star-star.baz"), anyDouble()); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void recordsKnown404HttpInteractionsAsSingleMetricWithPathAndTemplateVariable() |
||||
throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
Config.class, MetricFilterAutoConfiguration.class); |
||||
Filter filter = context.getBean(Filter.class); |
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(new MetricFilterTestController()) |
||||
.addFilter(filter).build(); |
||||
mvc.perform(get("/knownPath/foo")).andExpect(status().isNotFound()); |
||||
verify(context.getBean(CounterService.class)) |
||||
.increment("status.404.knownPath.someVariable"); |
||||
verify(context.getBean(GaugeService.class)) |
||||
.submit(eq("response.knownPath.someVariable"), anyDouble()); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void records404HttpInteractionsAsSingleMetric() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
Config.class, MetricFilterAutoConfiguration.class); |
||||
Filter filter = context.getBean(Filter.class); |
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(new MetricFilterTestController()) |
||||
.addFilter(filter).build(); |
||||
mvc.perform(get("/unknownPath/1")).andExpect(status().isNotFound()); |
||||
mvc.perform(get("/unknownPath/2")).andExpect(status().isNotFound()); |
||||
verify(context.getBean(CounterService.class), times(2)) |
||||
.increment("status.404.unmapped"); |
||||
verify(context.getBean(GaugeService.class), times(2)) |
||||
.submit(eq("response.unmapped"), anyDouble()); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void records302HttpInteractionsAsSingleMetric() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
Config.class, MetricFilterAutoConfiguration.class, RedirectFilter.class); |
||||
MetricsFilter filter = context.getBean(MetricsFilter.class); |
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(new MetricFilterTestController()) |
||||
.addFilter(filter).addFilter(context.getBean(RedirectFilter.class)) |
||||
.build(); |
||||
mvc.perform(get("/unknownPath/1")).andExpect(status().is3xxRedirection()); |
||||
mvc.perform(get("/unknownPath/2")).andExpect(status().is3xxRedirection()); |
||||
verify(context.getBean(CounterService.class), times(2)) |
||||
.increment("status.302.unmapped"); |
||||
verify(context.getBean(GaugeService.class), times(2)) |
||||
.submit(eq("response.unmapped"), anyDouble()); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void skipsFilterIfMissingServices() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
MetricFilterAutoConfiguration.class); |
||||
assertThat(context.getBeansOfType(Filter.class).size()).isEqualTo(0); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void skipsFilterIfPropertyDisabled() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); |
||||
TestPropertyValues.of("management.metrics.filter.enabled:false").applyTo(context); |
||||
context.register(Config.class, MetricFilterAutoConfiguration.class); |
||||
context.refresh(); |
||||
assertThat(context.getBeansOfType(Filter.class).size()).isEqualTo(0); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void controllerMethodThatThrowsUnhandledException() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
Config.class, MetricFilterAutoConfiguration.class); |
||||
Filter filter = context.getBean(Filter.class); |
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(new MetricFilterTestController()) |
||||
.addFilter(filter).build(); |
||||
try { |
||||
mvc.perform(get("/unhandledException")) |
||||
.andExpect(status().isInternalServerError()); |
||||
} |
||||
catch (NestedServletException ex) { |
||||
// Expected
|
||||
} |
||||
verify(context.getBean(CounterService.class)) |
||||
.increment("status.500.unhandledException"); |
||||
verify(context.getBean(GaugeService.class)) |
||||
.submit(eq("response.unhandledException"), anyDouble()); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void gaugeServiceThatThrows() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
Config.class, MetricFilterAutoConfiguration.class); |
||||
GaugeService gaugeService = context.getBean(GaugeService.class); |
||||
willThrow(new IllegalStateException()).given(gaugeService).submit(anyString(), |
||||
anyDouble()); |
||||
Filter filter = context.getBean(Filter.class); |
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(new MetricFilterTestController()) |
||||
.addFilter(filter).build(); |
||||
mvc.perform(get("/templateVarTest/foo")).andExpect(status().isOk()); |
||||
verify(context.getBean(CounterService.class)) |
||||
.increment("status.200.templateVarTest.someVariable"); |
||||
verify(context.getBean(GaugeService.class)) |
||||
.submit(eq("response.templateVarTest.someVariable"), anyDouble()); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void correctlyRecordsMetricsForDeferredResultResponse() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
Config.class, MetricFilterAutoConfiguration.class); |
||||
MetricsFilter filter = context.getBean(MetricsFilter.class); |
||||
CountDownLatch latch = new CountDownLatch(1); |
||||
MockMvc mvc = MockMvcBuilders |
||||
.standaloneSetup(new MetricFilterTestController(latch)).addFilter(filter) |
||||
.build(); |
||||
String attributeName = MetricsFilter.class.getName() + ".StopWatch"; |
||||
MvcResult result = mvc.perform(post("/create")).andExpect(status().isOk()) |
||||
.andExpect(request().asyncStarted()) |
||||
.andExpect(request().attribute(attributeName, is(notNullValue()))) |
||||
.andReturn(); |
||||
latch.countDown(); |
||||
mvc.perform(asyncDispatch(result)).andExpect(status().isCreated()) |
||||
.andExpect(request().attribute(attributeName, is(nullValue()))); |
||||
verify(context.getBean(CounterService.class)).increment("status.201.create"); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void correctlyRecordsMetricsForFailedDeferredResultResponse() |
||||
throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
Config.class, MetricFilterAutoConfiguration.class); |
||||
MetricsFilter filter = context.getBean(MetricsFilter.class); |
||||
CountDownLatch latch = new CountDownLatch(1); |
||||
MockMvc mvc = MockMvcBuilders |
||||
.standaloneSetup(new MetricFilterTestController(latch)).addFilter(filter) |
||||
.build(); |
||||
String attributeName = MetricsFilter.class.getName() + ".StopWatch"; |
||||
MvcResult result = mvc.perform(post("/createFailure")).andExpect(status().isOk()) |
||||
.andExpect(request().asyncStarted()) |
||||
.andExpect(request().attribute(attributeName, is(notNullValue()))) |
||||
.andReturn(); |
||||
latch.countDown(); |
||||
try { |
||||
mvc.perform(asyncDispatch(result)); |
||||
fail(); |
||||
} |
||||
catch (Exception ex) { |
||||
assertThat(result.getRequest().getAttribute(attributeName)).isNull(); |
||||
verify(context.getBean(CounterService.class)) |
||||
.increment("status.500.createFailure"); |
||||
} |
||||
finally { |
||||
context.close(); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void records5xxxHttpInteractionsAsSingleMetric() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
Config.class, MetricFilterAutoConfiguration.class, |
||||
ServiceUnavailableFilter.class); |
||||
MetricsFilter filter = context.getBean(MetricsFilter.class); |
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(new MetricFilterTestController()) |
||||
.addFilter(filter) |
||||
.addFilter(context.getBean(ServiceUnavailableFilter.class)).build(); |
||||
mvc.perform(get("/unknownPath/1")).andExpect(status().isServiceUnavailable()); |
||||
mvc.perform(get("/unknownPath/2")).andExpect(status().isServiceUnavailable()); |
||||
verify(context.getBean(CounterService.class), times(2)) |
||||
.increment("status.503.unmapped"); |
||||
verify(context.getBean(GaugeService.class), times(2)) |
||||
.submit(eq("response.unmapped"), anyDouble()); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void additionallyRecordsMetricsWithHttpMethodNameIfConfigured() |
||||
throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); |
||||
context.register(Config.class, MetricFilterAutoConfiguration.class); |
||||
TestPropertyValues |
||||
.of("management.metrics.filter.gauge-submissions=merged,per-http-method", |
||||
"management.metrics.filter.counter-submissions=merged,per-http-method") |
||||
.applyTo(context); |
||||
context.refresh(); |
||||
Filter filter = context.getBean(Filter.class); |
||||
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/test/path"); |
||||
MockHttpServletResponse response = new MockHttpServletResponse(); |
||||
FilterChain chain = mock(FilterChain.class); |
||||
willAnswer((invocation) -> { |
||||
response.setStatus(200); |
||||
return null; |
||||
}).given(chain).doFilter(request, response); |
||||
filter.doFilter(request, response, chain); |
||||
verify(context.getBean(GaugeService.class)).submit(eq("response.test.path"), |
||||
anyDouble()); |
||||
verify(context.getBean(GaugeService.class)).submit(eq("response.PUT.test.path"), |
||||
anyDouble()); |
||||
verify(context.getBean(CounterService.class)) |
||||
.increment(eq("status.200.test.path")); |
||||
verify(context.getBean(CounterService.class)) |
||||
.increment(eq("status.PUT.200.test.path")); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void doesNotRecordRolledUpMetricsIfConfigured() throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); |
||||
context.register(Config.class, MetricFilterAutoConfiguration.class); |
||||
TestPropertyValues |
||||
.of("management.metrics.filter.gauge-submissions=", |
||||
"management.metrics.filter.counter-submissions=") |
||||
.applyTo(context); |
||||
context.refresh(); |
||||
Filter filter = context.getBean(Filter.class); |
||||
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/test/path"); |
||||
MockHttpServletResponse response = new MockHttpServletResponse(); |
||||
FilterChain chain = mock(FilterChain.class); |
||||
willAnswer((invocation) -> { |
||||
response.setStatus(200); |
||||
return null; |
||||
}).given(chain).doFilter(request, response); |
||||
filter.doFilter(request, response, chain); |
||||
verify(context.getBean(GaugeService.class), never()).submit(anyString(), |
||||
anyDouble()); |
||||
verify(context.getBean(CounterService.class), never()).increment(anyString()); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void whenExceptionIsThrownResponseStatusIsUsedWhenResponseHasBeenCommitted() |
||||
throws Exception { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); |
||||
try { |
||||
context.register(Config.class, MetricFilterAutoConfiguration.class); |
||||
context.refresh(); |
||||
Filter filter = context.getBean(Filter.class); |
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", |
||||
"/test/path"); |
||||
MockHttpServletResponse response = new MockHttpServletResponse(); |
||||
FilterChain chain = mock(FilterChain.class); |
||||
willAnswer((invocation) -> { |
||||
response.setStatus(200); |
||||
response.setCommitted(true); |
||||
throw new IOException(); |
||||
}).given(chain).doFilter(request, response); |
||||
try { |
||||
filter.doFilter(request, response, chain); |
||||
fail(); |
||||
} |
||||
catch (IOException ex) { |
||||
// Continue
|
||||
} |
||||
verify(context.getBean(CounterService.class)) |
||||
.increment(eq("status.200.test.path")); |
||||
} |
||||
finally { |
||||
context.close(); |
||||
} |
||||
} |
||||
|
||||
@Configuration |
||||
public static class Config { |
||||
|
||||
@Bean |
||||
public CounterService counterService() { |
||||
return mock(CounterService.class); |
||||
} |
||||
|
||||
@Bean |
||||
public GaugeService gaugeService() { |
||||
return mock(GaugeService.class); |
||||
} |
||||
|
||||
} |
||||
|
||||
@RestController |
||||
class MetricFilterTestController { |
||||
|
||||
private final CountDownLatch latch; |
||||
|
||||
MetricFilterTestController() { |
||||
this(null); |
||||
} |
||||
|
||||
MetricFilterTestController(CountDownLatch latch) { |
||||
this.latch = latch; |
||||
} |
||||
|
||||
@RequestMapping("templateVarTest/{someVariable}") |
||||
public String testTemplateVariableResolution(@PathVariable String someVariable) { |
||||
return someVariable; |
||||
} |
||||
|
||||
@RequestMapping("wildcardMapping/*") |
||||
public String testWildcardMapping() { |
||||
return "wildcard"; |
||||
} |
||||
|
||||
@RequestMapping("doubleWildcardMapping/**/baz") |
||||
public String testDoubleWildcardMapping() { |
||||
return "doubleWildcard"; |
||||
} |
||||
|
||||
@RequestMapping("templateVarRegexTest/{someVariable:[a-z]+}") |
||||
public String testTemplateVariableRegexResolution( |
||||
@PathVariable String someVariable) { |
||||
return someVariable; |
||||
} |
||||
|
||||
@RequestMapping("knownPath/{someVariable}") |
||||
@ResponseStatus(HttpStatus.NOT_FOUND) |
||||
@ResponseBody |
||||
public String testKnownPathWith404Response(@PathVariable String someVariable) { |
||||
return someVariable; |
||||
} |
||||
|
||||
@ResponseBody |
||||
@RequestMapping("unhandledException") |
||||
public String testException() { |
||||
throw new RuntimeException(); |
||||
} |
||||
|
||||
@RequestMapping("create") |
||||
public DeferredResult<ResponseEntity<String>> create() { |
||||
final DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(); |
||||
new Thread(() -> { |
||||
try { |
||||
MetricFilterTestController.this.latch.await(); |
||||
result.setResult(new ResponseEntity<>("Done", HttpStatus.CREATED)); |
||||
} |
||||
catch (InterruptedException ex) { |
||||
} |
||||
}).start(); |
||||
return result; |
||||
} |
||||
|
||||
@RequestMapping("createFailure") |
||||
public DeferredResult<ResponseEntity<String>> createFailure() { |
||||
final DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(); |
||||
new Thread(() -> { |
||||
try { |
||||
MetricFilterTestController.this.latch.await(); |
||||
result.setErrorResult(new Exception("It failed")); |
||||
} |
||||
catch (InterruptedException ex) { |
||||
} |
||||
}).start(); |
||||
return result; |
||||
} |
||||
|
||||
} |
||||
|
||||
@Component |
||||
@Order(0) |
||||
public static class RedirectFilter extends OncePerRequestFilter { |
||||
|
||||
@Override |
||||
protected void doFilterInternal(HttpServletRequest request, |
||||
HttpServletResponse response, FilterChain chain) |
||||
throws ServletException, IOException { |
||||
// send redirect before filter chain is executed, like Spring Security sending
|
||||
// us back to a login page
|
||||
response.sendRedirect("http://example.com"); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Component |
||||
@Order(0) |
||||
public static class ServiceUnavailableFilter extends OncePerRequestFilter { |
||||
|
||||
@Override |
||||
protected void doFilterInternal(HttpServletRequest request, |
||||
HttpServletResponse response, FilterChain chain) |
||||
throws ServletException, IOException { |
||||
|
||||
response.sendError(HttpStatus.SERVICE_UNAVAILABLE.value()); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,108 +0,0 @@
@@ -1,108 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import com.codahale.metrics.Gauge; |
||||
import com.codahale.metrics.MetricRegistry; |
||||
import org.junit.After; |
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.boot.actuate.metrics.CounterService; |
||||
import org.springframework.boot.actuate.metrics.GaugeService; |
||||
import org.springframework.boot.actuate.metrics.buffer.BufferCounterService; |
||||
import org.springframework.boot.actuate.metrics.buffer.BufferGaugeService; |
||||
import org.springframework.boot.actuate.metrics.dropwizard.DropwizardMetricServices; |
||||
import org.springframework.boot.actuate.metrics.reader.MetricReader; |
||||
import org.springframework.boot.actuate.metrics.reader.PrefixMetricReader; |
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
||||
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 MetricRepositoryAutoConfiguration}. |
||||
* |
||||
* @author Phillip Webb |
||||
* @author Dave Syer |
||||
*/ |
||||
public class MetricRepositoryAutoConfigurationTests { |
||||
|
||||
private AnnotationConfigApplicationContext context; |
||||
|
||||
@After |
||||
public void after() { |
||||
if (this.context != null) { |
||||
this.context.close(); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void createServices() throws Exception { |
||||
this.context = new AnnotationConfigApplicationContext( |
||||
MetricRepositoryAutoConfiguration.class); |
||||
GaugeService gaugeService = this.context.getBean(BufferGaugeService.class); |
||||
assertThat(gaugeService).isNotNull(); |
||||
assertThat(this.context.getBean(BufferCounterService.class)).isNotNull(); |
||||
assertThat(this.context.getBean(PrefixMetricReader.class)).isNotNull(); |
||||
gaugeService.submit("foo", 2.7); |
||||
MetricReader bean = this.context.getBean(MetricReader.class); |
||||
assertThat(bean.findOne("gauge.foo").getValue()).isEqualTo(2.7); |
||||
} |
||||
|
||||
@Test |
||||
public void dropwizardInstalledIfPresent() { |
||||
this.context = new AnnotationConfigApplicationContext( |
||||
MetricsDropwizardAutoConfiguration.class, |
||||
MetricRepositoryAutoConfiguration.class); |
||||
GaugeService gaugeService = this.context.getBean(GaugeService.class); |
||||
assertThat(gaugeService).isNotNull(); |
||||
gaugeService.submit("foo", 2.7); |
||||
DropwizardMetricServices exporter = this.context |
||||
.getBean(DropwizardMetricServices.class); |
||||
assertThat(exporter).isEqualTo(gaugeService); |
||||
MetricRegistry registry = this.context.getBean(MetricRegistry.class); |
||||
@SuppressWarnings("unchecked") |
||||
Gauge<Double> gauge = (Gauge<Double>) registry.getMetrics().get("gauge.foo"); |
||||
assertThat(gauge.getValue()).isEqualTo(new Double(2.7)); |
||||
} |
||||
|
||||
@Test |
||||
public void skipsIfBeansExist() throws Exception { |
||||
this.context = new AnnotationConfigApplicationContext(Config.class, |
||||
MetricRepositoryAutoConfiguration.class); |
||||
assertThat(this.context.getBeansOfType(BufferGaugeService.class)).isEmpty(); |
||||
assertThat(this.context.getBeansOfType(BufferCounterService.class)).isEmpty(); |
||||
} |
||||
|
||||
@Configuration |
||||
public static class Config { |
||||
|
||||
@Bean |
||||
public GaugeService gaugeService() { |
||||
return mock(GaugeService.class); |
||||
} |
||||
|
||||
@Bean |
||||
public CounterService counterService() { |
||||
return mock(CounterService.class); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,141 @@
@@ -0,0 +1,141 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry; |
||||
import io.micrometer.core.instrument.Statistic; |
||||
import io.micrometer.core.instrument.binder.JvmMemoryMetrics; |
||||
import io.micrometer.core.instrument.binder.LogbackMetrics; |
||||
import io.micrometer.core.instrument.binder.MeterBinder; |
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; |
||||
import org.springframework.boot.test.web.client.TestRestTemplate; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Import; |
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.test.context.TestPropertySource; |
||||
import org.springframework.test.context.junit4.SpringRunner; |
||||
import org.springframework.test.web.client.MockRestServiceServer; |
||||
import org.springframework.web.bind.annotation.GetMapping; |
||||
import org.springframework.web.bind.annotation.RestController; |
||||
import org.springframework.web.client.RestTemplate; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.springframework.test.web.client.ExpectedCount.once; |
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; |
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; |
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; |
||||
|
||||
/** |
||||
* Tests for {@link MetricsAutoConfiguration}. |
||||
* |
||||
* @author Jon Schneider |
||||
*/ |
||||
@RunWith(SpringRunner.class) |
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = MetricsAutoConfigurationTests.MetricsApp.class) |
||||
@TestPropertySource(properties = "metrics.use-global-registry=false") |
||||
public class MetricsAutoConfigurationTests { |
||||
|
||||
@Autowired |
||||
private ApplicationContext context; |
||||
|
||||
@Autowired |
||||
private RestTemplate external; |
||||
|
||||
@Autowired |
||||
private TestRestTemplate loopback; |
||||
|
||||
@Autowired |
||||
private MeterRegistry registry; |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
@Test |
||||
public void restTemplateIsInstrumented() { |
||||
MockRestServiceServer server = MockRestServiceServer.bindTo(this.external) |
||||
.build(); |
||||
server.expect(once(), requestTo("/api/external")) |
||||
.andExpect(method(HttpMethod.GET)).andRespond(withSuccess( |
||||
"{\"message\": \"hello\"}", MediaType.APPLICATION_JSON)); |
||||
assertThat(this.external.getForObject("/api/external", Map.class)) |
||||
.containsKey("message"); |
||||
assertThat(this.registry.find("http.client.requests").value(Statistic.Count, 1.0) |
||||
.timer()).isPresent(); |
||||
} |
||||
|
||||
@Test |
||||
public void requestMappingIsInstrumented() { |
||||
this.loopback.getForObject("/api/people", Set.class); |
||||
assertThat(this.registry.find("http.server.requests").value(Statistic.Count, 1.0) |
||||
.timer()).isPresent(); |
||||
} |
||||
|
||||
@Test |
||||
public void automaticallyRegisteredBinders() { |
||||
assertThat(this.context.getBeansOfType(MeterBinder.class).values()) |
||||
.hasAtLeastOneElementOfType(LogbackMetrics.class) |
||||
.hasAtLeastOneElementOfType(JvmMemoryMetrics.class); |
||||
} |
||||
|
||||
@Configuration |
||||
@ImportAutoConfiguration({ MetricsAutoConfiguration.class, |
||||
JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, |
||||
WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class, |
||||
ServletWebServerFactoryAutoConfiguration.class }) |
||||
@Import(PersonController.class) |
||||
static class MetricsApp { |
||||
|
||||
@Bean |
||||
public MeterRegistry registry() { |
||||
return new SimpleMeterRegistry(); |
||||
} |
||||
|
||||
@Bean |
||||
public RestTemplate restTemplate() { |
||||
return new RestTemplate(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@RestController |
||||
static class PersonController { |
||||
|
||||
@GetMapping("/api/people") |
||||
Set<String> personName() { |
||||
return Collections.singleton("Jon"); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,91 +0,0 @@
@@ -1,91 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import com.codahale.metrics.Reservoir; |
||||
import com.codahale.metrics.UniformReservoir; |
||||
import org.junit.After; |
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.boot.actuate.metrics.dropwizard.DropwizardMetricServices; |
||||
import org.springframework.boot.actuate.metrics.dropwizard.ReservoirFactory; |
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.test.util.ReflectionTestUtils; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link MetricsDropwizardAutoConfiguration}. |
||||
* |
||||
* @author Lucas Saldanha |
||||
*/ |
||||
public class MetricsDropwizardAutoConfigurationTests { |
||||
|
||||
private AnnotationConfigApplicationContext context; |
||||
|
||||
@After |
||||
public void after() { |
||||
if (this.context != null) { |
||||
this.context.close(); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void dropwizardWithoutCustomReservoirConfigured() { |
||||
this.context = new AnnotationConfigApplicationContext( |
||||
MetricsDropwizardAutoConfiguration.class); |
||||
DropwizardMetricServices dropwizardMetricServices = this.context |
||||
.getBean(DropwizardMetricServices.class); |
||||
ReservoirFactory reservoirFactory = (ReservoirFactory) ReflectionTestUtils |
||||
.getField(dropwizardMetricServices, "reservoirFactory"); |
||||
assertThat(reservoirFactory.getReservoir("test")).isNull(); |
||||
} |
||||
|
||||
@Test |
||||
public void dropwizardWithCustomReservoirConfigured() { |
||||
this.context = new AnnotationConfigApplicationContext( |
||||
MetricsDropwizardAutoConfiguration.class, Config.class); |
||||
DropwizardMetricServices dropwizardMetricServices = this.context |
||||
.getBean(DropwizardMetricServices.class); |
||||
ReservoirFactory reservoirFactory = (ReservoirFactory) ReflectionTestUtils |
||||
.getField(dropwizardMetricServices, "reservoirFactory"); |
||||
assertThat(reservoirFactory.getReservoir("test")) |
||||
.isInstanceOf(UniformReservoir.class); |
||||
} |
||||
|
||||
@Configuration |
||||
static class Config { |
||||
|
||||
@Bean |
||||
public ReservoirFactory reservoirFactory() { |
||||
return new UniformReservoirFactory(); |
||||
} |
||||
|
||||
} |
||||
|
||||
private static class UniformReservoirFactory implements ReservoirFactory { |
||||
|
||||
@Override |
||||
public Reservoir getReservoir(String name) { |
||||
return new UniformReservoir(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,382 +0,0 @@
@@ -1,382 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics; |
||||
|
||||
import java.sql.SQLException; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import javax.sql.DataSource; |
||||
|
||||
import com.zaxxer.hikari.HikariDataSource; |
||||
import org.apache.commons.dbcp2.BasicDataSource; |
||||
import org.junit.After; |
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.cache.CacheStatisticsAutoConfiguration; |
||||
import org.springframework.boot.actuate.autoconfigure.web.servlet.MockServletWebServerFactory; |
||||
import org.springframework.boot.actuate.cache.CachePublicMetrics; |
||||
import org.springframework.boot.actuate.metrics.DataSourcePublicMetrics; |
||||
import org.springframework.boot.actuate.metrics.Metric; |
||||
import org.springframework.boot.actuate.metrics.PublicMetrics; |
||||
import org.springframework.boot.actuate.metrics.SystemPublicMetrics; |
||||
import org.springframework.boot.actuate.metrics.TomcatPublicMetrics; |
||||
import org.springframework.boot.actuate.metrics.reader.MetricReaderPublicMetrics; |
||||
import org.springframework.boot.actuate.metrics.rich.RichGauge; |
||||
import org.springframework.boot.actuate.metrics.rich.RichGaugeReader; |
||||
import org.springframework.boot.actuate.metrics.rich.RichGaugeReaderPublicMetrics; |
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration; |
||||
import org.springframework.boot.jdbc.DataSourceBuilder; |
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; |
||||
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; |
||||
import org.springframework.cache.CacheManager; |
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheManager; |
||||
import org.springframework.context.ConfigurableApplicationContext; |
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Primary; |
||||
import org.springframework.core.annotation.Order; |
||||
import org.springframework.jdbc.core.ConnectionCallback; |
||||
import org.springframework.jdbc.core.JdbcTemplate; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.junit.Assert.fail; |
||||
import static org.mockito.BDDMockito.given; |
||||
import static org.mockito.Mockito.mock; |
||||
|
||||
/** |
||||
* Tests for {@link PublicMetricsAutoConfiguration}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @author Dave Syer |
||||
* @author Phillip Webb |
||||
*/ |
||||
public class PublicMetricsAutoConfigurationTests { |
||||
|
||||
private ConfigurableApplicationContext context; |
||||
|
||||
@After |
||||
public void after() { |
||||
if (this.context != null) { |
||||
this.context.close(); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void systemPublicMetrics() throws Exception { |
||||
load(); |
||||
assertThat(this.context.getBeansOfType(SystemPublicMetrics.class)).hasSize(1); |
||||
} |
||||
|
||||
@Test |
||||
public void metricReaderPublicMetrics() throws Exception { |
||||
load(); |
||||
assertThat(this.context.getBeansOfType(MetricReaderPublicMetrics.class)) |
||||
.hasSize(2); |
||||
} |
||||
|
||||
@Test |
||||
public void richGaugePublicMetrics() { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( |
||||
RichGaugeReaderConfig.class, MetricRepositoryAutoConfiguration.class, |
||||
PublicMetricsAutoConfiguration.class); |
||||
RichGaugeReader richGaugeReader = context.getBean(RichGaugeReader.class); |
||||
assertThat(richGaugeReader).isNotNull(); |
||||
given(richGaugeReader.findAll()) |
||||
.willReturn(Collections.singletonList(new RichGauge("bar", 3.7d))); |
||||
RichGaugeReaderPublicMetrics publicMetrics = context |
||||
.getBean(RichGaugeReaderPublicMetrics.class); |
||||
assertThat(publicMetrics).isNotNull(); |
||||
Collection<Metric<?>> metrics = publicMetrics.metrics(); |
||||
assertThat(metrics).isNotNull(); |
||||
assertThat(6).isEqualTo(metrics.size()); |
||||
assertHasMetric(metrics, new Metric<>("bar.val", 3.7d)); |
||||
assertHasMetric(metrics, new Metric<>("bar.avg", 3.7d)); |
||||
assertHasMetric(metrics, new Metric<>("bar.min", 3.7d)); |
||||
assertHasMetric(metrics, new Metric<>("bar.max", 3.7d)); |
||||
assertHasMetric(metrics, new Metric<>("bar.alpha", -1.d)); |
||||
assertHasMetric(metrics, new Metric<>("bar.count", 1L)); |
||||
context.close(); |
||||
} |
||||
|
||||
@Test |
||||
public void noDataSource() { |
||||
load(); |
||||
assertThat(this.context.getBeansOfType(DataSourcePublicMetrics.class)).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
public void autoDataSource() throws SQLException { |
||||
load(DataSourceAutoConfiguration.class); |
||||
PublicMetrics bean = this.context.getBean(DataSourcePublicMetrics.class); |
||||
this.context.getBean(DataSource.class).getConnection().close(); |
||||
Collection<Metric<?>> metrics = bean.metrics(); |
||||
assertMetrics(metrics, "datasource.primary.active", "datasource.primary.usage"); |
||||
} |
||||
|
||||
@Test |
||||
public void multipleDataSources() { |
||||
load(MultipleDataSourcesConfig.class); |
||||
PublicMetrics bean = this.context.getBean(DataSourcePublicMetrics.class); |
||||
Collection<Metric<?>> metrics = bean.metrics(); |
||||
assertMetrics(metrics, "datasource.tomcat.active", "datasource.tomcat.usage", |
||||
"datasource.commonsDbcp.active", "datasource.commonsDbcp.usage"); |
||||
// Hikari won't work unless a first connection has been retrieved
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate( |
||||
this.context.getBean("hikariDS", DataSource.class)); |
||||
jdbcTemplate.execute((ConnectionCallback<Void>) (connection) -> null); |
||||
Collection<Metric<?>> anotherMetrics = bean.metrics(); |
||||
assertMetrics(anotherMetrics, "datasource.tomcat.active", |
||||
"datasource.tomcat.usage", "datasource.hikariDS.active", |
||||
"datasource.hikariDS.usage", "datasource.commonsDbcp.active", |
||||
"datasource.commonsDbcp.usage"); |
||||
} |
||||
|
||||
@Test |
||||
public void multipleDataSourcesWithPrimary() { |
||||
load(MultipleDataSourcesWithPrimaryConfig.class); |
||||
PublicMetrics bean = this.context.getBean(DataSourcePublicMetrics.class); |
||||
Collection<Metric<?>> metrics = bean.metrics(); |
||||
assertMetrics(metrics, "datasource.primary.active", "datasource.primary.usage", |
||||
"datasource.commonsDbcp.active", "datasource.commonsDbcp.usage"); |
||||
} |
||||
|
||||
@Test |
||||
public void multipleDataSourcesWithCustomPrimary() { |
||||
load(MultipleDataSourcesWithCustomPrimaryConfig.class); |
||||
PublicMetrics bean = this.context.getBean(DataSourcePublicMetrics.class); |
||||
Collection<Metric<?>> metrics = bean.metrics(); |
||||
assertMetrics(metrics, "datasource.primary.active", "datasource.primary.usage", |
||||
"datasource.dataSource.active", "datasource.dataSource.usage"); |
||||
} |
||||
|
||||
@Test |
||||
public void customPrefix() { |
||||
load(MultipleDataSourcesWithPrimaryConfig.class, |
||||
CustomDataSourcePublicMetrics.class); |
||||
PublicMetrics bean = this.context.getBean(DataSourcePublicMetrics.class); |
||||
Collection<Metric<?>> metrics = bean.metrics(); |
||||
assertMetrics(metrics, "ds.first.active", "ds.first.usage", "ds.second.active", |
||||
"ds.second.usage"); |
||||
} |
||||
|
||||
@Test |
||||
public void tomcatMetrics() throws Exception { |
||||
loadWeb(TomcatConfiguration.class); |
||||
assertThat(this.context.getBeansOfType(TomcatPublicMetrics.class)).hasSize(1); |
||||
} |
||||
|
||||
@Test |
||||
public void noCacheMetrics() { |
||||
load(); |
||||
assertThat(this.context.getBeansOfType(CachePublicMetrics.class)).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
public void autoCacheManager() { |
||||
load(CacheConfiguration.class); |
||||
CachePublicMetrics bean = this.context.getBean(CachePublicMetrics.class); |
||||
Collection<Metric<?>> metrics = bean.metrics(); |
||||
assertMetrics(metrics, "cache.books.size", "cache.speakers.size"); |
||||
} |
||||
|
||||
@Test |
||||
public void multipleCacheManagers() { |
||||
load(MultipleCacheConfiguration.class); |
||||
CachePublicMetrics bean = this.context.getBean(CachePublicMetrics.class); |
||||
Collection<Metric<?>> metrics = bean.metrics(); |
||||
assertMetrics(metrics, "cache.books.size", "cache.second_speakers.size", |
||||
"cache.first_speakers.size", "cache.users.size"); |
||||
} |
||||
|
||||
private void assertHasMetric(Collection<Metric<?>> metrics, Metric<?> metric) { |
||||
for (Metric<?> m : metrics) { |
||||
if (m.getValue().equals(metric.getValue()) |
||||
&& m.getName().equals(metric.getName())) { |
||||
return; |
||||
} |
||||
} |
||||
fail("Metric " + metric.toString() + " not found in " + metrics.toString()); |
||||
} |
||||
|
||||
private void assertMetrics(Collection<Metric<?>> metrics, String... keys) { |
||||
Map<String, Number> content = new HashMap<>(); |
||||
for (Metric<?> metric : metrics) { |
||||
content.put(metric.getName(), metric.getValue()); |
||||
} |
||||
for (String key : keys) { |
||||
assertThat(content).containsKey(key); |
||||
} |
||||
} |
||||
|
||||
private void loadWeb(Class<?>... config) { |
||||
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(); |
||||
if (config.length > 0) { |
||||
context.register(config); |
||||
} |
||||
context.register(DataSourcePoolMetadataProvidersConfiguration.class, |
||||
CacheStatisticsAutoConfiguration.class, |
||||
PublicMetricsAutoConfiguration.class, MockServletWebServerFactory.class); |
||||
context.refresh(); |
||||
this.context = context; |
||||
} |
||||
|
||||
private void load(Class<?>... config) { |
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); |
||||
if (config.length > 0) { |
||||
context.register(config); |
||||
} |
||||
context.register(DataSourcePoolMetadataProvidersConfiguration.class, |
||||
CacheStatisticsAutoConfiguration.class, |
||||
PublicMetricsAutoConfiguration.class); |
||||
context.refresh(); |
||||
this.context = context; |
||||
} |
||||
|
||||
@Configuration |
||||
static class MultipleDataSourcesConfig { |
||||
|
||||
@Bean |
||||
public DataSource tomcatDataSource() { |
||||
return InitializedBuilder.create() |
||||
.type(org.apache.tomcat.jdbc.pool.DataSource.class).build(); |
||||
} |
||||
|
||||
@Bean |
||||
public DataSource hikariDS() { |
||||
return InitializedBuilder.create().type(HikariDataSource.class).build(); |
||||
} |
||||
|
||||
@Bean |
||||
public DataSource commonsDbcpDataSource() { |
||||
return InitializedBuilder.create().type(BasicDataSource.class).build(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class MultipleDataSourcesWithPrimaryConfig { |
||||
|
||||
@Bean |
||||
@Primary |
||||
public DataSource myDataSource() { |
||||
return InitializedBuilder.create() |
||||
.type(org.apache.tomcat.jdbc.pool.DataSource.class).build(); |
||||
} |
||||
|
||||
@Bean |
||||
public DataSource commonsDbcpDataSource() { |
||||
return InitializedBuilder.create().type(BasicDataSource.class).build(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class MultipleDataSourcesWithCustomPrimaryConfig { |
||||
|
||||
@Bean |
||||
@Primary |
||||
public DataSource myDataSource() { |
||||
return InitializedBuilder.create() |
||||
.type(org.apache.tomcat.jdbc.pool.DataSource.class).build(); |
||||
} |
||||
|
||||
@Bean |
||||
public DataSource dataSource() { |
||||
return InitializedBuilder.create().type(BasicDataSource.class).build(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class CustomDataSourcePublicMetrics { |
||||
|
||||
@Bean |
||||
public DataSourcePublicMetrics myDataSourcePublicMetrics() { |
||||
return new DataSourcePublicMetrics() { |
||||
@Override |
||||
protected String createPrefix(String dataSourceName, |
||||
DataSource dataSource, boolean primary) { |
||||
return (primary ? "ds.first." : "ds.second"); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class RichGaugeReaderConfig { |
||||
|
||||
@Bean |
||||
public RichGaugeReader richGaugeReader() { |
||||
return mock(RichGaugeReader.class); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class TomcatConfiguration { |
||||
|
||||
@Bean |
||||
public TomcatServletWebServerFactory webServerFactory() { |
||||
return new TomcatServletWebServerFactory(0); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class CacheConfiguration { |
||||
|
||||
@Bean |
||||
public CacheManager cacheManager() { |
||||
return new ConcurrentMapCacheManager("books", "speakers"); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class MultipleCacheConfiguration { |
||||
|
||||
@Bean |
||||
@Order(1) |
||||
public CacheManager first() { |
||||
return new ConcurrentMapCacheManager("books", "speakers"); |
||||
} |
||||
|
||||
@Bean |
||||
@Order(2) |
||||
public CacheManager second() { |
||||
return new ConcurrentMapCacheManager("users", "speakers"); |
||||
} |
||||
|
||||
} |
||||
|
||||
private static class InitializedBuilder { |
||||
|
||||
public static DataSourceBuilder create() { |
||||
return DataSourceBuilder.create() |
||||
.driverClassName("org.hsqldb.jdbc.JDBCDriver") |
||||
.url("jdbc:hsqldb:mem:test").username("sa"); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.autoconfigure.metrics.export.simple; |
||||
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry; |
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.AutoConfigurations; |
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner; |
||||
import org.springframework.test.context.junit4.SpringRunner; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link SimpleExportConfiguration}. |
||||
* |
||||
* @author Jon Schneider |
||||
*/ |
||||
@RunWith(SpringRunner.class) |
||||
public class SimpleExportConfigurationTests { |
||||
|
||||
@Test |
||||
public void simpleMeterRegistryIsInTheCompositeWhenNoOtherRegistryIs() { |
||||
new ApplicationContextRunner() |
||||
.withPropertyValues("metrics.atlas.enabled=false", |
||||
"metrics.datadog.enabled=false", "metrics.ganglia.enabled=false", |
||||
"metrics.graphite.enabled=false", "metrics.influx.enabled=false", |
||||
"metrics.jmx.enabled=false", "metrics.prometheus.enabled=false") |
||||
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class)) |
||||
.run((context) -> { |
||||
CompositeMeterRegistry meterRegistry = context |
||||
.getBean(CompositeMeterRegistry.class); |
||||
assertThat(meterRegistry.getRegistries()).hasSize(1); |
||||
assertThat(meterRegistry.getRegistries()) |
||||
.hasOnlyElementsOfType(SimpleMeterRegistry.class); |
||||
}); |
||||
} |
||||
|
||||
} |
||||
@ -1,60 +0,0 @@
@@ -1,60 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.integration; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.beans.factory.annotation.Qualifier; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.PublicMetricsAutoConfiguration; |
||||
import org.springframework.boot.actuate.metrics.reader.MetricReaderPublicMetrics; |
||||
import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Import; |
||||
import org.springframework.test.annotation.DirtiesContext; |
||||
import org.springframework.test.context.junit4.SpringRunner; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link SpringIntegrationMetricReader}. |
||||
* |
||||
* @author Artem Bilan |
||||
*/ |
||||
@RunWith(SpringRunner.class) |
||||
@SpringBootTest("spring.jmx.enabled=false") |
||||
@DirtiesContext |
||||
public class SpringIntegrationMetricReaderNoJmxTests { |
||||
|
||||
@Autowired |
||||
@Qualifier("springIntegrationPublicMetrics") |
||||
private MetricReaderPublicMetrics integrationMetricReader; |
||||
|
||||
@Test |
||||
public void test() { |
||||
assertThat(this.integrationMetricReader.metrics().size() > 0).isTrue(); |
||||
} |
||||
|
||||
@Configuration |
||||
@Import({ IntegrationAutoConfiguration.class, PublicMetricsAutoConfiguration.class }) |
||||
protected static class TestConfiguration { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,66 +0,0 @@
@@ -1,66 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.integration; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.context.annotation.Import; |
||||
import org.springframework.integration.support.management.IntegrationManagementConfigurer; |
||||
import org.springframework.test.annotation.DirtiesContext; |
||||
import org.springframework.test.context.junit4.SpringRunner; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link SpringIntegrationMetricReader}. |
||||
* |
||||
* @author Dave Syer |
||||
* @author Artem Bilan |
||||
*/ |
||||
@RunWith(SpringRunner.class) |
||||
@SpringBootTest("spring.jmx.enabled=true") |
||||
@DirtiesContext |
||||
public class SpringIntegrationMetricReaderTests { |
||||
|
||||
@Autowired |
||||
private SpringIntegrationMetricReader reader; |
||||
|
||||
@Test |
||||
public void test() { |
||||
assertThat(this.reader.count() > 0).isTrue(); |
||||
} |
||||
|
||||
@Configuration |
||||
@Import({ JmxAutoConfiguration.class, IntegrationAutoConfiguration.class }) |
||||
protected static class TestConfiguration { |
||||
|
||||
@Bean |
||||
public SpringIntegrationMetricReader reader( |
||||
IntegrationManagementConfigurer managementConfigurer) { |
||||
return new SpringIntegrationMetricReader(managementConfigurer); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,133 +0,0 @@
@@ -1,133 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.cache; |
||||
|
||||
import java.lang.management.ManagementFactory; |
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
import javax.management.AttributeNotFoundException; |
||||
import javax.management.InstanceNotFoundException; |
||||
import javax.management.MBeanException; |
||||
import javax.management.MBeanServer; |
||||
import javax.management.MalformedObjectNameException; |
||||
import javax.management.ObjectName; |
||||
import javax.management.ReflectionException; |
||||
|
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import org.springframework.cache.Cache; |
||||
import org.springframework.cache.CacheManager; |
||||
|
||||
/** |
||||
* Base {@link CacheStatisticsProvider} implementation that uses JMX to retrieve the cache |
||||
* statistics. |
||||
* |
||||
* @param <C> The cache type |
||||
* @author Stephane Nicoll |
||||
* @since 1.3.0 |
||||
*/ |
||||
public abstract class AbstractJmxCacheStatisticsProvider<C extends Cache> |
||||
implements CacheStatisticsProvider<C> { |
||||
|
||||
private static final Logger logger = LoggerFactory |
||||
.getLogger(AbstractJmxCacheStatisticsProvider.class); |
||||
|
||||
private MBeanServer mBeanServer; |
||||
|
||||
private final Map<String, ObjectNameWrapper> caches = new ConcurrentHashMap<>(); |
||||
|
||||
@Override |
||||
public CacheStatistics getCacheStatistics(CacheManager cacheManager, C cache) { |
||||
try { |
||||
ObjectName objectName = internalGetObjectName(cache); |
||||
return (objectName == null ? null : getCacheStatistics(objectName)); |
||||
} |
||||
catch (MalformedObjectNameException ex) { |
||||
throw new IllegalStateException(ex); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Return the {@link ObjectName} of the MBean that is managing the specified cache or |
||||
* {@code null} if none is found. |
||||
* @param cache the cache to handle |
||||
* @return the object name of the cache statistics MBean |
||||
* @throws MalformedObjectNameException if the {@link ObjectName} for that cache is |
||||
* invalid |
||||
*/ |
||||
protected abstract ObjectName getObjectName(C cache) |
||||
throws MalformedObjectNameException; |
||||
|
||||
/** |
||||
* Return the current {@link CacheStatistics} snapshot from the MBean identified by |
||||
* the specified {@link ObjectName}. |
||||
* @param objectName the object name of the cache statistics MBean |
||||
* @return the current cache statistics |
||||
*/ |
||||
protected abstract CacheStatistics getCacheStatistics(ObjectName objectName); |
||||
|
||||
private ObjectName internalGetObjectName(C cache) |
||||
throws MalformedObjectNameException { |
||||
String cacheName = cache.getName(); |
||||
ObjectNameWrapper value = this.caches.get(cacheName); |
||||
if (value != null) { |
||||
return value.objectName; |
||||
} |
||||
ObjectName objectName = getObjectName(cache); |
||||
this.caches.put(cacheName, new ObjectNameWrapper(objectName)); |
||||
return objectName; |
||||
} |
||||
|
||||
protected MBeanServer getMBeanServer() { |
||||
if (this.mBeanServer == null) { |
||||
this.mBeanServer = ManagementFactory.getPlatformMBeanServer(); |
||||
} |
||||
return this.mBeanServer; |
||||
} |
||||
|
||||
protected <T> T getAttribute(ObjectName objectName, String attributeName, |
||||
Class<T> type) { |
||||
try { |
||||
Object attribute = getMBeanServer().getAttribute(objectName, attributeName); |
||||
return type.cast(attribute); |
||||
} |
||||
catch (MBeanException | ReflectionException ex) { |
||||
throw new IllegalStateException(ex); |
||||
} |
||||
catch (AttributeNotFoundException ex) { |
||||
throw new IllegalStateException("Unexpected: MBean with name '" + objectName |
||||
+ "' " + "does not expose attribute with name " + attributeName, ex); |
||||
} |
||||
catch (InstanceNotFoundException ex) { |
||||
logger.warn("Cache statistics are no longer available", ex); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
private static class ObjectNameWrapper { |
||||
|
||||
private final ObjectName objectName; |
||||
|
||||
ObjectNameWrapper(ObjectName objectName) { |
||||
this.objectName = objectName; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,160 +0,0 @@
@@ -1,160 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.cache; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.HashSet; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.boot.actuate.metrics.Metric; |
||||
import org.springframework.boot.actuate.metrics.PublicMetrics; |
||||
import org.springframework.cache.Cache; |
||||
import org.springframework.cache.CacheManager; |
||||
import org.springframework.cache.transaction.TransactionAwareCacheDecorator; |
||||
import org.springframework.core.ResolvableType; |
||||
import org.springframework.util.ClassUtils; |
||||
import org.springframework.util.LinkedMultiValueMap; |
||||
import org.springframework.util.MultiValueMap; |
||||
|
||||
/** |
||||
* A {@link PublicMetrics} implementation that provides cache statistics. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 2.0.0 |
||||
*/ |
||||
public class CachePublicMetrics implements PublicMetrics { |
||||
|
||||
private final Map<String, CacheManager> cacheManagers; |
||||
|
||||
private final Collection<CacheStatisticsProvider<?>> statisticsProviders; |
||||
|
||||
/** |
||||
* Create a new {@link CachePublicMetrics} instance. |
||||
* @param cacheManagers the cache managers |
||||
* @param statisticsProviders the statistics providers |
||||
*/ |
||||
public CachePublicMetrics(Map<String, CacheManager> cacheManagers, |
||||
Collection<CacheStatisticsProvider<?>> statisticsProviders) { |
||||
this.cacheManagers = cacheManagers; |
||||
this.statisticsProviders = statisticsProviders; |
||||
} |
||||
|
||||
@Override |
||||
public Collection<Metric<?>> metrics() { |
||||
Collection<Metric<?>> metrics = new HashSet<>(); |
||||
for (Map.Entry<String, List<CacheManagerBean>> entry : getCacheManagerBeans() |
||||
.entrySet()) { |
||||
addMetrics(metrics, entry.getKey(), entry.getValue()); |
||||
} |
||||
return metrics; |
||||
} |
||||
|
||||
private MultiValueMap<String, CacheManagerBean> getCacheManagerBeans() { |
||||
MultiValueMap<String, CacheManagerBean> cacheManagerNamesByCacheName = new LinkedMultiValueMap<>(); |
||||
for (Map.Entry<String, CacheManager> entry : this.cacheManagers.entrySet()) { |
||||
for (String cacheName : entry.getValue().getCacheNames()) { |
||||
cacheManagerNamesByCacheName.add(cacheName, |
||||
new CacheManagerBean(entry.getKey(), entry.getValue())); |
||||
} |
||||
} |
||||
return cacheManagerNamesByCacheName; |
||||
} |
||||
|
||||
private void addMetrics(Collection<Metric<?>> metrics, String cacheName, |
||||
List<CacheManagerBean> cacheManagerBeans) { |
||||
for (CacheManagerBean cacheManagerBean : cacheManagerBeans) { |
||||
CacheManager cacheManager = cacheManagerBean.getCacheManager(); |
||||
Cache cache = unwrapIfNecessary(cacheManager.getCache(cacheName)); |
||||
CacheStatistics statistics = getCacheStatistics(cache, cacheManager); |
||||
if (statistics != null) { |
||||
String prefix = cacheName; |
||||
if (cacheManagerBeans.size() > 1) { |
||||
prefix = cacheManagerBean.getBeanName() + "_" + prefix; |
||||
} |
||||
prefix = "cache." + prefix + (prefix.endsWith(".") ? "" : "."); |
||||
metrics.addAll(statistics.toMetrics(prefix)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private Cache unwrapIfNecessary(Cache cache) { |
||||
if (ClassUtils.isPresent( |
||||
"org.springframework.cache.transaction.TransactionAwareCacheDecorator", |
||||
getClass().getClassLoader())) { |
||||
return TransactionAwareCacheDecoratorHandler.unwrapIfNecessary(cache); |
||||
} |
||||
return cache; |
||||
} |
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) |
||||
private CacheStatistics getCacheStatistics(Cache cache, CacheManager cacheManager) { |
||||
if (this.statisticsProviders != null) { |
||||
for (CacheStatisticsProvider provider : this.statisticsProviders) { |
||||
Class<?> cacheType = ResolvableType |
||||
.forClass(CacheStatisticsProvider.class, provider.getClass()) |
||||
.resolveGeneric(); |
||||
if (cacheType.isInstance(cache)) { |
||||
CacheStatistics statistics = provider.getCacheStatistics(cacheManager, |
||||
cache); |
||||
if (statistics != null) { |
||||
return statistics; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
private static class CacheManagerBean { |
||||
|
||||
private final String beanName; |
||||
|
||||
private final CacheManager cacheManager; |
||||
|
||||
CacheManagerBean(String beanName, CacheManager cacheManager) { |
||||
this.beanName = beanName; |
||||
this.cacheManager = cacheManager; |
||||
} |
||||
|
||||
public String getBeanName() { |
||||
return this.beanName; |
||||
} |
||||
|
||||
public CacheManager getCacheManager() { |
||||
return this.cacheManager; |
||||
} |
||||
|
||||
} |
||||
|
||||
private static class TransactionAwareCacheDecoratorHandler { |
||||
|
||||
private static Cache unwrapIfNecessary(Cache cache) { |
||||
try { |
||||
if (cache instanceof TransactionAwareCacheDecorator) { |
||||
return ((TransactionAwareCacheDecorator) cache).getTargetCache(); |
||||
} |
||||
} |
||||
catch (NoClassDefFoundError ex) { |
||||
// Ignore
|
||||
} |
||||
return cache; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,66 +0,0 @@
@@ -1,66 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2015 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.boot.actuate.cache; |
||||
|
||||
import java.util.Collection; |
||||
|
||||
import org.springframework.boot.actuate.metrics.Metric; |
||||
|
||||
/** |
||||
* Snapshot of the statistics of a given cache. {@code CacheStatistics} instances have a |
||||
* very short life as it represents the statistics of a cache at one particular point in |
||||
* time. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 1.3.0 |
||||
*/ |
||||
public interface CacheStatistics { |
||||
|
||||
/** |
||||
* Generate the relevant {@link Metric} instances based on the specified prefix. |
||||
* @param prefix the metrics prefix (ends with '.') |
||||
* @return the metrics corresponding to this instance |
||||
*/ |
||||
Collection<Metric<?>> toMetrics(String prefix); |
||||
|
||||
/** |
||||
* Return the size of the cache or {@code null} if that information is not available. |
||||
* @return the size of the cache or {@code null} |
||||
*/ |
||||
Long getSize(); |
||||
|
||||
/** |
||||
* Return the ratio of cache requests which were hits as a value between 0 and 1 where |
||||
* 0 means that the hit ratio is 0% and 1 means it is 100%. |
||||
* <p> |
||||
* This may also return {@code null} if the cache-specifics statistics does not |
||||
* provide the necessary information |
||||
* @return the hit ratio or {@code null} |
||||
*/ |
||||
Double getHitRatio(); |
||||
|
||||
/** |
||||
* Return the ratio of cache requests which were misses as value between 0 and 1 where |
||||
* 0 means that the miss ratio is 0% and 1 means it is 100%. |
||||
* <p> |
||||
* This may also return {@code null} if the cache-specifics statistics does not |
||||
* provide the necessary information |
||||
* @return the miss ratio or {@code null} |
||||
*/ |
||||
Double getMissRatio(); |
||||
|
||||
} |
||||
@ -1,42 +0,0 @@
@@ -1,42 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.cache; |
||||
|
||||
import org.springframework.cache.Cache; |
||||
import org.springframework.cache.CacheManager; |
||||
|
||||
/** |
||||
* Provide a {@link CacheStatistics} based on a {@link Cache}. |
||||
* |
||||
* @param <C> The {@link Cache} type |
||||
* @author Stephane Nicoll |
||||
* @author Phillip Webb |
||||
* @since 1.3.0 |
||||
*/ |
||||
@FunctionalInterface |
||||
public interface CacheStatisticsProvider<C extends Cache> { |
||||
|
||||
/** |
||||
* Return the current {@link CacheStatistics} snapshot for the specified {@link Cache} |
||||
* or {@code null} if the given cache could not be handled. |
||||
* @param cacheManager the {@link CacheManager} handling this cache |
||||
* @param cache the cache to handle |
||||
* @return the current cache statistics or {@code null} |
||||
*/ |
||||
CacheStatistics getCacheStatistics(CacheManager cacheManager, C cache); |
||||
|
||||
} |
||||
@ -1,46 +0,0 @@
@@ -1,46 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2016 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.boot.actuate.cache; |
||||
|
||||
import com.github.benmanes.caffeine.cache.stats.CacheStats; |
||||
|
||||
import org.springframework.cache.CacheManager; |
||||
import org.springframework.cache.caffeine.CaffeineCache; |
||||
|
||||
/** |
||||
* {@link CacheStatisticsProvider} implementation for Caffeine. |
||||
* |
||||
* @author Eddú Meléndez |
||||
* @since 1.4.0 |
||||
*/ |
||||
public class CaffeineCacheStatisticsProvider |
||||
implements CacheStatisticsProvider<CaffeineCache> { |
||||
|
||||
@Override |
||||
public CacheStatistics getCacheStatistics(CacheManager cacheManager, |
||||
CaffeineCache cache) { |
||||
DefaultCacheStatistics statistics = new DefaultCacheStatistics(); |
||||
statistics.setSize(cache.getNativeCache().estimatedSize()); |
||||
CacheStats caffeineStatistics = cache.getNativeCache().stats(); |
||||
if (caffeineStatistics.requestCount() > 0) { |
||||
statistics.setHitRatio(caffeineStatistics.hitRate()); |
||||
statistics.setMissRatio(caffeineStatistics.missRate()); |
||||
} |
||||
return statistics; |
||||
} |
||||
|
||||
} |
||||
@ -1,39 +0,0 @@
@@ -1,39 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2015 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.boot.actuate.cache; |
||||
|
||||
import org.springframework.cache.CacheManager; |
||||
import org.springframework.cache.concurrent.ConcurrentMapCache; |
||||
|
||||
/** |
||||
* {@link CacheStatisticsProvider} implementation for {@link ConcurrentMapCache}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class ConcurrentMapCacheStatisticsProvider |
||||
implements CacheStatisticsProvider<ConcurrentMapCache> { |
||||
|
||||
@Override |
||||
public CacheStatistics getCacheStatistics(CacheManager cacheManager, |
||||
ConcurrentMapCache cache) { |
||||
DefaultCacheStatistics statistics = new DefaultCacheStatistics(); |
||||
statistics.setSize((long) cache.getNativeCache().size()); |
||||
return statistics; |
||||
} |
||||
|
||||
} |
||||
@ -1,90 +0,0 @@
@@ -1,90 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.cache; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
|
||||
import org.springframework.boot.actuate.metrics.Metric; |
||||
|
||||
/** |
||||
* A default {@link CacheStatistics} implementation. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class DefaultCacheStatistics implements CacheStatistics { |
||||
|
||||
private Long size; |
||||
|
||||
private Double hitRatio; |
||||
|
||||
private Double missRatio; |
||||
|
||||
@Override |
||||
public Collection<Metric<?>> toMetrics(String prefix) { |
||||
Collection<Metric<?>> result = new ArrayList<>(); |
||||
addMetric(result, prefix + "size", getSize()); |
||||
addMetric(result, prefix + "hit.ratio", getHitRatio()); |
||||
addMetric(result, prefix + "miss.ratio", getMissRatio()); |
||||
return result; |
||||
} |
||||
|
||||
public void setGetCacheCounts(long hitCount, long missCount) { |
||||
long total = hitCount + missCount; |
||||
if (total > 0) { |
||||
double hitRatio = hitCount / (double) total; |
||||
setHitRatio(hitRatio); |
||||
setMissRatio(1 - hitRatio); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public Long getSize() { |
||||
return this.size; |
||||
} |
||||
|
||||
public void setSize(Long size) { |
||||
this.size = size; |
||||
} |
||||
|
||||
@Override |
||||
public Double getHitRatio() { |
||||
return this.hitRatio; |
||||
} |
||||
|
||||
public void setHitRatio(Double hitRatio) { |
||||
this.hitRatio = hitRatio; |
||||
} |
||||
|
||||
@Override |
||||
public Double getMissRatio() { |
||||
return this.missRatio; |
||||
} |
||||
|
||||
public void setMissRatio(Double missRatio) { |
||||
this.missRatio = missRatio; |
||||
} |
||||
|
||||
private <T extends Number> void addMetric(Collection<Metric<?>> metrics, String name, |
||||
T value) { |
||||
if (value != null) { |
||||
metrics.add(new Metric<>(name, value)); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,55 +0,0 @@
@@ -1,55 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2016 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.boot.actuate.cache; |
||||
|
||||
import net.sf.ehcache.statistics.StatisticsGateway; |
||||
|
||||
import org.springframework.cache.CacheManager; |
||||
import org.springframework.cache.ehcache.EhCacheCache; |
||||
|
||||
/** |
||||
* {@link CacheStatisticsProvider} implementation for EhCache. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class EhCacheStatisticsProvider implements CacheStatisticsProvider<EhCacheCache> { |
||||
|
||||
@Override |
||||
public CacheStatistics getCacheStatistics(CacheManager cacheManager, |
||||
EhCacheCache cache) { |
||||
DefaultCacheStatistics statistics = new DefaultCacheStatistics(); |
||||
StatisticsGateway ehCacheStatistics = cache.getNativeCache().getStatistics(); |
||||
statistics.setSize(ehCacheStatistics.getSize()); |
||||
double hitRatio = cacheHitRatio(ehCacheStatistics); |
||||
if (!Double.isNaN(hitRatio)) { |
||||
// ratio is calculated 'racily' and can drift marginally above unity,
|
||||
// so we cap it here
|
||||
double sanitizedHitRatio = (hitRatio > 1 ? 1 : hitRatio); |
||||
statistics.setHitRatio(sanitizedHitRatio); |
||||
statistics.setMissRatio(1 - sanitizedHitRatio); |
||||
} |
||||
return statistics; |
||||
} |
||||
|
||||
private double cacheHitRatio(StatisticsGateway stats) { |
||||
long hitCount = stats.cacheHitCount(); |
||||
long missCount = stats.cacheMissCount(); |
||||
return ((double) hitCount) / (hitCount + missCount); |
||||
} |
||||
|
||||
} |
||||
@ -1,46 +0,0 @@
@@ -1,46 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2015 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.boot.actuate.cache; |
||||
|
||||
import com.hazelcast.core.IMap; |
||||
import com.hazelcast.monitor.LocalMapStats; |
||||
import com.hazelcast.spring.cache.HazelcastCache; |
||||
|
||||
import org.springframework.cache.CacheManager; |
||||
|
||||
/** |
||||
* {@link CacheStatisticsProvider} implementation for Hazelcast. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class HazelcastCacheStatisticsProvider |
||||
implements CacheStatisticsProvider<HazelcastCache> { |
||||
|
||||
@Override |
||||
public CacheStatistics getCacheStatistics(CacheManager cacheManager, |
||||
HazelcastCache cache) { |
||||
DefaultCacheStatistics statistics = new DefaultCacheStatistics(); |
||||
LocalMapStats mapStatistics = ((IMap<?, ?>) cache.getNativeCache()) |
||||
.getLocalMapStats(); |
||||
statistics.setSize(mapStatistics.getOwnedEntryCount()); |
||||
statistics.setGetCacheCounts(mapStatistics.getHits(), |
||||
mapStatistics.getGetOperationCount() - mapStatistics.getHits()); |
||||
return statistics; |
||||
} |
||||
|
||||
} |
||||
@ -1,73 +0,0 @@
@@ -1,73 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2015 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.boot.actuate.cache; |
||||
|
||||
import java.util.Set; |
||||
|
||||
import javax.management.MalformedObjectNameException; |
||||
import javax.management.ObjectInstance; |
||||
import javax.management.ObjectName; |
||||
|
||||
import org.infinispan.spring.provider.SpringCache; |
||||
|
||||
/** |
||||
* {@link CacheStatisticsProvider} implementation for Infinispan. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class InfinispanCacheStatisticsProvider |
||||
extends AbstractJmxCacheStatisticsProvider<SpringCache> { |
||||
|
||||
@Override |
||||
protected ObjectName getObjectName(SpringCache cache) |
||||
throws MalformedObjectNameException { |
||||
ObjectName name = new ObjectName( |
||||
"org.infinispan:component=Statistics,type=Cache,name=\"" + cache.getName() |
||||
+ "(local)\",*"); |
||||
Set<ObjectInstance> instances = getMBeanServer().queryMBeans(name, null); |
||||
if (instances.size() == 1) { |
||||
return instances.iterator().next().getObjectName(); |
||||
} |
||||
// None or more than one
|
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
protected CacheStatistics getCacheStatistics(ObjectName objectName) { |
||||
DefaultCacheStatistics statistics = new DefaultCacheStatistics(); |
||||
Integer size = getAttribute(objectName, "numberOfEntries", Integer.class); |
||||
if (size != null) { |
||||
statistics.setSize((long) size); |
||||
if (size > 0) { |
||||
// Let's initialize the stats if we have some data
|
||||
initializeStats(objectName, statistics); |
||||
} |
||||
} |
||||
return statistics; |
||||
} |
||||
|
||||
private void initializeStats(ObjectName objectName, |
||||
DefaultCacheStatistics statistics) { |
||||
Double hitRatio = getAttribute(objectName, "hitRatio", Double.class); |
||||
if ((hitRatio != null)) { |
||||
statistics.setHitRatio(hitRatio); |
||||
statistics.setMissRatio(1 - hitRatio); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,63 +0,0 @@
@@ -1,63 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2015 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.boot.actuate.cache; |
||||
|
||||
import java.util.Set; |
||||
|
||||
import javax.management.MalformedObjectNameException; |
||||
import javax.management.ObjectInstance; |
||||
import javax.management.ObjectName; |
||||
|
||||
import org.springframework.cache.jcache.JCacheCache; |
||||
|
||||
/** |
||||
* {@link CacheStatisticsProvider} implementation for a JSR-107 compliant cache. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class JCacheCacheStatisticsProvider |
||||
extends AbstractJmxCacheStatisticsProvider<JCacheCache> { |
||||
|
||||
@Override |
||||
protected ObjectName getObjectName(JCacheCache cache) |
||||
throws MalformedObjectNameException { |
||||
ObjectName name = new ObjectName( |
||||
"javax.cache:type=CacheStatistics,Cache=" + cache.getName() + ",*"); |
||||
Set<ObjectInstance> instances = getMBeanServer().queryMBeans(name, null); |
||||
if (instances.size() == 1) { |
||||
return instances.iterator().next().getObjectName(); |
||||
} |
||||
// None or more than one
|
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
protected CacheStatistics getCacheStatistics(ObjectName objectName) { |
||||
DefaultCacheStatistics statistics = new DefaultCacheStatistics(); |
||||
Float hitPercentage = getAttribute(objectName, "CacheHitPercentage", Float.class); |
||||
Float missPercentage = getAttribute(objectName, "CacheMissPercentage", |
||||
Float.class); |
||||
if ((hitPercentage != null && missPercentage != null) |
||||
&& (hitPercentage > 0 || missPercentage > 0)) { |
||||
statistics.setHitRatio(hitPercentage / (double) 100); |
||||
statistics.setMissRatio(missPercentage / (double) 100); |
||||
} |
||||
return statistics; |
||||
} |
||||
|
||||
} |
||||
@ -1,20 +0,0 @@
@@ -1,20 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
*/ |
||||
|
||||
/** |
||||
* Actuator support for cache statistics. |
||||
*/ |
||||
package org.springframework.boot.actuate.cache; |
||||
@ -1,44 +0,0 @@
@@ -1,44 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2013 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.boot.actuate.metrics; |
||||
|
||||
/** |
||||
* A service that can be used to increment, decrement and reset a named counter value. |
||||
* |
||||
* @author Dave Syer |
||||
*/ |
||||
public interface CounterService { |
||||
|
||||
/** |
||||
* Increment the specified counter by 1. |
||||
* @param metricName the name of the counter |
||||
*/ |
||||
void increment(String metricName); |
||||
|
||||
/** |
||||
* Decrement the specified counter by 1. |
||||
* @param metricName the name of the counter |
||||
*/ |
||||
void decrement(String metricName); |
||||
|
||||
/** |
||||
* Reset the specified counter. |
||||
* @param metricName the name of the counter |
||||
*/ |
||||
void reset(String metricName); |
||||
|
||||
} |
||||
@ -1,127 +0,0 @@
@@ -1,127 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.HashMap; |
||||
import java.util.LinkedHashSet; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import javax.annotation.PostConstruct; |
||||
import javax.sql.DataSource; |
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadata; |
||||
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider; |
||||
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProviders; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.annotation.Primary; |
||||
|
||||
/** |
||||
* A {@link PublicMetrics} implementation that provides data source usage statistics. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 2.0.0 |
||||
*/ |
||||
public class DataSourcePublicMetrics implements PublicMetrics { |
||||
|
||||
private static final String DATASOURCE_SUFFIX = "dataSource"; |
||||
|
||||
@Autowired |
||||
private ApplicationContext applicationContext; |
||||
|
||||
@Autowired |
||||
private Collection<DataSourcePoolMetadataProvider> providers; |
||||
|
||||
private final Map<String, DataSourcePoolMetadata> metadataByPrefix = new HashMap<>(); |
||||
|
||||
@PostConstruct |
||||
public void initialize() { |
||||
DataSource primaryDataSource = getPrimaryDataSource(); |
||||
DataSourcePoolMetadataProvider provider = new DataSourcePoolMetadataProviders( |
||||
this.providers); |
||||
for (Map.Entry<String, DataSource> entry : this.applicationContext |
||||
.getBeansOfType(DataSource.class).entrySet()) { |
||||
String beanName = entry.getKey(); |
||||
DataSource bean = entry.getValue(); |
||||
String prefix = createPrefix(beanName, bean, bean.equals(primaryDataSource)); |
||||
DataSourcePoolMetadata poolMetadata = provider |
||||
.getDataSourcePoolMetadata(bean); |
||||
if (poolMetadata != null) { |
||||
this.metadataByPrefix.put(prefix, poolMetadata); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public Collection<Metric<?>> metrics() { |
||||
Set<Metric<?>> metrics = new LinkedHashSet<>(); |
||||
for (Map.Entry<String, DataSourcePoolMetadata> entry : this.metadataByPrefix |
||||
.entrySet()) { |
||||
String prefix = entry.getKey(); |
||||
prefix = (prefix.endsWith(".") ? prefix : prefix + "."); |
||||
DataSourcePoolMetadata metadata = entry.getValue(); |
||||
addMetric(metrics, prefix + "active", metadata.getActive()); |
||||
addMetric(metrics, prefix + "usage", metadata.getUsage()); |
||||
} |
||||
return metrics; |
||||
} |
||||
|
||||
private <T extends Number> void addMetric(Set<Metric<?>> metrics, String name, |
||||
T value) { |
||||
if (value != null) { |
||||
metrics.add(new Metric<>(name, value)); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Create the prefix to use for the metrics to associate with the given |
||||
* {@link DataSource}. |
||||
* @param name the name of the data source bean |
||||
* @param dataSource the data source to configure |
||||
* @param primary if this data source is the primary data source |
||||
* @return a prefix for the given data source |
||||
*/ |
||||
protected String createPrefix(String name, DataSource dataSource, boolean primary) { |
||||
if (primary) { |
||||
return "datasource.primary"; |
||||
} |
||||
if (name.length() > DATASOURCE_SUFFIX.length() |
||||
&& name.toLowerCase().endsWith(DATASOURCE_SUFFIX.toLowerCase())) { |
||||
name = name.substring(0, name.length() - DATASOURCE_SUFFIX.length()); |
||||
} |
||||
return "datasource." + name; |
||||
} |
||||
|
||||
/** |
||||
* Attempt to locate the primary {@link DataSource} (i.e. either the only data source |
||||
* available or the one amongst the candidates marked as {@link Primary}). Return |
||||
* {@code null} if there no primary data source could be found. |
||||
* @return the primary datasource |
||||
*/ |
||||
private DataSource getPrimaryDataSource() { |
||||
try { |
||||
return this.applicationContext.getBean(DataSource.class); |
||||
} |
||||
catch (NoSuchBeanDefinitionException ex) { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,40 +0,0 @@
@@ -1,40 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics; |
||||
|
||||
/** |
||||
* A service that can be used to submit a named double value for storage and analysis. Any |
||||
* statistics or analysis that needs to be carried out is best left for other concerns, |
||||
* but ultimately they are under control of the implementation of this service. For |
||||
* instance, the value submitted here could be a method execution timing result, and it |
||||
* would go to a backend that keeps a histogram of recent values for comparison purposes. |
||||
* Or it could be a simple measurement of a sensor value (like a temperature reading) to |
||||
* be passed on to a monitoring system in its raw form. |
||||
* |
||||
* @author Dave Syer |
||||
*/ |
||||
@FunctionalInterface |
||||
public interface GaugeService { |
||||
|
||||
/** |
||||
* Set the specified gauge value. |
||||
* @param metricName the name of the gauge to set |
||||
* @param value the value of the gauge |
||||
*/ |
||||
void submit(String metricName, double value); |
||||
|
||||
} |
||||
@ -1,137 +0,0 @@
@@ -1,137 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics; |
||||
|
||||
import java.util.Date; |
||||
|
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.ObjectUtils; |
||||
|
||||
/** |
||||
* Immutable class that can be used to hold any arbitrary system measurement value (a |
||||
* named numeric value with a timestamp). For example a metric might record the number of |
||||
* active connections to a server, or the temperature of a meeting room. |
||||
* |
||||
* @param <T> the value type |
||||
* @author Dave Syer |
||||
*/ |
||||
public class Metric<T extends Number> { |
||||
|
||||
private final String name; |
||||
|
||||
private final T value; |
||||
|
||||
private final Date timestamp; |
||||
|
||||
/** |
||||
* Create a new {@link Metric} instance for the current time. |
||||
* @param name the name of the metric |
||||
* @param value the value of the metric |
||||
*/ |
||||
public Metric(String name, T value) { |
||||
this(name, value, new Date()); |
||||
} |
||||
|
||||
/** |
||||
* Create a new {@link Metric} instance. |
||||
* @param name the name of the metric |
||||
* @param value the value of the metric |
||||
* @param timestamp the timestamp for the metric |
||||
*/ |
||||
public Metric(String name, T value, Date timestamp) { |
||||
Assert.notNull(name, "Name must not be null"); |
||||
this.name = name; |
||||
this.value = value; |
||||
this.timestamp = timestamp; |
||||
} |
||||
|
||||
/** |
||||
* Returns the name of the metric. |
||||
* @return the name |
||||
*/ |
||||
public String getName() { |
||||
return this.name; |
||||
} |
||||
|
||||
/** |
||||
* Returns the value of the metric. |
||||
* @return the value |
||||
*/ |
||||
public T getValue() { |
||||
return this.value; |
||||
} |
||||
|
||||
public Date getTimestamp() { |
||||
return this.timestamp; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "Metric [name=" + this.name + ", value=" + this.value + ", timestamp=" |
||||
+ this.timestamp + "]"; |
||||
} |
||||
|
||||
/** |
||||
* Create a new {@link Metric} with an incremented value. |
||||
* @param amount the amount that the new metric will differ from this one |
||||
* @return a new {@link Metric} instance |
||||
*/ |
||||
public Metric<Long> increment(int amount) { |
||||
return new Metric<>(this.getName(), |
||||
Long.valueOf(this.getValue().longValue() + amount)); |
||||
} |
||||
|
||||
/** |
||||
* Create a new {@link Metric} with a different value. |
||||
* @param <S> the metric value type |
||||
* @param value the value of the new metric |
||||
* @return a new {@link Metric} instance |
||||
*/ |
||||
public <S extends Number> Metric<S> set(S value) { |
||||
return new Metric<>(this.getName(), value); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
final int prime = 31; |
||||
int result = 1; |
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.name); |
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.timestamp); |
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.value); |
||||
return result; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
if (this == obj) { |
||||
return true; |
||||
} |
||||
if (obj == null) { |
||||
return false; |
||||
} |
||||
if (obj instanceof Metric) { |
||||
Metric<?> other = (Metric<?>) obj; |
||||
boolean rtn = true; |
||||
rtn = rtn && ObjectUtils.nullSafeEquals(this.name, other.name); |
||||
rtn = rtn && ObjectUtils.nullSafeEquals(this.timestamp, other.timestamp); |
||||
rtn = rtn && ObjectUtils.nullSafeEquals(this.value, other.value); |
||||
return rtn; |
||||
} |
||||
return super.equals(obj); |
||||
} |
||||
|
||||
} |
||||
@ -1,193 +0,0 @@
@@ -1,193 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics; |
||||
|
||||
import java.lang.management.ClassLoadingMXBean; |
||||
import java.lang.management.GarbageCollectorMXBean; |
||||
import java.lang.management.ManagementFactory; |
||||
import java.lang.management.MemoryUsage; |
||||
import java.lang.management.ThreadMXBean; |
||||
import java.util.Collection; |
||||
import java.util.LinkedHashSet; |
||||
import java.util.List; |
||||
|
||||
import org.springframework.core.Ordered; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
/** |
||||
* A {@link PublicMetrics} implementation that provides various system-related metrics. |
||||
* |
||||
* @author Dave Syer |
||||
* @author Christian Dupuis |
||||
* @author Stephane Nicoll |
||||
* @author Johannes Edmeier |
||||
* @since 2.0.0 |
||||
*/ |
||||
public class SystemPublicMetrics implements PublicMetrics, Ordered { |
||||
|
||||
private long timestamp; |
||||
|
||||
public SystemPublicMetrics() { |
||||
this.timestamp = System.currentTimeMillis(); |
||||
} |
||||
|
||||
@Override |
||||
public int getOrder() { |
||||
return Ordered.HIGHEST_PRECEDENCE + 10; |
||||
} |
||||
|
||||
@Override |
||||
public Collection<Metric<?>> metrics() { |
||||
Collection<Metric<?>> result = new LinkedHashSet<>(); |
||||
addBasicMetrics(result); |
||||
addManagementMetrics(result); |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Add basic system metrics. |
||||
* @param result the result |
||||
*/ |
||||
protected void addBasicMetrics(Collection<Metric<?>> result) { |
||||
// NOTE: ManagementFactory must not be used here since it fails on GAE
|
||||
Runtime runtime = Runtime.getRuntime(); |
||||
result.add(newMemoryMetric("mem", |
||||
runtime.totalMemory() + getTotalNonHeapMemoryIfPossible())); |
||||
result.add(newMemoryMetric("mem.free", runtime.freeMemory())); |
||||
result.add(new Metric<>("processors", runtime.availableProcessors())); |
||||
result.add(new Metric<>("instance.uptime", |
||||
System.currentTimeMillis() - this.timestamp)); |
||||
} |
||||
|
||||
private long getTotalNonHeapMemoryIfPossible() { |
||||
try { |
||||
return ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getUsed(); |
||||
} |
||||
catch (Throwable ex) { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Add metrics from ManagementFactory if possible. Note that ManagementFactory is not |
||||
* available on Google App Engine. |
||||
* @param result the result |
||||
*/ |
||||
private void addManagementMetrics(Collection<Metric<?>> result) { |
||||
try { |
||||
// Add JVM up time in ms
|
||||
result.add(new Metric<>("uptime", |
||||
ManagementFactory.getRuntimeMXBean().getUptime())); |
||||
result.add(new Metric<>("systemload.average", |
||||
ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage())); |
||||
addHeapMetrics(result); |
||||
addNonHeapMetrics(result); |
||||
addThreadMetrics(result); |
||||
addClassLoadingMetrics(result); |
||||
addGarbageCollectionMetrics(result); |
||||
} |
||||
catch (NoClassDefFoundError ex) { |
||||
// Expected on Google App Engine
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Add JVM heap metrics. |
||||
* @param result the result |
||||
*/ |
||||
protected void addHeapMetrics(Collection<Metric<?>> result) { |
||||
MemoryUsage memoryUsage = ManagementFactory.getMemoryMXBean() |
||||
.getHeapMemoryUsage(); |
||||
result.add(newMemoryMetric("heap.committed", memoryUsage.getCommitted())); |
||||
result.add(newMemoryMetric("heap.init", memoryUsage.getInit())); |
||||
result.add(newMemoryMetric("heap.used", memoryUsage.getUsed())); |
||||
result.add(newMemoryMetric("heap", memoryUsage.getMax())); |
||||
} |
||||
|
||||
/** |
||||
* Add JVM non-heap metrics. |
||||
* @param result the result |
||||
*/ |
||||
private void addNonHeapMetrics(Collection<Metric<?>> result) { |
||||
MemoryUsage memoryUsage = ManagementFactory.getMemoryMXBean() |
||||
.getNonHeapMemoryUsage(); |
||||
result.add(newMemoryMetric("nonheap.committed", memoryUsage.getCommitted())); |
||||
result.add(newMemoryMetric("nonheap.init", memoryUsage.getInit())); |
||||
result.add(newMemoryMetric("nonheap.used", memoryUsage.getUsed())); |
||||
result.add(newMemoryMetric("nonheap", memoryUsage.getMax())); |
||||
} |
||||
|
||||
private Metric<Long> newMemoryMetric(String name, long bytes) { |
||||
return new Metric<>(name, bytes / 1024); |
||||
} |
||||
|
||||
/** |
||||
* Add thread metrics. |
||||
* @param result the result |
||||
*/ |
||||
protected void addThreadMetrics(Collection<Metric<?>> result) { |
||||
ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean(); |
||||
result.add( |
||||
new Metric<>("threads.peak", (long) threadMxBean.getPeakThreadCount())); |
||||
result.add(new Metric<>("threads.daemon", |
||||
(long) threadMxBean.getDaemonThreadCount())); |
||||
result.add(new Metric<>("threads.totalStarted", |
||||
threadMxBean.getTotalStartedThreadCount())); |
||||
result.add(new Metric<>("threads", (long) threadMxBean.getThreadCount())); |
||||
} |
||||
|
||||
/** |
||||
* Add class loading metrics. |
||||
* @param result the result |
||||
*/ |
||||
protected void addClassLoadingMetrics(Collection<Metric<?>> result) { |
||||
ClassLoadingMXBean classLoadingMxBean = ManagementFactory.getClassLoadingMXBean(); |
||||
result.add( |
||||
new Metric<>("classes", (long) classLoadingMxBean.getLoadedClassCount())); |
||||
result.add(new Metric<>("classes.loaded", |
||||
classLoadingMxBean.getTotalLoadedClassCount())); |
||||
result.add(new Metric<>("classes.unloaded", |
||||
classLoadingMxBean.getUnloadedClassCount())); |
||||
} |
||||
|
||||
/** |
||||
* Add garbage collection metrics. |
||||
* @param result the result |
||||
*/ |
||||
protected void addGarbageCollectionMetrics(Collection<Metric<?>> result) { |
||||
List<GarbageCollectorMXBean> garbageCollectorMxBeans = ManagementFactory |
||||
.getGarbageCollectorMXBeans(); |
||||
for (GarbageCollectorMXBean garbageCollectorMXBean : garbageCollectorMxBeans) { |
||||
String name = beautifyGcName(garbageCollectorMXBean.getName()); |
||||
result.add(new Metric<>("gc." + name + ".count", |
||||
garbageCollectorMXBean.getCollectionCount())); |
||||
result.add(new Metric<>("gc." + name + ".time", |
||||
garbageCollectorMXBean.getCollectionTime())); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Turn GC names like 'PS Scavenge' or 'PS MarkSweep' into something that is more |
||||
* metrics friendly. |
||||
* @param name the source name |
||||
* @return a metric friendly name |
||||
*/ |
||||
private String beautifyGcName(String name) { |
||||
return StringUtils.replace(name, " ", "_").toLowerCase(); |
||||
} |
||||
|
||||
} |
||||
@ -1,96 +0,0 @@
@@ -1,96 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
import org.apache.catalina.Container; |
||||
import org.apache.catalina.Context; |
||||
import org.apache.catalina.Manager; |
||||
import org.apache.catalina.session.ManagerBase; |
||||
|
||||
import org.springframework.beans.BeansException; |
||||
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer; |
||||
import org.springframework.boot.web.server.WebServer; |
||||
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.ApplicationContextAware; |
||||
|
||||
/** |
||||
* A {@link PublicMetrics} implementation that provides Tomcat statistics. |
||||
* |
||||
* @author Johannes Edmeier |
||||
* @author Phillip Webb |
||||
* @since 2.0.0 |
||||
*/ |
||||
public class TomcatPublicMetrics implements PublicMetrics, ApplicationContextAware { |
||||
|
||||
private ApplicationContext applicationContext; |
||||
|
||||
@Override |
||||
public Collection<Metric<?>> metrics() { |
||||
if (this.applicationContext instanceof ServletWebServerApplicationContext) { |
||||
Manager manager = getManager( |
||||
(ServletWebServerApplicationContext) this.applicationContext); |
||||
if (manager != null) { |
||||
return metrics(manager); |
||||
} |
||||
} |
||||
return Collections.emptySet(); |
||||
} |
||||
|
||||
private Manager getManager(ServletWebServerApplicationContext applicationContext) { |
||||
WebServer webServer = applicationContext.getWebServer(); |
||||
if (webServer instanceof TomcatWebServer) { |
||||
return getManager((TomcatWebServer) webServer); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
private Manager getManager(TomcatWebServer webServer) { |
||||
for (Container container : webServer.getTomcat().getHost().findChildren()) { |
||||
if (container instanceof Context) { |
||||
return ((Context) container).getManager(); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
private Collection<Metric<?>> metrics(Manager manager) { |
||||
List<Metric<?>> metrics = new ArrayList<>(2); |
||||
if (manager instanceof ManagerBase) { |
||||
addMetric(metrics, "httpsessions.max", |
||||
((ManagerBase) manager).getMaxActiveSessions()); |
||||
} |
||||
addMetric(metrics, "httpsessions.active", manager.getActiveSessions()); |
||||
return metrics; |
||||
} |
||||
|
||||
private void addMetric(List<Metric<?>> metrics, String name, Integer value) { |
||||
metrics.add(new Metric<>(name, value)); |
||||
} |
||||
|
||||
@Override |
||||
public void setApplicationContext(ApplicationContext applicationContext) |
||||
throws BeansException { |
||||
this.applicationContext = applicationContext; |
||||
} |
||||
|
||||
} |
||||
@ -1,158 +0,0 @@
@@ -1,158 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.aggregate; |
||||
|
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
|
||||
import org.springframework.boot.actuate.metrics.Metric; |
||||
import org.springframework.boot.actuate.metrics.reader.MetricReader; |
||||
import org.springframework.boot.actuate.metrics.repository.InMemoryMetricRepository; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
/** |
||||
* A metric reader that aggregates values from a source reader, normally one that has been |
||||
* collecting data from many sources in the same form (like a scaled-out application). The |
||||
* source has metrics with names in the form {@code *.*.counter.**} and |
||||
* {@code *.*.[anything].**}, and the result has metric names in the form |
||||
* {@code aggregate.count.**} and {@code aggregate.[anything].**}. Counters are summed and |
||||
* anything else (i.e. gauges) are aggregated by choosing the most recent value. |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class AggregateMetricReader implements MetricReader { |
||||
|
||||
private MetricReader source; |
||||
|
||||
private String keyPattern = "d.d"; |
||||
|
||||
private String prefix = "aggregate."; |
||||
|
||||
public AggregateMetricReader(MetricReader source) { |
||||
this.source = source; |
||||
} |
||||
|
||||
/** |
||||
* Pattern that tells the aggregator what to do with the keys from the source |
||||
* repository. The keys in the source repository are assumed to be period separated, |
||||
* and the pattern is in the same format, e.g. "d.d.k.d". The pattern segments are |
||||
* matched against the source keys and a rule is applied: |
||||
* <ul> |
||||
* <li>"d" means "discard" this key segment (useful for global prefixes like system |
||||
* identifiers, or aggregate keys a.k.a. physical identifiers)</li> |
||||
* <li>"k" means "keep" it with no change (useful for logical identifiers like app |
||||
* names)</li> |
||||
* </ul> |
||||
* Default is "d.d" (we assume there is a global prefix of length 2). |
||||
* @param keyPattern the keyPattern to set |
||||
*/ |
||||
public void setKeyPattern(String keyPattern) { |
||||
this.keyPattern = keyPattern; |
||||
} |
||||
|
||||
/** |
||||
* Prefix to apply to all output metrics. A period will be appended if not present in |
||||
* the provided value. |
||||
* @param prefix the prefix to use (default "aggregator.") |
||||
*/ |
||||
public void setPrefix(String prefix) { |
||||
if (StringUtils.hasText(prefix) && !prefix.endsWith(".")) { |
||||
prefix = prefix + "."; |
||||
} |
||||
this.prefix = prefix; |
||||
} |
||||
|
||||
@Override |
||||
public Metric<?> findOne(String metricName) { |
||||
if (!metricName.startsWith(this.prefix)) { |
||||
return null; |
||||
} |
||||
InMemoryMetricRepository result = new InMemoryMetricRepository(); |
||||
String baseName = metricName.substring(this.prefix.length()); |
||||
for (Metric<?> metric : this.source.findAll()) { |
||||
String name = getSourceKey(metric.getName()); |
||||
if (baseName.equals(name)) { |
||||
update(result, name, metric); |
||||
} |
||||
} |
||||
return result.findOne(metricName); |
||||
} |
||||
|
||||
@Override |
||||
public Iterable<Metric<?>> findAll() { |
||||
InMemoryMetricRepository result = new InMemoryMetricRepository(); |
||||
for (Metric<?> metric : this.source.findAll()) { |
||||
String key = getSourceKey(metric.getName()); |
||||
if (key != null) { |
||||
update(result, key, metric); |
||||
} |
||||
} |
||||
return result.findAll(); |
||||
} |
||||
|
||||
@Override |
||||
public long count() { |
||||
Set<String> names = new HashSet<>(); |
||||
for (Metric<?> metric : this.source.findAll()) { |
||||
String name = getSourceKey(metric.getName()); |
||||
if (name != null) { |
||||
names.add(name); |
||||
} |
||||
} |
||||
return names.size(); |
||||
} |
||||
|
||||
private void update(InMemoryMetricRepository result, String key, Metric<?> metric) { |
||||
String name = this.prefix + key; |
||||
Metric<?> aggregate = result.findOne(name); |
||||
if (aggregate == null) { |
||||
aggregate = new Metric<Number>(name, metric.getValue(), |
||||
metric.getTimestamp()); |
||||
} |
||||
else if (key.contains("counter.")) { |
||||
// accumulate all values
|
||||
aggregate = new Metric<Number>(name, |
||||
metric.increment(aggregate.getValue().intValue()).getValue(), |
||||
metric.getTimestamp()); |
||||
} |
||||
else if (aggregate.getTimestamp().before(metric.getTimestamp())) { |
||||
// sort by timestamp and only take the latest
|
||||
aggregate = new Metric<Number>(name, metric.getValue(), |
||||
metric.getTimestamp()); |
||||
} |
||||
result.set(aggregate); |
||||
} |
||||
|
||||
private String getSourceKey(String name) { |
||||
String[] keys = StringUtils.delimitedListToStringArray(name, "."); |
||||
String[] patterns = StringUtils.delimitedListToStringArray(this.keyPattern, "."); |
||||
StringBuilder builder = new StringBuilder(); |
||||
for (int i = 0; i < patterns.length; i++) { |
||||
if ("k".equals(patterns[i])) { |
||||
builder.append(builder.length() > 0 ? "." : ""); |
||||
builder.append(keys[i]); |
||||
} |
||||
} |
||||
for (int i = patterns.length; i < keys.length; i++) { |
||||
builder.append(builder.length() > 0 ? "." : ""); |
||||
builder.append(keys[i]); |
||||
} |
||||
return builder.toString(); |
||||
} |
||||
|
||||
} |
||||
@ -1,20 +0,0 @@
@@ -1,20 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
*/ |
||||
|
||||
/** |
||||
* Classes for aggregation metrics. |
||||
*/ |
||||
package org.springframework.boot.actuate.metrics.aggregate; |
||||
@ -1,48 +0,0 @@
@@ -1,48 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2016 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.boot.actuate.metrics.buffer; |
||||
|
||||
/** |
||||
* Base class for a mutable buffer containing a timestamp and a value. |
||||
* |
||||
* @param <T> the value type |
||||
* @author Dave Syer |
||||
* @author Phillip Webb |
||||
*/ |
||||
abstract class Buffer<T extends Number> { |
||||
|
||||
private volatile long timestamp; |
||||
|
||||
Buffer(long timestamp) { |
||||
this.timestamp = timestamp; |
||||
} |
||||
|
||||
public long getTimestamp() { |
||||
return this.timestamp; |
||||
} |
||||
|
||||
public void setTimestamp(long timestamp) { |
||||
this.timestamp = timestamp; |
||||
} |
||||
|
||||
/** |
||||
* Returns the buffer value. |
||||
* @return the value of the buffer |
||||
*/ |
||||
public abstract T getValue(); |
||||
|
||||
} |
||||
@ -1,71 +0,0 @@
@@ -1,71 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.buffer; |
||||
|
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
import org.springframework.boot.actuate.metrics.CounterService; |
||||
|
||||
/** |
||||
* Fast implementation of {@link CounterService} using {@link CounterBuffers}. |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class BufferCounterService implements CounterService { |
||||
|
||||
private final ConcurrentHashMap<String, String> names = new ConcurrentHashMap<>(); |
||||
|
||||
private final CounterBuffers buffers; |
||||
|
||||
/** |
||||
* Create a {@link BufferCounterService} instance. |
||||
* @param buffers the underlying buffers used to store metrics |
||||
*/ |
||||
public BufferCounterService(CounterBuffers buffers) { |
||||
this.buffers = buffers; |
||||
} |
||||
|
||||
@Override |
||||
public void increment(String metricName) { |
||||
this.buffers.increment(wrap(metricName), 1L); |
||||
} |
||||
|
||||
@Override |
||||
public void decrement(String metricName) { |
||||
this.buffers.increment(wrap(metricName), -1L); |
||||
} |
||||
|
||||
@Override |
||||
public void reset(String metricName) { |
||||
this.buffers.reset(wrap(metricName)); |
||||
} |
||||
|
||||
private String wrap(String metricName) { |
||||
String cached = this.names.get(metricName); |
||||
if (cached != null) { |
||||
return cached; |
||||
} |
||||
if (metricName.startsWith("counter") || metricName.startsWith("meter")) { |
||||
return metricName; |
||||
} |
||||
String name = "counter." + metricName; |
||||
this.names.put(metricName, name); |
||||
return name; |
||||
} |
||||
|
||||
} |
||||
@ -1,62 +0,0 @@
@@ -1,62 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.buffer; |
||||
|
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
import org.springframework.boot.actuate.metrics.GaugeService; |
||||
|
||||
/** |
||||
* Fast implementation of {@link GaugeService} using {@link GaugeBuffers}. |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class BufferGaugeService implements GaugeService { |
||||
|
||||
private final ConcurrentHashMap<String, String> names = new ConcurrentHashMap<>(); |
||||
|
||||
private final GaugeBuffers buffers; |
||||
|
||||
/** |
||||
* Create a {@link BufferGaugeService} instance. |
||||
* @param buffers the underlying buffers used to store metrics |
||||
*/ |
||||
public BufferGaugeService(GaugeBuffers buffers) { |
||||
this.buffers = buffers; |
||||
} |
||||
|
||||
@Override |
||||
public void submit(String metricName, double value) { |
||||
this.buffers.set(wrap(metricName), value); |
||||
} |
||||
|
||||
private String wrap(String metricName) { |
||||
String cached = this.names.get(metricName); |
||||
if (cached != null) { |
||||
return cached; |
||||
} |
||||
if (metricName.startsWith("gauge") || metricName.startsWith("histogram") |
||||
|| metricName.startsWith("timer")) { |
||||
return metricName; |
||||
} |
||||
String name = "gauge." + metricName; |
||||
this.names.put(metricName, name); |
||||
return name; |
||||
} |
||||
|
||||
} |
||||
@ -1,90 +0,0 @@
@@ -1,90 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.buffer; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Date; |
||||
import java.util.List; |
||||
import java.util.function.Predicate; |
||||
import java.util.regex.Pattern; |
||||
|
||||
import org.springframework.boot.actuate.metrics.Metric; |
||||
import org.springframework.boot.actuate.metrics.reader.MetricReader; |
||||
import org.springframework.boot.actuate.metrics.reader.PrefixMetricReader; |
||||
|
||||
/** |
||||
* {@link MetricReader} implementation using {@link CounterBuffers} and |
||||
* {@link GaugeBuffers}. |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class BufferMetricReader implements MetricReader, PrefixMetricReader { |
||||
|
||||
private static final Predicate<String> ALL = Pattern.compile(".*").asPredicate(); |
||||
|
||||
private final CounterBuffers counterBuffers; |
||||
|
||||
private final GaugeBuffers gaugeBuffers; |
||||
|
||||
public BufferMetricReader(CounterBuffers counterBuffers, GaugeBuffers gaugeBuffers) { |
||||
this.counterBuffers = counterBuffers; |
||||
this.gaugeBuffers = gaugeBuffers; |
||||
} |
||||
|
||||
@Override |
||||
public Metric<?> findOne(String name) { |
||||
Buffer<?> buffer = this.counterBuffers.find(name); |
||||
if (buffer == null) { |
||||
buffer = this.gaugeBuffers.find(name); |
||||
} |
||||
return (buffer == null ? null : asMetric(name, buffer)); |
||||
} |
||||
|
||||
@Override |
||||
public Iterable<Metric<?>> findAll() { |
||||
return findAll(BufferMetricReader.ALL); |
||||
} |
||||
|
||||
@Override |
||||
public Iterable<Metric<?>> findAll(String prefix) { |
||||
return findAll(Pattern.compile(prefix + ".*").asPredicate()); |
||||
} |
||||
|
||||
@Override |
||||
public long count() { |
||||
return this.counterBuffers.count() + this.gaugeBuffers.count(); |
||||
} |
||||
|
||||
private Iterable<Metric<?>> findAll(Predicate<String> predicate) { |
||||
final List<Metric<?>> metrics = new ArrayList<>(); |
||||
collectMetrics(this.gaugeBuffers, predicate, metrics); |
||||
collectMetrics(this.counterBuffers, predicate, metrics); |
||||
return metrics; |
||||
} |
||||
|
||||
private <T extends Number, B extends Buffer<T>> void collectMetrics( |
||||
Buffers<B> buffers, Predicate<String> predicate, |
||||
final List<Metric<?>> metrics) { |
||||
buffers.forEach(predicate, (name, value) -> metrics.add(asMetric(name, value))); |
||||
} |
||||
|
||||
private <T extends Number> Metric<T> asMetric(String name, Buffer<T> buffer) { |
||||
return new Metric<>(name, buffer.getValue(), new Date(buffer.getTimestamp())); |
||||
} |
||||
|
||||
} |
||||
@ -1,62 +0,0 @@
@@ -1,62 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.buffer; |
||||
|
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.function.BiConsumer; |
||||
import java.util.function.Consumer; |
||||
import java.util.function.Predicate; |
||||
|
||||
/** |
||||
* Base class used to manage a map of {@link Buffer} objects. |
||||
* |
||||
* @param <B> The buffer type |
||||
* @author Dave Syer |
||||
* @author Phillip Webb |
||||
*/ |
||||
abstract class Buffers<B extends Buffer<?>> { |
||||
|
||||
private final ConcurrentHashMap<String, B> buffers = new ConcurrentHashMap<>(); |
||||
|
||||
public void forEach(final Predicate<String> predicate, |
||||
BiConsumer<String, B> consumer) { |
||||
this.buffers.forEach((name, value) -> { |
||||
if (predicate.test(name)) { |
||||
consumer.accept(name, value); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
public B find(String name) { |
||||
return this.buffers.get(name); |
||||
} |
||||
|
||||
public int count() { |
||||
return this.buffers.size(); |
||||
} |
||||
|
||||
protected final void doWith(String name, Consumer<B> consumer) { |
||||
B buffer = this.buffers.get(name); |
||||
if (buffer == null) { |
||||
buffer = this.buffers.computeIfAbsent(name, (k) -> createBuffer()); |
||||
} |
||||
consumer.accept(buffer); |
||||
} |
||||
|
||||
protected abstract B createBuffer(); |
||||
|
||||
} |
||||
@ -1,49 +0,0 @@
@@ -1,49 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2016 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.boot.actuate.metrics.buffer; |
||||
|
||||
import java.util.concurrent.atomic.LongAdder; |
||||
|
||||
/** |
||||
* Mutable buffer containing a long adder (Java 8) and a timestamp. |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class CounterBuffer extends Buffer<Long> { |
||||
|
||||
private final LongAdder adder; |
||||
|
||||
public CounterBuffer(long timestamp) { |
||||
super(timestamp); |
||||
this.adder = new LongAdder(); |
||||
} |
||||
|
||||
public void add(long delta) { |
||||
this.adder.add(delta); |
||||
} |
||||
|
||||
public void reset() { |
||||
this.adder.reset(); |
||||
} |
||||
|
||||
@Override |
||||
public Long getValue() { |
||||
return this.adder.sum(); |
||||
} |
||||
|
||||
} |
||||
@ -1,43 +0,0 @@
@@ -1,43 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2015 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.boot.actuate.metrics.buffer; |
||||
|
||||
/** |
||||
* Mutable buffer containing a double value and a timestamp. |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class GaugeBuffer extends Buffer<Double> { |
||||
|
||||
private volatile double value; |
||||
|
||||
public GaugeBuffer(long timestamp) { |
||||
super(timestamp); |
||||
this.value = 0; |
||||
} |
||||
|
||||
@Override |
||||
public Double getValue() { |
||||
return this.value; |
||||
} |
||||
|
||||
public void setValue(double value) { |
||||
this.value = value; |
||||
} |
||||
|
||||
} |
||||
@ -1,39 +0,0 @@
@@ -1,39 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.buffer; |
||||
|
||||
/** |
||||
* Fast writes to in-memory metrics store using {@link GaugeBuffer}. |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class GaugeBuffers extends Buffers<GaugeBuffer> { |
||||
|
||||
public void set(String name, double value) { |
||||
doWith(name, (buffer) -> { |
||||
buffer.setTimestamp(System.currentTimeMillis()); |
||||
buffer.setValue(value); |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
protected GaugeBuffer createBuffer() { |
||||
return new GaugeBuffer(0L); |
||||
} |
||||
|
||||
} |
||||
@ -1,20 +0,0 @@
@@ -1,20 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2015 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. |
||||
*/ |
||||
|
||||
/** |
||||
* Metrics buffering support. |
||||
*/ |
||||
package org.springframework.boot.actuate.metrics.buffer; |
||||
@ -1,279 +0,0 @@
@@ -1,279 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.dropwizard; |
||||
|
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.concurrent.ConcurrentMap; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
import com.codahale.metrics.Counter; |
||||
import com.codahale.metrics.Gauge; |
||||
import com.codahale.metrics.Histogram; |
||||
import com.codahale.metrics.Meter; |
||||
import com.codahale.metrics.Metric; |
||||
import com.codahale.metrics.MetricRegistry; |
||||
import com.codahale.metrics.Reservoir; |
||||
import com.codahale.metrics.Timer; |
||||
|
||||
import org.springframework.boot.actuate.metrics.CounterService; |
||||
import org.springframework.boot.actuate.metrics.GaugeService; |
||||
import org.springframework.core.ResolvableType; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* A {@link GaugeService} and {@link CounterService} that sends data to a Dropwizard |
||||
* {@link MetricRegistry} based on a naming convention. |
||||
* <ul> |
||||
* <li>Updates to {@link #increment(String)} with names in "meter.*" are treated as |
||||
* {@link Meter} events</li> |
||||
* <li>Other deltas are treated as simple {@link Counter} values</li> |
||||
* <li>Inputs to {@link #submit(String, double)} with names in "histogram.*" are treated |
||||
* as {@link Histogram} updates</li> |
||||
* <li>Inputs to {@link #submit(String, double)} with names in "timer.*" are treated as |
||||
* {@link Timer} updates</li> |
||||
* <li>Other metrics are treated as simple {@link Gauge} values (single valued |
||||
* measurements of type double)</li> |
||||
* </ul> |
||||
* |
||||
* @author Dave Syer |
||||
* @author Jay Anderson |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
public class DropwizardMetricServices implements CounterService, GaugeService { |
||||
|
||||
private final MetricRegistry registry; |
||||
|
||||
private final ReservoirFactory reservoirFactory; |
||||
|
||||
private final ConcurrentMap<String, SimpleGauge> gauges = new ConcurrentHashMap<>(); |
||||
|
||||
private final ConcurrentHashMap<String, String> names = new ConcurrentHashMap<>(); |
||||
|
||||
/** |
||||
* Create a new {@link DropwizardMetricServices} instance. |
||||
* @param registry the underlying metric registry |
||||
*/ |
||||
public DropwizardMetricServices(MetricRegistry registry) { |
||||
this(registry, null); |
||||
} |
||||
|
||||
/** |
||||
* Create a new {@link DropwizardMetricServices} instance. |
||||
* @param registry the underlying metric registry |
||||
* @param reservoirFactory the factory that instantiates the {@link Reservoir} that |
||||
* will be used on Timers and Histograms |
||||
*/ |
||||
public DropwizardMetricServices(MetricRegistry registry, |
||||
ReservoirFactory reservoirFactory) { |
||||
this.registry = registry; |
||||
this.reservoirFactory = (reservoirFactory == null ? ReservoirFactory.NONE |
||||
: reservoirFactory); |
||||
} |
||||
|
||||
@Override |
||||
public void increment(String name) { |
||||
incrementInternal(name, 1L); |
||||
} |
||||
|
||||
@Override |
||||
public void decrement(String name) { |
||||
incrementInternal(name, -1L); |
||||
} |
||||
|
||||
private void incrementInternal(String name, long value) { |
||||
if (name.startsWith("meter")) { |
||||
Meter meter = this.registry.meter(name); |
||||
meter.mark(value); |
||||
} |
||||
else { |
||||
name = wrapCounterName(name); |
||||
Counter counter = this.registry.counter(name); |
||||
counter.inc(value); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void submit(String name, double value) { |
||||
if (name.startsWith("histogram")) { |
||||
submitHistogram(name, value); |
||||
} |
||||
else if (name.startsWith("timer")) { |
||||
submitTimer(name, value); |
||||
} |
||||
else { |
||||
name = wrapGaugeName(name); |
||||
setGaugeValue(name, value); |
||||
} |
||||
} |
||||
|
||||
private void submitTimer(String name, double value) { |
||||
long longValue = (long) value; |
||||
Timer metric = register(name, new TimerMetricRegistrar()); |
||||
metric.update(longValue, TimeUnit.MILLISECONDS); |
||||
} |
||||
|
||||
private void submitHistogram(String name, double value) { |
||||
long longValue = (long) value; |
||||
Histogram metric = register(name, new HistogramMetricRegistrar()); |
||||
metric.update(longValue); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private <T extends Metric> T register(String name, MetricRegistrar<T> registrar) { |
||||
Reservoir reservoir = this.reservoirFactory.getReservoir(name); |
||||
if (reservoir == null) { |
||||
return registrar.register(this.registry, name); |
||||
} |
||||
Metric metric = this.registry.getMetrics().get(name); |
||||
if (metric != null) { |
||||
registrar.checkExisting(metric); |
||||
return (T) metric; |
||||
} |
||||
try { |
||||
return this.registry.register(name, registrar.createForReservoir(reservoir)); |
||||
} |
||||
catch (IllegalArgumentException ex) { |
||||
Metric added = this.registry.getMetrics().get(name); |
||||
registrar.checkExisting(added); |
||||
return (T) added; |
||||
} |
||||
} |
||||
|
||||
private void setGaugeValue(String name, double value) { |
||||
// NOTE: Dropwizard provides no way to do this atomically
|
||||
SimpleGauge gauge = this.gauges.get(name); |
||||
if (gauge == null) { |
||||
SimpleGauge newGauge = new SimpleGauge(value); |
||||
gauge = this.gauges.putIfAbsent(name, newGauge); |
||||
if (gauge == null) { |
||||
this.registry.register(name, newGauge); |
||||
return; |
||||
} |
||||
} |
||||
gauge.setValue(value); |
||||
} |
||||
|
||||
private String wrapGaugeName(String metricName) { |
||||
return wrapName(metricName, "gauge."); |
||||
} |
||||
|
||||
private String wrapCounterName(String metricName) { |
||||
return wrapName(metricName, "counter."); |
||||
} |
||||
|
||||
private String wrapName(String metricName, String prefix) { |
||||
String cached = this.names.get(metricName); |
||||
if (cached != null) { |
||||
return cached; |
||||
} |
||||
if (metricName.startsWith(prefix)) { |
||||
return metricName; |
||||
} |
||||
String name = prefix + metricName; |
||||
this.names.put(metricName, name); |
||||
return name; |
||||
} |
||||
|
||||
@Override |
||||
public void reset(String name) { |
||||
if (!name.startsWith("meter")) { |
||||
name = wrapCounterName(name); |
||||
} |
||||
this.registry.remove(name); |
||||
} |
||||
|
||||
/** |
||||
* Simple {@link Gauge} implementation to {@literal double} value. |
||||
*/ |
||||
private final static class SimpleGauge implements Gauge<Double> { |
||||
|
||||
private volatile double value; |
||||
|
||||
private SimpleGauge(double value) { |
||||
this.value = value; |
||||
} |
||||
|
||||
@Override |
||||
public Double getValue() { |
||||
return this.value; |
||||
} |
||||
|
||||
public void setValue(double value) { |
||||
this.value = value; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Strategy used to register metrics. |
||||
*/ |
||||
private static abstract class MetricRegistrar<T extends Metric> { |
||||
|
||||
private final Class<T> type; |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
MetricRegistrar() { |
||||
this.type = (Class<T>) ResolvableType |
||||
.forClass(MetricRegistrar.class, getClass()).resolveGeneric(); |
||||
} |
||||
|
||||
public void checkExisting(Metric metric) { |
||||
Assert.isInstanceOf(this.type, metric, |
||||
"Different metric type already registered"); |
||||
} |
||||
|
||||
protected abstract T register(MetricRegistry registry, String name); |
||||
|
||||
protected abstract T createForReservoir(Reservoir reservoir); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* {@link MetricRegistrar} for {@link Timer} metrics. |
||||
*/ |
||||
private static class TimerMetricRegistrar extends MetricRegistrar<Timer> { |
||||
|
||||
@Override |
||||
protected Timer register(MetricRegistry registry, String name) { |
||||
return registry.timer(name); |
||||
} |
||||
|
||||
@Override |
||||
protected Timer createForReservoir(Reservoir reservoir) { |
||||
return new Timer(reservoir); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* {@link MetricRegistrar} for {@link Histogram} metrics. |
||||
*/ |
||||
private static class HistogramMetricRegistrar extends MetricRegistrar<Histogram> { |
||||
|
||||
@Override |
||||
protected Histogram register(MetricRegistry registry, String name) { |
||||
return registry.histogram(name); |
||||
} |
||||
|
||||
@Override |
||||
protected Histogram createForReservoir(Reservoir reservoir) { |
||||
return new Histogram(reservoir); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,45 +0,0 @@
@@ -1,45 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.dropwizard; |
||||
|
||||
import com.codahale.metrics.Reservoir; |
||||
|
||||
/** |
||||
* Factory interface that can be used by {@link DropwizardMetricServices} to create a |
||||
* custom {@link Reservoir}. |
||||
* |
||||
* @author Lucas Saldanha |
||||
* @author Phillip Webb |
||||
* @since 1.5.0 |
||||
*/ |
||||
@FunctionalInterface |
||||
public interface ReservoirFactory { |
||||
|
||||
/** |
||||
* Default empty {@link ReservoirFactory} implementation. |
||||
*/ |
||||
ReservoirFactory NONE = (name) -> null; |
||||
|
||||
/** |
||||
* Return the {@link Reservoir} instance to use or {@code null} if a custom reservoir |
||||
* is not needed. |
||||
* @param name the name of the metric |
||||
* @return a reservoir instance or {@code null} |
||||
*/ |
||||
Reservoir getReservoir(String name); |
||||
|
||||
} |
||||
@ -1,20 +0,0 @@
@@ -1,20 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2015 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. |
||||
*/ |
||||
|
||||
/** |
||||
* Metrics integration with Dropwizard Metrics. |
||||
*/ |
||||
package org.springframework.boot.actuate.metrics.dropwizard; |
||||
@ -1,184 +0,0 @@
@@ -1,184 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.export; |
||||
|
||||
import java.io.Closeable; |
||||
import java.io.Flushable; |
||||
import java.io.IOException; |
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.Date; |
||||
import java.util.concurrent.atomic.AtomicBoolean; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
|
||||
import org.springframework.boot.actuate.metrics.Metric; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
/** |
||||
* Base class for metric exporters that have common features, principally a prefix for |
||||
* exported metrics and filtering by timestamp (so only new values are included in the |
||||
* export). |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public abstract class AbstractMetricExporter implements Exporter, Closeable, Flushable { |
||||
|
||||
private static final Log logger = LogFactory.getLog(AbstractMetricExporter.class); |
||||
|
||||
private final String prefix; |
||||
|
||||
private Date earliestTimestamp = new Date(); |
||||
|
||||
private boolean ignoreTimestamps = false; |
||||
|
||||
private boolean sendLatest = true; |
||||
|
||||
private volatile AtomicBoolean processing = new AtomicBoolean(false); |
||||
|
||||
private Date latestTimestamp = new Date(0L); |
||||
|
||||
public AbstractMetricExporter(String prefix) { |
||||
this.prefix = (!StringUtils.hasText(prefix) ? "" |
||||
: (prefix.endsWith(".") ? prefix : prefix + ".")); |
||||
} |
||||
|
||||
/** |
||||
* The earliest time for which data will be exported. |
||||
* @param earliestTimestamp the timestamp to set |
||||
*/ |
||||
public void setEarliestTimestamp(Date earliestTimestamp) { |
||||
this.earliestTimestamp = earliestTimestamp; |
||||
} |
||||
|
||||
/** |
||||
* Ignore timestamps (export all metrics). |
||||
* @param ignoreTimestamps the flag to set |
||||
*/ |
||||
public void setIgnoreTimestamps(boolean ignoreTimestamps) { |
||||
this.ignoreTimestamps = ignoreTimestamps; |
||||
} |
||||
|
||||
/** |
||||
* Send only the data that changed since the last export. |
||||
* @param sendLatest the flag to set |
||||
*/ |
||||
public void setSendLatest(boolean sendLatest) { |
||||
this.sendLatest = sendLatest; |
||||
} |
||||
|
||||
@Override |
||||
public void export() { |
||||
if (this.processing.compareAndSet(false, true)) { |
||||
long latestTimestamp = System.currentTimeMillis(); |
||||
try { |
||||
exportGroups(); |
||||
} |
||||
catch (Exception ex) { |
||||
logger.warn("Could not write to MetricWriter: " + ex.getClass() + ": " |
||||
+ ex.getMessage()); |
||||
} |
||||
finally { |
||||
this.latestTimestamp = new Date(latestTimestamp); |
||||
flushQuietly(); |
||||
this.processing.set(false); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void exportGroups() { |
||||
for (String group : groups()) { |
||||
Collection<Metric<?>> values = new ArrayList<>(); |
||||
for (Metric<?> metric : next(group)) { |
||||
Date timestamp = metric.getTimestamp(); |
||||
if (canExportTimestamp(timestamp)) { |
||||
values.add(getPrefixedMetric(metric)); |
||||
} |
||||
} |
||||
if (!values.isEmpty()) { |
||||
write(group, values); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private Metric<?> getPrefixedMetric(Metric<?> metric) { |
||||
String name = this.prefix + metric.getName(); |
||||
return new Metric<Number>(name, metric.getValue(), metric.getTimestamp()); |
||||
} |
||||
|
||||
private boolean canExportTimestamp(Date timestamp) { |
||||
if (this.ignoreTimestamps) { |
||||
return true; |
||||
} |
||||
if (this.earliestTimestamp.after(timestamp)) { |
||||
return false; |
||||
} |
||||
if (this.sendLatest && this.latestTimestamp.after(timestamp)) { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
private void flushQuietly() { |
||||
try { |
||||
flush(); |
||||
} |
||||
catch (Exception ex) { |
||||
logger.warn("Could not flush MetricWriter: " + ex.getClass() + ": " |
||||
+ ex.getMessage()); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void close() throws IOException { |
||||
export(); |
||||
flushQuietly(); |
||||
} |
||||
|
||||
@Override |
||||
public void flush() { |
||||
} |
||||
|
||||
/** |
||||
* Generate a group of metrics to iterate over in the form of a set of Strings (e.g. |
||||
* prefixes). If the metrics to be exported partition into groups identified by a |
||||
* String, subclasses should override this method. Otherwise the default should be |
||||
* fine (iteration over all metrics). |
||||
* @return groups of metrics to iterate over (default singleton empty string) |
||||
*/ |
||||
protected Iterable<String> groups() { |
||||
return Collections.singleton(""); |
||||
} |
||||
|
||||
/** |
||||
* Write the values associated with a group. |
||||
* @param group the group to write |
||||
* @param values the values to write |
||||
*/ |
||||
protected abstract void write(String group, Collection<Metric<?>> values); |
||||
|
||||
/** |
||||
* Get the next group of metrics to write. |
||||
* @param group the group name to write |
||||
* @return some metrics to write |
||||
*/ |
||||
protected abstract Iterable<Metric<?>> next(String group); |
||||
|
||||
} |
||||
@ -1,38 +0,0 @@
@@ -1,38 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.export; |
||||
|
||||
/** |
||||
* Generic interface for metric exports. As you scale up metric collection you will often |
||||
* need to buffer metric data locally and export it periodically (e.g. for aggregation |
||||
* across a cluster), so this is the marker interface for those operations. The trigger of |
||||
* an export operation might be periodic or event driven, but it remains outside the scope |
||||
* of this interface. You might for instance create an instance of an Exporter and trigger |
||||
* it using a {@code @Scheduled} annotation in a Spring ApplicationContext. |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
@FunctionalInterface |
||||
public interface Exporter { |
||||
|
||||
/** |
||||
* Export metric data. |
||||
*/ |
||||
void export(); |
||||
|
||||
} |
||||
@ -1,244 +0,0 @@
@@ -1,244 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.export; |
||||
|
||||
import java.io.Flushable; |
||||
import java.lang.reflect.Method; |
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.concurrent.ConcurrentMap; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
|
||||
import org.springframework.boot.actuate.metrics.Metric; |
||||
import org.springframework.boot.actuate.metrics.reader.MetricReader; |
||||
import org.springframework.boot.actuate.metrics.writer.CompositeMetricWriter; |
||||
import org.springframework.boot.actuate.metrics.writer.CounterWriter; |
||||
import org.springframework.boot.actuate.metrics.writer.Delta; |
||||
import org.springframework.boot.actuate.metrics.writer.GaugeWriter; |
||||
import org.springframework.boot.actuate.metrics.writer.MetricWriter; |
||||
import org.springframework.util.ClassUtils; |
||||
import org.springframework.util.ObjectUtils; |
||||
import org.springframework.util.PatternMatchUtils; |
||||
import org.springframework.util.ReflectionUtils; |
||||
|
||||
/** |
||||
* {@link Exporter} that "exports" by copying metric data from a source |
||||
* {@link MetricReader} to a destination {@link MetricWriter}. Actually the output writer |
||||
* can be a {@link GaugeWriter}, in which case all metrics are simply output as their |
||||
* current value. If the output writer is also a {@link CounterWriter} then metrics whose |
||||
* names begin with "counter." are special: instead of writing them out as simple gauges |
||||
* the writer will increment the counter value. This involves the exporter storing the |
||||
* previous value of the counter so the delta can be computed. For best results with the |
||||
* counters, do not use the exporter concurrently in multiple threads (normally it will |
||||
* only be used periodically and sequentially, even if it is in a background thread, and |
||||
* this is fine). |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class MetricCopyExporter extends AbstractMetricExporter { |
||||
|
||||
private static final Log logger = LogFactory.getLog(MetricCopyExporter.class); |
||||
|
||||
private final MetricReader reader; |
||||
|
||||
private final GaugeWriter writer; |
||||
|
||||
private final CounterWriter counter; |
||||
|
||||
private ConcurrentMap<String, Long> counts = new ConcurrentHashMap<>(); |
||||
|
||||
private String[] includes = new String[0]; |
||||
|
||||
private String[] excludes = new String[0]; |
||||
|
||||
/** |
||||
* Create a new {@link MetricCopyExporter} instance. |
||||
* @param reader the metric reader |
||||
* @param writer the metric writer |
||||
*/ |
||||
public MetricCopyExporter(MetricReader reader, GaugeWriter writer) { |
||||
this(reader, writer, ""); |
||||
} |
||||
|
||||
/** |
||||
* Create a new {@link MetricCopyExporter} instance. |
||||
* @param reader the metric reader |
||||
* @param writer the metric writer |
||||
* @param prefix the name prefix |
||||
*/ |
||||
public MetricCopyExporter(MetricReader reader, GaugeWriter writer, String prefix) { |
||||
super(prefix); |
||||
this.reader = reader; |
||||
this.writer = writer; |
||||
if (writer instanceof CounterWriter) { |
||||
this.counter = (CounterWriter) writer; |
||||
} |
||||
else { |
||||
this.counter = null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Set the include patterns used to filter metrics. |
||||
* @param includes the include patterns |
||||
*/ |
||||
public void setIncludes(String... includes) { |
||||
if (includes != null) { |
||||
this.includes = includes; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Set the exclude patterns used to filter metrics. |
||||
* @param excludes the exclude patterns |
||||
*/ |
||||
public void setExcludes(String... excludes) { |
||||
if (excludes != null) { |
||||
this.excludes = excludes; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
protected Iterable<Metric<?>> next(String group) { |
||||
if (ObjectUtils.isEmpty(this.includes) && ObjectUtils.isEmpty(this.excludes)) { |
||||
return this.reader.findAll(); |
||||
} |
||||
return new PatternMatchingIterable(MetricCopyExporter.this.reader); |
||||
} |
||||
|
||||
@Override |
||||
protected void write(String group, Collection<Metric<?>> values) { |
||||
for (Metric<?> value : values) { |
||||
if (value.getName().startsWith("counter.") && this.counter != null) { |
||||
this.counter.increment(calculateDelta(value)); |
||||
} |
||||
else { |
||||
this.writer.set(value); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private Delta<?> calculateDelta(Metric<?> value) { |
||||
long delta = value.getValue().longValue(); |
||||
Long old = this.counts.replace(value.getName(), delta); |
||||
if (old != null) { |
||||
delta = delta - old; |
||||
} |
||||
else { |
||||
this.counts.putIfAbsent(value.getName(), delta); |
||||
} |
||||
return new Delta<>(value.getName(), delta, value.getTimestamp()); |
||||
} |
||||
|
||||
@Override |
||||
public void flush() { |
||||
flush(this.writer); |
||||
} |
||||
|
||||
private void flush(GaugeWriter writer) { |
||||
if (writer instanceof CompositeMetricWriter) { |
||||
for (MetricWriter child : (CompositeMetricWriter) writer) { |
||||
flush(child); |
||||
} |
||||
} |
||||
try { |
||||
if (ClassUtils.isPresent("java.io.Flushable", null)) { |
||||
if (writer instanceof Flushable) { |
||||
((Flushable) writer).flush(); |
||||
return; |
||||
} |
||||
} |
||||
Method method = ReflectionUtils.findMethod(writer.getClass(), "flush"); |
||||
if (method != null) { |
||||
ReflectionUtils.invokeMethod(method, writer); |
||||
} |
||||
} |
||||
catch (Exception ex) { |
||||
logger.warn("Could not flush MetricWriter: " + ex.getClass() + ": " |
||||
+ ex.getMessage()); |
||||
} |
||||
} |
||||
|
||||
private class PatternMatchingIterable implements Iterable<Metric<?>> { |
||||
|
||||
private final MetricReader reader; |
||||
|
||||
PatternMatchingIterable(MetricReader reader) { |
||||
this.reader = reader; |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<Metric<?>> iterator() { |
||||
return new PatternMatchingIterator(this.reader.findAll().iterator()); |
||||
} |
||||
|
||||
} |
||||
|
||||
private class PatternMatchingIterator implements Iterator<Metric<?>> { |
||||
|
||||
private Metric<?> buffer = null; |
||||
|
||||
private Iterator<Metric<?>> iterator; |
||||
|
||||
PatternMatchingIterator(Iterator<Metric<?>> iterator) { |
||||
this.iterator = iterator; |
||||
} |
||||
|
||||
@Override |
||||
public boolean hasNext() { |
||||
if (this.buffer != null) { |
||||
return true; |
||||
} |
||||
this.buffer = findNext(); |
||||
return this.buffer != null; |
||||
} |
||||
|
||||
private Metric<?> findNext() { |
||||
while (this.iterator.hasNext()) { |
||||
Metric<?> metric = this.iterator.next(); |
||||
if (isMatch(metric)) { |
||||
return metric; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
private boolean isMatch(Metric<?> metric) { |
||||
String[] includes = MetricCopyExporter.this.includes; |
||||
String[] excludes = MetricCopyExporter.this.excludes; |
||||
String name = metric.getName(); |
||||
if (ObjectUtils.isEmpty(includes) |
||||
|| PatternMatchUtils.simpleMatch(includes, name)) { |
||||
return !PatternMatchUtils.simpleMatch(excludes, name); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public Metric<?> next() { |
||||
Metric<?> metric = this.buffer; |
||||
this.buffer = null; |
||||
return metric; |
||||
} |
||||
|
||||
}; |
||||
|
||||
} |
||||
@ -1,265 +0,0 @@
@@ -1,265 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.export; |
||||
|
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
import java.util.Map.Entry; |
||||
|
||||
import javax.annotation.PostConstruct; |
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
import org.springframework.util.PatternMatchUtils; |
||||
|
||||
/** |
||||
* Configuration properties for metrics export. |
||||
* |
||||
* @author Dave Syer |
||||
* @author Simon Buettner |
||||
* @since 1.3.0 |
||||
*/ |
||||
@ConfigurationProperties(prefix = "spring.metrics.export") |
||||
public class MetricExportProperties extends TriggerProperties { |
||||
|
||||
/** |
||||
* Specific trigger properties per MetricWriter bean name. |
||||
*/ |
||||
private Map<String, SpecificTriggerProperties> triggers = new LinkedHashMap<>(); |
||||
|
||||
private Aggregate aggregate = new Aggregate(); |
||||
|
||||
private Redis redis = new Redis(); |
||||
|
||||
private Statsd statsd = new Statsd(); |
||||
|
||||
@PostConstruct |
||||
public void setUpDefaults() { |
||||
TriggerProperties defaults = this; |
||||
for (Entry<String, SpecificTriggerProperties> entry : this.triggers.entrySet()) { |
||||
String key = entry.getKey(); |
||||
SpecificTriggerProperties value = entry.getValue(); |
||||
if (value.getNames() == null || value.getNames().length == 0) { |
||||
value.setNames(new String[] { key }); |
||||
} |
||||
} |
||||
if (defaults.isSendLatest() == null) { |
||||
defaults.setSendLatest(true); |
||||
} |
||||
if (defaults.getDelayMillis() == null) { |
||||
defaults.setDelayMillis(5000); |
||||
} |
||||
for (TriggerProperties value : this.triggers.values()) { |
||||
if (value.isSendLatest() == null) { |
||||
value.setSendLatest(defaults.isSendLatest()); |
||||
} |
||||
if (value.getDelayMillis() == null) { |
||||
value.setDelayMillis(defaults.getDelayMillis()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Configuration for triggers on individual named writers. Each value can individually |
||||
* specify a name pattern explicitly, or else the map key will be used if the name is |
||||
* not set. |
||||
* @return the writers |
||||
*/ |
||||
public Map<String, SpecificTriggerProperties> getTriggers() { |
||||
return this.triggers; |
||||
} |
||||
|
||||
public Aggregate getAggregate() { |
||||
return this.aggregate; |
||||
} |
||||
|
||||
public void setAggregate(Aggregate aggregate) { |
||||
this.aggregate = aggregate; |
||||
} |
||||
|
||||
public Redis getRedis() { |
||||
return this.redis; |
||||
} |
||||
|
||||
public void setRedis(Redis redis) { |
||||
this.redis = redis; |
||||
} |
||||
|
||||
public Statsd getStatsd() { |
||||
return this.statsd; |
||||
} |
||||
|
||||
public void setStatsd(Statsd statsd) { |
||||
this.statsd = statsd; |
||||
} |
||||
|
||||
/** |
||||
* Find a matching trigger configuration. |
||||
* @param name the bean name to match |
||||
* @return a matching configuration if there is one |
||||
*/ |
||||
public TriggerProperties findTrigger(String name) { |
||||
for (SpecificTriggerProperties value : this.triggers.values()) { |
||||
if (PatternMatchUtils.simpleMatch(value.getNames(), name)) { |
||||
return value; |
||||
} |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Aggregate properties. |
||||
*/ |
||||
public static class Aggregate { |
||||
|
||||
/** |
||||
* Prefix for global repository if active. Should be unique for this JVM, but most |
||||
* useful if it also has the form "a.b" where "a" is unique to this logical |
||||
* process (this application) and "b" is unique to this physical process. If you |
||||
* set spring.application.name elsewhere, then the default will be in the right |
||||
* form. |
||||
*/ |
||||
private String prefix = ""; |
||||
|
||||
/** |
||||
* Pattern that tells the aggregator what to do with the keys from the source |
||||
* repository. The keys in the source repository are assumed to be period |
||||
* separated, and the pattern is in the same format, e.g. "d.d.k.d". Here "d" |
||||
* means "discard" and "k" means "keep" the key segment in the corresponding |
||||
* position in the source. |
||||
*/ |
||||
private String keyPattern = ""; |
||||
|
||||
public String getPrefix() { |
||||
return this.prefix; |
||||
} |
||||
|
||||
public void setPrefix(String prefix) { |
||||
this.prefix = prefix; |
||||
} |
||||
|
||||
public String getKeyPattern() { |
||||
return this.keyPattern; |
||||
} |
||||
|
||||
public void setKeyPattern(String keyPattern) { |
||||
this.keyPattern = keyPattern; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Redis properties. |
||||
*/ |
||||
public static class Redis { |
||||
|
||||
/** |
||||
* Prefix for redis repository if active. Should be globally unique across all |
||||
* processes sharing the same repository. |
||||
*/ |
||||
private String prefix = "spring.metrics"; |
||||
|
||||
/** |
||||
* Key for redis repository export (if active). Should be globally unique for a |
||||
* system sharing a redis repository across multiple processes. |
||||
*/ |
||||
private String key = "keys.spring.metrics"; |
||||
|
||||
public String getPrefix() { |
||||
return this.prefix; |
||||
} |
||||
|
||||
public void setPrefix(String prefix) { |
||||
this.prefix = prefix; |
||||
} |
||||
|
||||
public String getKey() { |
||||
return this.key; |
||||
} |
||||
|
||||
public void setKey(String key) { |
||||
this.key = key; |
||||
} |
||||
|
||||
public String getAggregatePrefix() { |
||||
// The common case including a standalone aggregator would have a prefix that
|
||||
// starts with the end of the key, so strip that bit off and call it the
|
||||
// aggregate prefix.
|
||||
if (this.key.startsWith("keys.")) { |
||||
String candidate = this.key.substring("keys.".length()); |
||||
if (this.prefix.startsWith(candidate)) { |
||||
return candidate; |
||||
} |
||||
return candidate; |
||||
} |
||||
// If the user went off piste, choose something that is safe (not empty) but
|
||||
// not the whole prefix (on the assumption that it contains dimension keys)
|
||||
if (this.prefix.contains(".") |
||||
&& this.prefix.indexOf(".") < this.prefix.length() - 1) { |
||||
return this.prefix.substring(this.prefix.indexOf(".") + 1); |
||||
} |
||||
return this.prefix; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Statsd properties. |
||||
*/ |
||||
public static class Statsd { |
||||
|
||||
/** |
||||
* Host of a statsd server to receive exported metrics. |
||||
*/ |
||||
private String host; |
||||
|
||||
/** |
||||
* Port of a statsd server to receive exported metrics. |
||||
*/ |
||||
private int port = 8125; |
||||
|
||||
/** |
||||
* Prefix for statsd exported metrics. |
||||
*/ |
||||
private String prefix; |
||||
|
||||
public String getHost() { |
||||
return this.host; |
||||
} |
||||
|
||||
public void setHost(String host) { |
||||
this.host = host; |
||||
} |
||||
|
||||
public int getPort() { |
||||
return this.port; |
||||
} |
||||
|
||||
public void setPort(int port) { |
||||
this.port = port; |
||||
} |
||||
|
||||
public String getPrefix() { |
||||
return this.prefix; |
||||
} |
||||
|
||||
public void setPrefix(String prefix) { |
||||
this.prefix = prefix; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,134 +0,0 @@
@@ -1,134 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.export; |
||||
|
||||
import java.io.Closeable; |
||||
import java.io.IOException; |
||||
import java.util.HashMap; |
||||
import java.util.HashSet; |
||||
import java.util.Map; |
||||
import java.util.Map.Entry; |
||||
import java.util.Set; |
||||
|
||||
import org.springframework.boot.actuate.metrics.reader.MetricReader; |
||||
import org.springframework.boot.actuate.metrics.writer.GaugeWriter; |
||||
import org.springframework.scheduling.annotation.SchedulingConfigurer; |
||||
import org.springframework.scheduling.config.IntervalTask; |
||||
import org.springframework.scheduling.config.ScheduledTaskRegistrar; |
||||
|
||||
/** |
||||
* {@link SchedulingConfigurer} to handle metrics {@link MetricCopyExporter export}. |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class MetricExporters implements SchedulingConfigurer, Closeable { |
||||
|
||||
private MetricReader reader; |
||||
|
||||
private Map<String, GaugeWriter> writers = new HashMap<>(); |
||||
|
||||
private final MetricExportProperties properties; |
||||
|
||||
private final Map<String, Exporter> exporters = new HashMap<>(); |
||||
|
||||
private final Set<String> closeables = new HashSet<>(); |
||||
|
||||
public MetricExporters(MetricExportProperties properties) { |
||||
this.properties = properties; |
||||
} |
||||
|
||||
public void setReader(MetricReader reader) { |
||||
this.reader = reader; |
||||
} |
||||
|
||||
public void setWriters(Map<String, GaugeWriter> writers) { |
||||
this.writers.putAll(writers); |
||||
} |
||||
|
||||
public void setExporters(Map<String, Exporter> exporters) { |
||||
this.exporters.putAll(exporters); |
||||
} |
||||
|
||||
@Override |
||||
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { |
||||
for (Entry<String, Exporter> entry : this.exporters.entrySet()) { |
||||
String name = entry.getKey(); |
||||
Exporter exporter = entry.getValue(); |
||||
TriggerProperties trigger = this.properties.findTrigger(name); |
||||
if (trigger != null) { |
||||
ExportRunner runner = new ExportRunner(exporter); |
||||
IntervalTask task = new IntervalTask(runner, trigger.getDelayMillis(), |
||||
trigger.getDelayMillis()); |
||||
taskRegistrar.addFixedDelayTask(task); |
||||
} |
||||
} |
||||
for (Entry<String, GaugeWriter> entry : this.writers.entrySet()) { |
||||
String name = entry.getKey(); |
||||
GaugeWriter writer = entry.getValue(); |
||||
TriggerProperties trigger = this.properties.findTrigger(name); |
||||
if (trigger != null) { |
||||
MetricCopyExporter exporter = getExporter(writer, trigger); |
||||
this.exporters.put(name, exporter); |
||||
this.closeables.add(name); |
||||
ExportRunner runner = new ExportRunner(exporter); |
||||
IntervalTask task = new IntervalTask(runner, trigger.getDelayMillis(), |
||||
trigger.getDelayMillis()); |
||||
taskRegistrar.addFixedDelayTask(task); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private MetricCopyExporter getExporter(GaugeWriter writer, |
||||
TriggerProperties trigger) { |
||||
MetricCopyExporter exporter = new MetricCopyExporter(this.reader, writer); |
||||
exporter.setIncludes(trigger.getIncludes()); |
||||
exporter.setExcludes(trigger.getExcludes()); |
||||
exporter.setSendLatest(trigger.isSendLatest()); |
||||
return exporter; |
||||
} |
||||
|
||||
public Map<String, Exporter> getExporters() { |
||||
return this.exporters; |
||||
} |
||||
|
||||
@Override |
||||
public void close() throws IOException { |
||||
for (String name : this.closeables) { |
||||
Exporter exporter = this.exporters.get(name); |
||||
if (exporter instanceof Closeable) { |
||||
((Closeable) exporter).close(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private static class ExportRunner implements Runnable { |
||||
|
||||
private final Exporter exporter; |
||||
|
||||
ExportRunner(Exporter exporter) { |
||||
this.exporter = exporter; |
||||
} |
||||
|
||||
@Override |
||||
public void run() { |
||||
this.exporter.export(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,118 +0,0 @@
@@ -1,118 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.export; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.concurrent.ConcurrentMap; |
||||
|
||||
import org.springframework.boot.actuate.metrics.Metric; |
||||
import org.springframework.boot.actuate.metrics.reader.PrefixMetricReader; |
||||
import org.springframework.boot.actuate.metrics.repository.MultiMetricRepository; |
||||
import org.springframework.boot.actuate.metrics.writer.Delta; |
||||
import org.springframework.boot.actuate.metrics.writer.PrefixMetricWriter; |
||||
|
||||
/** |
||||
* A convenient exporter for a group of metrics from a {@link PrefixMetricReader}. Exports |
||||
* all metrics whose name starts with a prefix (or all metrics if the prefix is empty). |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class PrefixMetricGroupExporter extends AbstractMetricExporter { |
||||
|
||||
private final PrefixMetricReader reader; |
||||
|
||||
private final PrefixMetricWriter writer; |
||||
|
||||
private ConcurrentMap<String, Long> counts = new ConcurrentHashMap<>(); |
||||
|
||||
private Set<String> groups = new HashSet<>(); |
||||
|
||||
/** |
||||
* Create a new exporter for metrics to a writer based on an empty prefix for the |
||||
* metric names. |
||||
* @param reader a reader as the source of metrics |
||||
* @param writer the writer to send the metrics to |
||||
*/ |
||||
public PrefixMetricGroupExporter(PrefixMetricReader reader, |
||||
PrefixMetricWriter writer) { |
||||
this(reader, writer, ""); |
||||
} |
||||
|
||||
/** |
||||
* Create a new exporter for metrics to a writer based on a prefix for the metric |
||||
* names. |
||||
* @param reader a reader as the source of metrics |
||||
* @param writer the writer to send the metrics to |
||||
* @param prefix the prefix for metrics to export |
||||
*/ |
||||
public PrefixMetricGroupExporter(PrefixMetricReader reader, PrefixMetricWriter writer, |
||||
String prefix) { |
||||
super(prefix); |
||||
this.reader = reader; |
||||
this.writer = writer; |
||||
} |
||||
|
||||
/** |
||||
* The groups to export. |
||||
* @param groups the groups to set |
||||
*/ |
||||
public void setGroups(Set<String> groups) { |
||||
this.groups = groups; |
||||
} |
||||
|
||||
@Override |
||||
protected Iterable<String> groups() { |
||||
if ((this.reader instanceof MultiMetricRepository) && this.groups.isEmpty()) { |
||||
return ((MultiMetricRepository) this.reader).groups(); |
||||
} |
||||
return this.groups; |
||||
} |
||||
|
||||
@Override |
||||
protected Iterable<Metric<?>> next(String group) { |
||||
return this.reader.findAll(group); |
||||
} |
||||
|
||||
@Override |
||||
protected void write(String group, Collection<Metric<?>> values) { |
||||
if (group.contains("counter.")) { |
||||
for (Metric<?> value : values) { |
||||
this.writer.increment(group, calculateDelta(value)); |
||||
} |
||||
} |
||||
else { |
||||
this.writer.set(group, values); |
||||
} |
||||
} |
||||
|
||||
private Delta<?> calculateDelta(Metric<?> value) { |
||||
long delta = value.getValue().longValue(); |
||||
Long old = this.counts.replace(value.getName(), delta); |
||||
if (old != null) { |
||||
delta = delta - old; |
||||
} |
||||
else { |
||||
this.counts.putIfAbsent(value.getName(), delta); |
||||
} |
||||
return new Delta<>(value.getName(), delta, value.getTimestamp()); |
||||
} |
||||
|
||||
} |
||||
@ -1,98 +0,0 @@
@@ -1,98 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.boot.actuate.metrics.export; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.HashSet; |
||||
|
||||
import org.springframework.boot.actuate.metrics.Metric; |
||||
import org.springframework.boot.actuate.metrics.repository.MultiMetricRepository; |
||||
import org.springframework.boot.actuate.metrics.rich.RichGauge; |
||||
import org.springframework.boot.actuate.metrics.rich.RichGaugeReader; |
||||
import org.springframework.boot.actuate.metrics.writer.MetricWriter; |
||||
import org.springframework.boot.actuate.metrics.writer.PrefixMetricWriter; |
||||
|
||||
/** |
||||
* Exporter or converter for {@link RichGauge} data to a metric-based back end. Each gauge |
||||
* measurement is stored as a set of related metrics with a common prefix (the name of the |
||||
* gauge), and suffixes that describe the data. For example, a gauge called {@code foo} is |
||||
* stored as {@code[foo.min, foo.max. foo.val, foo.count, foo.avg, foo.alpha]}. If the |
||||
* {@link MetricWriter} provided is a {@link MultiMetricRepository} then the values for a |
||||
* gauge will be stored as a group, and hence will be retrievable from the repository in a |
||||
* single query (or optionally individually). |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class RichGaugeExporter extends AbstractMetricExporter { |
||||
|
||||
private static final String MIN = ".min"; |
||||
|
||||
private static final String MAX = ".max"; |
||||
|
||||
private static final String COUNT = ".count"; |
||||
|
||||
private static final String VALUE = ".val"; |
||||
|
||||
private static final String AVG = ".avg"; |
||||
|
||||
private static final String ALPHA = ".alpha"; |
||||
|
||||
private final RichGaugeReader reader; |
||||
|
||||
private final PrefixMetricWriter writer; |
||||
|
||||
public RichGaugeExporter(RichGaugeReader reader, PrefixMetricWriter writer) { |
||||
this(reader, writer, ""); |
||||
} |
||||
|
||||
public RichGaugeExporter(RichGaugeReader reader, PrefixMetricWriter writer, |
||||
String prefix) { |
||||
super(prefix); |
||||
this.reader = reader; |
||||
this.writer = writer; |
||||
} |
||||
|
||||
@Override |
||||
protected Iterable<Metric<?>> next(String group) { |
||||
RichGauge rich = this.reader.findOne(group); |
||||
Collection<Metric<?>> metrics = new ArrayList<>(); |
||||
metrics.add(new Metric<Number>(group + MIN, rich.getMin())); |
||||
metrics.add(new Metric<Number>(group + MAX, rich.getMax())); |
||||
metrics.add(new Metric<Number>(group + COUNT, rich.getCount())); |
||||
metrics.add(new Metric<Number>(group + VALUE, rich.getValue())); |
||||
metrics.add(new Metric<Number>(group + AVG, rich.getAverage())); |
||||
metrics.add(new Metric<Number>(group + ALPHA, rich.getAlpha())); |
||||
return metrics; |
||||
} |
||||
|
||||
@Override |
||||
protected Iterable<String> groups() { |
||||
Collection<String> names = new HashSet<>(); |
||||
for (RichGauge rich : this.reader.findAll()) { |
||||
names.add(rich.getName()); |
||||
} |
||||
return names; |
||||
} |
||||
|
||||
@Override |
||||
protected void write(String group, Collection<Metric<?>> values) { |
||||
this.writer.set(group, values); |
||||
} |
||||
|
||||
} |
||||
@ -1,40 +0,0 @@
@@ -1,40 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2015 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.boot.actuate.metrics.export; |
||||
|
||||
/** |
||||
* Trigger for specific names or patterns. |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public class SpecificTriggerProperties extends TriggerProperties { |
||||
|
||||
/** |
||||
* Names (or patterns) for bean names that this configuration applies to. |
||||
*/ |
||||
private String[] names; |
||||
|
||||
public String[] getNames() { |
||||
return this.names; |
||||
} |
||||
|
||||
public void setNames(String[] names) { |
||||
this.names = names; |
||||
} |
||||
|
||||
} |
||||
@ -1,94 +0,0 @@
@@ -1,94 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2015 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.boot.actuate.metrics.export; |
||||
|
||||
/** |
||||
* Abstract base class for trigger properties. |
||||
* |
||||
* @author Dave Syer |
||||
* @since 1.3.0 |
||||
*/ |
||||
public abstract class TriggerProperties { |
||||
|
||||
/** |
||||
* Delay in milliseconds between export ticks. Metrics are exported to external |
||||
* sources on a schedule with this delay. |
||||
*/ |
||||
private Long delayMillis; |
||||
|
||||
/** |
||||
* Flag to enable metric export (assuming a MetricWriter is available). |
||||
*/ |
||||
private boolean enabled = true; |
||||
|
||||
/** |
||||
* Flag to switch off any available optimizations based on not exporting unchanged |
||||
* metric values. |
||||
*/ |
||||
private Boolean sendLatest; |
||||
|
||||
/** |
||||
* List of patterns for metric names to include. |
||||
*/ |
||||
private String[] includes; |
||||
|
||||
/** |
||||
* List of patterns for metric names to exclude. Applied after the includes. |
||||
*/ |
||||
private String[] excludes; |
||||
|
||||
public String[] getIncludes() { |
||||
return this.includes; |
||||
} |
||||
|
||||
public void setIncludes(String[] includes) { |
||||
this.includes = includes; |
||||
} |
||||
|
||||
public void setExcludes(String[] excludes) { |
||||
this.excludes = excludes; |
||||
} |
||||
|
||||
public String[] getExcludes() { |
||||
return this.excludes; |
||||
} |
||||
|
||||
public boolean isEnabled() { |
||||
return this.enabled; |
||||
} |
||||
|
||||
public void setEnabled(boolean enabled) { |
||||
this.enabled = enabled; |
||||
} |
||||
|
||||
public Long getDelayMillis() { |
||||
return this.delayMillis; |
||||
} |
||||
|
||||
public void setDelayMillis(long delayMillis) { |
||||
this.delayMillis = delayMillis; |
||||
} |
||||
|
||||
public Boolean isSendLatest() { |
||||
return this.sendLatest; |
||||
} |
||||
|
||||
public void setSendLatest(boolean sendLatest) { |
||||
this.sendLatest = sendLatest; |
||||
} |
||||
|
||||
} |
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue