Quarkus Micrometer deployment module that provides build-time processing for metrics collection and monitoring capabilities in Quarkus applications
—
Compatibility layer providing seamless migration from MicroProfile Metrics to Micrometer, enabling existing applications to use MicroProfile Metrics annotations while leveraging Micrometer's backend infrastructure.
Main processor that handles MicroProfile Metrics API compatibility and annotation transformation.
/**
* Deployment processor for MicroProfile Metrics API compatibility
*/
@BuildSteps
public class MicroprofileMetricsProcessor {
/**
* Adds MP Metrics API dependency to Jandex index
* @return IndexDependencyBuildItem for MP Metrics API
*/
@BuildStep(onlyIf = MicroprofileMetricsEnabled.class)
public IndexDependencyBuildItem addDependencies();
/**
* Enables auto-injection of @Metric annotations
* @return AnnotationsTransformerBuildItem for @Metric injection
*/
@BuildStep(onlyIf = MicroprofileMetricsEnabled.class)
public AnnotationsTransformerBuildItem autoInjectMetric();
/**
* Registers MP Metrics beans for CDI
* @return AdditionalBeanBuildItem with MP Metrics bean classes
*/
@BuildStep(onlyIf = MicroprofileMetricsEnabled.class)
public AdditionalBeanBuildItem registerBeanClasses();
/**
* Logs compatibility warnings for MP Metrics usage
* @param indexBuildItem Combined index for annotation scanning
*/
@BuildStep(onlyIf = MicroprofileMetricsEnabled.class)
public void logWarningForMpMetricsUsage(CombinedIndexBuildItem indexBuildItem);
/**
* Adds @Dependent scope to metrics beans
* @return AnnotationsTransformerBuildItem for scope transformation
*/
@BuildStep(onlyIf = MicroprofileMetricsEnabled.class)
public AnnotationsTransformerBuildItem transformBeanScope();
/**
* Processes MP Metrics annotations and generates adapter classes
* @param indexBuildItem Combined index for annotation processing
* @param generatedClasses Producer for generated class build items
*/
@BuildStep(onlyIf = MicroprofileMetricsEnabled.class)
public void processAnnotatedMetrics(
CombinedIndexBuildItem indexBuildItem,
BuildProducer<GeneratedClassBuildItem> generatedClasses
);
/**
* Configures MP Metrics registry adapter
* @param rootRegistry Root meter registry build item
* @return SyntheticBeanBuildItem for registry adapter
*/
@BuildStep(onlyIf = MicroprofileMetricsEnabled.class)
@Record(ExecutionTime.RUNTIME_INIT)
public SyntheticBeanBuildItem configureRegistry(
RootMeterRegistryBuildItem rootRegistry
);
// Enablement condition
public static class MicroprofileMetricsEnabled implements BooleanSupplier;
}Utility class providing DotName constants for all MicroProfile Metrics annotations.
/**
* Constants for MicroProfile Metrics DotNames and utilities
*/
public final class MetricDotNames {
// Package constant
public static final String MICROMETER_EXTENSION_PKG = "io.quarkus.micrometer.runtime.binder.mpmetrics";
// MP Metrics binder
public static final DotName MP_METRICS_BINDER = DotName
.createSimple("io.quarkus.micrometer.runtime.binder.mpmetrics.MpMetricsBinder");
// MP Metrics annotation DotNames
public static final DotName CONCURRENT_GAUGE_ANNOTATION = DotName
.createSimple("org.eclipse.microprofile.metrics.annotation.ConcurrentGauge");
public static final DotName COUNTED_ANNOTATION = DotName
.createSimple("org.eclipse.microprofile.metrics.annotation.Counted");
public static final DotName GAUGE_ANNOTATION = DotName
.createSimple("org.eclipse.microprofile.metrics.annotation.Gauge");
public static final DotName METERED_ANNOTATION = DotName
.createSimple("org.eclipse.microprofile.metrics.annotation.Metered");
public static final DotName SIMPLY_TIMED_ANNOTATION = DotName
.createSimple("org.eclipse.microprofile.metrics.annotation.SimplyTimed");
public static final DotName TIMED_ANNOTATION = DotName
.createSimple("org.eclipse.microprofile.metrics.annotation.Timed");
// Registry and metrics DotNames
public static final DotName METRIC_REGISTRY = DotName
.createSimple("org.eclipse.microprofile.metrics.MetricRegistry");
public static final DotName METRIC_ANNOTATION = DotName
.createSimple("org.eclipse.microprofile.metrics.annotation.Metric");
public static final DotName METRIC = DotName
.createSimple("org.eclipse.microprofile.metrics.Metric");
public static final DotName ANNOTATED_GAUGE_ADAPTER = DotName
.createSimple("io.quarkus.micrometer.runtime.binder.mpmetrics.AnnotatedGaugeAdapter");
// JAX-RS and REST related DotNames
public static final DotName JAXRS_PATH = DotName.createSimple("jakarta.ws.rs.Path");
public static final DotName REST_CONTROLLER = DotName
.createSimple("org.springframework.web.bind.annotation.RestController");
// Interceptor and producer DotNames
public static final DotName CONCURRENT_GAUGE_INTERCEPTOR = DotName
.createSimple("io.quarkus.micrometer.runtime.binder.mpmetrics.ConcurrentGaugeInterceptor");
public static final DotName COUNTED_INTERCEPTOR = DotName
.createSimple("io.quarkus.micrometer.runtime.binder.mpmetrics.CountedInterceptor");
public static final DotName INJECTED_METRIC_PRODUCER = DotName
.createSimple("io.quarkus.micrometer.runtime.binder.mpmetrics.InjectedMetricProducer");
public static final DotName TIMED_INTERCEPTOR = DotName
.createSimple("io.quarkus.micrometer.runtime.binder.mpmetrics.TimedInterceptor");
public static final DotName MP_METRICS_REGISTRY_PRODUCER = DotName
.createSimple("io.quarkus.micrometer.runtime.binder.mpmetrics.MpMetricsRegistryProducer");
// Set of all individual metric annotation DotNames
public static final Set<DotName> individualMetrics = new HashSet<>(Arrays.asList(
CONCURRENT_GAUGE_ANNOTATION,
COUNTED_ANNOTATION,
GAUGE_ANNOTATION,
METERED_ANNOTATION,
SIMPLY_TIMED_ANNOTATION,
TIMED_ANNOTATION
));
/**
* Check if annotation map contains any MP Metrics annotations
* @param annotations Map of annotations to check
* @return true if any MP Metrics annotations are present
*/
public static boolean containsMetricAnnotation(Map<DotName, List<AnnotationInstance>> annotations);
/**
* Check if class is a known metrics subsystem class
* @param classInfo Class information to analyze
* @return true if class is part of metrics subsystem
*/
public static boolean knownClass(ClassInfo classInfo);
/**
* Check if class is single-instance (REST endpoint or singleton scope)
* @param classInfo Class information to analyze
* @return true if class is single-instance
*/
public static boolean isSingleInstance(ClassInfo classInfo);
}Utility class for transforming MicroProfile Metrics annotations to Micrometer equivalents.
/**
* Utility for transforming MP Metrics annotations for Micrometer compatibility
*/
public final class AnnotationHandler {
/**
* Creates annotation transformer for single annotation type
* @param index Jandex index for annotation scanning
* @param sourceAnnotation Source MP Metrics annotation to transform
* @return AnnotationTransformerBuildItem for transformation
*/
public static AnnotationTransformerBuildItem transformAnnotations(
IndexView index,
DotName sourceAnnotation
);
/**
* Creates annotation transformer with source and target annotations
* @param index Jandex index for annotation scanning
* @param sourceAnnotation Source MP Metrics annotation
* @param targetAnnotation Target Micrometer annotation
* @return AnnotationTransformerBuildItem for transformation
*/
public static AnnotationTransformerBuildItem transformAnnotations(
IndexView index,
DotName sourceAnnotation,
DotName targetAnnotation
);
/**
* Removes @Counted annotation when @Timed is present (avoids duplication)
* @param index Jandex index for annotation scanning
* @return AnnotationTransformerBuildItem for removing conflicting annotations
*/
public static AnnotationTransformerBuildItem removeCountedWhenTimed(IndexView index);
}Specialized handler for processing @Gauge annotations and generating adapter classes.
/**
* Handler for @Gauge annotation processing and adapter class generation
*/
public final class GaugeAnnotationHandler {
/**
* Processes all @Gauge annotations and generates adapter classes
* @param index Jandex index for annotation scanning
* @param generatedClasses Producer for generated class build items
*/
public static void processAnnotatedGauges(
IndexView index,
BuildProducer<GeneratedClassBuildItem> generatedClasses
);
/**
* Creates adapter class for specific @Gauge annotation
* @param method Method annotated with @Gauge
* @param gauge The @Gauge annotation instance
* @param generatedClasses Producer for generated class build items
*/
public static void createClass(
MethodInfo method,
AnnotationInstance gauge,
BuildProducer<GeneratedClassBuildItem> generatedClasses
);
}Data class that processes and normalizes MicroProfile Metrics annotation attributes.
/**
* Processes and normalizes MP Metrics annotation attributes
*/
public final class MetricAnnotationInfo {
/** Processed metric name */
public final String name;
/** Metric description */
public final String description;
/** Metric unit */
public final String unit;
/** Processed tags array */
public final String[] tags;
/**
* Constructor that processes annotation attributes
* @param annotation The MP Metrics annotation instance
* @param classInfo Class containing the annotation
*/
public MetricAnnotationInfo(AnnotationInstance annotation, ClassInfo classInfo);
/**
* Returns processed annotation values as array
* @return String array with name, description, unit, and tags
*/
public String[] getAnnotationValues();
/**
* Static utility for metric name concatenation
* @param prefix Name prefix
* @param suffix Name suffix
* @return Concatenated metric name
*/
public static String append(String prefix, String suffix);
/**
* Static utility for processing tag attributes
* @param annotation Annotation containing tag information
* @return Processed tags array
*/
public static String[] createTags(AnnotationInstance annotation);
}Usage Examples:
// Example MP Metrics annotations that are automatically transformed:
@Timed(name = "process_duration", description = "Time to process request")
@Counted(name = "process_count", description = "Number of processed requests")
public class ProcessingService {
@Gauge(name = "queue_size", unit = "items")
public int getQueueSize() {
return queue.size();
}
@Metered(name = "error_rate")
public void processWithErrorTracking() {
// Processing logic
}
}
// The compatibility layer automatically transforms these to Micrometer equivalents:
// @Timed -> @io.micrometer.core.annotation.Timed
// @Counted -> @io.micrometer.core.annotation.Counted
// @Gauge -> Generated adapter class + Micrometer Gauge registration
// @Metered -> Micrometer meter registrationAnnotation Transformation Examples:
// Custom extension using MP Metrics compatibility
@BuildSteps
public class CustomMpMetricsProcessor {
@BuildStep(onlyIf = MicroprofileMetricsProcessor.MicroprofileMetricsEnabled.class)
AnnotationTransformerBuildItem transformCustomAnnotations(CombinedIndexBuildItem index) {
return AnnotationHandler.transformAnnotations(
index.getIndex(),
DotName.createSimple("org.eclipse.microprofile.metrics.annotation.Timed")
);
}
@BuildStep
void processCustomGauges(
CombinedIndexBuildItem indexBuildItem,
BuildProducer<GeneratedClassBuildItem> generatedClasses
) {
GaugeAnnotationHandler.processAnnotatedGauges(
indexBuildItem.getIndex(),
generatedClasses
);
}
}
// Checking for MP Metrics usage
@BuildStep
void validateMetricsUsage(CombinedIndexBuildItem indexBuildItem) {
Collection<AnnotationInstance> annotations = indexBuildItem.getIndex()
.getAnnotations(MetricDotNames.TIMED_ANNOTATION);
if (MetricDotNames.containsMetricAnnotation(annotations)) {
// Handle MP Metrics annotation presence
}
}Configuration Examples:
# Enable MicroProfile Metrics compatibility (enabled by default when MP Metrics API is present)
quarkus.micrometer.binder.mp-metrics.enabled=true
# Configure MP Metrics registry adapter
quarkus.micrometer.registry-config.add-mp-metrics-tags=true
# Enable compatibility warnings
quarkus.log.category."io.quarkus.micrometer.deployment.binder.mpmetrics".level=WARNThe MicroProfile Metrics compatibility layer provides seamless migration by:
Install with Tessl CLI
npx tessl i tessl/maven-io-quarkus--quarkus-micrometer-deployment