Saltar al contenido principal

Capítulo 2: Los Endpoints de Actuator

Introducción​

Actuator proporciona numerosos endpoints listos para usar. Este capítulo explora los más útiles y le muestra cómo crear los suyos propios.


🎯 Objetivos del Capítulo​

Al final de este capítulo, usted sabrá:

  1. ✅ Utilizar todos los endpoints nativos
  2. ✅ Comprender cuándo utilizar cada endpoint
  3. ✅ Crear endpoints personalizados
  4. ✅ Filtrar y formatear las respuestas

1. Lista de Endpoints​

Endpoints Básicos​

EndpointDescripción¿Sensible?
/actuatorLista todos los endpointsNo
/actuator/healthEstado de saludNo
/actuator/infoInformación de la aplicaciónNo

Endpoints de Análisis​

EndpointDescripción¿Sensible?
/actuator/beansLista todos los beans de SpringSí
/actuator/conditionsCondiciones de auto-configuraciónSí
/actuator/configpropsPropiedades de configuraciónSí
/actuator/envVariables de entornoSí
/actuator/mappingsTodos los @RequestMappingSí

Endpoints de Métricas​

EndpointDescripción¿Sensible?
/actuator/metricsLista las métricasNo
/actuator/metrics/\{name\}Una métrica específicaNo
/actuator/prometheusFormato PrometheusNo

Endpoints de Depuración​

EndpointDescripción¿Sensible?
/actuator/loggersNiveles de logSí
/actuator/threaddumpDump de hilosSí
/actuator/heapdumpDump de memoria (archivo)Sí
/actuator/httptraceHistorial HTTPSí

Endpoints de Acciones​

EndpointDescripción¿Sensible?
/actuator/shutdownDetener la aplicaciónSí
/actuator/refreshRefrescar la configuraciónSí

2. Endpoints en Detalle​

/actuator/beans​

Lista todos los beans de Spring de la aplicación:

curl http://localhost:8080/actuator/beans
{
"contexts": {
"application": {
"beans": {
"userService": {
"aliases": [],
"scope": "singleton",
"type": "com.example.service.UserService",
"dependencies": ["userRepository"]
},
"userController": {
"aliases": [],
"scope": "singleton",
"type": "com.example.controller.UserController",
"dependencies": ["userService"]
}
}
}
}
}

Utilidad: Depurar la inyección de dependencias.


/actuator/conditions​

Muestra por qué las auto-configuraciones han sido aplicadas o no:

curl http://localhost:8080/actuator/conditions
{
"contexts": {
"application": {
"positiveMatches": {
"DataSourceAutoConfiguration": [{
"condition": "OnClassCondition",
"message": "@ConditionalOnClass found required classes 'javax.sql.DataSource'"
}]
},
"negativeMatches": {
"RedisAutoConfiguration": {
"notMatched": [{
"condition": "OnClassCondition",
"message": "@ConditionalOnClass did not find required class 'org.springframework.data.redis.core.RedisOperations'"
}]
}
}
}
}
}

Utilidad: Comprender por qué una funcionalidad está activada o desactivada.


/actuator/env​

Muestra todas las fuentes de configuración:

curl http://localhost:8080/actuator/env
{
"activeProfiles": ["dev"],
"propertySources": [
{
"name": "systemProperties",
"properties": {
"java.version": {"value": "17.0.1"}
}
},
{
"name": "applicationConfig: [classpath:/application.properties]",
"properties": {
"spring.datasource.url": {"value": "jdbc:h2:mem:testdb"}
}
}
]
}

Una propiedad específica:

curl http://localhost:8080/actuator/env/spring.datasource.url

/actuator/mappings​

Lista todos los endpoints HTTP de la aplicación:

curl http://localhost:8080/actuator/mappings
{
"contexts": {
"application": {
"mappings": {
"dispatcherServlets": {
"dispatcherServlet": [
{
"handler": "com.example.controller.UserController#getAll()",
"predicate": "{GET /api/users}",
"details": {
"requestMappingConditions": {
"methods": ["GET"],
"patterns": ["/api/users"]
}
}
}
]
}
}
}
}
}

Utilidad: Ver todos los endpoints disponibles.


/actuator/loggers​

Ver y modificar los niveles de log en caliente:

# Ver todos los loggers
curl http://localhost:8080/actuator/loggers

# Un logger específico
curl http://localhost:8080/actuator/loggers/com.example.service
{
"configuredLevel": null,
"effectiveLevel": "DEBUG"
}

Modificar un nivel en caliente (POST):

curl -X POST http://localhost:8080/actuator/loggers/com.example.service \
-H "Content-Type: application/json" \
-d '{"configuredLevel": "DEBUG"}'

