Exporting Spring Boot Actuator Metrics (& Dropwizard Metrics) to Statsd

前端 未结 4 446
慢半拍i
慢半拍i 2020-12-09 20:40

I\'m trying to export all of the metrics which are visible at the endpoint /metrics to a StatsdMetricWriter.

I\'ve got the following config

相关标签:
4条回答
  • 2020-12-09 21:07

    I had the same problem and found a solution here: https://github.com/tzolov/export-metrics-example

    Just add a MetricsEndpointMetricReader to your config and everything available at th e/metrics endpoint will be published to the StatsdMetricWriter.

    Here is a complete example config for spring boot 1.3.x and dropwizard metrics-jvm 3.1.x:

    import com.codahale.metrics.MetricRegistry;
    import com.codahale.metrics.jvm.GarbageCollectorMetricSet;
    import com.codahale.metrics.jvm.MemoryUsageGaugeSet;
    import com.codahale.metrics.jvm.ThreadStatesGaugeSet;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.actuate.autoconfigure.ExportMetricWriter;
    import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
    import org.springframework.boot.actuate.endpoint.MetricsEndpointMetricReader;
    import org.springframework.boot.actuate.metrics.Metric;
    import org.springframework.boot.actuate.metrics.statsd.StatsdMetricWriter;
    import org.springframework.boot.actuate.metrics.writer.Delta;
    import org.springframework.boot.actuate.metrics.writer.MetricWriter;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class MetricsConfiguration {
    
      @Bean
      public MetricRegistry metricRegistry() {
        final MetricRegistry metricRegistry = new MetricRegistry();
    
        metricRegistry.register("jvm.memory",new MemoryUsageGaugeSet());
        metricRegistry.register("jvm.thread-states",new ThreadStatesGaugeSet());
        metricRegistry.register("jvm.garbage-collector",new GarbageCollectorMetricSet());
    
        return metricRegistry;
      }
    
      /*
       * Reading all metrics that appear on the /metrics endpoint to expose them to metrics writer beans.
       */
      @Bean
      public MetricsEndpointMetricReader metricsEndpointMetricReader(final MetricsEndpoint metricsEndpoint) {
        return new MetricsEndpointMetricReader(metricsEndpoint);
      }
    
      @Bean
      @ConditionalOnProperty(prefix = "statsd", name = {"prefix", "host", "port"})
      @ExportMetricWriter
      public MetricWriter statsdMetricWriter(@Value("${statsd.prefix}") String statsdPrefix,
                                         @Value("${statsd.host}") String statsdHost,
                                         @Value("${statsd.port}") int statsdPort) {
        return new StatsdMetricWriter(statsdPrefix, statsdHost, statsdPort);
      }
    
    }
    
    0 讨论(0)
  • 2020-12-09 21:08

    From what I've seen in spring-boot code, only calls to CounterService and GaugeService implementations are forwarded to dropwizard's MetricRegistry.

    Therefore, as you already observed, only counter.* and gauge.* metrics from the /metrics endpoint will end up in Statsd.

    System and JVM metrics are exposed through custom SystemPublicMetrics class, which doesn't use counter or gauge service.

    I'm not sure if there is a simpler solution (maybe someone from Spring team will comment), but one way to do it (not spring-boot specific) would be to use a scheduled task that periodically writes system stats to the MetricRegistry.

    0 讨论(0)
  • 2020-12-09 21:30

    To register JVM metrics you can use the JVM related MetricSets supplied by codehale.metrics.jvm library. You can just add the whole set without supplying whether they are gauges or counters.

    Here is my example code where I am registering jvm related metrics:

    @Configuration
    @EnableMetrics(proxyTargetClass = true)
    public class MetricsConfig {
    
    @Autowired
    private StatsdProperties statsdProperties;
    
    @Autowired
    private MetricsEndpoint metricsEndpoint;
    
    @Autowired
    private DataSourcePublicMetrics dataSourcePublicMetrics;
    
    @Bean
    @ExportMetricReader
    public MetricReader metricReader() {
        return new MetricRegistryMetricReader(metricRegistry());
    }
    
    public MetricRegistry metricRegistry() {
        final MetricRegistry metricRegistry = new MetricRegistry();
    
        //jvm metrics
        metricRegistry.register("jvm.gc",new GarbageCollectorMetricSet());
        metricRegistry.register("jvm.mem",new MemoryUsageGaugeSet());
        metricRegistry.register("jvm.thread-states",new ThreadStatesGaugeSet());
    
        return metricRegistry;
    }
    
    @Bean
    @ConditionalOnProperty(prefix = "metrics.writer.statsd", name = {"host", "port"})
    @ExportMetricWriter
    public MetricWriter statsdMetricWriter() {
        return new StatsdMetricWriter(
                statsdProperties.getPrefix(),
                statsdProperties.getHost(),
                statsdProperties.getPort()
        );
    }
    

    }

    Note: I am using spring boot version 1.3.0.M4

    0 讨论(0)
  • 2020-12-09 21:31

    Enjoy! (see the public metrics logged in console as dropwizard metrics)

    @Configuration
    @EnableMetrics
    @EnableScheduling
    public class MetricsReporter extends MetricsConfigurerAdapter {
    
        @Autowired private SystemPublicMetrics systemPublicMetrics;
        private MetricRegistry metricRegistry;
    
        @Scheduled(fixedDelay = 5000)
        void exportPublicMetrics() {
            for (Metric<?> metric : systemPublicMetrics.metrics()) {
                Counter counter = metricRegistry.counter(metric.getName());
                counter.dec(counter.getCount());
                counter.inc(Double.valueOf(metric.getValue().toString()).longValue());
            }
        }
    
        @Override
        public void configureReporters(MetricRegistry metricRegistry) {
            this.metricRegistry = metricRegistry;
            ConsoleReporter.forRegistry(metricRegistry).build().start(10, TimeUnit.SECONDS);
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题