Codahale 指标:在普通 Java 中使用 @Timed 指标注释

Codahale Metrics: using @Timed metrics annotation in plain Java

我正在尝试使用 codahale 指标向普通 Java 应用程序添加指标。我想使用 @Timed 注释,但我不清楚它使用哪个 MetricRegistry,或者如何告诉它使用哪个 MetricRegistry。该应用程序是一个普通的 Java 8 应用程序,使用 Maven 3 构建,没有 Spring,没有 Hibernate。

我在 dropwizard 文档中找不到任何关于如何实现 @Timed 的文档: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 和其他 Metrics 注释在常规 Java 应用程序中工作。

附加信息:我觉得这很奇怪的原因是我添加了 Lombok 框架并且 @Slf4j 注释确实有效。我在 Maven pom.xml:

中添加了 Lombok 作为依赖项
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.14.8</version>
</dependency>

而且我可以使用@Sl4fj class 注释将记录器添加到 class 而不会弄乱成员变量:

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

因此,如果仅通过添加一个依赖项就可以做到这一点,我想我只是缺少一个依赖项或配置来使 codahale @Timed 注释正常工作,如上所述。

(顺便看看龙目岛,它会让你的生活更轻松:http://projectlombok.org/

长话短说,如果没有某种 AOP(无论是 Spring AOP 还是 AspectJ),您都无法使用 @Timed

一两周前,我还决定向我们的项目添加指标并选择 AspectJ 来完成这项任务(主要是因为我过去出于类似目的使用它,并且因为它允许编译时织入,而 Spring 仅允许通过代理运行。

您应该能够在这里找到所有必要的信息和说明:https://github.com/astefanutti/metrics-aspectj

至于 Lombok,我猜他们使用内置的 javac 注释处理器:

Another point of contention is the implementation of both the code supporting IDE integration as well as the javac annotation processor. Both of these pieces of Project Lombok make use of non-public APIs to accomplish their sorcery. This means that there is a risk that Project Lombok will be broken with subsequent IDE or JDK releases.

正如另一个答案所述,您必须在应用程序中有一些东西来监听您的实例化 类 并检查它们是否有 @Timed 注释。

如果您使用的是 Guice,您可以使用:https://github.com/palominolabs/metrics-guice

Use the built-in MetricRegistry accessed from the bootstrap parameter in the initialize method of your application class.

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

AOP is overkill and not appropriate for use of @timed, generally speaking.

默认指标注册表将@timed 指标写入 ConcurrentHashMap 并且不附加任何有意义的侦听器。

DropWizard Bootstrap 构造函数:

/**
 * 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>();
}

So you need to build/start/register the appropriate metric registry in order to see results.

这里我用的是JMX:

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

这就是您需要做的全部。

这是一个输出示例(运行 jconsole 针对您的 Java application/server 查看 JMX 结果):

您也可以为此使用 stagemonitor-core。请参阅文档 here and here。优点是 stagemonitor(顺便说一句,它是免费和开源的)不依赖于任何基于容器的 AOP,例如 Spring AOP 或 EJB 拦截器。它通过运行时附件使用字节码操作,这意味着您甚至不必在应用程序启动时添加 -javaagent 标志 - 一个简单的依赖项就足够了。

如果您想测量 Web 应用程序或远程 EJB 应用程序中的执行时间,您甚至不必手动注释您的代码。此外,stagemonitor 还提供预配置的 Grafana 和 Kibana 仪表板。

免责声明:我是 stagemonitor 的开发者之一

如果您在容器内并使用 Dropwizard 的检测库之一,那么使用 @Timed 实际上并不需要使用 AOP,正如之前在评分最高的答案中所声称的那样。例如,请参阅 Jersey 2.x 模块,如果您阅读 source.

,您可以看到它使用了反射(就像我看过的其他模块一样)

您可以在 the Dropwizard docs 中相应的“Instrumenting ____”要点下阅读所有这些模块。

我知道 OP 显然不在这样的容器中工作,但我想提供此信息,因为我们中的许多人正在寻找这个答案可能正在使用现代 Web 服务,该服务可以在其运行时注册此类资源环境。

在较新的 Dropwizard 版本中(我使用的是 0.9.2),您可以通过设置环境 io.dropwizard.setup.Environment 访问默认值 MetricRegistry。这个默认 MetricRegistry 已经有一个 InstrumentedResourceMethodApplicationListener 与之关联,它会监听您资源的所有指标。

如果您已经使用 JerseyEnvironment 注册资源,

environment.jersey().register(resource);

您只需使用 @Timed@Metered@ExceptionMetered 注释您的资源方法(或 class)以注册相应的指标。

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

您可以将 Reporter(如 Slf4jReporterJmxReporter)分配给默认值 MetricRegistry,如

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

作为快速测试以查看您的指标是否已实际注册,您可以 GET 调用 URL http://localhost:8081/metrics 或相应的管理指标 URL 在您的测试环境中。

其他一些版本要求您显式注册 InstrumentedResourceMethodApplicationListener,如图 in this Doc

这个simple/right-to-the-point例子https://karollotkowski.wordpress.com/2015/10/19/api-endpoint-in-one-minute-with-dropwizard/只是展示了它只需要注释