Введение в Метрики Dropwizard

1. Вступление

Metrics - это библиотека Java, которая предоставляет измерительные приборы для приложений Java.

Он имеет несколько модулей, и в этой статье мы разработаем модуль metrics-core, модуль metrics-healthchecks, модуль metrics-servlets и модуль metrics-servlet, а также сделаем набросок для остального, для справки.

2. Модуль metrics-core

2.1. Зависимости Maven

Для использования модуля metrics-core требуется только одна зависимость, которую необходимо добавить в файл pom.xml :

<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-core</artifactId>
    <version>3.1.2</version>
</dependency>

И вы можете найти его последнюю версию Вот .

2.2. MetricRegistry

Проще говоря, мы будем использовать класс MetricRegistry для регистрации одного или нескольких показателей.

Мы можем использовать один реестр метрик для всех наших метрик, но если мы хотим использовать разные методы отчетности для разных метрик, мы также можем разделить наши метрики на группы и использовать разные реестры метрик для каждой группы.

Давайте создадим MetricRegistry сейчас:

MetricRegistry metricRegistry = new MetricRegistry();

И тогда мы можем зарегистрировать некоторые метрики с помощью этой MetricRegistry :

Meter meter1 = new Meter();
metricRegistry.register("meter1", meter1);

Meter meter2 = metricRegistry.meter("meter2");

Существует два основных способа создания новой метрики: создание экземпляра самостоятельно или получение его из реестра метрик. Как вы можете видеть, мы использовали оба из них в приведенном выше примере, мы создаем экземпляр объекта Meter meter1 и получаем другой объект Meter meter2, созданный metricRegistry .

В реестре метрик каждая метрика имеет уникальное имя, так как мы использовали «meter1» и «meter2» в качестве названий метрики выше. MetricRegistry также предоставляет набор статических вспомогательных методов, чтобы помочь нам создать правильные имена метрик:

String name1 = MetricRegistry.name(Filter.class, "request", "count");
String name2 = MetricRegistry.name("CustomFilter", "response", "count");

Если нам нужно управлять набором метрических реестров, мы можем использовать класс SharedMetricRegistries , который является одноэлементным и поточно-ориентированным. Мы можем добавить в него регистр метрик, извлечь из него этот регистр метрик и удалить его:

SharedMetricRegistries.add("default", metricRegistry);
MetricRegistry retrievedMetricRegistry = SharedMetricRegistries.getOrCreate("default");
SharedMetricRegistries.remove("default");

** 3. Метрики Концепции

**

Модуль metrics-core предоставляет несколько часто используемых типов метрик:

Meter , Gauge , Counter , Histogram и Timer и Reporter для вывода значений метрик _. _

3.1. Meter

Meter измеряет количество и частоту событий:

Meter meter = new Meter();
long initCount = meter.getCount();
assertThat(initCount, equalTo(0L));

meter.mark();
assertThat(meter.getCount(), equalTo(1L));

meter.mark(20);
assertThat(meter.getCount(), equalTo(21L));

double meanRate = meter.getMeanRate();
double oneMinRate = meter.getOneMinuteRate();
double fiveMinRate = meter.getFiveMinuteRate();
double fifteenMinRate = meter.getFifteenMinuteRate();

Метод getCount () возвращает счетчик событий, а метод mark () добавляет 1 или n к счетчику событий. Объект Meter предоставляет четыре показателя, которые представляют средние значения для всего времени жизни Meter , за последнюю минуту, за последние пять минут и за последний квартал соответственно.

3.2. Gauge

Gauge - это интерфейс, который просто используется для возврата определенного значения. Модуль metrics-core предоставляет несколько его реализаций:

RatioGauge , CachedGauge , DerivativeGauge и http://metrics.dropwizard.io/3.1 0,0/apidocs/ком/codahale/метрики/JmxAttributeGauge.html[ JmxAttributeGauge ].

RatioGauge - это абстрактный класс, который измеряет отношение одного значения к другому.

Давайте посмотрим, как его использовать. Сначала мы реализуем класс AttendanceRatioGauge :

public class AttendanceRatioGauge extends RatioGauge {
    private int attendanceCount;
    private int courseCount;

    @Override
    protected Ratio getRatio() {
        return Ratio.of(attendanceCount, courseCount);
    }

