Production-ready application metrics for GuicedEE using Vert.x 5 Dropwizard Metrics and the MicroProfile Metrics 5.1 API.
Annotate your methods with standard @Counted, @Timed, and custom @MetricMethod β interceptors are bound through Guice AOP, metrics are collected into a shared MetricRegistry, and a Prometheus-compatible scrape endpoint is exposed on the Vert.x Web Router automatically.
Built on Vert.x Dropwizard Metrics Β· MicroProfile Metrics Β· Dropwizard Metrics Β· Google Guice Β· JPMS module com.guicedee.metrics Β· Java 25+
<dependency>
<groupId>com.guicedee</groupId>
<artifactId>metrics</artifactId>
</dependency>Gradle (Kotlin DSL)
implementation("com.guicedee:metrics:2.0.0-SNAPSHOT")- MicroProfile Metrics annotations β
@Countedand@Timedare intercepted via Guice AOP and bridged to Dropwizard Metrics counters/timers - Custom
@MetricMethodβ annotate any method to auto-increment a named counter; if the method returns a numeric type the counter value is returned - Vert.x Dropwizard integration β
MetricsVertxConfiguratorconfiguresDropwizardMetricsOptionson theVertxBuilderbefore Vert.x starts, enabling built-in event bus, HTTP server/client, pool, and datagram metrics - Annotation-driven configuration β
@MetricsOptionson any class or package configures the registry name, JMX, base name, monitored URIs, Graphite, and Prometheus - Environment variable overrides β every
@MetricsOptionsattribute can be overridden via system properties or environment variables - Prometheus scrape endpoint β
PrometheusMetricsConfiguratorregisters aGET /metricshandler that renders all Dropwizard metrics in Prometheus exposition format - Graphite reporting β built-in
GraphiteReportersends metrics to a Graphite server at a configurable interval - JMX exposure β metrics are optionally published as JMX MBeans
- Extensible interceptors β implement the
MetricsSPI to register custom annotation β interceptor bindings discovered viaServiceLoader - Type-safe metric enumerations β
VertxMetrics,HttpServerMetrics,HttpClientMetrics,EventBusMetrics,PoolMetrics,NetServerMetrics,DatagramMetricsfor programmatic access - MicroProfile MetricRegistry bridge β
MPMetricRegistrywraps Dropwizard'sMetricRegistryso the standardorg.eclipse.microprofile.metrics.MetricRegistryis injectable
Step 1 β Annotate a configuration class with @MetricsOptions:
@MetricsOptions(
enabled = true,
jmxEnabled = true,
baseName = "my-app",
monitoredHttpServerUris = {
@Match(value = "/api/.*", type = Match.MatchType.REGEX, alias = "api-calls")
},
prometheus = @PrometheusOptions(enabled = true, endpoint = "/metrics")
)
public class MyAppConfig {
}Step 2 β Annotate methods with MicroProfile Metrics annotations:
import org.eclipse.microprofile.metrics.annotation.Counted;
import org.eclipse.microprofile.metrics.annotation.Timed;
public class OrderService {
@Counted(name = "orders-placed", tags = {"env=prod"})
public void placeOrder(Order order) {
// ... business logic
}
@Timed(name = "order-processing-time")
public void processOrder(Order order) {
// ... long-running logic
}
}Step 3 β Bootstrap GuicedEE (metrics start automatically):
IGuiceContext.registerModuleForScanning.add("my.app");
IGuiceContext.instance();
// Vert.x metrics are collecting
// GET /metrics returns Prometheus exposition formatNo JPMS provides declaration is needed β the metrics module is registered automatically via its own service providers.
IGuiceContext.instance()
ββ IGuicePreStartup hooks
ββ MetricsPreStartup.onStartup() (sortOrder = MIN_VALUE + 40)
ββ Scan for @MetricsOptions annotation via ClassGraph
ββ Resolve environment variable overrides
ββ VertxConfigurator SPIs (before Vert.x starts)
ββ MetricsVertxConfigurator.builder()
ββ Build DropwizardMetricsOptions from @MetricsOptions
ββ Configure monitored URIs, routes, event bus handlers, client endpoints
ββ Apply to VertxBuilder via VertxOptions.setMetricsOptions()
ββ Guice injector created
ββ MetricsModule.configure()
ββ bind(MetricRegistry.class) from SharedMetricRegistries
ββ bind(MP MetricRegistry.class) via MPMetricRegistryProvider
ββ Bind CountedInterceptor for @Counted
ββ Bind TimedInterceptor for @Timed
ββ Bind MetricMethodInterceptor for @MetricMethod
ββ Load Metrics SPI for custom interceptors
ββ Setup GraphiteReporter (if enabled)
ββ IGuicePostStartup hooks
ββ VertxWebServerPostStartup (from web module)
ββ PrometheusMetricsConfigurator.builder() (sortOrder = MIN_VALUE + 70)
ββ Register GET handler at prometheus endpoint path
Increments a monotonic counter each time the method is invoked:
@Counted(name = "api-requests", tags = {"endpoint=users"})
public List<User> getUsers() {
return userRepository.findAll();
}The annotation can be placed on the method or on the class (applies to all methods). If name is empty, it defaults to ClassName.methodName.
Measures method execution time with quantile snapshots:
@Timed(name = "db-query-time", tags = {"table=orders"})
public List<Order> queryOrders() {
return orderRepository.findAll();
}The timer records count, min, max, mean, and percentile distributions (p50, p75, p95, p98, p99, p999).
A custom GuicedEE annotation that increments a named counter. If the method returns a numeric type (long, int, double, float), the counter value is returned instead of the method's result:
@MetricMethod(name = "items-processed", tags = {"source=api"})
public long processItem(String itemName) {
// ... logic
return 0; // replaced with current counter value
}If the method has a String parameter, it is used as a dynamic name suffix. If name is empty, the string parameter becomes the metric name.
Place @MetricsOptions on any class or package to configure the metrics subsystem:
@MetricsOptions(
enabled = true,
registryName = "vertx",
jmxEnabled = true,
jmxDomain = "vertx",
baseName = "vertx",
monitoredHttpServerUris = {
@Match(value = "/api/.*", type = Match.MatchType.REGEX, alias = "api")
},
monitoredEventBusHandlers = {
@Match(value = "orders.*", type = Match.MatchType.REGEX)
},
graphite = @GraphiteOptions(
enabled = true,
host = "graphite.local",
port = 2003,
prefix = "my-app"
),
prometheus = @PrometheusOptions(
enabled = true,
endpoint = "/metrics",
port = 9090
)
)
public class MyAppConfig {
}| Attribute | Default | Description |
|---|---|---|
enabled |
true |
Enable or disable metrics collection |
registryName |
"vertx" |
Dropwizard SharedMetricRegistries name |
jmxEnabled |
true |
Expose metrics as JMX MBeans |
jmxDomain |
"vertx" |
JMX domain name |
baseName |
"vertx" |
Base prefix for all metric names |
monitoredEventBusHandlers |
{} |
Event bus addresses to monitor |
monitoredHttpServerUris |
{} |
HTTP server URIs to monitor |
monitoredHttpServerRoutes |
{} |
HTTP server routes to monitor |
monitoredHttpClientEndpoints |
{} |
HTTP client endpoints to monitor |
graphite |
disabled | Graphite reporter configuration |
prometheus |
disabled | Prometheus scrape endpoint configuration |
Each monitored URI/handler/route uses a @Match annotation:
| Attribute | Default | Description |
|---|---|---|
value |
(required) | Pattern to match (address, URI, etc.) |
type |
EQUALS |
EQUALS for exact match, REGEX for pattern match |
alias |
"" |
Optional alias for the metric name |
| Attribute | Default | Description |
|---|---|---|
enabled |
false |
Enable Graphite reporting |
host |
"localhost" |
Graphite server hostname |
port |
2003 |
Graphite pickle protocol port |
prefix |
"" |
Metric name prefix |
| Attribute | Default | Description |
|---|---|---|
enabled |
false |
Enable Prometheus scrape endpoint |
endpoint |
"/metrics" |
HTTP path for the scrape handler |
port |
9090 |
Prometheus port (informational) |
Every @MetricsOptions attribute can be overridden with a system property or environment variable:
| Variable | Overrides | Example |
|---|---|---|
METRICS_ENABLED |
enabled |
false |
METRICS_REGISTRY_NAME |
registryName |
my-registry |
METRICS_JMX_ENABLED |
jmxEnabled |
false |
METRICS_JMX_DOMAIN |
jmxDomain |
my-app |
METRICS_BASE_NAME |
baseName |
my-app |
METRICS_GRAPHITE_ENABLED |
graphite.enabled |
true |
METRICS_GRAPHITE_HOST |
graphite.host |
graphite.prod |
METRICS_GRAPHITE_PORT |
graphite.port |
2003 |
METRICS_GRAPHITE_PREFIX |
graphite.prefix |
prod.myapp |
METRICS_PROMETHEUS_ENABLED |
prometheus.enabled |
true |
METRICS_PROMETHEUS_ENDPOINT |
prometheus.endpoint |
/prom/metrics |
METRICS_PROMETHEUS_PORT |
prometheus.port |
9090 |
Environment variables take precedence over annotation values.
Both Dropwizard and MicroProfile registries are injectable:
import com.codahale.metrics.MetricRegistry;
import org.eclipse.microprofile.metrics.MetricRegistry;
public class MonitoringService {
@Inject
private com.codahale.metrics.MetricRegistry dropwizardRegistry;
@Inject
private org.eclipse.microprofile.metrics.MetricRegistry mpRegistry;
}Use type-safe enums to look up Vert.x metrics by name:
| Enum | Base name | Examples |
|---|---|---|
VertxMetrics |
vertx |
event-loop-size, worker-pool-size |
HttpServerMetrics |
vertx.http.servers.<host>:<port> |
requests, connections, responses-2xx |
HttpClientMetrics |
vertx.http.clients |
requests, endpoint.%s.ttfb |
EventBusMetrics |
vertx.eventbus |
handlers, messages.sent, messages.pending |
PoolMetrics |
vertx.pools.<type>.<name> |
queue-size, in-use, pool-ratio |
NetServerMetrics |
vertx.net.servers.<host>:<port> |
open-netsockets, bytes-read |
DatagramMetrics |
vertx.datagram |
sockets, bytes-written |
@Inject
com.codahale.metrics.MetricRegistry registry;
public long getActiveConnections() {
return registry.getCounters()
.get(HttpServerMetrics.CONNECTIONS.toString())
.getCount();
}Enums with placeholders provide a format() method:
// vertx.eventbus.handlers.orders
String name = EventBusMetrics.HANDLERS_ADDRESS.format("orders");Register custom annotations and their interceptors by implementing the Metrics SPI:
public class MyCustomMetrics implements Metrics {
@Override
public Map<Class<? extends Annotation>, Class<? extends MethodInterceptor>> annotations() {
return Map.of(MyGauged.class, MyGaugedInterceptor.class);
}
}Register via JPMS:
module my.app {
requires com.guicedee.metrics;
provides com.guicedee.metrics.Metrics
with my.app.MyCustomMetrics;
}The module declares uses Metrics; and discovers implementations via ServiceLoader. Each annotation β interceptor pair is bound in Guice AOP during MetricsModule.configure().
When @PrometheusOptions(enabled = true) is set, a GET handler is registered at the configured endpoint (default /metrics). The response is text/plain; version=0.0.4 in Prometheus exposition format:
# TYPE my_app_orders_placed counter
my_app_orders_placed 42
# TYPE my_app_order_processing_time_count summary
my_app_order_processing_time_count 15
# TYPE my_app_order_processing_time summary
my_app_order_processing_time{quantile="0.5"} 0.125
my_app_order_processing_time{quantile="0.95"} 0.350
my_app_order_processing_time{quantile="0.99"} 0.500
All metric types are rendered: gauges, counters, histograms (as summaries with quantiles), meters (count + rates), and timers (count + quantiles + rates).
A docker-compose.yml is provided for a local monitoring stack:
docker-compose up -dThis starts:
| Service | Port | Purpose |
|---|---|---|
| Graphite | 8080 (Web UI), 2003 (pickle) |
Metrics storage and graphing |
| Grafana | 3000 |
Dashboard visualization (login: admin/admin) |
| Prometheus | 9090 |
Metrics scraping and alerting |
- Login to Grafana at
http://localhost:3000 - Go to Connections β Data Sources
- Add Graphite with URL
http://graphite:80 - Add Prometheus with URL
http://prometheus:9090 - Click Save & Test
A prometheus.yml is included that scrapes host.docker.internal:9090/metrics every 15 seconds.
com.guicedee.metrics
βββ com.guicedee.guicedinjection (GuicedEE runtime β scanning, Guice, lifecycle)
βββ com.guicedee.client (GuicedEE SPI contracts)
βββ com.guicedee.vertx (Vert.x lifecycle β VertxConfigurator SPI)
βββ com.guicedee.vertx.web (Vert.x Web β Router, optional for Prometheus endpoint)
βββ io.vertx.metrics.dropwizard (Vert.x Dropwizard Metrics integration)
βββ com.codahale.metrics (Dropwizard Metrics core + Graphite reporter)
βββ io.vertx.core (Vert.x core)
βββ com.guicedee.modules.services.metrics (MicroProfile Metrics API β annotations, SPI)
Module name: com.guicedee.metrics
The module:
- exports
com.guicedee.metrics,com.guicedee.metrics.implementations,com.guicedee.metrics.enumerations,com.guicedee.metrics.implementations.mp - provides
IGuiceModulewithMetricsModule - provides
IGuicePreStartupwithMetricsPreStartup - provides
VertxConfiguratorwithMetricsVertxConfigurator - provides
VertxRouterConfiguratorwithPrometheusMetricsConfigurator - uses
Metrics(SPI for custom annotation interceptors)
| Class | Role |
|---|---|
MetricsOptions |
Annotation β configures registry, JMX, monitored URIs, Graphite, Prometheus |
Match |
Annotation β defines URI/address match patterns with EQUALS or REGEX type |
MetricMethod |
Annotation β marks a method as a counted metric with dynamic naming |
Metrics |
SPI β register custom annotation β interceptor bindings |
MetricsPreStartup |
IGuicePreStartup β scans for @MetricsOptions and resolves env overrides |
MetricsVertxConfigurator |
VertxConfigurator β applies DropwizardMetricsOptions to the VertxBuilder |
MetricsModule |
IGuiceModule β binds registries, interceptors, Graphite reporter |
CountedInterceptor |
Guice AOP MethodInterceptor for @Counted |
TimedInterceptor |
Guice AOP MethodInterceptor for @Timed |
MetricMethodInterceptor |
Guice AOP MethodInterceptor for @MetricMethod |
PrometheusMetricsConfigurator |
VertxRouterConfigurator β mounts the Prometheus scrape endpoint |
PrometheusMetricsHandler |
Handler<RoutingContext> β renders metrics in Prometheus exposition format |
MPMetricRegistryProvider |
Guice Provider β creates the MicroProfile MetricRegistry bridge |
Issues and pull requests are welcome β please add tests for new metric types or interceptors.