Spring Boot: how to modify health check response data format - spring-boot

My application enables health check with application properties like below.
# health check config
management.endpoint.health.show-details=always
management.endpoints.web.base-path=/
management.endpoints.web.path-mapping.health=health
So if i request GET /health to application.
i get this reponse.
{
"status": "UP",
"components": {
"db": {
"status": "UP",
"details": {
"database": "H2",
"validationQuery": "isValid()"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 247862915072,
"free": 139563880448,
"threshold": 10485760,
"path": "C:\\Users\\~~",
"exists": true
}
},
"ping": {
"status": "UP"
}
}
}
When i saw this response. i dont wanna response some data like database type (H2).
I know that i can't change response data from actutator.
But is there way to modify data like below code in spring boot?
#RestController
#RequestMapping("/health")
public class HealthController {
#GetMapping()
public HealthResponse get() {
// Below code is just example. i wonder that i can get origin /health api data.
HealthOriginResponse origin = HealthModule.getData()
return new HealthResponse(origin.status, origin.db.status, origin.diskSpace.status);
}
}
If there is no way. i consider to use interceptor for modifying.

Related

Why does my Spring Boot Actuator tell me the application state is DOWN in K8S, but UP outside

I have a Spring boot application with actuator enabled so that I can use the /actuator/health URIs as probes. My application talks to redis, JMS and cosmos so those are checked as part of the health response.
When I run the application at my command prompt I get the following JSON response, with a HTTP 200 code indicating all is well.
{
"status": "UP",
"components": {
"cosmos": {
"status": "UP",...
},
"diskSpace": {
"status": "UP",...
},
"grpcChannel": {
"status": "UP",...
},
"jms": {
"status": "UP",...
}
},
"ping": {
"status": "UP"
},
"redis": {
"status": "UP",...
}
}
}
When I deploy the application to a K8S environment (Rancher locally or Azure in the cloud) the application knows it is now in a K8S environment and so adds some additional stuff to the health check. However while the main components are all UP - as for the local run - I now get a 503 Service Unavailable response code and the livenessState is DOWN and the readinessState is OUT_OF_SERVICE.
{
"status": "DOWN",
"components": {
"cosmos": {
"status": "UP",...
},
"diskSpace": {
"status": "UP",...
},
"grpcChannel": {
"status": "UP",...
},
"jms": {
"status": "UP",...
}
},
"livenessState": {
"status": "DOWN"
},
"ping": {
"status": "UP"
},
"readinessState": {
"status": "OUT_OF_SERVICE"
},
"redis": {
"status": "UP",
"details": {
"cluster_size": 3,
"slots_up": 16384,
"slots_fail": 0
}
}
},
"groups": [
"liveness",
"readiness"
]
}
What additional checks is the actuator doing when in K8S and what do I need to do for actuator to report it is all OK? Any suggestions as to how to troubleshoot the problem?
I have searched for more information on SO and the wider web, but cannot find anything that helps find out what the K8S checks are specifically looking for.
Thank you.

Springboot actuator health component check puts whole service as down?

we have multiple health checks for our application, but if one of the components health check fails - then the status of the whole application changes to "DOWN".
What we want is the application status to still be "UP", even if a single component fails.
How to prevent a single failing component check to change the application status?
Here is an example of our health checks:
{
"status": "UP",
"components": {
"db": {
"status": "UP",
"details": { "database": "MariaDB", "validationQuery": "isValid()" }
},
"discoveryComposite": {
"description": "Discovery Client not initialized",
"status": "UNKNOWN",
"components": {
"discoveryClient": {
"description": "Discovery Client not initialized",
"status": "UNKNOWN"
}
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 117404147712,
"free": 102471593984,
"threshold": 10485760,
"exists": true
}
},
"linkFlow": {
"status": "UP",
"details": { "message": "LinkFLow er tilgjengelig" }
},
"nissy": {
"status": "UP",
"details": { "message": "Nissy er tilgjengelig" }
},
"ping": { "status": "UP" },
"reactiveDiscoveryClients": {
"description": "Discovery Client not initialized",
"status": "UNKNOWN",
"components": {
"Simple Reactive Discovery Client": {
"description": "Discovery Client not initialized",
"status": "UNKNOWN"
}
}
},
"refreshScope": { "status": "UP" },
"zisson": {
"status": "UP",
"details": { "message": "Zisson API er tilgjengelig" }
}
}
}
Implementation of healthcheck:
#Component
#Slf4j
public class ZissonHealthIndicator implements HealthIndicator {
private final ZissonAPIGateway zissonAPIGateway;
public ZissonHealthIndicator(ZissonAPIGateway zissonAPIGateway) {
this.zissonAPIGateway = zissonAPIGateway;
}
#Override
public Health health() {
if (zissonAPIGateway.isAvailable()) {
return Health.up().withDetail("message", "Zisson API er tilgjengelig").build();
}
log.warn("Helsesjekk: Zisson er utilgjengelig");
return Health.down().withDetail("message", "Zisson er ikke tilgjengelig").build();
}
}
Yes you can. Just create your own StatusAggregator:
#Component
public class CustomHealthAggregator extends SimpleStatusAggregator {
#Override
public Status getAggregateStatus(Set<Status> statuses) {
// or some othe logic here
if (statuses.contains(Status.UP)) {
return Status.UP;
}
return super.getAggregateStatus(statuses);
}
}