   //standard constructors
}

И тогда мы проверяем это:

RatioGauge ratioGauge = new AttendanceRatioGauge(15, 20);

assertThat(ratioGauge.getValue(), equalTo(0.75));

CachedGauge - еще один абстрактный класс, который может кэшировать значение, поэтому он очень полезен, когда значения требуют больших затрат. Чтобы использовать его, нам нужно реализовать класс ActiveUsersGauge :

public class ActiveUsersGauge extends CachedGauge<List<Long>> {

    @Override
    protected List<Long> loadValue() {
        return getActiveUserCount();
    }

    private List<Long> getActiveUserCount() {
        List<Long> result = new ArrayList<Long>();
        result.add(12L);
        return result;
    }

   //standard constructors
}

Затем мы проверяем, работает ли он так, как ожидалось:

Gauge<List<Long>> activeUsersGauge = new ActiveUsersGauge(15, TimeUnit.MINUTES);
List<Long> expected = new ArrayList<>();
expected.add(12L);

assertThat(activeUsersGauge.getValue(), equalTo(expected));

Мы устанавливаем время истечения срока действия кэша до 15 минут при создании экземпляра ActiveUsersGauge .

DerivativeGauge также является абстрактным классом, и он позволяет вам извлекать значение из другого Gauge в качестве его значения.

Давайте посмотрим на пример:

public class ActiveUserCountGauge extends DerivativeGauge<List<Long>, Integer> {

    @Override
    protected Integer transform(List<Long> value) {
        return value.size();
    }

   //standard constructors
}

Этот Gauge получает свое значение из ActiveUsersGauge , поэтому мы ожидаем, что это будет значение из размера базового списка:

Gauge<List<Long>> activeUsersGauge = new ActiveUsersGauge(15, TimeUnit.MINUTES);
Gauge<Integer> activeUserCountGauge = new ActiveUserCountGauge(activeUsersGauge);

assertThat(activeUserCountGauge.getValue(), equalTo(1));

JmxAttributeGauge используется, когда нам нужен доступ к метрикам других библиотек, предоставляемым через JMX.

3.3. Counter

Counter используется для записи приращений и уменьшений:

Counter counter = new Counter();
long initCount = counter.getCount();
assertThat(initCount, equalTo(0L));

counter.inc();
assertThat(counter.getCount(), equalTo(1L));

counter.inc(11);
assertThat(counter.getCount(), equalTo(12L));

counter.dec();
assertThat(counter.getCount(), equalTo(11L));

counter.dec(6);
assertThat(counter.getCount(), equalTo(5L));

3.4. Histogram

Histogram используется для отслеживания потока значений Long и анализирует их статистические характеристики, такие как max, min, среднее значение, медиана, стандартное отклонение, 75-й процентиль и так далее:

Histogram histogram = new Histogram(new UniformReservoir());
histogram.update(5);
long count1 = histogram.getCount();
assertThat(count1, equalTo(1L));

Snapshot snapshot1 = histogram.getSnapshot();
assertThat(snapshot1.getValues().length, equalTo(1));
assertThat(snapshot1.getValues()[0], equalTo(5L));

histogram.update(20);
long count2 = histogram.getCount();
assertThat(count2, equalTo(2L));

Snapshot snapshot2 = histogram.getSnapshot();
assertThat(snapshot2.getValues().length, equalTo(2));
assertThat(snapshot2.getValues()[1], equalTo(20L));
assertThat(snapshot2.getMax(), equalTo(20L));
assertThat(snapshot2.getMean(), equalTo(12.5));
assertEquals(10.6, snapshot2.getStdDev(), 0.1);
assertThat(snapshot2.get75thPercentile(), equalTo(20.0));
assertThat(snapshot2.get999thPercentile(), equalTo(20.0));

Histogram производит выборку данных, используя выборку из резервуара, и когда мы создаем экземпляр объекта Histogram , нам нужно явно установить его резервуар.

Reservoir - это интерфейс, а ядро ​​метрик обеспечивает четыре их реализации:

В приведенном выше разделе мы упоминали, что метрика также может быть создана MetricRegistry, помимо использования конструктора _. Когда мы используем metricRegistry.histogram () , он возвращает экземпляр Histogram с реализацией ExponentiallyDecayingReservoir_ .

