Codahale Metrics: использование аннотации @Timed metrics в простой Java

Я пытаюсь добавить метрики к простому Java-приложению, используя метрики codahale. Я хотел бы использовать аннотацию @Timed, но мне непонятно, какой MetricRegistry он использует или как сказать, какой MetricRegistry использовать. Приложение представляет собой обычное приложение Java 8, построенное с помощью Maven 3, no Spring, без спящего режима.

Я не могу найти документацию о том, как реализовать @Timed в документации dropwizard: https://dropwizard.github.io/metrics/3.1.0/manual/

Я добавил эти зависимости:

<dependency>
  <groupId>io.dropwizard.metrics</groupId>
  <artifactId>metrics-core</artifactId>
  <version>3.1.0</version>
</dependency>
<dependency>
  <groupId>com.codahale.metrics</groupId>
  <artifactId>metrics-annotation</artifactId>
  <version>3.0.2</version>
</dependency>

Когда я использую программный вызов Timer, я могу получать отчеты, потому что знаю, какой MetricsRegistry используется:

static final MetricRegistry metrics = new MetricRegistry();
private void update() throws SQLException {
  Timer.Context time = metrics.timer("domainobject.update").time();
  try {
    [...]
  } finally {
    time.stop();
  }
}

Но когда я использую гораздо более элегантную аннотацию @Timed, я понятия не имею, какой реестр используется, и поэтому я не могу создать репортера, а это значит, что я не могу сообщить о показателях (я даже не уверен, что это действительно что-то делает):

@Timed(name = "domainobject.update")
private void update() throws SQLException {
    [...]
}

Просьба сообщить, как сделать аннотации @Timed и другие метрики в обычном Java-приложении.

Дополнительная информация: Причина, по которой я нахожу это странным, заключается в том, что я добавил структуру Lombok, и аннотации @Slf4j работают. Я добавил Lombok как зависимость в maven pom.xml:

<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.14.8</version>
</dependency>

И я могу использовать аннотацию класса @Sl4fj для добавления регистратора в класс без загромождения переменных-членов:

@Slf4j
public class App {
  public void logsome(){
    log.info("Hello there");
  }
}

Итак, если это возможно, просто добавив зависимость, я считаю, что просто не хватает зависимости или конфигурации, чтобы получить работу аннотации codahale @Timed, как описано выше.

