43

I am trying to add metrics to a plain Java application using codahale metrics. I'd like to use the @Timed annotation, but it is unclear to me which MetricRegistry it uses, or how to tell it which MetricRegistry to use. The application is a plain Java 8 application, built with Maven 3, no Spring, no Hibernate.

I can not find any documentation on how to implement @Timed in the dropwizard documentation: https://dropwizard.github.io/metrics/3.1.0/manual/

I've added these dependencies:

<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>

When I use a programatic call to Timer, I can get reports because I know which MetricsRegistry is used:

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

But when I use the much more elegant @Timed annotation, I have no idea which registry is used, and therefore I can not create a reporter, which means I can not get the metrics reported (I'm not even sure if this actually does anything):

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

Please advise on how to make the @Timed and other Metrics annotations work in a regular Java application.

Additional info: The reason I am finding this strange is that I have added the Lombok framework and the @Slf4j annotations do work. I added Lombok as a dependency in the maven pom.xml:

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

And I can use the @Sl4fj class annotation to add a logger to the class without cluttering up the member variables:

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

So if that's possible by just adding a dependency, I reckon I am just missing a dependency or configuration to get the codahale @Timed annotation work, as described above.

(by the way, check out Lombok, it will make your life easier: http://projectlombok.org/ )

4

8 回答 8

19

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

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

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

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

另一个争论点是支持 IDE 集成的代码以及 javac 注释处理器的实现。这两个项目 Lombok 都使用非公共 API 来完成他们的魔法。这意味着 Project Lombok 存在被后续 IDE 或 JDK 版本破坏的风险。

于 2015-02-14T11:35:48.090 回答
12

如果您在容器内并使用 Dropwizard 的仪器库之一,则使用@Timed实际上并不需要使用 AOP,正如之前在顶级答案中所声称的那样。例如,请参阅 Jersey 2.x 模块,如果您阅读源代码,您可以看到它使用反射(就像我看过的其他模块一样)。

您可以在Dropwizard 文档中相应的“ Instrumenting ____ ”项目符号下阅读所有这些模块。

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

于 2016-08-23T16:05:50.037 回答
5

使用从应用程序类的初始化方法中的引导参数访问的内置 MetricRegistry。

@Override
public void initialize(final Bootstrap<Configuration> bootstrap) {
    final JmxReporter reporter = JmxReporter.forRegistry(bootstrap.getMetricRegistry()).build();
    reporter.start();
}
于 2015-08-04T19:21:31.213 回答
4

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

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

于 2015-03-08T01:27:49.707 回答
3

一般来说,AOP 是矫枉过正,不适合使用@timed。

默认指标注册表将@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>();
}

因此,您需要构建/启动/注册适当的指标注册表才能看到结果。

这里我使用 JMX:

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

这就是你需要做的。

这是一个输出示例(针对您的 Java 应用程序/服务器运行 jconsole 以查看 JMX 结果):

在此处输入图像描述

于 2016-03-22T23:14:51.830 回答
1

这个简单/直接的示例https://karollotkowski.wordpress.com/2015/10/19/api-endpoint-in-one-minute-with-dropwizard/只是表明它只需要注释

在此处输入图像描述

于 2018-04-16T20:01:24.600 回答
0

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

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

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

于 2016-05-19T09:33:16.983 回答
0

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

如果你已经在下面注册了一个资源JerseyEnvironment

environment.jersey().register(resource);

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

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

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

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

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

其他一些版本要求您显式注册一个InstrumentedResourceMethodApplicationListener,如本文档中所示

于 2017-07-07T15:38:13.640 回答