Spring Boot publie des informations et métriques sur le déploiement et le fonctionnement d’une application avec Actuator.
Configuration
Pour activer Actuator, on ajoute une dépendance vers son starter.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Actuator a nativement un ensemble de endpoints qu’il publie en Web ou en JMX. Par défaut, seul le endpoint Health est publié.
Web endpoints
Le endpoint racine /actuator
donne la liste des endpoints, avec leur URL.
On l’appelle la page de découverte et elle peut être désactivée.
management.endpoints.web.discovery.enabled=false
Il faut noter que ce contexte est relatif au contexte racine de l’application défini par server.servlet.context-path
.
Il peut être modifié et cette modification est répercutée sur tous les endpoints.
management.endpoints.web.base-path=/management
On peut aussi modifier le port. Dans ce cas, l’URL d’accès ne contient plus le contexte racine de l’application, mais celui du management qui est vide par défaut.
management.server.port=9999
management.server.base-path=/xxx
Par défaut, seul le endpoint Health est publié, en version simplifiée. On peut publier explicitement chaque endpoint en Web, inclure l’ensemble de ceux qui sont actifs ou en exclure certains.
management.endpoints.web.exposure.include=metrics,info
#ou
management.endpoints.web.exposure.include='*'
management.endpoints.web.exposure.exclude=health,beans
La liste des endpoints actifs par défaut dépend de l’applications. Les suivants sont systématiquement (ou souvent) présents pour connaître l’état de l’application :
Les suivants sont systématiquement (ou souvent) présents pour le débogage d’un déploiement :
-
/info : informations statiques de l’application
-
/mappings : liste des endpoints applicatifs
-
/beans, /conditions, /configprops, /env : pour déboguer un déploiement, liste de composants Spring dans le contexte, évaluation des conditions pour l’auto-configuration, données utilisées pour les classes annotées avec
@ConfigurationProperties
et contenu duConfigurableEnvironment
-
/scheduledtasks, /quartz : tâches planifiées
-
/loggers : liste et configuration des loggers
-
/liquibase, /flyway : initialisations de la base de données par Liquibase ou Flyway
Les endpoints suivants ne sont publiés que dans certaines conditions.
-
/startup ; fournit les étapes de démarrage si l’application est configurée avec un
BufferingApplicationStartup
-
/shutdown : arrêt de l’application avec une requête POST ; doit être activé explicitement et CSRF désactivé
-
/httpexchanges[1], /httptrace[2] : échanges requête/réponse HTTP, s’il y a un bean `HttpExchangeRepository`[1] ou `HttpTraceRepository`[2]
-
/sessions : gestion des sessions pour une application stateful
-
/auditevents : événement d’audit, s’il y a un bean
AuditEventRepository
-
/integrationgraph : avec Spring Integration
Les chemins des différents endpoints peuvent aussi être reconfigurés.
Par exemple pour /health
:
management.endpoints.web.path-mapping.health=healthcheck
Chaque endpoint activé par défaut peut être désactivé dans la configuration.
Par exemple pour /health
:
management.endpoint.health.enabled=false
A contrario, un endpoint désactivé par défaut, peut être activé.
management.endpoint.shutdown.enabled=true
D’autres endpoints peuvent être ajoutés via des librairies ou développements personnalisés.
Health
Le endpoint /health
est activé par défaut.
Par défaut, ce endpoint ne donne qu’une information globale.
~$ curl http://localhost:9999/actuator/health
{"status":"UP"}
On peut le configurer pour avoir le détail.
management.endpoint.health.show-details: always
~$ curl http://localhost:9999/actuator/health
{
"status":"UP",
"components": {
"db":{
"status":"UP",
"details":{
"database":"PostgreSQL",
"validationQuery":"isValid()"
}
},
"diskSpace": {
"status":"UP",
"details": {
"total":502392610816,
"free":381957959680,
"threshold":10485760,
"exists":true
}
},
"ping":{
"status":"UP"
}
}
}
Metrics
Le endpoint /metrics
est activé par défaut.
Sa racine fournit une liste de noms, sans valeur.
~$ curl http://localhost:9999/actuator/metrics
{
"names": [
"application.ready.time",
"application.started.time",
"disk.free",
"disk.total",
"executor.active",
"executor.completed",
"executor.pool.core",
"executor.pool.max",
"executor.pool.size",
...
]
}
La structure des noms est unidimensionnelle, à la façon de prometheus.
Les informations les plus couramment utilisées concernent la ou les datasource(s) (hikaricp.connections.*
), la mémoire (jvm.memory.*
), le ramasse-miettes (jvm.gc.*
) ou la CPU (process.cpu.usage
).
Chaque nom peut ensuite être utilisé pour accéder à une métrique.
~$ curl http://localhost:9999/metrics/jvm.memory.used
{
"name": "jvm.memory.used",
"description": "The amount of used memory",
"baseUnit": "bytes",
"measurements": [
{
"statistic": "VALUE",
"value": 383617384
}
],
"availableTags": [
{
"tag": "area",
"values": [
"heap",
"nonheap"
]
},
{
"tag": "id",
"values": [
"G1 Survivor Space",
"Compressed Class Space",
"Metaspace",
"CodeCache",
"G1 Old Gen",
"G1 Eden Space"
]
}
]
}
Comme on le voit dans cet exemple, les métriques sont organisées via des tags, qu’on peut utiliser en paramètre des requêtes.
~$ curl http://localhost:9999/actuator/metrics/jvm.memory.used?tag=area:heap
{
"name": "jvm.memory.used",
"description": "The amount of used memory",
"baseUnit": "bytes",
"measurements": [
{
"statistic": "VALUE",
"value": 132698240
}
],
"availableTags": [
{
"tag": "id",
"values": [
"G1 Survivor Space",
"G1 Old Gen",
"G1 Eden Space"
]
}
]
}
Métriques Spring MVC
La métrique http.server.requests
des requêtes traitées par Spring MVC est activée par défaut.
Elle peut être désactivée dans la configuration.
management.metrics.web.server.request.autotime.enabled=false
Sans tag, elle fournit des statistique globales, avec le nombre de requêtes traitées, le temps total de traitement et la durée de traitement maximal pour une requête.
~$ curl http://localhost:9999/actuator/metrics/http.server.requests
{
"name": "http.server.requests",
"baseUnit": "seconds",
"measurements": [
{
"statistic": "COUNT",
"value": 754
},
{
"statistic": "TOTAL_TIME",
"value": 134.09375702
},
{
"statistic": "MAX",
"value": 0.76434196
}
]
}
On peut ensuite accéder à des données plus précises via les tags method
, uri
et status
.
~$ curl http://localhost:9999/actuator/metrics/http.server.requests?tag=uri:/secured/roles&tag=method:GET
{
"name": "http.server.requests",
"description": null,
"baseUnit": "seconds",
"measurements": [
{
"statistic": "COUNT",
"value": 56
},
{
"statistic": "TOTAL_TIME",
"value": 5.121863713
},
{
"statistic": "MAX",
"value": 0.143918815
}
]
}
C’est pas vraiment pratique pour détecter les requêtes lentes, mais on a pas mal de détails.
Métriques Spring Data
La métrique spring.data.repository.invocations
des repositories de Spring Data est activée par défaut.
Elle peut être désactivée dans la configuration.
management.metrics.data.repository.autotime.enabled=false
Son fonctionnement est similaire à celui de Spring MVC, avec une vue globale.
~$ curl http://localhost:9999/actuator/metrics/spring.data.repository.invocations
{
"name": "spring.data.repository.invocations",
"description": null,
"baseUnit": "seconds",
"measurements": [
{
"statistic": "COUNT",
"value": 293
},
{
"statistic": "TOTAL_TIME",
"value": 2.293597305
},
{
"statistic": "MAX",
"value": 0
}
]
}
On retrouve aussi des tags pour entrer dans les détails.
~$ curl http://localhost:9999/actuator/metrics/spring.data.repository.invocations?tag=repository:ClientRepository'&'method=findAll
Statistiques Hibernate
Les statistique d’Hibernate sont désactivées par défaut. Pour les avoir dans les métriques, il faut les activer et ajouter l’extension Micrometer.
Pour activer les statistiques Hibernate, sans les publier dans actuator:
spring.jpa.properties.hibernate.generate_statistics=true
Puis pour les publier, il faut ajouter une dépendance vers hibernate-micrometer
.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-micrometer</artifactId>
<version>${hibernate.version}</version>
</dependency>
Micrometer
La mécanique interne des métriques de l'actuator du endpoint s’appuie sur Micrometer, avec la publication des métriques sur un endpoint /actuator/metrics
.
Grâce à Micrometer, les métriques peuvent être publiées sur un outil de monitoring externe comme Graphite, Prometheus ou Elastic.
Grâce à Micrometer, il est aussi possible d’ajouter des métriques personnalisées.
Depuis n’importe quel bean, en injectant MeterRegistry
, on peut ajouter les métriques de son choix.
private final Counter createClientCallCounter;
public ClientService(MeterRegistry meterRegistry) {
Counter createClientCallCounter = Counter.builder("jtips.client.create")
.description("Nombre de création de Client")
.register(meterRegistry);
}
public Client create(Client client) {
createClientCallCounter.increment();
...
}
L’autre solution, plus modulaire, c’est de publier un bean qui implémente MeterBinder
et qui publie un ensemble de meters.
Info
Le endpoint /info
publie des informations statiques de l’application.
Les informations sont publiées par l’intermédiaire de contributeurs qui sont tous désactivés par défaut.
De ce fait, sans autre configuration, le résultat reste vide.
Le contributeur env
publie l’ensemble des propriétés info.*
.
Il était activé par défaut jusqu’à Spring Boot 2.5 et a été désactivé dans les versions suivantes (attention aux migrations).
management.info.env.enabled=true
info.application.name=JTips examples
info.application.version=1.2.3
~$ curl http://localhost:9999/actuator/info
{
"application": {
"name": "JTips examples",
"version": "1.2.3"
}
}
Le contributeur java
publie des informations du runtime Java.
management.info.java.enabled=true
~$ curl http://localhost:9999/actuator/info
{
"java": {
"vendor": "Private Build",
"version": "17.0.5",
"runtime": {
"name": "OpenJDK Runtime Environment",
"version": "17.0.5"
},
"jvm": {
"name": "OpenJDK 64-Bit Server VM",
"vendor": "Private Build",
"version": "17.0.5"
}
}
}
Le contributeur build
publie les informations du fichier /META-INF/build-info.properties
généré au moment du build.
Ça se configure avec Maven (ou gradle).
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Ce contributeur est activé par défaut et publie les informations à condition que le fichier soit présent.
~$ curl http://localhost:9999/actuator/info
{
"build": {
"artifact": "spring-boot-example",
"name": "JTips examples with Spring Boot",
"time": 1672075975.823000000,
"version": "1.2.3",
"group": "info.jtips"
}
}
Le contributeur git
publie les informations présentes dans le fichier git.properties
généré au moment du build.
<build>
<plugins>
<plugin>
<groupId>io.github.git-commit-id</groupId>
<artifactId>git-commit-id-maven-plugin</artifactId>
<version>5.0.0</version>
<executions>
<execution>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
</configuration>
</plugin>
</plugins>
</build>
Ce contributeur est activé par défaut et publie les informations à condition que le fichier soit présent.
~$ curl http://localhost:9999/actuator/info
{
"git": {
"branch": "main",
"commit": {
"id": "0cff7b1",
"time": 1671009439.000000000
}
}
}
Les informations publiées par ce endpoint sont disponibles sous forme de beans, de type |
Il est possible d’ajouter des informations personnalisées en publiant un bean de type InfoContributor
.
Env
Depuis Spring Boot 3, les valeurs fournies par le endpoint /env
sont cachées.
Pour les afficher, il faut configurer la propriété management.endpoint.env.show-values
.
Les valeurs possibles pour cette propriété sont:
-
ALWAYS
, pour voir les valeurs, -
NEVER
, par défaut, -
WHEN_AUTHORIZED
, si l’authentification est activée.
Il y a le même comportement pour /configprops
, et la propriété management.endpoint.configprops.show-values
équivalente.
Lorsqu’on décide d’afficher les valeurs, on se retrouve avec des mots de passe ou des secrets qu’on ne souhaiterait pas montrer.
Pour choisir quelles valeurs doivent être cachées malgré tout, il faut créer un bean qui implémente SanitizingFunction
.
@Component
public class ActuatorSanitizingFunction implements SanitizingFunction {
@Value("${application.actuator.keys-to-sanitize:}")
private String[] excludedKeys;
@Override
public SanitizableData apply(SanitizableData data) {
if (Arrays.stream(excludedKeys).anyMatch(excludedKey -> data.getKey().endsWith(excludedKey))) {
return data.withValue(SanitizableData.SANITIZED_VALUE);
}
return data;
}
}
Références
Les exemples de cette page ont été testés avec Spring Boot 2.7.