3.5. Timer

Timer используется для отслеживания нескольких временных интервалов, которые представлены объектами Context , а также предоставляет их статистические данные:

Timer timer = new Timer();
Timer.Context context1 = timer.time();
TimeUnit.SECONDS.sleep(5);
long elapsed1 = context1.stop();

assertEquals(5000000000L, elapsed1, 1000000);
assertThat(timer.getCount(), equalTo(1L));
assertEquals(0.2, timer.getMeanRate(), 0.1);

Timer.Context context2 = timer.time();
TimeUnit.SECONDS.sleep(2);
context2.close();

assertThat(timer.getCount(), equalTo(2L));
assertEquals(0.3, timer.getMeanRate(), 0.1);

3.6. Reporter

Когда нам нужно вывести наши измерения, мы можем использовать Reporter . Это интерфейс, и модуль metrics-core предоставляет несколько его реализаций, таких как ConsoleReporter , CsvReporter , http://metrics.dropwizard.io/3.1.0/apidocs/com/codahale/metrics/Slf4jReporter .html[ Slf4jReporter ], JmxReporter и так далее.

Здесь мы используем ConsoleReporter в качестве примера:

MetricRegistry metricRegistry = new MetricRegistry();

Meter meter = metricRegistry.meter("meter");
meter.mark();
meter.mark(200);
Histogram histogram = metricRegistry.histogram("histogram");
histogram.update(12);
histogram.update(17);
Counter counter = metricRegistry.counter("counter");
counter.inc();
counter.dec();

ConsoleReporter reporter = ConsoleReporter.forRegistry(metricRegistry).build();
reporter.start(5, TimeUnit.MICROSECONDS);
reporter.report();

Вот пример выходных данных ConsoleReporter:

-- Histograms ------------------------------------------------------------------
histogram
count = 2
min = 12
max = 17
mean = 14.50
stddev = 2.50
median = 17.00
75% <= 17.00
95% <= 17.00
98% <= 17.00
99% <= 17.00
99.9% <= 17.00

-- Meters ----------------------------------------------------------------------
meter
count = 201
mean rate = 1756.87 events/second
1-minute rate = 0.00 events/second
5-minute rate = 0.00 events/second
15-minute rate = 0.00 events/second

4. Модуль metrics-healthchecks

Metrics имеет расширенный модуль metrics-healthchecks для проверки работоспособности.

4.1. Зависимости Maven

Чтобы использовать модуль metrics-healthchecks, нам нужно добавить эту зависимость в файл pom.xml :

<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-healthchecks</artifactId>
    <version>3.1.2</version>
</dependency>

И вы можете найти его последнюю версию Вот .

4.2. Использование

Во-первых, нам нужно несколько классов, которые отвечают за конкретные операции проверки работоспособности, и эти классы должны реализовывать HealthCheck .

Например, мы используем DatabaseHealthCheck и UserCenterHealthCheck :

public class DatabaseHealthCheck extends HealthCheck {

    @Override
    protected Result check() throws Exception {
        return Result.healthy();
    }
}
public class UserCenterHealthCheck extends HealthCheck {

    @Override
    protected Result check() throws Exception {
        return Result.healthy();
    }
}

Затем нам нужен HealthCheckRegistry (который похож на MetricRegistry ), и зарегистрируйте DatabaseHealthCheck и UserCenterHealthCheck с ним:

HealthCheckRegistry healthCheckRegistry = new HealthCheckRegistry();
healthCheckRegistry.register("db", new DatabaseHealthCheck());
healthCheckRegistry.register("uc", new UserCenterHealthCheck());

assertThat(healthCheckRegistry.getNames().size(), equalTo(2));

Мы также можем отменить регистрацию HealthCheck :

healthCheckRegistry.unregister("uc");

assertThat(healthCheckRegistry.getNames().size(), equalTo(1));

Мы можем запустить все экземпляры HealthCheck :

Map<String, HealthCheck.Result> results = healthCheckRegistry.runHealthChecks();
for (Map.Entry<String, HealthCheck.Result> entry : results.entrySet()) {
    assertThat(entry.getValue().isHealthy(), equalTo(true));
}