Utilidad: ¡Activar DEBUG en producción sin reiniciar!


/actuator/threaddump​

Muestra el estado de todos los hilos:

curl http://localhost:8080/actuator/threaddump
{
"threads": [
{
"threadName": "http-nio-8080-exec-1",
"threadId": 23,
"blockedTime": -1,
"blockedCount": 0,
"waitedTime": -1,
"waitedCount": 2,
"lockName": null,
"threadState": "RUNNABLE",
"stackTrace": [
{
"className": "java.net.SocketInputStream",
"methodName": "socketRead0",
"lineNumber": -2,
"nativeMethod": true
}
]
}
]
}

Utilidad: Detectar deadlocks, hilos bloqueados.


/actuator/heapdump​

Genera un archivo heap dump (¡atención: pesado!):

curl -O http://localhost:8080/actuator/heapdump
# Genera un archivo heapdump que puede analizar con VisualVM o MAT

Utilidad: Analizar fugas de memoria.


/actuator/shutdown (¡Peligroso!)​

Detiene la aplicación de forma limpia:

# Debe ser activado explícitamente
management.endpoint.shutdown.enabled=true
curl -X POST http://localhost:8080/actuator/shutdown
{
"message": "Shutting down, bye..."
}

⚠️ ¡Debe asegurarse absolutamente!


3. Endpoints Personalizados​

Crear un Endpoint Simple​

import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.stereotype.Component;

@Component
@Endpoint(id = "custom")
public class CustomEndpoint {

@ReadOperation
public Map<String, Object> customInfo() {
return Map.of(
"status", "operational",
"timestamp", LocalDateTime.now(),
"version", "1.0.0"
);
}
}
curl http://localhost:8080/actuator/custom
{
"status": "operational",
"timestamp": "2024-01-15T10:30:00",
"version": "1.0.0"
}

Endpoint con Parámetros​

@Component
@Endpoint(id = "features")
public class FeaturesEndpoint {

private final Map<String, Boolean> features = new ConcurrentHashMap<>();

@ReadOperation
public Map<String, Boolean> getAllFeatures() {
return features;
}

@ReadOperation
public Boolean getFeature(@Selector String name) {
return features.getOrDefault(name, false);
}

@WriteOperation
public void setFeature(@Selector String name, boolean enabled) {
features.put(name, enabled);
}

@DeleteOperation
public void deleteFeature(@Selector String name) {
features.remove(name);
}
}
# Leer todas las features
curl http://localhost:8080/actuator/features

# Leer una feature
curl http://localhost:8080/actuator/features/dark-mode

# Activar una feature
curl -X POST "http://localhost:8080/actuator/features/dark-mode?enabled=true"

# Eliminar una feature
curl -X DELETE http://localhost:8080/actuator/features/dark-mode

Endpoint para Estadísticas de Negocio​

@Component
@Endpoint(id = "business-stats")
@RequiredArgsConstructor
public class BusinessStatsEndpoint {

private final OrderRepository orderRepository;
private final UserRepository userRepository;

@ReadOperation
public Map<String, Object> getStats() {
return Map.of(
"totalUsers", userRepository.count(),
"totalOrders", orderRepository.count(),
"ordersToday", orderRepository.countByCreatedAtAfter(LocalDate.now().atStartOfDay()),
"revenue", orderRepository.sumTotalAmount()
);
}
}

4. Web Endpoints vs JMX​

Exposición Web (HTTP)​

# Exponer vía HTTP
management.endpoints.web.exposure.include=health,info,metrics

Exposición JMX​

# Exponer vía JMX (para JConsole, VisualVM)
management.endpoints.jmx.exposure.include=*

# Desactivar JMX si no se utiliza
spring.jmx.enabled=false

5. Resumen​

Endpoints Recomendados en Producción​

EndpointExposiciónUso
/healthPúblicoLoad balancer, K8s
/infoPúblicoVersión, build
/metricsInternoPrometheus
/prometheusInternoScraping
/loggersAdminDebug en caliente

Endpoints a Proteger​

/actuator/env         → ¡Expone secretos!
/actuator/heapdump → ¡Datos sensibles!
/actuator/shutdown → ¡Detiene la app!
/actuator/beans → Arquitectura interna

Crear un Endpoint​

@Component
@Endpoint(id = "my-endpoint")
public class MyEndpoint {

@ReadOperation // GET
public Data read() { }

@WriteOperation // POST
public void write() { }

@DeleteOperation // DELETE
public void delete() { }
}

🎯 Próximo Paso​

Los endpoints están bien, pero ¿cómo medir el rendimiento? ¡Pasemos a las métricas!

➡️ Capítulo 3: Métricas con Micrometer


⬅️ Volver al Módulo 11