0

I have a java REST service developed using Quarkus.

Now I'm trying to add some metrics to the service using the MicroProfile Metrics supported by Quarkus Metrics Implementation.

My goal is to use a Counter metric to count the number of exceptions thrown in the application.

Hence, I have added the required annotation to mark the Exception (I have implemented a custom exception) constructor to be registered as a Counted metric. Currently, my code looks like this.

public class MyException extends RuntimeException {

   @Counted(name = "errorCounterMetric", description = "Meter metric for exception description")
   public MyException(final String errorMsg, final Throwable exception) {
      super(errorMsg, exception);
   }

}

So, every time the above exception constructer is called, the relevant counter metric should also be increased by 1.

However, the problem is that the MicroProfile metrics endpoint always shows the value of the above metric as 0, regardless of the number of times the exception is raised.

Can someone help me to understand the problem here, or whether there is a better approach to achieve the same outcome?

gayashanbc
  • 937
  • 1
  • 15
  • 30

1 Answers1

3

In Quarkus, the @Counted annotation is implemented as a CDI (Contexts and Dependency Injection) interceptor. It requires the annotated object to be a managed bean (such that it can be wrapped in a proxied object to allow method invocations to be intercepted).

An exception isn't usually a bean (and you don't usually want to create/manage exceptions using a CDI bean lifecycle). If I attempt your example, CDI wants more information so that it can construct the intercepted bean (which is clearly not your intent):

Caused by: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type java.lang.String and qualifiers [@Default]
        - java member: ....CountedException#<init>()
        - declared on CLASS bean [types=[java.io.Serializable, java.lang.Exception, java.lang.Throwable, ....CountedException, java.lang.RuntimeException, java.lang.Object], qualifiers=[@Default, @Any], target=....CountedException]

What I believe you want to do is simply count how many times this kind of exception is created. For this, you should skip trying to use annotations, and just use a counter directly, e.g. using the Micrometer extension:

public class CountedException extends RuntimeException {
    public CountedException(final String errorMsg, final Throwable exception) {
        super(errorMsg, exception);
        Metrics.counter("errorCounterMetric").increment();
    }
}

Using MP Metrics is similar:

public class CountedException extends RuntimeException {
    public CountedException(final String errorMsg, final Throwable exception) {
        super(errorMsg, exception);
        MetricRegistries.get(Type.APPLICATION).counter("errorCounterMetric").inc();
    }
}

Same outcome, but you avoid lifecycle confusion around beans.

As an interesting aside, this would allow you to record more information about why these exceptions are being created.

For example (using micrometer naming conventions, too):

public class CountedException extends RuntimeException {
    public CountedException(final String errorMsg, final Throwable exception) {
        super(errorMsg, exception);
        String cause = exception == null ? "null" : exception.getClass().getSimpleName();
        Metrics.counter("error.counter.metric", "cause", cause).increment();
    }
}

or MP Metrics:

public class CountedException extends RuntimeException {
    public CountedException(final String errorMsg, final Throwable exception) {
        super(errorMsg, exception);
        String cause = exception == null ? "null" : exception.getClass().getSimpleName();
        MetricRegistries.get(Type.APPLICATION).counter("errorCounterMetric", new Tag("cause", cause)).inc();
    }
}

This should still have a nicely bounded cardinality, but (making something up) you would get a view of how often this exception was created to wrap a NullPointerException, or an IOException, or a null, or...

ebullient
  • 1,250
  • 7
  • 16