Issue
I am currently working with a health monitoring framework implemented using the Spring Boot Actuator "health" endpoint. The Actuator infrastructure supports the creation of custom health checks and also provides a number of built-in health checks; one of these is DataSourceHealthIndicator
.
DataSourceHealthIndicator
is part of the org.springframework.boot.actuate.health
package, and is currently being used by our health framework to check the health of data sources. I have a need to use my own, slightly modified version of DataSourceHealthIndicator
and to disable the "default."
I have tried the solutions suggested here and here, with no luck. What could I be doing wrong?
Thanks!
Edit: 8/18/2016, 3:38 PM EST
I've renamed my bean to dbHealthIndicator
and added the following to my configuration class:
@Bean
public HealthIndicator dbHealthIndicator() {
return new dbHealthIndicator();
}
I am now getting the following exceptions:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataAccessMapperFactory' defined in class path resource [udtContext.xml]
java.lang.RuntimeException: java.sql.SQLException: Unable to start the Universal Connection Pool: oracle.ucp.UniversalConnectionPoolException
Edit: 8/19/2016, 9:22 AM EST
This may help to demonstrate what I am trying to do. Currently, my /health
endpoint returns something that looks like this:
dataSource: {
status: "UP",
database: "mySql",
hello: "hello"
}
I would like for it to return something more like this, where the integer beside "result" is a status code returned by a stored procedure in my database:
dataSource: {
status: "UP",
database: "mySql",
hello: "hello",
result: 0
}
This is the method in DataSourceHealthIndicator.java
that performs the check:
private void doDataSourceHealthCheck(Health.Builder builder) throws Exception {
String product = getProduct();
builder.up().withDetail("database", product);
String validationQuery = getValidationQuery(product);
if (StringUtils.hasText(validationQuery)) {
try {
// Avoid calling getObject as it breaks MySQL on Java 7
List<Object> results = this.jdbcTemplate.query(validationQuery,
new SingleColumnRowMapper());
Object result = DataAccessUtils.requiredSingleResult(results);
builder.withDetail("hello", result);
}
catch (Exception ex) {
builder.down(ex);
}
}
}
I need to add eight lines of code to this method, under builder.withDetail("hello", result);
, to perform the call to the stored proc. I do not want to "decompile" the default class, and I am unable to override this method because it is private. I was thinking I could copy the DataSourceHealthIndicator.java
code in my own bean, add my code, and rewire Spring to use this version instead, but I don't know if this is possible.
Solution
Normally I look at the configuration for that HealthIndicator
. In this case it is the HealthIndicatorAutoConfiguration.DataSourcesHealthIndicatorConfiguration
. As the first linked suggestion stated. You need to name your custom bean dbHealthIndicator
so that the @ConditionalOnMissingBean(name = "dbHealthIndicator")
doesn't allow the default to be registered.
Providing some startup logs or details of what isn't working for you would help people troubleshoot.
Here is an example of how I got it to work:
@SpringBootApplication
public class StackoverflowWebmvcSandboxApplication {
@Bean
public HealthIndicator dbHealthIndicator() {
return new HealthIndicator() {
@Override
public Health health() {
return Health.status(Status.UP).withDetail("hello", "hi").build();
}
};
}
public static void main(String[] args) {
SpringApplication.run(StackoverflowWebmvcSandboxApplication.class, args);
}
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
}
}
The /health
endpoint then returned:
{
"status": "UP",
"db": {
"status": "UP",
"hello": "hi"
},
"diskSpace": {
"status": "UP",
"total": 127927316480,
"free": 17191956480,
"threshold": 10485760
}
}
Answered By - Shawn Clark
Answer Checked By - Candace Johnson (JavaFixing Volunteer)