Наконец, мы можем запустить конкретный экземпляр HealthCheck :

healthCheckRegistry.runHealthCheck("db");

5. Модуль metrics-servlets

Метрики предоставляет нам несколько полезных сервлетов, которые позволяют нам получать доступ к данным, связанным с метриками, через HTTP-запросы.

5.1. Зависимости Maven

Чтобы использовать модуль metrics-servlets, нам нужно добавить эту зависимость в файл pom.xml :

<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-servlets</artifactId>
    <version>3.1.2</version>
</dependency>

И вы можете найти его последнюю версию Вот .

5.2. HealthCheckServlet Usage

HealthCheckServlet предоставляет результаты проверки работоспособности. Во-первых, нам нужно создать ServletContextListener , который предоставляет нашу HealthCheckRegistry :

public class MyHealthCheckServletContextListener
  extends HealthCheckServlet.ContextListener {

    public static HealthCheckRegistry HEALTH__CHECK__REGISTRY
      = new HealthCheckRegistry();

    static {
        HEALTH__CHECK__REGISTRY.register("db", new DatabaseHealthCheck());
    }

    @Override
    protected HealthCheckRegistry getHealthCheckRegistry() {
        return HEALTH__CHECK__REGISTRY;
    }
}

Затем мы добавляем этот слушатель и HealthCheckServlet в файл web.xml :

<listener>
    <listener-class>com.baeldung.metrics.servlets.MyHealthCheckServletContextListener</listener-class>
</listener>
<servlet>
    <servlet-name>healthCheck</servlet-name>
    <servlet-class>com.codahale.metrics.servlets.HealthCheckServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>healthCheck</servlet-name>
    <url-pattern>/healthcheck</url-pattern>
</servlet-mapping>

Теперь мы можем запустить веб-приложение и отправить запрос GET по адресу «http://localhost: 8080/healthcheck», чтобы получить результаты проверки работоспособности. Его ответ должен быть таким:

{
  "db": {
    "healthy": true
  }
}

5.3. ThreadDumpServlet Использование

ThreadDumpServlet предоставляет информацию обо всех активных потоках в JVM, их состояниях, их трассировках стека и состоянии любых блокировок, которые они могут ожидать. Если мы хотим использовать его, нам просто нужно добавить их в файл web.xml :

<servlet>
    <servlet-name>threadDump</servlet-name>
    <servlet-class>com.codahale.metrics.servlets.ThreadDumpServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>threadDump</servlet-name>
    <url-pattern>/threaddump</url-pattern>
</servlet-mapping>

Данные дампа потока будут доступны по адресу «http://localhost: 8080/threaddump».

5.4. PingServlet Использование

PingServlet может использоваться для проверки работоспособности приложения. Мы добавляем их в файл web.xml :

<servlet>
    <servlet-name>ping</servlet-name>
    <servlet-class>com.codahale.metrics.servlets.PingServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ping</servlet-name>
    <url-pattern>/ping</url-pattern>
</servlet-mapping>

Затем отправьте запрос GET по адресу «http://localhost: 8080/ping». Код статуса ответа - 200, а его содержание - «понг».

5.5. MetricsServlet Использование

MetricsServlet предоставляет данные метрик. Во-первых, нам нужно создать ServletContextListener , который раскрывает нашу MetricRegistry :

public class MyMetricsServletContextListener
  extends MetricsServlet.ContextListener {
    private static MetricRegistry METRIC__REGISTRY
     = new MetricRegistry();

    static {
        Counter counter = METRIC__REGISTRY.counter("m01-counter");
        counter.inc();

        Histogram histogram = METRIC__REGISTRY.histogram("m02-histogram");
        histogram.update(5);
        histogram.update(20);
        histogram.update(100);
    }

    @Override
    protected MetricRegistry getMetricRegistry() {
        return METRIC__REGISTRY;
    }
}

И этот слушатель, и MetricsServlet должны быть добавлены в web.xml :

<listener>
    <listener-class>com.codahale.metrics.servlets.MyMetricsServletContextListener</listener-class>
</listener>
<servlet>
    <servlet-name>metrics</servlet-name>
    <servlet-class>com.codahale.metrics.servlets.MetricsServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>metrics</servlet-name>
    <url-pattern>/metrics</url-pattern>
