Dirac implémente MicroProfile Metrics 5.1.1, dont le vocabulaire fixe les quatre primitives Counter, Gauge, Histogram, Timer, leurs scopes (APPLICATION, BASE, VENDOR), et leur exposition en deux formats (OpenMetrics text et JSON). Cette page balaie ces choix et précise les invariants posés par l’implémentation Vidocq.

Les quatre types de métriques

MP Metrics 5.0 a simplifié la surface héritée des versions 1.x et 2.x : Meter, ConcurrentGauge et SimpleTimer ont été retirés. Restent quatre primitives :

Type Annotation Description

Counter

@Counted

Compteur monotone incrémental. Implémentation : LongAdder sans contention.

Gauge<T>

@Gauge

Valeur instantanée renvoyée par une méthode du bean. Résolu une fois au démarrage via MethodHandle, jamais par java.lang.reflect.Proxy.

Histogram

(non annotable dans le JAR API 5.1.1 utilisé)

Distribution de valeurs avec percentiles configurables (p50–p999 par défaut) et buckets optionnels.

Timer

@Timed

Durée d’invocation mesurée en System.nanoTime(), agrégée par un HistogramImpl interne. Format de sortie : summary OpenMetrics.

Le JAR microprofile-metrics-api:5.1.1 utilisé dans dirac-mp-metrics-api n’expose pas l’annotation @Histogram au niveau spec — les histogrammes sont registrés programmatiquement via MetricRegistry.histogram(…​), ou indirectement par @Timed.

Trois scopes obligatoires

La spec §1.3 distingue trois registres, alimentés et lus séparément :

Scope Rôle

APPLICATION

Métriques applicatives. Injectable sans qualifier (registre par défaut).

BASE

Métriques JVM standardisées : cpu.processCpuLoad, gc.total, memory.usedHeap, thread.count, classloader.loadedClasses.count, jvm.uptime. Peuplées par BaseMetricsRegistrar au démarrage.

VENDOR

Métriques propres au runtime — initialement vide côté Dirac, extensible.

Côté injection :

@Inject
MetricRegistry application;                              // APPLICATION par défaut

@Inject @RegistryScope(scope = MetricRegistry.BASE_SCOPE)
MetricRegistry base;

@Inject @RegistryScope(scope = MetricRegistry.VENDOR_SCOPE)
MetricRegistry vendor;

Identité d’une métrique : MetricID

Le couple (name, tags) est l’identité unique. Deux compteurs portant le même nom mais des tags différents sont des métriques distinctes ; deux compteurs portant le même nom et les mêmes tags sont la même métrique.

counter("http_requests_total", new Tag("method", "GET"));
counter("http_requests_total", new Tag("method", "POST"));
// → deux Counter distincts, agrégés dans la même famille OpenMetrics

MetricID est un record immuable. Le registre est un ConcurrentHashMap<MetricID, Metric> par scope.

Tags

Les tags sont des paires (clé, valeur) arbitraires. Trois sources se combinent :

  1. Tags d’annotation — fixés au moment de la déclaration : @Counted(tags = "endpoint=orders").

  2. Tags globaux applicatifs — clé mp.metrics.tags, p. ex. mp.metrics.tags=app=orders,env=prod. Ajoutés à toutes les métriques de l’application.

  3. Tag mp_scope — injecté automatiquement par le formatter OpenMetrics avec la valeur du scope (application, base, vendor).

L’unicité d’une métrique se calcule sur l’union de ces tags après application des règles spec §3.

Formats d’exposition

Deux formats sont produits par dirac-core, tous deux écrits à la main avec StringBuilder :

Format Détail

OpenMetrics / Prometheus text

Content-Type text/plain;version=0.0.4. Lignes # HELP, # TYPE, puis échantillons. Émis par OpenMetricsFormatter. Format par défaut sans Accept.

JSON

Content-Type application/json. Arborescence MP Metrics §3.2 — un objet par scope, contenant un objet par métrique. Émis par JsonMetricsFormatter, sans moteur JSON tiers, dans l’esprit de Champollion.

La négociation de contenu est portée par MetricsEndpoint (Référence).

Configuration de la distribution

Les histogrammes et les minuteries lisent trois clés mp.metrics.distribution.* via MicroProfile Config :

Clé Effet

mp.metrics.distribution.percentiles

Liste de percentiles (0.5,0.95,0.99) émis par les snapshots — globale, ou par métrique via la forme nom=valeurs.

mp.metrics.distribution.histogram.buckets

Buckets fixes pour les Histogram — globale ou par métrique.

mp.metrics.distribution.timer.buckets

Buckets fixes pour les Timer, exprimés en ms, s, ns etc. — globale ou par métrique.

Une valeur vide (mp.metrics.distribution.percentiles=) désactive complètement les percentiles. L’application est portée par DistributionConfig dans dirac-core.

Endpoint REST GET /metrics

Quand dirac-rest et Cassini sont sur le classpath, trois chemins sont exposés :

Route Effet

GET /metrics

Tous les scopes, format négocié sur Accept.

GET /metrics/{scope}

Un seul scope (application | base | vendor). 404 si inconnu.

GET /metrics/{scope}/{name}

Une seule famille de métriques. 404 si introuvable.

L’endpoint est optionnel : si dirac-rest n’est pas déclaré, les métriques restent accessibles programmatiquement via MetricRegistry.

Pour aller plus loin