health details no longer show up in SBA UI after SpringBoot upgrade

I upgraded my apps from SpringBoot 2.1.18 to SpringBoot 2.5.7 and I see that health details such as diskSpace no longer show up in SpringBootAdmin UI after the upgrade. I am using SBA 2.0.0 and have not changed that.
The health endpoint still includes them, but the top level key has been renamed from details to components. I assumed that was what was confusing SBA, but even stranger my custom health indicator still displays in SBA despite this.
Any idea how I can solve this?
old
{
"status": "OUT_OF_SERVICE",
"details": {
"myCustomHealthIndicator": {
"status": "OUT_OF_SERVICE",
"details": {
"Reason": "Suspect State message received",
"StateText": "Connection failed; Channel disconnected"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 107361579008,
"free": 94436716544,
"threshold": 10485760
}
},
"refreshScope": {
"status": "UP"
}
}
}
new
{
"status": "OUT_OF_SERVICE",
"components": {
"diskSpace": {
"status": "UP",
"details": {
"total": 107361579008,
"free": 100102447104,
"threshold": 10485760,
"exists": true
}
},
"livenessState": {
"status": "UP"
},
"ping": {
"status": "UP"
},
"readinessState": {
"status": "UP"
},
"myCustomHealthIndicator": {
"status": "OUT_OF_SERVICE",
"details": {
"Reason": "Suspect State message received",
"StateText": "Connection failed; Channel disconnected"
}
}
},
"groups": [
"liveness",
"readiness"
]
}
Solved by upgrading to Spring Boot Admin Server 2.5.4 ( de.codecentric:spring-boot-admin-starter-server:jar:2.5.4 )

Is it possible to change Actuator health api response structure to custom response

I have my healthIndicators written for different databases which extend the AbstractHealthIndicator from spring.
But the end consumer expects the response in a different format in which the common keys and data expected are different.
Actual :
{
"status": "DOWN",
"details": {
"B": {
"status": "UP",
"details": {
"reachable": true
}
},
"A": {
"status": "DOWN",
"details": {
"reachable": false
}
}
}
}
Expected :
{
"result": true,
"data": {
"modules": [
{
"name": "A",
"status": "OK"
},
{
"name": "B",
"status": "DOWN"
},
]
}
}
Is it possible to write a converter, which can do this ?
I don't think you can change the format of the /health endpoint without changing the internal actuator's code.
However its possible to create your own endpoint that will maintain the reference to the Health endpoint (its a bean after all, and therefore can be injected), so that its #GetOperation would call the original "health" endpoint, obtain the results and convert them to your custom format.
The original Health Endpoint is implemented in this class

400 Bad Request in Spring Boot Swagger UI for POST

I've created a Spring Boot application with RestController. I enabled Swagger UI and it works fine as I can login to the UI and execute any GET methods. But for POST methods accepting objects in the body, when I fire off the request using Swagger UI, it always returns 400 status code. I can see the request never reached the particular POST method. May I know if any special config I need for Swagger UI?
The particular method in my Spring Boot RestController
#ApiOperation(value = "Query requests by search criteria")
#RequestMapping(value = "/api/query", method = POST)
public PageResult<MyPOJO> find(#RequestBody SearchRequest request) {
//implementation omitted.
}
and I'm using
"io.springfox:springfox-swagger2:2.1.2",
"io.springfox:springfox-swagger-ui:2.1.2"
This one (generated by Swagger UI) for the corresponding api gives me 400 bad request:
{
"listEntrySearchCriteria": {
"summary": {
"createdBy": "string",
"createdOn": "2016-03-21T10:33:05.048Z",
"effectiveEnd": "2016-03-21T10:33:05.048Z",
"effectiveStart": "2016-03-21T10:33:05.048Z",
"id": 0,
"region": "string",
"type": "ETB",
"updatedBy": "string",
"updatedOn": "2016-03-21T10:33:05.048Z",
"version": 0
}
},
"listSummarySearchCriteria": {
"effectiveEnd": "2016-03-21T10:33:05.048Z",
"effectiveStart": "2016-03-21T10:33:05.048Z",
"statuses": [
"string"
],
"types": [
"string"
]
},
"pageRequest": {
"orders": [
{
"direction": "ASC",
"ignoreCase": true,
"nullHandling": "NATIVE",
"property": "string"
}
],
"page": 0,
"size": 0
}
}
But if I supply a random request for the same method, it at least reaches my method:
{
"orders": [
{
"direction": "ASC",
"ignoreCase": true,
"nullHandling": "NATIVE",
"property": "id"
}
],
"page": 0,
"size": 0
}

Resources