</servlet-mapping>

Это будет показано в нашем веб-приложении по адресу «http://localhost: 8080/metrics». Его ответ должен содержать различные данные метрик:

{
  "version": "3.0.0",
  "gauges": {},
  "counters": {
    "m01-counter": {
      "count": 1
    }
  },
  "histograms": {
    "m02-histogram": {
      "count": 3,
      "max": 100,
      "mean": 41.66666666666666,
      "min": 5,
      "p50": 20,
      "p75": 100,
      "p95": 100,
      "p98": 100,
      "p99": 100,
      "p999": 100,
      "stddev": 41.69998667732268
    }
  },
  "meters": {},
  "timers": {}
}

5.6. AdminServlet Использование

AdminServlet агрегаты HealthCheckServlet , ThreadDumpServlet , MetricsServlet и PingServlet .

Давайте добавим их в web.xml :

<servlet>
    <servlet-name>admin</servlet-name>
    <servlet-class>com.codahale.metrics.servlets.AdminServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>admin</servlet-name>
    <url-pattern>/admin/** </url-pattern>
</servlet-mapping>

Теперь к нему можно получить доступ по адресу «http://localhost: 8080/admin». Мы получим страницу, содержащую четыре ссылки, по одной для каждого из этих четырех сервлетов.

Обратите внимание, что если мы хотим выполнить проверку работоспособности и получить доступ к данным метрик, эти два слушателя все еще необходимы.

6. Модуль metrics-servlet

Модуль metrics-servlet предоставляет Filter , который имеет несколько метрик: счетчики для кодов состояния, счетчик для количества активных запросов и таймер для продолжительности запроса.

6.1. Зависимости Maven

Чтобы использовать этот модуль, давайте сначала добавим зависимость в pom.xml :

<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-servlet</artifactId>
    <version>3.1.2</version>
</dependency>

И вы можете найти его последнюю версию Вот .

6.2. Использование

Чтобы использовать его, нам нужно создать ServletContextListener , который выставляет нашу MetricRegistry InstrumentedFilter

public class MyInstrumentedFilterContextListener
  extends InstrumentedFilterContextListener {

    public static MetricRegistry REGISTRY = new MetricRegistry();

    @Override
    protected MetricRegistry getMetricRegistry() {
        return REGISTRY;
    }
}

Затем мы добавляем их в web.xml :

<listener>
     <listener-class>
         com.baeldung.metrics.servlet.MyInstrumentedFilterContextListener
     </listener-class>
</listener>

<filter>
    <filter-name>instrumentFilter</filter-name>
    <filter-class>
        com.codahale.metrics.servlet.InstrumentedFilter
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>instrumentFilter</filter-name>
    <url-pattern>/** </url-pattern>
</filter-mapping>

Теперь InstrumentedFilter может работать. Если мы хотим получить доступ к данным метрики, мы можем сделать это через MetricRegistry REGISTRY .

7. Другие модули

За исключением модулей, которые мы представили выше, у Metrics есть несколько других модулей для разных целей:

  • metrics-jvm : предоставляет несколько полезных метрик для инструментов JVM

внутренности ** metrics-ehcache : предоставляет InstrumentedEhcache , декоратор для

Кэши Ehcache ** metrics-httpclient : предоставляет классы для инструментария Apache

HttpClient (версия 4.x) ** metrics-log4j : предоставляет InstrumentedAppender , Log4j Appender

реализация для log4j 1.x, которая записывает скорость зарегистрированных событий по их уровень регистрации ** metrics-log4j2 : аналогично metrics-log4j, только для log4j 2.x

  • metrics-logback : предоставляет InstrumentedAppender , Logback

Appender реализация, которая записывает скорость зарегистрированных событий по их уровень регистрации ** metrics-json : предоставляет HealthCheckModule и MetricsModule для

Джексон

Более того, помимо этих основных модулей проекта, некоторые другие third партийные библиотеки обеспечивают интеграцию с другими библиотеками и средами.

8. Заключение

Инструментарий приложений является распространенным требованием, поэтому в этой статье мы представили Metrics, надеясь, что это поможет вам решить вашу проблему.

Как всегда, полный исходный код для примера доступен over на GitHub .