Direct access to Spring Boot Actuator Health beans/data?

Viewed 1269

From a Sprig Boot application is it possible access the actuator/health data directly without making a rest call and parsing the results?

Ideally I could autowire a bean and then be able to fetch the object representation of the health data with a method call.

For example if my health endpoint is showing something like this:

{
    "status": "UP",
    "components": {
        "db": {
            "status": "UP",
            "details": {
                "database": "PostgreSQL",
                "result": 1,
                "validationQuery": "SELECT 1"
            }
        },
        "diskSpace": {
            "status": "UP",
            "details": {
                "total": 499963174912,
                "free": 389081399296,
                "threshold": 10485760
            }
        },
        "ping": {
            "status": "UP"
        },
        "redis": {
            "status": "UP",
            "details": {
                "version": "3.2.12"
            }
        }
    }
}

Then which components could I autowire to find out each of those bits of information?

3 Answers

Sure you can inject the according Endpoint. For example if you are interested in the HealthEndpoint you could do:

@RestController
public class ActuatorController {

    private final HealthEndpoint healthEndpoint;

    public ActuatorController(HealthEndpoint healthEndpoint) {
        this.healthEndpoint = healthEndpoint;
    }

    @GetMapping("health")
    public String health() {
        return healthEndpoint.health().getStatus().getCode();
    }
}

There is probably a better way to get the health data but this worked for me.

@RestController
public class HealthController {
    @Autowired
    HealthContributor[] healthContributors;
    
    
    @GetMapping("/health")
    public Map<String, String> health() {
        Map<String, String> components = new HashMap<String, String>();
        for(HealthContributor healthContributor : healthContributors) {
            String componentName = healthContributor.getClass().getSimpleName().replace("HealthIndicator", "").replace("HealthCheckIndicator", "");
            String status = ((HealthIndicator)(healthContributor)).health().getStatus().toString();
            //To get details
            //Map<String,Object> details = ((HealthIndicator)(healthContributor)).health().getDetails();
            
            components.put(componentName, status);
            
        }
        return components;
    }
    
}

Example Output:

{
  "Mail":"UP",
  "Ping":"UP",
  "Camel":"UP",
  "DiskSpace":"UP"
}

To Mock the HealthContributor[] you may try to use Mockito like below:

@Profile("test")
@Configuration
public class HealthContributorsMockConfig {


    @Primary
    @Bean(name = "healthContributors")
    public HealthContributor[] healthContributors() {
        HealthContributor[] healthContributors = new HealthContributor[2];
        
        HealthContributor healthContributorA = Mockito.mock(HealthIndicator.class, new Answer<Object>() {

            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                // TODO Auto-generated method stub
                Health health = Health.up().build();
                return health;
            }
            
        });
        
        HealthContributor healthContributorB = Mockito.mock(HealthIndicator.class, new Answer<Object>() {

            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                // TODO Auto-generated method stub
                Health health = Health.down().build();
                return health;
            }
            
        });
        
        healthContributors[0] = healthContributorA;
        healthContributors[1] = healthContributorB;
        return healthContributors;
        
    }
}

Also, the info and health points are enabled in actuator by default and you don't need to expose them manually. The moment you add the dependency to your pom.xml it will be enabled and you can access the url endpoints without exposing them

Related