(кстати, проверьте Ломбок, это облегчит вашу жизнь: http://projectlombok.org/)

Ответ 1

Короче говоря, вы не можете использовать @Timed без какого-либо AOP (будь то Spring AOP или AspectJ).

Неделя или две назад я также решил добавить показатели к нашему проекту и выбрал AspectJ для этой задачи (главным образом потому, что я использовал его в прошлом для аналогичной цели и потому, что он позволяет компилировать время, когда Spring позволяет только время выполнения через прокси).

Здесь вы сможете найти всю необходимую информацию и инструкции: https://github.com/astefanutti/metrics-aspectj.

Что касается Lombok, я предполагаю, что они используют встроенный процессор аннотаций javac:

Еще одна точка зрения - реализация как кода, поддерживающего интеграцию IDE, так и процессора обработки аннотаций javac. Обе эти части проекта Lombok используют непубличные API для достижения своего колдовства. Это означает, что существует риск того, что Project Lombok будет разорван с последующими релизами IDE или JDK.

Ответ 2

Использование @Timed фактически не требует использования AOP, как ранее утверждалось в самом высоком ответе, если вы находитесь внутри контейнера и используете одну из библиотек инструментов Dropwizard. Например, см. Модуль Jersey 2.x, который вы можете увидеть, используя отражение (как и другие, на которые я смотрел), если вы читаете источник.

Вы можете прочитать все эти модули в документах Dropwizard под соответствующими марками "Instrumenting ____".

Я понимаю, что OP явно не работал в таком контейнере, но я хотел предложить эту информацию, так как многие из нас, которые ищут этот ответ, могут работать над современной веб-службой, которая может регистрировать такие ресурсы в своей среде выполнения.

Ответ 3

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

@Override
public void initialize(final Bootstrap<Configuration> bootstrap) {
    final JmxReporter reporter = JmxReporter.forRegistry(bootstrap.getMetricRegistry()).build();
    reporter.start();
}

Ответ 4

Как было сказано в другом ответе, вы должны иметь что-то в приложении для прослушивания ваших экземпляров и проверить их для аннотации @Timed.

Если вы используете Guice, вы можете использовать: https://github.com/palominolabs/metrics-guice

Ответ 5

AOP является излишним и не подходит для использования @timed, как правило, говоря.

Реестр метрик по умолчанию записывает метрики @timed в ConcurrentHashMap и не добавляет никаких значимых слушателей.

Конструктор DropStage DropWizard:

/**
 * Creates a new {@link Bootstrap} for the given application.
 * @param application a Dropwizard {@link Application}
 */
public Bootstrap(Application<T> application) {
    this.application = application;
    this.objectMapper = Jackson.newObjectMapper();
    this.bundles = Lists.newArrayList();
    this.configuredBundles = Lists.newArrayList();
    this.commands = Lists.newArrayList();
    this.validatorFactory = Validators.newValidatorFactory();


    // returns new ConcurrentHashMap<String, Metric>(); 
    this.metricRegistry = new MetricRegistry(); 


    this.configurationSourceProvider = new FileConfigurationSourceProvider();
    this.classLoader = Thread.currentThread().getContextClassLoader();
    this.configurationFactoryFactory = new DefaultConfigurationFactoryFactory<T>();
}

Итак, вам нужно создать/запустить/зарегистрировать соответствующий реестр метрик в чтобы увидеть результаты.

Здесь я использую JMX:

@Override
public void initialize(Bootstrap<PayloadStorageConfiguration> bootstrap) {
    JmxReporter.forRegistry(bootstrap.getMetricRegistry()).build().start();
}

Это все, что вам нужно сделать.

Здесь приведен пример вывода (запустите jconsole против вашего приложения Java/сервера для просмотра результатов JMX):

введите описание изображения здесь

Ответ 6

Для этого также можно использовать stagemonitor-core. Смотрите здесь здесь и здесь. Преимущество состоит в том, что stagemonitor (который является свободным и открытым исходным кодом) не зависит от каких-либо AOP, подобных AOP или AJB-перехватчикам. Он использует манипуляцию с байт-кодом через приложение времени выполнения, что означает, что вам даже не нужно добавлять флаг -javaagent к запуску вашего приложения - достаточно простой зависимости.

Если вы хотите измерить время выполнения в веб-приложении или в удаленном приложении EJB, вам даже не нужно вручную аннотировать ваш код. Кроме того, stagemonitor предлагает предварительно сконфигурированные приборные панели Grafana и Kibana.

Отказ от ответственности: я один из разработчиков stagemonitor

Ответ 7

В новых версиях Dropwizard (я использую 0.9.2) вы можете получить доступ по умолчанию MetricRegistry через среду настройки io.dropwizard.setup.Environment. У этого по умолчанию MetricRegistry уже есть связанный с ним InstrumentedResourceMethodApplicationListener, который прослушивает все показатели ваших ресурсов.

Если вы зарегистрировали ресурс с JerseyEnvironment, как указано ниже,

environment.jersey().register(resource);

вам нужно только аннотировать свой ресурсный метод (или класс) с помощью @Timed, @Metered или @ExceptionMetered, чтобы зарегистрировать соответствующие показатели.

@POST
@Timed
public String show() {
    return "yay";
}

Вы можете назначить Reporter (например, Slf4jReporter или JmxReporter) по умолчанию MetricRegistry, как в разделе

Slf4jReporter.forRegistry(environment.metrics()).build();

В качестве быстрого теста, чтобы проверить, действительно ли были зарегистрированы ваши показатели, вы можете сделать вызов GET на URL http://localhost:8081/metrics или соответствующий URL-адрес Admin Metrics в тестовой среде.

В некоторых других версиях вам необходимо явно зарегистрировать InstrumentedResourceMethodApplicationListener, как показано в этом документе