I'm using SmallRye implementation for Eclipse Microprofile Metrics in a project that uses Quarkus at version 1.7.3. I need to collect a random Integer value returned by a method in an ApplicationScoped class as a metric, but when I use @Gauge the method is invoked by the metrics infrastructure. It doesn't work for me because I need to provide a parameter to that method so it can make sense. Is there a way to collect this metric when the method is invoked by my own application and not by the Microprofile implementation?
In my scenario I send an Item to an external API and wait for them to respond using my API. This is asynchronous, should take at least 2 minutes and an avarege of 5 to 6 minutes, but it can sometimes take several minutes. So when I receive the response I first retrieve the Item from my database and before I do whatever I need to do with it I call the method timeWaitingForResponseMinutes passing the Item I just retrieved from the database as a parameter:
@Gauge(name = "timeWaitingForResponseMinutes", description = "Time waiting for a response for the Item in minutes", unit = MetricUnits.NONE)
public Integer timeWaitingForResponseMinutes(Item item) {
Timestamp nowTimestamp = Timestamp.from(Instant.now());
long nowMilliseconds = nowTimestamp.getTime();
long itemMilliseconds = item.getTimestampItemSent().getTime();
Integer minutesWaiting = (int)((nowMilliseconds - itemMilliseconds) / (60 * 1000));
return minutesWaiting;
}
This Item has a java.sql.Timestamp field called timestampItemSent that I use to compare with current time. The @Gauge is not working like that since the method should have no parameters. I'm taking the error message: Unable to export metric company_controller_ItemController_timeWaitingForResponseMinutes: java.lang.IllegalArgumentException
Any help will be very much appreciated.
Essentially what you need is to time a span that is defined by two different methods in your code, one for starting the span and one for ending it. I do not think it is doable with annotations, it is doable however with a bit of programming. You can inject a metric in a CDI bean, so I would modify the timeWaitingForResponseMinutes
as follows:
import org.eclipse.microprofile.metrics.Timer;
import java.util.concurrent.TimeUnit;
@ApplicationScoped
public class MyResponseTimer {
@Inject
@Metric(name = "timeWaitingForResponseMinutes", description = "Time waiting for a response for the Item in minutes", unit = MetricUnits.MINUTES)
private Timer timer;
public void timeWaitingForResponseMinutes(Item item) {
Timestamp nowTimestamp = Timestamp.from(Instant.now());
long nowMilliseconds = nowTimestamp.getTime();
long itemMilliseconds = item.getTimestampItemSent().getTime();
long minutesWaiting = ((nowMilliseconds - itemMilliseconds) / (60 * 1000));
timer.update(minutesWaiting, TimeUnit.MINUTES);
}
}
Now inject this bean and just call timeWaitingForResponseMinutes
as you wanted, passing your Item
. (You will see many pieces of your own code, note however that I changed the unit of the metric to MINUTES to make sense)