Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2014-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package de.codecentric.boot.admin.sample.health;

import org.springframework.boot.health.contributor.Health;
import org.springframework.boot.health.contributor.HealthIndicator;

/**
* A sample {@link HealthIndicator} that simulates checking connectivity to an external
* API. In a real application this would perform an actual HTTP call or similar check.
*/
public class ExternalApiHealthIndicator implements HealthIndicator {

@Override
public Health health() {
// Simulate a reachable external API
return Health.down().withDetail("url", "https://api.example.com").withDetail("responseTime", "42ms").build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2014-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package de.codecentric.boot.admin.sample.health;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Stream;

import org.springframework.boot.health.contributor.CompositeHealthContributor;
import org.springframework.boot.health.contributor.HealthContributor;
import org.springframework.boot.health.contributor.HealthContributors;

/**
* A {@link CompositeHealthContributor} that groups related external-dependency health
* checks under a single {@code /actuator/health/externalServices} entry.
*
* <p>
* Spring Boot aggregates the individual {@link HealthContributor}s and rolls up the worst
* status to the composite level, so a single degraded dependency is immediately visible
* both in the top-level health summary and in the drill-down view.
*
* <p>
* The composite is registered as a bean named {@code externalServices} in
* {@link HealthContributorConfig}, which causes Spring Boot Actuator to expose it at
* {@code /actuator/health/externalServices}.
*/
// tag::composite-health-contributor[]
public class ExternalServicesHealthContributor implements CompositeHealthContributor {

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

public ExternalServicesHealthContributor(ExternalApiHealthIndicator externalApi,
MessageBrokerHealthIndicator messageBroker) {
contributors.put("externalApi", externalApi);
contributors.put("messageBroker", messageBroker);
}

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

@Override
public Stream<HealthContributors.Entry> stream() {
return contributors.entrySet()
.stream()
.map((entry) -> new HealthContributors.Entry(entry.getKey(), entry.getValue()));
}

}
// end::composite-health-contributor[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright 2014-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package de.codecentric.boot.admin.sample.health;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* Registers the individual health indicators and the composite contributor as Spring
* beans.
*
* <p>
* The bean name {@code externalServices} is used by Spring Boot Actuator as the path
* segment, so the composite becomes available at
* {@code /actuator/health/externalServices}.
*/
@Configuration(proxyBeanMethods = false)
public class HealthContributorConfig {

@Bean
public ExternalApiHealthIndicator externalApiHealthIndicator() {
return new ExternalApiHealthIndicator();
}

@Bean
public MessageBrokerHealthIndicator messageBrokerHealthIndicator() {
return new MessageBrokerHealthIndicator();
}

// tag::composite-health-contributor-bean[]
@Bean
public ExternalServicesHealthContributor externalServices(ExternalApiHealthIndicator externalApi,
MessageBrokerHealthIndicator messageBroker) {
return new ExternalServicesHealthContributor(externalApi, messageBroker);
}
// end::composite-health-contributor-bean[]

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2014-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package de.codecentric.boot.admin.sample.health;

import org.springframework.boot.health.contributor.Health;
import org.springframework.boot.health.contributor.HealthIndicator;

/**
* A sample {@link HealthIndicator} that simulates checking an internal message broker. In
* a real application this would verify queue depth, connection status, etc.
*/
public class MessageBrokerHealthIndicator implements HealthIndicator {

@Override
public Health health() {
// Simulate a healthy message broker
return Health.unknown().withDetail("broker", "in-memory-stub").withDetail("queueDepth", 0).build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ export default {
@apply bg-gray-200 text-black text-xs inline-flex items-center uppercase rounded overflow-hidden px-3 py-1;
}
.up {
@apply bg-green-200 text-green-700;
@apply bg-status-up-bg text-status-up-text;
}
.down,
.out_of_service {
@apply bg-red-200 text-red-700;
@apply bg-status-down-bg text-status-down-text;
}
.restricted {
@apply bg-yellow-200 text-yellow-700;
@apply bg-status-restricted-bg text-status-restricted-text;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,17 @@ export default {
@apply text-gray-500 mx-auto;
}
.application-status__icon--UP {
color: #48c78e;
color: var(--color-status-up);
}
.application-status__icon--RESTRICTED {
color: #ffe08a;
color: var(--color-status-restricted);
}
.application-status__icon--OUT_OF_SERVICE,
.application-status__icon--DOWN {
color: #f14668;
color: var(--color-status-down);
}
.application-status__icon--UNKNOWN,
.application-status__icon--OFFLINE {
color: #7a7a7a;
color: var(--color-status-unknown);
}
</style>
22 changes: 22 additions & 0 deletions spring-boot-admin-server-ui/src/main/frontend/theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

@import 'tailwindcss';

@custom-variant dark (&:where(.dark, .dark *));
@plugin "@tailwindcss/forms";
@plugin "@tailwindcss/typography";
Expand All @@ -30,4 +31,25 @@
--color-sba-700: var(--main-700);
--color-sba-800: var(--main-800);
--color-sba-900: var(--main-900);

/* ── Status colour tokens ─────────────────────────────────────────────
* Tailwind utilities: text-status-up, bg-status-up-bg, etc.
* Single source of truth for UP/DOWN/RESTRICTED/UNKNOWN across all
* components (sba-status-badge, sba-status, wallboard, health panel).
*/
--color-status-up: var(--color-green-400);
--color-status-up-bg: var(--color-green-200);
--color-status-up-text: var(--color-green-700);

--color-status-down: var(--color-red-400);
--color-status-down-bg: var(--color-red-200);
--color-status-down-text: var(--color-red-700);

--color-status-restricted: var(--color-yellow-500);
--color-status-restricted-bg: var(--color-yellow-200);
--color-status-restricted-text: var(--color-yellow-700);

--color-status-unknown: var(--color-gray-400);
--color-status-unknown-bg: var(--color-gray-200);
--color-status-unknown-text: var(--color-gray-700);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exports[`HealthDetails > Health .details > should format object details correctl
<dd
aria-label="validChains"
aria-labelledby="health-detail-v-7__validChains"
class="col-span-4"
class="health-row__detail-value"
data-v-4727d85f=""
role="definition"
>
Expand Down
Loading
Loading