How to implement a custom CompositeHealthContributor
Asked Answered
M

2

6

I want to display the following Health-Information:

{
   "status":"UP", 
   "components": {
          "myHealthComposite": {
                "status":"UP",
                "components": {
                        "myFirstHealthIndicator": { "status":"UP" },
                        "mySecondHealthIndicator": { "status":"UP" }
                }
          }
    },
    "groups":[]
}

From the latest Spring Boot Actuator Documentation I should implement "myFirstHealthIndactor" and "mySecondHealthIndicator" with the "HealthIndicator"-Interface and composite them with the "CompositeHealthContributor"-Interface. But for "CompositeHealthContributor" I need an excample and in the Documentation I can not found something usefull for me.

Can someone help me with that, please?

Greetings

Edit:

myFirstHealthIndicator

@Component
public class MyFirstHealthIndicator implements HealthIndicator {

    @Override
    public Health health() {
        return Health.up().build();
    }

}

mySecondHealthIndicator

@Component
public class MySecondHealthIndicator implements HealthIndicator {

    @Override
    public Health health() {
        return Health.up().build();
    }

}

myHealthComposite

@Component
public class MyHealthComposite implements CompositeHealthContributor {

    @Override
    public HealthContributor getContributor(String name) {
        return null;
    }

    @Override
    public Iterator<NamedContributor<HealthContributor>> iterator() {
        return null;
    }

}
Macerate answered 2/12, 2019 at 12:6 Comment(2)
@QtRoS I can not post a great example because I need an advise how to implement a CompositeContributor but I hope you can work with my edited question.Macerate
"From the latest Spring Boot Actuator Documentation" Can you please give us the source (so that we are on the same level)?Celestyna
C
6

A very simple and hard coded solution that outputs the expected.

Please remove the @Component annotation from MyFirstHealthIndicator and MySecondHealthIndicator. Otherwise, they are also listed as separate components.

MyFirstHealthIndicator

public class MyFirstHealthIndicator implements HealthIndicator {

    @Override
    public Health health() {
        return Health.up().build();
    }

}

MySecondHealthIndicator

public class MySecondHealthIndicator implements HealthIndicator {

    @Override
    public Health health() {
        return Health.up().build();
    }

}

MyHealthComposite

@Component
public class MyHealthComposite implements CompositeHealthContributor {

    private Map<String, HealthContributor> contributors = new LinkedHashMap<>();

    MyHealthComposite() {
        this.contributors.put("myFirstHealthIndicator", new MyFirstHealthIndicator());
        this.contributors.put("mySecondHealthIndicator", new MySecondHealthIndicator());
    }

    @Override
    public HealthContributor getContributor(String name) {
        return contributors.get(name);
    }

    @Override
    public Iterator<NamedContributor<HealthContributor>> iterator() {
        return contributors.entrySet().stream()
                .map((entry) -> NamedContributor.of(entry.getKey(), entry.getValue())).iterator();
    }
}

Please enable the management.endpoint.health.show-components=always in your application.properties.

The output looks like:

{
  "status": "UP",
  "components": {
    "diskSpace": {
      "status": "UP"
    },
    "myHealthComposite": {
      "status": "UP",
      "components": {
        "myFirstHealthIndicator": {
          "status": "UP"
        },
        "mySecondHealthIndicator": {
          "status": "UP"
        }
      }
    },
    "ping": {
      "status": "UP"
    }
  }
}

However, this is not my solution, but is adopted from BindersHealthIndicatorAutoConfiguration from spring-cloud-stream and adapted to the requirements.

Celestyna answered 6/12, 2019 at 17:57 Comment(1)
What if I need to autowire something into MyFirstHealthIndicator or MySecondHealthIndicator and I don't want to display duplicated components.Tanta
S
1

If you need to autowire something into your health indicators without duplicating health components:

HealthIndicatorProvider

public interface HealthIndicatorProvider {
    String getName();
    HealthIndicator getHealthIndicator();
}

MyFirstHealthIndicatorProvider

@Component
public class MyFirstHealthIndicatorProvider implements HealthIndicatorProvider {
    private final SomethingToAutowire1 somethingToAutoWire1;

    public MyFirstHealthIndicatorProvider(SomethingToAutowire1 somethingToAutoWire1) {
        this.somethingToAutoWire1 = somethingToAutoWire1;
    }

    public String getName() {
        return "myFirstHealthIndicator";
    }

    public HealthIndicator getHealthIndicator() {
        return new HealthIndicator() {
            @Override
            public Health health() {
                return Health.up().build();
            }
        };
    }
}

MySecondHealthIndicatorProvider

@Component
public class MySecondHealthIndicatorProvider implements HealthIndicatorProvider {
    private final SomethingToAutowire2 somethingToAutoWire2;

    public MySecondHealthIndicatorProvider(SomethingToAutowire2 somethingToAutoWire2) {
        this.somethingToAutoWire2 = somethingToAutoWire2;
    }

    public String getName() {
        return "mySecondHealthIndicator";
    }

    public HealthIndicator getHealthIndicator() {
        return new HealthIndicator() {
            @Override
            public Health health() {
                return Health.up().build();
            }
        };
    }
}

MyCompositeHealthConfig

@Configuration
public class MyCompositeHealthConfig {

    @Bean
    public CompositeHealthContributor myHealthComposite(List<HealthIndicatorProvider> healthIndicatorProviders) {
        return CompositeHealthContributor.fromMap(
                healthIndicatorProviders.stream().collect(Collectors.toMap(
                        HealthIndicatorProvider::getName,
                        HealthIndicatorProvider::getHealthIndicator
                ))
        );
    }

}
Smashing answered 23/8, 2023 at 21:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.