Unified metrics support for helidon and javalin
Closed this issue · 3 comments
I'm using the helidon generator and everything works as expected, but If I want to add metrics I need to manually intrument the Controller class in order to support for instance timers for each endpoint.
It would be great if we could use some sort of annotations in the generator in order to support automatic metric instrumentation.
I know avaje-metrics might have something like that, but that's the avaje lib I have the least experience with. (I use the OTEL/newrelic java agent mainly). @rbygrave would know more about it.
automatic metric instrumentation.
avaje-metrics automatically instruments all @Controller
(plus all "components" be they Spring Components, avaje-inject components [@Singleton
, @Component
] or JEE Components @Stateless
etc.
So this is how I do it. The docs are poor / outdated / need work.
That is, we don't need any extra annotations, just enable avaje-metrics enhancement.
I use avaje-metrics because it is a lot lighter than other metrics libs (Dropwizard, Micrometer etc), and so the "instrument ALL public methods of ALL components in the application" is completely acceptable [in terms of extra memory consumption and cpu overhead].
Dependency - avaje metrics with publishing to graphite
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-metrics-graphite</artifactId>
<version>9.4</version>
</dependency>
In maven / build / plugins
<plugin> <!-- perform avaje metrics enhancement -->
<groupId>io.avaje.metrics</groupId>
<artifactId>metrics-maven-plugin</artifactId>
<version>9.3</version>
<extensions>true</extensions>
</plugin>
mvn clean process-classes
... and you will see output showing the classes that were instrumented
...
[INFO] --- enhance:9.3:enhance (default-enhance) @ myapplication ---
[INFO] classSource=... classDestination=...manifestPackages=[] classPathSize:65
[INFO] Add timed metric app.MyService.doStuff
[INFO] Add timed metric app.MyOtherService.alsoDoThings
...
Build a GraphiteReporter
String environment = "dev"; // ....
return GraphiteReporter.builder()
.prefix(environment + ".myApplicationName.")
.hostname(grafanaHost)
.port(grafanaPort)
.database(myEbeanDatabase) // optional if you are using ebean orm, also report all the query execution metrics etc
.build();
Report the metrics periodically:
graphiteReporter.report()
Using Lambda? We probably want to use ScheduledTask to support sending metrics in the background and handling lambda suspending. That is, prevent suspending the lambda when part way through background metrics reporting [wait for background metrics reporting to complete if it is in progress. If the lambdas are long living then this isn't that necessary].
// (1) create a io.avaje.metrics.ScheduledTask (a helper for periodic reporting metrics when using lambda)
var scheduledTask = ScheduledTask.builder()
.schedule(60, 60, TimeUnit.SECONDS)
.task(graphiteReporter::report)
.build();
// (2) start it (once)
scheduledTask.start();
// (3) at the end of a lambda execution ...
// ... wait for the metrics reporting to complete if it is active.
scheduledTask.waitIfRunning(2000, TimeUnit.MILLISECONDS);
try {
// perform lambda execution
} finally {
scheduledTask.waitIfRunning(2000, TimeUnit.MILLISECONDS);
}
Many Thanks!