skip to Main Content

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?

4

Answers


  1. 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();
        }
    }
    
    Login or Signup to reply.
  2. 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

    Login or Signup to reply.
  3. 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;
            
        }
    }
    
    Login or Signup to reply.
  4. This example uses the HealthContributorRegistry to retrieve the name of the HealthIndicator. It also takes into account CompositeHealthContributors.

    import org.springframework.boot.actuate.health.CompositeHealthContributor;
    import org.springframework.boot.actuate.health.HealthContributor;
    import org.springframework.boot.actuate.health.HealthContributorRegistry;
    import org.springframework.boot.actuate.health.HealthIndicator;
    import org.springframework.boot.actuate.health.NamedContributor;
    import org.springframework.stereotype.Service;
    
    @Service
    public class CustomHealthService {
        private final HealthContributorRegistry healthContributorRegistry;
    
        public CustomHealthService(HealthContributorRegistry healthContributorRegistry) {
            this.healthContributorRegistry = healthContributorRegistry;
        }
    
        public void printHealth() {
            healthContributorRegistry.forEach(this::printHealthIndicatorStatus);
        }
    
        private void printHealthIndicatorStatus(NamedContributor<HealthContributor> contributor) {
            if (contributor.getContributor() instanceof HealthIndicator) {
                System.out.println("Health indicator '" + contributor.getName() + "' has health: '" + ((HealthIndicator) contributor.getContributor()).health() + "'");
            } else if (contributor.getContributor() instanceof CompositeHealthContributor) {
                ((CompositeHealthContributor) contributor.getContributor()).forEach(this::printHealthIndicatorStatus);
            } else {
                throw new RuntimeException("Unexpected HealthContributor type " + contributor.getClass().getName());
            }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search