~/.m2/repository/org/springframework/boot/spring-boot-actuator/1.4.3.RELEASE/spring-boot-actuator-1.4.3.RELEASE-sources.jar!/org/springframework/boot/actuate/autoconfigure/MetricsDropwizardAutoConfiguration.javajava
@Configuration @ConditionalOnClass(MetricRegistry.class) @AutoConfigureBefore(MetricRepositoryAutoConfiguration.class) public class MetricsDropwizardAutoConfiguration { @Bean @ConditionalOnMissingBean public MetricRegistry metricRegistry() { return new MetricRegistry(); } @Bean @ConditionalOnMissingBean({ DropwizardMetricServices.class, CounterService.class, GaugeService.class }) public DropwizardMetricServices dropwizardMetricServices( MetricRegistry metricRegistry) { return new DropwizardMetricServices(metricRegistry); } @Bean public MetricReaderPublicMetrics dropwizardPublicMetrics( MetricRegistry metricRegistry) { MetricRegistryMetricReader reader = new MetricRegistryMetricReader( metricRegistry); return new MetricReaderPublicMetrics(reader); } }
這裏將dropwizard的metrics包裝爲MetricReaderPublicMetricsspring
~/.m2/repository/org/springframework/boot/spring-boot-actuator/1.4.3.RELEASE/spring-boot-actuator-1.4.3.RELEASE-sources.jar!/org/springframework/boot/actuate/metrics/reader/MetricRegistryMetricReader.javatomcat
public class MetricRegistryMetricReader implements MetricReader, MetricRegistryListener { private static final Log logger = LogFactory.getLog(MetricRegistryMetricReader.class); private static final Map<Class<?>, Set<String>> numberKeys = new ConcurrentHashMap<Class<?>, Set<String>>(); private final Object monitor = new Object(); private final Map<String, String> names = new ConcurrentHashMap<String, String>(); private final MultiValueMap<String, String> reverse = new LinkedMultiValueMap<String, String>(); private final MetricRegistry registry; public MetricRegistryMetricReader(MetricRegistry registry) { this.registry = registry; registry.addListener(this); } @Override public Metric<?> findOne(String metricName) { String name = this.names.get(metricName); if (name == null) { return null; } com.codahale.metrics.Metric metric = this.registry.getMetrics().get(name); if (metric == null) { return null; } if (metric instanceof Counter) { Counter counter = (Counter) metric; return new Metric<Number>(metricName, counter.getCount()); } if (metric instanceof Gauge) { Object value = ((Gauge<?>) metric).getValue(); if (value instanceof Number) { return new Metric<Number>(metricName, (Number) value); } if (logger.isDebugEnabled()) { logger.debug("Ignoring gauge '" + name + "' (" + metric + ") as its value is not a Number"); } return null; } if (metric instanceof Sampling) { if (metricName.contains(".snapshot.")) { Number value = getMetric(((Sampling) metric).getSnapshot(), metricName); if (metric instanceof Timer) { // convert back to MILLISEC value = TimeUnit.MILLISECONDS.convert(value.longValue(), TimeUnit.NANOSECONDS); } return new Metric<Number>(metricName, value); } } return new Metric<Number>(metricName, getMetric(metric, metricName)); } @Override public Iterable<Metric<?>> findAll() { return new Iterable<Metric<?>>() { @Override public Iterator<Metric<?>> iterator() { Set<Metric<?>> metrics = new HashSet<Metric<?>>(); for (String name : MetricRegistryMetricReader.this.names.keySet()) { Metric<?> metric = findOne(name); if (metric != null) { metrics.add(metric); } } return metrics.iterator(); } }; } @Override public long count() { return this.names.size(); } @Override public void onGaugeAdded(String name, Gauge<?> gauge) { this.names.put(name, name); synchronized (this.monitor) { this.reverse.add(name, name); } } @Override public void onGaugeRemoved(String name) { remove(name); } @Override public void onCounterAdded(String name, Counter counter) { this.names.put(name, name); synchronized (this.monitor) { this.reverse.add(name, name); } } @Override public void onCounterRemoved(String name) { remove(name); } @Override public void onHistogramAdded(String name, Histogram histogram) { for (String key : getNumberKeys(histogram)) { String metricName = name + "." + key; this.names.put(metricName, name); synchronized (this.monitor) { this.reverse.add(name, metricName); } } for (String key : getNumberKeys(histogram.getSnapshot())) { String metricName = name + ".snapshot." + key; this.names.put(metricName, name); synchronized (this.monitor) { this.reverse.add(name, metricName); } } } @Override public void onHistogramRemoved(String name) { remove(name); } @Override public void onMeterAdded(String name, Meter meter) { for (String key : getNumberKeys(meter)) { String metricName = name + "." + key; this.names.put(metricName, name); synchronized (this.monitor) { this.reverse.add(name, metricName); } } } @Override public void onMeterRemoved(String name) { remove(name); } @Override public void onTimerAdded(String name, Timer timer) { for (String key : getNumberKeys(timer)) { String metricName = name + "." + key; this.names.put(metricName, name); synchronized (this.monitor) { this.reverse.add(name, metricName); } } for (String key : getNumberKeys(timer.getSnapshot())) { String metricName = name + ".snapshot." + key; this.names.put(metricName, name); synchronized (this.monitor) { this.reverse.add(name, metricName); } } } @Override public void onTimerRemoved(String name) { remove(name); } private void remove(String name) { List<String> keys; synchronized (this.monitor) { keys = this.reverse.remove(name); } if (keys != null) { for (String key : keys) { this.names.remove(name + "." + key); } } } private static Set<String> getNumberKeys(Object metric) { Set<String> result = numberKeys.get(metric.getClass()); if (result == null) { result = new HashSet<String>(); } if (result.isEmpty()) { for (PropertyDescriptor descriptor : BeanUtils .getPropertyDescriptors(metric.getClass())) { if (ClassUtils.isAssignable(Number.class, descriptor.getPropertyType())) { result.add(descriptor.getName()); } } numberKeys.put(metric.getClass(), result); } return result; } private static Number getMetric(Object metric, String metricName) { String key = StringUtils.getFilenameExtension(metricName); return (Number) new BeanWrapperImpl(metric).getPropertyValue(key); } }
~/.m2/repository/org/springframework/boot/spring-boot-actuator/1.4.3.RELEASE/spring-boot-actuator-1.4.3.RELEASE-sources.jar!/org/springframework/boot/actuate/autoconfigure/PublicMetricsAutoConfiguration.javaapp
@Configuration @AutoConfigureBefore(EndpointAutoConfiguration.class) @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>> metricReadersProvider) { this.metricReaders = metricReadersProvider.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() { return new CachePublicMetrics(); } } @Configuration @ConditionalOnClass(IntegrationMBeanExporter.class) @ConditionalOnBean(IntegrationMBeanExporter.class) @ConditionalOnJava(JavaVersion.SEVEN) @UsesJava7 static class IntegrationMetricsConfiguration { @Bean @ConditionalOnMissingBean(name = "springIntegrationPublicMetrics") public MetricReaderPublicMetrics springIntegrationPublicMetrics( IntegrationMBeanExporter exporter) { return new MetricReaderPublicMetrics( new SpringIntegrationMetricReader(exporter)); } } }
這裏既有SystemPublicMetrics,也有MetricReaderPublicMetrics,使用了CompositeMetricReaderide
~/.m2/repository/org/springframework/boot/spring-boot-actuator/1.4.3.RELEASE/spring-boot-actuator-1.4.3.RELEASE-sources.jar!/org/springframework/boot/actuate/endpoint/MetricsEndpoint.javaspring-boot
@ConfigurationProperties(prefix = "endpoints.metrics") public class MetricsEndpoint extends AbstractEndpoint<Map<String, Object>> { private final List<PublicMetrics> publicMetrics; /** * Create a new {@link MetricsEndpoint} instance. * @param publicMetrics the metrics to expose */ public MetricsEndpoint(PublicMetrics publicMetrics) { this(Collections.singleton(publicMetrics)); } /** * Create a new {@link MetricsEndpoint} instance. * @param publicMetrics the metrics to expose. The collection will be sorted using the * {@link AnnotationAwareOrderComparator}. */ public MetricsEndpoint(Collection<PublicMetrics> publicMetrics) { super("metrics"); Assert.notNull(publicMetrics, "PublicMetrics must not be null"); this.publicMetrics = new ArrayList<PublicMetrics>(publicMetrics); AnnotationAwareOrderComparator.sort(this.publicMetrics); } public void registerPublicMetrics(PublicMetrics metrics) { this.publicMetrics.add(metrics); AnnotationAwareOrderComparator.sort(this.publicMetrics); } public void unregisterPublicMetrics(PublicMetrics metrics) { this.publicMetrics.remove(metrics); } @Override public Map<String, Object> invoke() { Map<String, Object> result = new LinkedHashMap<String, Object>(); List<PublicMetrics> metrics = new ArrayList<PublicMetrics>(this.publicMetrics); for (PublicMetrics publicMetric : metrics) { try { for (Metric<?> metric : publicMetric.metrics()) { result.put(metric.getName(), metric.getValue()); } } catch (Exception ex) { // Could not evaluate metrics } } return result; } }
這裏將public metric暴露在/metrics的endpoint上this