├── CODEOWNERS ├── ui ├── screenshot.png ├── screenshot_settings.png ├── src │ └── main │ │ └── webapp │ │ └── health-ui │ │ ├── style.css │ │ ├── logo.png │ │ ├── favicon.ico │ │ ├── refresh.png │ │ ├── settings.png │ │ └── index.html ├── README.md └── pom.xml ├── .github ├── project.yml ├── dependabot.yml └── workflows │ ├── update-milestone.yml │ ├── prepare-release.yml │ ├── release.yml │ ├── publish-tck.yml │ ├── build.yml │ └── review-release.yml ├── doc ├── antora.yml ├── modules │ └── ROOT │ │ ├── nav.adoc │ │ └── pages │ │ ├── index.adoc │ │ ├── wellness.adoc │ │ ├── custom-config-properties.adoc │ │ ├── health-registry.adoc │ │ ├── async-checks.adoc │ │ ├── health-groups.adoc │ │ └── static-access.adoc └── antora-playbook.yml ├── testsuite ├── tck │ └── src │ │ ├── test │ │ ├── resources │ │ │ ├── META-INF │ │ │ │ ├── services │ │ │ │ │ └── org.jboss.arquillian.core.spi.LoadableExtension │ │ │ │ └── beans.xml │ │ │ └── arquillian.xml │ │ └── java │ │ │ └── io │ │ │ └── smallrye │ │ │ └── health │ │ │ ├── SmallRyeHealthExtension.java │ │ │ └── SmallRyeHealthArchiveProcessor.java │ │ └── main │ │ └── java │ │ └── io │ │ └── smallrye │ │ └── health │ │ ├── SmallRyeHealthServlet.java │ │ ├── SmallRyeLivenessServlet.java │ │ ├── SmallRyeStartupServlet.java │ │ ├── SmallRyeWellnessServlet.java │ │ ├── SmallRyeReadinessServlet.java │ │ └── SmallRyeHealthGroupServlet.java ├── experimental │ ├── src │ │ └── test │ │ │ ├── resources │ │ │ ├── META-INF │ │ │ │ ├── services │ │ │ │ │ └── org.jboss.arquillian.core.spi.LoadableExtension │ │ │ │ └── beans.xml │ │ │ └── arquillian.xml │ │ │ └── java │ │ │ └── io │ │ │ └── smallrye │ │ │ └── health │ │ │ ├── deployment │ │ │ ├── DependentCallRecorder.java │ │ │ ├── ContextInfo.java │ │ │ ├── SuccessStartup.java │ │ │ ├── SuccessWellness.java │ │ │ ├── SuccessLiveness.java │ │ │ ├── FailedLiveness.java │ │ │ ├── HealthGroup1.java │ │ │ ├── SuccessReadiness.java │ │ │ ├── NullHealthCheckProducer.java │ │ │ ├── TestHealthContentFilter.java │ │ │ ├── TestHealthContentFilter2.java │ │ │ ├── DefaultGroupExplicit.java │ │ │ ├── HealthGroup12.java │ │ │ ├── ContextHealthCheck.java │ │ │ ├── FailedLivenessAsync.java │ │ │ ├── SuccessLivenessAsync.java │ │ │ ├── FailedReadinessAsync.java │ │ │ ├── SuccessReadinessAsync.java │ │ │ ├── ChangingLivenessHealthCheck.java │ │ │ ├── DependentHealthCheck.java │ │ │ ├── AsyncDependentHealthCheck.java │ │ │ ├── ChangingReadinessHealthCheckAsync.java │ │ │ ├── RequestFilter.java │ │ │ ├── SuccessfulWellness.java │ │ │ ├── FailedWellness.java │ │ │ ├── FailedHealthGroup2.java │ │ │ ├── FailedStartupAsync.java │ │ │ ├── SuccessfulWellnessAsync.java │ │ │ ├── SuccessfulStartupAsync.java │ │ │ └── TestHealthObserver.java │ │ │ ├── SmallRyeHealthExtension.java │ │ │ ├── test │ │ │ ├── DeploymentUtils.java │ │ │ ├── NullHealthCheckProducerTest.java │ │ │ ├── WellnessFailedTest.java │ │ │ ├── SingleStartupAsyncFailedTest.java │ │ │ ├── ContextPropagatedHealthTest.java │ │ │ ├── SingleStartupAsyncSuccessfulTest.java │ │ │ ├── SingleCustomSuccessfulTest.java │ │ │ ├── WellnessSuccessfulTest.java │ │ │ ├── AllCustomFailedTest.java │ │ │ ├── MultipleCustomFailedTest.java │ │ │ ├── AsyncHealthTest.java │ │ │ ├── AsyncFailedHealthTest.java │ │ │ ├── AdditionalHealthPropertiesTest.java │ │ │ ├── DependentHealthChecksTest.java │ │ │ ├── ChangingHealthTest.java │ │ │ ├── AsyncSyncHealthTest.java │ │ │ ├── HealthContentFilterTest.java │ │ │ └── DisableHealthCheckTest.java │ │ │ └── SmallRyeHealthArchiveProcessor.java │ └── pom.xml └── pom.xml ├── implementation ├── src │ ├── main │ │ ├── resources │ │ │ └── META-INF │ │ │ │ ├── services │ │ │ │ └── org.eclipse.microprofile.health.spi.HealthCheckResponseProvider │ │ │ │ └── beans.xml │ │ └── java │ │ │ └── io │ │ │ └── smallrye │ │ │ └── health │ │ │ ├── ResponseProvider.java │ │ │ ├── HealthMessages.java │ │ │ ├── Response.java │ │ │ ├── event │ │ │ └── SmallRyeHealthStatusChangeEvent.java │ │ │ ├── HealthLogging.java │ │ │ ├── SmallRyeHealth.java │ │ │ ├── ResponseBuilder.java │ │ │ ├── registry │ │ │ ├── HealthRegistryImpl.java │ │ │ └── HealthRegistries.java │ │ │ ├── HealthStatus.java │ │ │ └── AsyncHealthCheckFactory.java │ └── test │ │ └── java │ │ └── io │ │ └── smallrye │ │ └── health │ │ ├── AsyncHealthCheckFactoryTest.java │ │ ├── ResponseBuilderTest.java │ │ ├── ProgrammaticAccessSanityTest.java │ │ ├── HealthCheckResponseProviderTest.java │ │ └── HealthStatusTest.java └── pom.xml ├── api ├── src │ └── main │ │ └── java │ │ └── io │ │ └── smallrye │ │ └── health │ │ └── api │ │ ├── HealthType.java │ │ ├── HealthContentFilter.java │ │ ├── AsyncHealthCheck.java │ │ ├── HealthGroups.java │ │ ├── Wellness.java │ │ └── HealthGroup.java └── pom.xml ├── provided-checks ├── src │ ├── main │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── beans.xml │ │ └── java │ │ │ └── io │ │ │ └── smallrye │ │ │ └── health │ │ │ └── checks │ │ │ ├── HeapMemoryHealthCheck.java │ │ │ ├── NonHeapMemoryHealthCheck.java │ │ │ ├── HealthChecksLogging.java │ │ │ ├── AbstractHeapMemoryHealthCheck.java │ │ │ ├── SystemLoadHealthCheck.java │ │ │ ├── SocketHealthCheck.java │ │ │ ├── InetAddressHealthCheck.java │ │ │ └── UrlHealthCheck.java │ └── test │ │ └── java │ │ └── io │ │ └── smallrye │ │ └── health │ │ └── checks │ │ ├── InetAddressHealthCheckTest.java │ │ ├── SocketHealthCheckTest.java │ │ └── UrlHealthCheckTest.java └── pom.xml ├── message-ranges.txt ├── release └── pom.xml ├── .gitignore └── README.adoc /CODEOWNERS: -------------------------------------------------------------------------------- 1 | .github @smallrye/config 2 | -------------------------------------------------------------------------------- /ui/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smallrye/smallrye-health/HEAD/ui/screenshot.png -------------------------------------------------------------------------------- /ui/screenshot_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smallrye/smallrye-health/HEAD/ui/screenshot_settings.png -------------------------------------------------------------------------------- /.github/project.yml: -------------------------------------------------------------------------------- 1 | name: SmallRye Health 2 | release: 3 | current-version: 4.3.0 4 | next-version: 4.3.1-SNAPSHOT 5 | -------------------------------------------------------------------------------- /doc/antora.yml: -------------------------------------------------------------------------------- 1 | name: smallrye-health 2 | title: SmallRye Health 3 | version: 3.2.0 4 | nav: 5 | - modules/ROOT/nav.adoc 6 | -------------------------------------------------------------------------------- /ui/src/main/webapp/health-ui/style.css: -------------------------------------------------------------------------------- 1 | .grid-item { 2 | width: 30%; 3 | } 4 | .gutter-sizer { 5 | width: 1%; 6 | } 7 | -------------------------------------------------------------------------------- /ui/src/main/webapp/health-ui/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smallrye/smallrye-health/HEAD/ui/src/main/webapp/health-ui/logo.png -------------------------------------------------------------------------------- /ui/src/main/webapp/health-ui/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smallrye/smallrye-health/HEAD/ui/src/main/webapp/health-ui/favicon.ico -------------------------------------------------------------------------------- /ui/src/main/webapp/health-ui/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smallrye/smallrye-health/HEAD/ui/src/main/webapp/health-ui/refresh.png -------------------------------------------------------------------------------- /ui/src/main/webapp/health-ui/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smallrye/smallrye-health/HEAD/ui/src/main/webapp/health-ui/settings.png -------------------------------------------------------------------------------- /testsuite/tck/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension: -------------------------------------------------------------------------------- 1 | io.smallrye.health.SmallRyeHealthExtension 2 | -------------------------------------------------------------------------------- /implementation/src/main/resources/META-INF/services/org.eclipse.microprofile.health.spi.HealthCheckResponseProvider: -------------------------------------------------------------------------------- 1 | io.smallrye.health.ResponseProvider 2 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension: -------------------------------------------------------------------------------- 1 | io.smallrye.health.SmallRyeHealthExtension 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /api/src/main/java/io/smallrye/health/api/HealthType.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.api; 2 | 3 | /** 4 | * The default types of health representing out-of-the-box health check groups. 5 | */ 6 | public enum HealthType { 7 | LIVENESS, 8 | READINESS, 9 | WELLNESS, 10 | STARTUP 11 | } 12 | -------------------------------------------------------------------------------- /provided-checks/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/DependentCallRecorder.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | public class DependentCallRecorder { 4 | 5 | public static volatile boolean healthCheckPreDestroyCalled = false; 6 | public static volatile boolean asyncHealthCheckPreDestroyCalled = false; 7 | 8 | } 9 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /doc/modules/ROOT/nav.adoc: -------------------------------------------------------------------------------- 1 | * xref:index.adoc[Index] 2 | * Features on top of the specification 3 | ** xref:async-checks.adoc[Asynchronous health checks] 4 | ** xref:health-groups.adoc[Health Groups] 5 | ** xref:health-registry.adoc[Health Registry] 6 | ** xref:wellness.adoc[Wellness] 7 | ** xref:static-access.adoc[Static access] 8 | ** xref:custom-config-properties.adoc[Custom Config properties] 9 | 10 | -------------------------------------------------------------------------------- /implementation/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/ContextInfo.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.enterprise.context.RequestScoped; 4 | 5 | @RequestScoped 6 | public class ContextInfo { 7 | 8 | private String value; 9 | 10 | public String getValue() { 11 | return value; 12 | } 13 | 14 | public void setValue(String value) { 15 | this.value = value; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/update-milestone.yml: -------------------------------------------------------------------------------- 1 | name: Update Milestone 2 | 3 | on: 4 | pull_request_target: 5 | types: [closed] 6 | 7 | jobs: 8 | update: 9 | runs-on: ubuntu-latest 10 | name: update-milestone 11 | if: ${{github.event.pull_request.merged == true}} 12 | 13 | steps: 14 | - uses: radcortez/milestone-set-action@main 15 | name: milestone set 16 | with: 17 | github-token: ${{secrets.GITHUB_TOKEN}} 18 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/health/ResponseProvider.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import org.eclipse.microprofile.health.HealthCheckResponseBuilder; 4 | import org.eclipse.microprofile.health.spi.HealthCheckResponseProvider; 5 | 6 | public class ResponseProvider implements HealthCheckResponseProvider { 7 | 8 | @Override 9 | public HealthCheckResponseBuilder createResponseBuilder() { 10 | return new ResponseBuilder(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.github/workflows/prepare-release.yml: -------------------------------------------------------------------------------- 1 | name: SmallRye Prepare Release 2 | 3 | on: 4 | pull_request: 5 | types: [ closed ] 6 | paths: 7 | - '.github/project.yml' 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | prepare-release: 15 | name: Prepare Release 16 | if: ${{ github.event.pull_request.merged == true}} 17 | uses: smallrye/.github/.github/workflows/prepare-release.yml@main 18 | secrets: inherit 19 | -------------------------------------------------------------------------------- /doc/antora-playbook.yml: -------------------------------------------------------------------------------- 1 | # partial playbook just for this project to be able to compile documentation without pushing it to GitHub 2 | # usage: antora generate antora-playbook.yml 3 | site: 4 | title: SmallRye Health only documentation 5 | start_page: smallrye-health::index.adoc 6 | content: 7 | sources: 8 | - url: .. 9 | start_path: doc 10 | branches: HEAD 11 | ui: 12 | bundle: 13 | url: https://github.com/smallrye/smallrye-antora-ui/blob/main/build/ui-bundle.zip?raw=true 14 | snapshot: true 15 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/SuccessStartup.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | 5 | import org.eclipse.microprofile.health.HealthCheck; 6 | import org.eclipse.microprofile.health.HealthCheckResponse; 7 | import org.eclipse.microprofile.health.Startup; 8 | 9 | @Startup 10 | @ApplicationScoped 11 | public class SuccessStartup implements HealthCheck { 12 | @Override 13 | public HealthCheckResponse call() { 14 | return HealthCheckResponse.up(SuccessStartup.class.getName()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/SuccessWellness.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | 5 | import org.eclipse.microprofile.health.HealthCheck; 6 | import org.eclipse.microprofile.health.HealthCheckResponse; 7 | 8 | import io.smallrye.health.api.Wellness; 9 | 10 | @Wellness 11 | @ApplicationScoped 12 | public class SuccessWellness implements HealthCheck { 13 | @Override 14 | public HealthCheckResponse call() { 15 | return HealthCheckResponse.up(SuccessWellness.class.getName()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/SuccessLiveness.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | 5 | import org.eclipse.microprofile.health.HealthCheck; 6 | import org.eclipse.microprofile.health.HealthCheckResponse; 7 | import org.eclipse.microprofile.health.Liveness; 8 | 9 | @Liveness 10 | @ApplicationScoped 11 | public class SuccessLiveness implements HealthCheck { 12 | @Override 13 | public HealthCheckResponse call() { 14 | return HealthCheckResponse.up(SuccessLiveness.class.getName()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/FailedLiveness.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | 5 | import org.eclipse.microprofile.health.HealthCheck; 6 | import org.eclipse.microprofile.health.HealthCheckResponse; 7 | import org.eclipse.microprofile.health.Liveness; 8 | 9 | @Liveness 10 | @ApplicationScoped 11 | public class FailedLiveness implements HealthCheck { 12 | 13 | @Override 14 | public HealthCheckResponse call() { 15 | return HealthCheckResponse.down(FailedLiveness.class.getName()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/HealthGroup1.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | 5 | import org.eclipse.microprofile.health.HealthCheck; 6 | import org.eclipse.microprofile.health.HealthCheckResponse; 7 | 8 | import io.smallrye.health.api.HealthGroup; 9 | 10 | @HealthGroup("health-group-1") 11 | @ApplicationScoped 12 | public class HealthGroup1 implements HealthCheck { 13 | 14 | @Override 15 | public HealthCheckResponse call() { 16 | return HealthCheckResponse.up("health-group-1"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/SuccessReadiness.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | 5 | import org.eclipse.microprofile.health.HealthCheck; 6 | import org.eclipse.microprofile.health.HealthCheckResponse; 7 | import org.eclipse.microprofile.health.Readiness; 8 | 9 | @Readiness 10 | @ApplicationScoped 11 | public class SuccessReadiness implements HealthCheck { 12 | @Override 13 | public HealthCheckResponse call() { 14 | return HealthCheckResponse.up(SuccessReadiness.class.getName()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/NullHealthCheckProducer.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | import jakarta.enterprise.context.Dependent; 5 | import jakarta.enterprise.inject.Produces; 6 | 7 | import org.eclipse.microprofile.health.HealthCheck; 8 | import org.eclipse.microprofile.health.Liveness; 9 | 10 | @ApplicationScoped 11 | public class NullHealthCheckProducer { 12 | 13 | @Produces 14 | @Dependent 15 | @Liveness 16 | public HealthCheck nullHealthCheck() { 17 | return null; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/TestHealthContentFilter.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | import jakarta.json.Json; 5 | import jakarta.json.JsonObject; 6 | 7 | import io.smallrye.health.api.HealthContentFilter; 8 | 9 | @ApplicationScoped 10 | public class TestHealthContentFilter implements HealthContentFilter { 11 | 12 | @Override 13 | public JsonObject filter(JsonObject payload) { 14 | return Json.createObjectBuilder(payload) 15 | .add("foo", "bar") 16 | .build(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/TestHealthContentFilter2.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | import jakarta.json.Json; 5 | import jakarta.json.JsonObject; 6 | 7 | import io.smallrye.health.api.HealthContentFilter; 8 | 9 | @ApplicationScoped 10 | public class TestHealthContentFilter2 implements HealthContentFilter { 11 | 12 | @Override 13 | public JsonObject filter(JsonObject payload) { 14 | return Json.createObjectBuilder(payload) 15 | .add("foo2", "bar2") 16 | .build(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/DefaultGroupExplicit.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | 5 | import org.eclipse.microprofile.health.HealthCheck; 6 | import org.eclipse.microprofile.health.HealthCheckResponse; 7 | 8 | import io.smallrye.health.api.HealthGroup; 9 | 10 | @HealthGroup("default-group") 11 | @ApplicationScoped 12 | public class DefaultGroupExplicit implements HealthCheck { 13 | 14 | @Override 15 | public HealthCheckResponse call() { 16 | return HealthCheckResponse.up(DefaultGroupExplicit.class.getName()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/HealthGroup12.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | 5 | import org.eclipse.microprofile.health.HealthCheck; 6 | import org.eclipse.microprofile.health.HealthCheckResponse; 7 | 8 | import io.smallrye.health.api.HealthGroup; 9 | 10 | @HealthGroup("health-group-1") 11 | @HealthGroup("health-group-2") 12 | @ApplicationScoped 13 | public class HealthGroup12 implements HealthCheck { 14 | 15 | @Override 16 | public HealthCheckResponse call() { 17 | return HealthCheckResponse.up("health-group-12"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/ContextHealthCheck.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | import jakarta.inject.Inject; 5 | 6 | import org.eclipse.microprofile.health.HealthCheck; 7 | import org.eclipse.microprofile.health.HealthCheckResponse; 8 | 9 | import io.smallrye.health.api.Wellness; 10 | 11 | @Wellness 12 | @ApplicationScoped 13 | public class ContextHealthCheck implements HealthCheck { 14 | 15 | @Inject 16 | ContextInfo context; 17 | 18 | @Override 19 | public HealthCheckResponse call() { 20 | return HealthCheckResponse.up(context.getValue()); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/resources/arquillian.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /implementation/src/test/java/io/smallrye/health/AsyncHealthCheckFactoryTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.BeforeEach; 5 | import org.junit.jupiter.api.Test; 6 | 7 | public class AsyncHealthCheckFactoryTest { 8 | 9 | private AsyncHealthCheckFactory asyncHealthCheckFactory; 10 | 11 | @BeforeEach 12 | public void beforeEach() { 13 | asyncHealthCheckFactory = new AsyncHealthCheckFactory(); 14 | } 15 | 16 | @Test 17 | public void nulluncheckedExceptionDataStyleTest() { 18 | Assertions.assertThrows(NullPointerException.class, () -> asyncHealthCheckFactory.setUncheckedExceptionDataStyle(null)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/resources/arquillian.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/health/HealthMessages.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import java.lang.invoke.MethodHandles; 4 | 5 | import org.jboss.logging.Messages; 6 | import org.jboss.logging.annotations.Message; 7 | import org.jboss.logging.annotations.MessageBundle; 8 | 9 | @MessageBundle(projectCode = "SRHCK", length = 5) 10 | interface HealthMessages { 11 | HealthMessages msg = Messages.getBundle(MethodHandles.lookup(), HealthMessages.class); 12 | 13 | @Message(id = 0, value = "Health Check contains an invalid name. Can not be null or empty.") 14 | IllegalArgumentException invalidHealthCheckName(); 15 | 16 | @Message(id = 1, value = "Health Check returned null.") 17 | NullPointerException healthCheckNull(); 18 | } 19 | -------------------------------------------------------------------------------- /doc/modules/ROOT/pages/index.adoc: -------------------------------------------------------------------------------- 1 | [[index]] 2 | = SmallRye Health Documentation 3 | 4 | SmallRye Health 3.0 is an implementation of the MicroProfile Health 3.0 specification. 5 | 6 | Runtimes that currently use it as their health monitoring implementation include: 7 | 8 | * https://quarkus.io/[Quarkus] 9 | * https://wildfly.org/[WildFly] 10 | * https://thorntail.io/[Thorntail] 11 | 12 | 13 | [[more-resources]] 14 | == More Resources 15 | 16 | * https://github.com/smallrye/smallrye-health/[SmallRye Health GitHub project repository] 17 | * https://github.com/eclipse/microprofile-health/[Eclipse MicroProfile Health repository] 18 | * https://download.eclipse.org/microprofile/microprofile-health-3.0/microprofile-health-spec-3.0.html[MicroProfile 3.0 specification text] 19 | -------------------------------------------------------------------------------- /message-ranges.txt: -------------------------------------------------------------------------------- 1 | # This document is intended to establish the ranges for message IDs in the various sub-projects. 2 | 3 | # Range = owner 4 | 5 | 00000-00999 = smallrye-health [io.smallrye.health] (messages) 6 | 7 | 01000-01999 = smallrye-health [io.smallrye.health] (logging) 8 | 9 | 02000-02999 = smallrye-health [io.smallrye.health.checks] (logging) 10 | 11 | 03000-03999 = 12 | 13 | 04000-04999 = 14 | 15 | 05000-05999 = 16 | 17 | 06000-06999 = 18 | 19 | 07000-07999 = 20 | 21 | 08000-08999 = 22 | 23 | 09000-09999 = 24 | 25 | 10000-10999 = 26 | 27 | 11000-11999 = 28 | 29 | 12000-12999 = 30 | 31 | 13000-13999 = 32 | 33 | 14000-14999 = 34 | 35 | 15000-15999 = 36 | 37 | 16000-16999 = 38 | 39 | 17000-17999 = 40 | 41 | 18000-18999 = 42 | 43 | 19000-19999 = -------------------------------------------------------------------------------- /release/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.smallrye 7 | smallrye-health-parent 8 | 4.3.1-SNAPSHOT 9 | 10 | 11 | smallrye-health-release 12 | 13 | SmallRye Health: Empty Release Project to Avoid Maven Bug 14 | Empty Release Project to Avoid Maven Bug 15 | 16 | pom 17 | 18 | 19 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/FailedLivenessAsync.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import java.time.Duration; 4 | 5 | import jakarta.enterprise.context.ApplicationScoped; 6 | 7 | import org.eclipse.microprofile.health.HealthCheckResponse; 8 | import org.eclipse.microprofile.health.Liveness; 9 | 10 | import io.smallrye.health.api.AsyncHealthCheck; 11 | import io.smallrye.mutiny.Uni; 12 | 13 | @Liveness 14 | @ApplicationScoped 15 | public class FailedLivenessAsync implements AsyncHealthCheck { 16 | 17 | @Override 18 | public Uni call() { 19 | return Uni.createFrom().item(HealthCheckResponse.down(FailedLivenessAsync.class.getName())) 20 | .onItem().delayIt().by(Duration.ofMillis(10)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/SuccessLivenessAsync.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import java.time.Duration; 4 | 5 | import jakarta.enterprise.context.ApplicationScoped; 6 | 7 | import org.eclipse.microprofile.health.HealthCheckResponse; 8 | import org.eclipse.microprofile.health.Liveness; 9 | 10 | import io.smallrye.health.api.AsyncHealthCheck; 11 | import io.smallrye.mutiny.Uni; 12 | 13 | @Liveness 14 | @ApplicationScoped 15 | public class SuccessLivenessAsync implements AsyncHealthCheck { 16 | 17 | @Override 18 | public Uni call() { 19 | return Uni.createFrom().item(HealthCheckResponse.up(SuccessLivenessAsync.class.getName())) 20 | .onItem().delayIt().by(Duration.ofMillis(10)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /implementation/src/test/java/io/smallrye/health/ResponseBuilderTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | public class ResponseBuilderTest { 7 | 8 | @Test 9 | public void testWhenNameIsNullThrowsIllegalArgumentException() { 10 | final ResponseBuilder responseBuilder = new ResponseBuilder(); 11 | Assertions.assertThrows(IllegalArgumentException.class, responseBuilder::build); 12 | } 13 | 14 | @Test 15 | public void testWhenNameIsEmptyStringThrowsIllegalArgumentException() { 16 | final ResponseBuilder responseBuilder = new ResponseBuilder(); 17 | responseBuilder.name(""); 18 | Assertions.assertThrows(IllegalArgumentException.class, responseBuilder::build); 19 | } 20 | } -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/FailedReadinessAsync.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import java.time.Duration; 4 | 5 | import jakarta.enterprise.context.ApplicationScoped; 6 | 7 | import org.eclipse.microprofile.health.HealthCheckResponse; 8 | import org.eclipse.microprofile.health.Readiness; 9 | 10 | import io.smallrye.health.api.AsyncHealthCheck; 11 | import io.smallrye.mutiny.Uni; 12 | 13 | @Readiness 14 | @ApplicationScoped 15 | public class FailedReadinessAsync implements AsyncHealthCheck { 16 | 17 | @Override 18 | public Uni call() { 19 | return Uni.createFrom().item(HealthCheckResponse.down(FailedReadinessAsync.class.getName())) 20 | .onItem().delayIt().by(Duration.ofMillis(10)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/SuccessReadinessAsync.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import java.time.Duration; 4 | 5 | import jakarta.enterprise.context.ApplicationScoped; 6 | 7 | import org.eclipse.microprofile.health.HealthCheckResponse; 8 | import org.eclipse.microprofile.health.Readiness; 9 | 10 | import io.smallrye.health.api.AsyncHealthCheck; 11 | import io.smallrye.mutiny.Uni; 12 | 13 | @Readiness 14 | @ApplicationScoped 15 | public class SuccessReadinessAsync implements AsyncHealthCheck { 16 | 17 | @Override 18 | public Uni call() { 19 | return Uni.createFrom().item(HealthCheckResponse.up(SuccessReadinessAsync.class.getName())) 20 | .onItem().delayIt().by(Duration.ofMillis(10)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/ChangingLivenessHealthCheck.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | import jakarta.enterprise.context.ApplicationScoped; 6 | 7 | import org.eclipse.microprofile.health.HealthCheck; 8 | import org.eclipse.microprofile.health.HealthCheckResponse; 9 | import org.eclipse.microprofile.health.Liveness; 10 | 11 | @Liveness 12 | @ApplicationScoped 13 | public class ChangingLivenessHealthCheck implements HealthCheck { 14 | 15 | private final AtomicInteger invocations = new AtomicInteger(0); 16 | 17 | @Override 18 | public HealthCheckResponse call() { 19 | return invocations.getAndIncrement() == 0 ? HealthCheckResponse.up("up") : HealthCheckResponse.down("down"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/DependentHealthCheck.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.annotation.PreDestroy; 4 | import jakarta.enterprise.context.Dependent; 5 | 6 | import org.eclipse.microprofile.health.HealthCheck; 7 | import org.eclipse.microprofile.health.HealthCheckResponse; 8 | import org.eclipse.microprofile.health.Liveness; 9 | 10 | @Dependent 11 | @Liveness 12 | public class DependentHealthCheck implements HealthCheck { 13 | 14 | @Override 15 | public org.eclipse.microprofile.health.HealthCheckResponse call() { 16 | return HealthCheckResponse.up(DependentHealthCheck.class.getName()); 17 | } 18 | 19 | @PreDestroy 20 | public void preDestroy() { 21 | DependentCallRecorder.healthCheckPreDestroyCalled = true; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/AsyncDependentHealthCheck.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import jakarta.annotation.PreDestroy; 4 | import jakarta.enterprise.context.Dependent; 5 | 6 | import org.eclipse.microprofile.health.HealthCheckResponse; 7 | import org.eclipse.microprofile.health.Liveness; 8 | 9 | import io.smallrye.health.api.AsyncHealthCheck; 10 | import io.smallrye.mutiny.Uni; 11 | 12 | @Dependent 13 | @Liveness 14 | public class AsyncDependentHealthCheck implements AsyncHealthCheck { 15 | 16 | @Override 17 | public Uni call() { 18 | return Uni.createFrom().item(HealthCheckResponse.up(AsyncDependentHealthCheck.class.getName())); 19 | } 20 | 21 | @PreDestroy 22 | public void preDestroy() { 23 | DependentCallRecorder.asyncHealthCheckPreDestroyCalled = true; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/ChangingReadinessHealthCheckAsync.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | import jakarta.enterprise.context.ApplicationScoped; 6 | 7 | import org.eclipse.microprofile.health.HealthCheckResponse; 8 | import org.eclipse.microprofile.health.Readiness; 9 | 10 | import io.smallrye.health.api.AsyncHealthCheck; 11 | import io.smallrye.mutiny.Uni; 12 | 13 | @Readiness 14 | @ApplicationScoped 15 | public class ChangingReadinessHealthCheckAsync implements AsyncHealthCheck { 16 | 17 | private final AtomicInteger invocations = new AtomicInteger(0); 18 | 19 | @Override 20 | public Uni call() { 21 | return Uni.createFrom() 22 | .item(invocations.getAndIncrement() == 0 ? HealthCheckResponse.up("up") : HealthCheckResponse.down("down")); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/health/Response.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import java.util.Map; 4 | import java.util.Optional; 5 | 6 | import org.eclipse.microprofile.health.HealthCheckResponse; 7 | 8 | class Response extends HealthCheckResponse { 9 | 10 | Response(String name, Status status, Map data) { 11 | this.name = name; 12 | this.status = status; 13 | this.data = data; 14 | } 15 | 16 | @Override 17 | public String getName() { 18 | return this.name; 19 | } 20 | 21 | @Override 22 | public Status getStatus() { 23 | return this.status; 24 | } 25 | 26 | @Override 27 | public Optional> getData() { 28 | return Optional.ofNullable(this.data); 29 | } 30 | 31 | private final String name; 32 | 33 | private final Status status; 34 | 35 | private final Map data; 36 | } 37 | -------------------------------------------------------------------------------- /ui/README.md: -------------------------------------------------------------------------------- 1 | # Health UI 2 | 3 | Even though MicroProfile Health API is build for System to System use, it's still nice to look at the output of /health. 4 | This library gives you a small web gui on top of ```/health``` 5 | 6 | ## Adding Health UI 7 | 8 | In ```pom.xml``` 9 | 10 | ```xml 11 | 12 | 13 | io.smallrye 14 | smallrye-health-ui 15 | XXXXX 16 | runtime 17 | 18 | 19 | ``` 20 | 21 | Then go to //health-ui, eg: http://localhost:8080/health-example/health-ui/ 22 | 23 | ## Example screenshot 24 | 25 | ### Dashboard 26 | 27 |  28 | 29 | ### Settings (to refresh automatically etc.) 30 | 31 |  32 | -------------------------------------------------------------------------------- /api/src/main/java/io/smallrye/health/api/HealthContentFilter.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.api; 2 | 3 | import jakarta.json.JsonObject; 4 | 5 | import io.smallrye.common.annotation.Experimental; 6 | 7 | /** 8 | * Implementations of this interface are invoked prior the health report to filter(remove, add, or modify) fields in the 9 | * returned JSON object. Individual implementations are collected through CDI so they must be annotated with some of the 10 | * bean-defining annotations (e.g., {@link jakarta.enterprise.context.ApplicationScoped}). 11 | */ 12 | @FunctionalInterface 13 | @Experimental("Health content filtering") 14 | public interface HealthContentFilter { 15 | 16 | /** 17 | * Filters (removes, adds, or modifies) fields in the provided {@link JsonObject}. 18 | * 19 | * @param payload An object representing the payload to be reported to the caller. 20 | */ 21 | JsonObject filter(JsonObject payload); 22 | } 23 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: SmallRye Release 2 | run-name: Perform ${{github.event.inputs.tag || github.ref_name}} Release 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | workflow_dispatch: 8 | inputs: 9 | tag: 10 | description: 'Tag to release' 11 | required: true 12 | 13 | permissions: 14 | attestations: write 15 | id-token: write 16 | # Needed for the publish-* workflows 17 | contents: write 18 | 19 | concurrency: 20 | group: ${{ github.workflow }}-${{ github.ref }} 21 | cancel-in-progress: true 22 | 23 | jobs: 24 | perform-release: 25 | name: Perform Release 26 | uses: smallrye/.github/.github/workflows/perform-release.yml@main 27 | secrets: inherit 28 | with: 29 | version: ${{github.event.inputs.tag || github.ref_name}} 30 | 31 | publish-tck: 32 | name: Publish TCK Report 33 | uses: ./.github/workflows/publish-tck.yml 34 | secrets: inherit 35 | with: 36 | version: ${{github.event.inputs.tag || github.ref_name}} 37 | -------------------------------------------------------------------------------- /implementation/src/test/java/io/smallrye/health/ProgrammaticAccessSanityTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | /** 7 | * Sanity test cases for classes that use injected config values but can be also initialized in non-CDI environments. 8 | */ 9 | public class ProgrammaticAccessSanityTest { 10 | 11 | @Test 12 | public void testSmallRyeHealthReporterInitialization() { 13 | SmallRyeHealthReporter reporter = new SmallRyeHealthReporter(); 14 | Assertions.assertNotNull(reporter); 15 | Assertions.assertNotNull(reporter.emptyChecksOutcome); 16 | Assertions.assertNotNull(reporter.additionalProperties); 17 | } 18 | 19 | @Test 20 | public void testAsyncHealthCheckFactoryInitialization() { 21 | AsyncHealthCheckFactory factory = new AsyncHealthCheckFactory(); 22 | Assertions.assertNotNull(factory); 23 | Assertions.assertNotNull(factory.uncheckedExceptionDataStyle); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/RequestFilter.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import java.io.IOException; 4 | 5 | import jakarta.inject.Inject; 6 | import jakarta.servlet.FilterChain; 7 | import jakarta.servlet.ServletException; 8 | import jakarta.servlet.annotation.WebFilter; 9 | import jakarta.servlet.http.HttpFilter; 10 | import jakarta.servlet.http.HttpServletRequest; 11 | import jakarta.servlet.http.HttpServletResponse; 12 | 13 | @WebFilter(urlPatterns = "*", filterName = "ContextInfoFilter") 14 | public class RequestFilter extends HttpFilter { 15 | 16 | public static final String TEST_CONTEXT_HEADER = "X-CONTEXT"; 17 | 18 | @Inject 19 | ContextInfo contextInfo; 20 | 21 | @Override 22 | protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) 23 | throws IOException, ServletException { 24 | var value = req.getHeader(TEST_CONTEXT_HEADER); 25 | contextInfo.setValue(value); 26 | super.doFilter(req, res, chain); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /provided-checks/src/main/java/io/smallrye/health/checks/HeapMemoryHealthCheck.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.checks; 2 | 3 | import java.lang.management.MemoryMXBean; 4 | 5 | import org.eclipse.microprofile.health.HealthCheckResponse; 6 | 7 | /** 8 | * Health check implementation that is checking heap memory usage against available heap memory 9 | * 10 | * 11 | * {@code 12 | * @Produces 13 | * @ApplicationScoped 14 | * @Liveness 15 | * HealthCheck check1() { 16 | * return new HeapMemoryHealthCheck(); 17 | * } 18 | * } 19 | * 20 | */ 21 | public class HeapMemoryHealthCheck extends AbstractHeapMemoryHealthCheck { 22 | 23 | public HeapMemoryHealthCheck() { 24 | super(); 25 | } 26 | 27 | public HeapMemoryHealthCheck(double maxPercentage) { 28 | super(maxPercentage); 29 | } 30 | 31 | @Override 32 | String name() { 33 | return "heap-memory"; 34 | } 35 | 36 | @Override 37 | public HealthCheckResponse call() { 38 | return getHealthCheckResponse(MemoryMXBean::getHeapMemoryUsage); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /provided-checks/src/main/java/io/smallrye/health/checks/NonHeapMemoryHealthCheck.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.checks; 2 | 3 | import java.lang.management.MemoryMXBean; 4 | 5 | import org.eclipse.microprofile.health.HealthCheckResponse; 6 | 7 | /** 8 | * Health check implementation that is checking memory usage against available memory 9 | * 10 | * 11 | * {@code 12 | * @Produces 13 | * @ApplicationScoped 14 | * @Liveness 15 | * HealthCheck check1() { 16 | * return new NonHeapMemoryHealthCheck(); 17 | * } 18 | * } 19 | * 20 | */ 21 | public class NonHeapMemoryHealthCheck extends AbstractHeapMemoryHealthCheck { 22 | 23 | public NonHeapMemoryHealthCheck() { 24 | super(); 25 | } 26 | 27 | public NonHeapMemoryHealthCheck(double maxPercentage) { 28 | super(maxPercentage); 29 | } 30 | 31 | @Override 32 | String name() { 33 | return "non-heap-memory"; 34 | } 35 | 36 | @Override 37 | public HealthCheckResponse call() { 38 | return getHealthCheckResponse(MemoryMXBean::getNonHeapMemoryUsage); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /testsuite/tck/src/main/java/io/smallrye/health/SmallRyeHealthServlet.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import java.io.IOException; 4 | 5 | import jakarta.inject.Inject; 6 | import jakarta.servlet.annotation.WebServlet; 7 | import jakarta.servlet.http.HttpServlet; 8 | import jakarta.servlet.http.HttpServletRequest; 9 | import jakarta.servlet.http.HttpServletResponse; 10 | 11 | @SuppressWarnings("serial") 12 | @WebServlet(name = "SmallRyeHealthServlet", urlPatterns = "/health") 13 | public class SmallRyeHealthServlet extends HttpServlet { 14 | 15 | @Override 16 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) { 17 | 18 | SmallRyeHealth health = reporter.getHealth(); 19 | if (health.isDown()) { 20 | resp.setStatus(503); 21 | } 22 | try { 23 | reporter.reportHealth(resp.getOutputStream(), health); 24 | } catch (IOException ioe) { 25 | HealthLogging.logger.error(ioe); 26 | resp.setStatus(500); 27 | } 28 | } 29 | 30 | @Inject 31 | private SmallRyeHealthReporter reporter; 32 | } 33 | -------------------------------------------------------------------------------- /implementation/src/test/java/io/smallrye/health/HealthCheckResponseProviderTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import java.util.Map; 4 | 5 | import org.eclipse.microprofile.health.HealthCheckResponse; 6 | import org.eclipse.microprofile.health.HealthCheckResponse.Status; 7 | import org.junit.jupiter.api.Assertions; 8 | import org.junit.jupiter.api.Test; 9 | 10 | public class HealthCheckResponseProviderTest { 11 | 12 | @Test 13 | public void testProvider() { 14 | 15 | HealthCheckResponse healthStatus = HealthCheckResponse.named("test") 16 | .up() 17 | .withData("a", "b") 18 | .withData("c", "d") 19 | .build(); 20 | 21 | Assertions.assertEquals("test", healthStatus.getName()); 22 | Assertions.assertSame(Status.UP, healthStatus.getStatus()); 23 | Map data = healthStatus.getData().get(); 24 | Assertions.assertEquals(2, data.size()); 25 | Assertions.assertEquals("b", data.get("a"), "Expected a"); 26 | Assertions.assertEquals("d", data.get("c"), "Expected c"); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /testsuite/tck/src/main/java/io/smallrye/health/SmallRyeLivenessServlet.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import java.io.IOException; 4 | 5 | import jakarta.inject.Inject; 6 | import jakarta.servlet.annotation.WebServlet; 7 | import jakarta.servlet.http.HttpServlet; 8 | import jakarta.servlet.http.HttpServletRequest; 9 | import jakarta.servlet.http.HttpServletResponse; 10 | 11 | @SuppressWarnings("serial") 12 | @WebServlet(name = "SmallRyeLivenessServlet", urlPatterns = "/health/live") 13 | public class SmallRyeLivenessServlet extends HttpServlet { 14 | 15 | @Override 16 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) { 17 | 18 | SmallRyeHealth health = reporter.getLiveness(); 19 | if (health.isDown()) { 20 | resp.setStatus(503); 21 | } 22 | try { 23 | reporter.reportHealth(resp.getOutputStream(), health); 24 | } catch (IOException ioe) { 25 | HealthLogging.logger.error(ioe); 26 | resp.setStatus(500); 27 | } 28 | } 29 | 30 | @Inject 31 | private SmallRyeHealthReporter reporter; 32 | } 33 | -------------------------------------------------------------------------------- /testsuite/tck/src/main/java/io/smallrye/health/SmallRyeStartupServlet.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import java.io.IOException; 4 | 5 | import jakarta.inject.Inject; 6 | import jakarta.servlet.annotation.WebServlet; 7 | import jakarta.servlet.http.HttpServlet; 8 | import jakarta.servlet.http.HttpServletRequest; 9 | import jakarta.servlet.http.HttpServletResponse; 10 | 11 | @SuppressWarnings("serial") 12 | @WebServlet(name = "SmallRyeStartupServlet", urlPatterns = "/health/started") 13 | public class SmallRyeStartupServlet extends HttpServlet { 14 | 15 | @Override 16 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) { 17 | 18 | SmallRyeHealth health = reporter.getStartup(); 19 | if (health.isDown()) { 20 | resp.setStatus(503); 21 | } 22 | try { 23 | reporter.reportHealth(resp.getOutputStream(), health); 24 | } catch (IOException ioe) { 25 | HealthLogging.logger.error(ioe); 26 | resp.setStatus(500); 27 | } 28 | } 29 | 30 | @Inject 31 | private SmallRyeHealthReporter reporter; 32 | } 33 | -------------------------------------------------------------------------------- /testsuite/tck/src/main/java/io/smallrye/health/SmallRyeWellnessServlet.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import java.io.IOException; 4 | 5 | import jakarta.inject.Inject; 6 | import jakarta.servlet.annotation.WebServlet; 7 | import jakarta.servlet.http.HttpServlet; 8 | import jakarta.servlet.http.HttpServletRequest; 9 | import jakarta.servlet.http.HttpServletResponse; 10 | 11 | @SuppressWarnings("serial") 12 | @WebServlet(name = "SmallRyeWellnessServlet", urlPatterns = "/health/well") 13 | public class SmallRyeWellnessServlet extends HttpServlet { 14 | 15 | @Override 16 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) { 17 | 18 | SmallRyeHealth health = reporter.getWellness(); 19 | if (health.isDown()) { 20 | resp.setStatus(503); 21 | } 22 | try { 23 | reporter.reportHealth(resp.getOutputStream(), health); 24 | } catch (IOException ioe) { 25 | HealthLogging.logger.error(ioe); 26 | resp.setStatus(500); 27 | } 28 | } 29 | 30 | @Inject 31 | private SmallRyeHealthReporter reporter; 32 | } 33 | -------------------------------------------------------------------------------- /testsuite/tck/src/main/java/io/smallrye/health/SmallRyeReadinessServlet.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import java.io.IOException; 4 | 5 | import jakarta.inject.Inject; 6 | import jakarta.servlet.annotation.WebServlet; 7 | import jakarta.servlet.http.HttpServlet; 8 | import jakarta.servlet.http.HttpServletRequest; 9 | import jakarta.servlet.http.HttpServletResponse; 10 | 11 | @SuppressWarnings("serial") 12 | @WebServlet(name = "SmallRyeReadinessServlet", urlPatterns = "/health/ready") 13 | public class SmallRyeReadinessServlet extends HttpServlet { 14 | 15 | @Override 16 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) { 17 | 18 | SmallRyeHealth health = reporter.getReadiness(); 19 | if (health.isDown()) { 20 | resp.setStatus(503); 21 | } 22 | try { 23 | reporter.reportHealth(resp.getOutputStream(), health); 24 | } catch (IOException ioe) { 25 | HealthLogging.logger.error(ioe); 26 | resp.setStatus(500); 27 | } 28 | } 29 | 30 | @Inject 31 | private SmallRyeHealthReporter reporter; 32 | } 33 | -------------------------------------------------------------------------------- /testsuite/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | smallrye-health-parent 5 | io.smallrye 6 | 4.3.1-SNAPSHOT 7 | 8 | 4.0.0 9 | 10 | smallrye-health-testsuite-parent 11 | SmallRye Health: Test Suite Parent 12 | pom 13 | 14 | 15 | experimental 16 | tck 17 | 18 | 19 | 20 | 21 | 22 | io.smallrye.testing 23 | smallrye-testing-bom-tck 24 | ${version.smallrye.testing} 25 | import 26 | pom 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/health/event/SmallRyeHealthStatusChangeEvent.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.event; 2 | 3 | import java.time.Instant; 4 | 5 | import io.smallrye.common.annotation.Experimental; 6 | import io.smallrye.health.SmallRyeHealth; 7 | import io.smallrye.health.api.HealthType; 8 | 9 | /** 10 | * Event for the health state changes. Can be consumed as a CDI event utilizing the 11 | * specification-defined qualifiers ({@link org.eclipse.microprofile.health.Liveness}, 12 | * {@link org.eclipse.microprofile.health.Readiness}). 13 | * 14 | * Example: 15 | * 16 | * 17 | * public void observeLiveness(@Observes @Liveness SmallRyeHealthStatusChangeEvent event) { 18 | * ... 19 | * } 20 | * 21 | */ 22 | @Experimental("Health change events") 23 | public record SmallRyeHealthStatusChangeEvent(Instant timestamp, HealthType healthType, SmallRyeHealth health) { 24 | 25 | public SmallRyeHealthStatusChangeEvent(SmallRyeHealth health) { 26 | this(null, health); 27 | } 28 | 29 | public SmallRyeHealthStatusChangeEvent(HealthType healthType, SmallRyeHealth health) { 30 | this(Instant.now(), healthType, health); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/java/io/smallrye/health/SmallRyeHealthExtension.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.smallrye.health; 18 | 19 | import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor; 20 | import org.jboss.arquillian.core.spi.LoadableExtension; 21 | 22 | public class SmallRyeHealthExtension implements LoadableExtension { 23 | @Override 24 | public void register(ExtensionBuilder builder) { 25 | builder.service(ApplicationArchiveProcessor.class, SmallRyeHealthArchiveProcessor.class); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/SmallRyeHealthExtension.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.smallrye.health; 18 | 19 | import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor; 20 | import org.jboss.arquillian.core.spi.LoadableExtension; 21 | 22 | public class SmallRyeHealthExtension implements LoadableExtension { 23 | @Override 24 | public void register(ExtensionBuilder builder) { 25 | builder.service(ApplicationArchiveProcessor.class, SmallRyeHealthArchiveProcessor.class); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/health/HealthLogging.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import java.lang.invoke.MethodHandles; 4 | 5 | import org.jboss.logging.BasicLogger; 6 | import org.jboss.logging.Logger; 7 | import org.jboss.logging.annotations.Cause; 8 | import org.jboss.logging.annotations.LogMessage; 9 | import org.jboss.logging.annotations.Message; 10 | import org.jboss.logging.annotations.MessageLogger; 11 | 12 | @MessageLogger(projectCode = "SRHCK", length = 5) 13 | interface HealthLogging extends BasicLogger { 14 | HealthLogging logger = Logger.getMessageLogger(MethodHandles.lookup(), HealthLogging.class, 15 | HealthLogging.class.getPackage().getName()); 16 | 17 | @LogMessage(level = Logger.Level.ERROR) 18 | @Message(id = 1000, value = "Error processing Health Checks") 19 | void healthCheckError(@Cause Throwable throwable); 20 | 21 | @LogMessage(level = Logger.Level.INFO) 22 | @Message(id = 1001, value = "Reporting health down status: %s") 23 | void healthDownStatus(String cause); 24 | 25 | @LogMessage(level = Logger.Level.ERROR) 26 | @Message(id = 1002, value = "Health change observer error") 27 | void healthChangeObserverError(@Cause Throwable throwable); 28 | } 29 | -------------------------------------------------------------------------------- /doc/modules/ROOT/pages/wellness.adoc: -------------------------------------------------------------------------------- 1 | [[wellness]] 2 | = Wellness 3 | 4 | The wellness is another health groups besides the liveness and readiness that can be standardized 5 | as a group of health checks that don't belong to either liveness (application restart) or 6 | readiness (traffic discards) but have a value for any post processing automatic or manual 7 | health monitoring. 8 | 9 | == The @Wellness annotation 10 | 11 | You can use the `@Wellness` annotation in a similar manner as `@Readiness` or `@Liveness`: 12 | 13 | [source,java] 14 | ---- 15 | @Wellness <1> 16 | @ApplicationScoped 17 | public class WellnessCheck implements HealthCheck { 18 | @Override 19 | public HealthCheckResponse call() { 20 | return HealthCheckResponse.up("wellness-check"); 21 | } 22 | } 23 | ---- 24 | <1> The `@Wellness` qualifier 25 | 26 | == Accessing the wellness checks 27 | 28 | The wellness checks are exposed under the `/health/well` endpoint. They are also available 29 | at grouped `/health` endpoint together with all other health checks (liveness, readiness, and 30 | health groups). 31 | 32 | == References 33 | 34 | * https://github.com/smallrye/smallrye-health/blob/main/api/src/main/java/io/smallrye/health/api/Wellness.java[`Wellness`] 35 | -------------------------------------------------------------------------------- /provided-checks/src/main/java/io/smallrye/health/checks/HealthChecksLogging.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.checks; 2 | 3 | import org.jboss.logging.BasicLogger; 4 | import org.jboss.logging.Logger; 5 | import org.jboss.logging.annotations.Cause; 6 | import org.jboss.logging.annotations.LogMessage; 7 | import org.jboss.logging.annotations.Message; 8 | import org.jboss.logging.annotations.MessageLogger; 9 | 10 | @MessageLogger(projectCode = "SRHCK", length = 5) 11 | interface HealthChecksLogging extends BasicLogger { 12 | HealthChecksLogging logger = Logger.getMessageLogger(HealthChecksLogging.class, 13 | HealthChecksLogging.class.getPackage().getName()); 14 | 15 | @LogMessage(level = Logger.Level.ERROR) 16 | @Message(id = 2000, value = "Reporting Socket health check error ") 17 | void socketHealthCheckError(@Cause Throwable throwable); 18 | 19 | @LogMessage(level = Logger.Level.ERROR) 20 | @Message(id = 2001, value = "Reporting InetAddress health check error ") 21 | void inetAddressHealthCheckError(@Cause Throwable throwable); 22 | 23 | @LogMessage(level = Logger.Level.ERROR) 24 | @Message(id = 2002, value = "Reporting URL health check error ") 25 | void urlHealthCheckError(@Cause Throwable throwable); 26 | } 27 | -------------------------------------------------------------------------------- /testsuite/tck/src/main/java/io/smallrye/health/SmallRyeHealthGroupServlet.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import java.io.IOException; 4 | 5 | import jakarta.inject.Inject; 6 | import jakarta.servlet.annotation.WebServlet; 7 | import jakarta.servlet.http.HttpServlet; 8 | import jakarta.servlet.http.HttpServletRequest; 9 | import jakarta.servlet.http.HttpServletResponse; 10 | 11 | @SuppressWarnings("serial") 12 | @WebServlet(name = "SmallRyeHealthGroupServlet", urlPatterns = "/health/group/*") 13 | public class SmallRyeHealthGroupServlet extends HttpServlet { 14 | 15 | @Override 16 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) { 17 | 18 | String pathInfo = req.getPathInfo(); 19 | SmallRyeHealth health = pathInfo != null ? reporter.getHealthGroup(pathInfo.substring(1)) : reporter.getHealthGroups(); 20 | if (health.isDown()) { 21 | resp.setStatus(503); 22 | } 23 | try { 24 | reporter.reportHealth(resp.getOutputStream(), health); 25 | } catch (IOException ioe) { 26 | HealthLogging.logger.error(ioe); 27 | resp.setStatus(500); 28 | } 29 | } 30 | 31 | @Inject 32 | private SmallRyeHealthReporter reporter; 33 | } 34 | -------------------------------------------------------------------------------- /.github/workflows/publish-tck.yml: -------------------------------------------------------------------------------- 1 | name: Publish TCK 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | version: 7 | required: true 8 | description: Tag version to perform release 9 | type: string 10 | 11 | jobs: 12 | publish-tck: 13 | name: Publish TCK 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | java: [ 17, 21 ] 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | name: checkout ${{inputs.version}} 22 | with: 23 | ref: ${{inputs.version}} 24 | 25 | - uses: actions/setup-java@v4 26 | name: set up jdk ${{matrix.java}} 27 | with: 28 | distribution: 'temurin' 29 | java-version: ${{matrix.java}} 30 | cache: 'maven' 31 | cache-dependency-path: '**/pom.xml' 32 | 33 | - name: generate tck report for jdk ${{matrix.java}} 34 | env: 35 | GH_TOKEN: ${{secrets.GITHUB_TOKEN}} 36 | ZIP_NAME: smallrye-health-${{inputs.version}}-tck-results-java-${{matrix.java}}.zip 37 | run: | 38 | mvn -B formatter:validate verify --file pom.xml 39 | cd testsuite/tck/target 40 | zip -r $ZIP_NAME surefire-reports/ 41 | gh release upload ${{inputs.version}} $ZIP_NAME 42 | -------------------------------------------------------------------------------- /provided-checks/src/test/java/io/smallrye/health/checks/InetAddressHealthCheckTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.checks; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import org.eclipse.microprofile.health.HealthCheckResponse; 6 | import org.junit.jupiter.api.Test; 7 | 8 | public class InetAddressHealthCheckTest { 9 | 10 | @Test 11 | public void testInetAddressCheck() { 12 | final InetAddressHealthCheck inetAddressHealthCheck = new InetAddressHealthCheck("127.0.0.1"); 13 | final HealthCheckResponse healthCheckResponse = inetAddressHealthCheck.call(); 14 | 15 | assertEquals(InetAddressHealthCheck.DEFAULT_NAME, healthCheckResponse.getName()); 16 | assertEquals("127.0.0.1", healthCheckResponse.getData().get().get("host")); 17 | assertEquals(HealthCheckResponse.Status.UP, healthCheckResponse.getStatus()); 18 | } 19 | 20 | @Test 21 | public void testInetAddressCheckNoneReachable() { 22 | final InetAddressHealthCheck inetAddressHealthCheck = new InetAddressHealthCheck("www.fdghreer.invalid"); 23 | final HealthCheckResponse healthCheckResponse = inetAddressHealthCheck.call(); 24 | 25 | assertEquals(HealthCheckResponse.Status.DOWN, healthCheckResponse.getStatus()); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore .svn metadata files 2 | .svn 3 | # ignore Maven generated target folders 4 | ~ 5 | target 6 | # ignore downloaded maven 7 | /tools/maven 8 | /tools/maven.zip 9 | # ignore eclipse files 10 | .project 11 | .classpath 12 | .settings 13 | .metadata 14 | .checkstyle 15 | # ignore m2e annotation processing files 16 | .factorypath 17 | # ignore IDEA files 18 | *.iml 19 | *.ipr 20 | *.iws 21 | .idea 22 | # ignore NetBeans files 23 | nbactions.xml 24 | nb-configuration.xml 25 | catalog.xml 26 | # 27 | maven-ant-tasks.jar 28 | test-output 29 | transaction.log 30 | # vim files 31 | *.swp 32 | /.gitk-tmp.* 33 | atlassian-ide-plugin.xml 34 | # temp files 35 | *~ 36 | # maven versions plugin 37 | pom.xml.versionsBackup 38 | # hprof dumps 39 | /*.hprof 40 | # ignore 'randomly' strewn around logs 41 | server.log 42 | # ignore java crashes 43 | hs_err_pid*.log 44 | # H2 databases produced by tests 45 | *.h2.db 46 | # JBoss transaction generated files 47 | PutObjectStoreDirHere 48 | # ignore mvn-rpmbuild repo 49 | /.m2 50 | # ignore eap repo 51 | local-repo-eap 52 | 53 | #These keep hanging around 54 | arquillian/*/server.log* 55 | client/shade/dependency-reduced-pom.xml 56 | 57 | #OS X stuff 58 | .DS_Store 59 | 60 | # Zanata files 61 | **/.zanata-cache/ 62 | .cache 63 | 64 | # antora 65 | doc/build 66 | 67 | -------------------------------------------------------------------------------- /api/src/main/java/io/smallrye/health/api/AsyncHealthCheck.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.api; 2 | 3 | import org.eclipse.microprofile.health.HealthCheckResponse; 4 | 5 | import io.smallrye.common.annotation.Experimental; 6 | import io.smallrye.mutiny.Uni; 7 | 8 | /** 9 | * The async health check procedure interface. 10 | * Invoked by consumers to verify the healthiness of a computing node in an asynchronous manner. 11 | * Unhealthy nodes are expected to be terminated. 12 | */ 13 | @FunctionalInterface 14 | @Experimental("Asynchronous Health Check procedures") 15 | public interface AsyncHealthCheck { 16 | 17 | /** 18 | * Invokes the health check procedure provided by the implementation of this interface. 19 | * Unlike synchronous checks, this method is used for asynchronous checks. The returned {@code Uni} 20 | * propagates the {@code HealthCheckResponse} as item. If the returned {@code Uni} produces 21 | * a failure, the check is considered as failed. Returning {@code null} is invalid and considers the 22 | * check failed. In addition, returning a {@code Uni} propagating a {@code null} value as the item 23 | * is considered also as a failure. 24 | * 25 | * @return {@link Uni} object containing information about the health check result 26 | */ 27 | Uni call(); 28 | } 29 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/health/SmallRyeHealth.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import static org.eclipse.microprofile.health.HealthCheckResponse.Status.DOWN; 4 | 5 | import java.util.Objects; 6 | 7 | import jakarta.json.JsonObject; 8 | 9 | import org.eclipse.microprofile.health.HealthCheckResponse; 10 | 11 | public class SmallRyeHealth { 12 | 13 | private final JsonObject payload; 14 | private final HealthCheckResponse.Status status; 15 | 16 | public SmallRyeHealth(JsonObject payload) { 17 | this.payload = payload; 18 | this.status = HealthCheckResponse.Status.valueOf(payload.getString("status")); 19 | } 20 | 21 | public JsonObject getPayload() { 22 | return payload; 23 | } 24 | 25 | public HealthCheckResponse.Status getStatus() { 26 | return status; 27 | } 28 | 29 | public boolean isDown() { 30 | return status.equals(DOWN); 31 | } 32 | 33 | @Override 34 | public int hashCode() { 35 | return Objects.hashCode(getPayload()); 36 | } 37 | 38 | @Override 39 | public boolean equals(Object obj) { 40 | if (this == obj) { 41 | return true; 42 | } 43 | if (!(obj instanceof SmallRyeHealth)) { 44 | return false; 45 | } 46 | SmallRyeHealth other = (SmallRyeHealth) obj; 47 | return Objects.equals(this.getPayload(), other.getPayload()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | :microprofile-health: https://github.com/eclipse/microprofile-health/ 2 | :ci: https://github.com/smallrye/smallrye-health/actions?query=workflow%3A%22SmallRye+Build%22 3 | :sonar: https://sonarcloud.io/dashboard?id=smallrye_smallrye-health 4 | 5 | image:https://github.com/smallrye/smallrye-health/workflows/SmallRye%20Build/badge.svg?branch=main[link={ci}] 6 | image:https://sonarcloud.io/api/project_badges/measure?project=smallrye_smallrye-health&metric=alert_status["Quality Gate Status", link={sonar}] 7 | image:https://img.shields.io/github/license/thorntail/thorntail.svg["License", link="http://www.apache.org/licenses/LICENSE-2.0"] 8 | image:https://img.shields.io/maven-central/v/io.smallrye/smallrye-health?color=green[] 9 | 10 | = SmallRye Health 11 | 12 | SmallRye Health is an implementation of {microprofile-health}[Eclipse MicroProfile Health]. 13 | 14 | == Instructions 15 | 16 | Compile and install this project: 17 | 18 | [source,bash] 19 | ---- 20 | mvn clean install 21 | ---- 22 | 23 | === Project structure 24 | 25 | * link:implementation[] - Implementation of the Eclipse MicroProfile Health API. 26 | * link:testsuite[] - Test suite to run the implementation against the Eclipse MicroProfile Health TCK. 27 | * link:doc[] - Project documentation. 28 | * link:ui[] - A small UI for /health 29 | 30 | === Links 31 | 32 | * http://github.com/smallrye/smallrye-health/[Project Homepage] 33 | * {microprofile-health}[Eclipse MicroProfile Health] 34 | 35 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/SuccessfulWellness.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | package io.smallrye.health.deployment; 23 | 24 | import jakarta.enterprise.context.ApplicationScoped; 25 | 26 | import org.eclipse.microprofile.health.HealthCheck; 27 | import org.eclipse.microprofile.health.HealthCheckResponse; 28 | 29 | import io.smallrye.health.api.Wellness; 30 | 31 | @Wellness 32 | @ApplicationScoped 33 | public class SuccessfulWellness implements HealthCheck { 34 | @Override 35 | public HealthCheckResponse call() { 36 | return HealthCheckResponse.up("successful-check"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/FailedWellness.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | package io.smallrye.health.deployment; 23 | 24 | import jakarta.enterprise.context.ApplicationScoped; 25 | 26 | import org.eclipse.microprofile.health.HealthCheck; 27 | import org.eclipse.microprofile.health.HealthCheckResponse; 28 | 29 | import io.smallrye.health.api.Wellness; 30 | 31 | /** 32 | * @author Antone Sabot-Durand 33 | */ 34 | @Wellness 35 | @ApplicationScoped 36 | public class FailedWellness implements HealthCheck { 37 | @Override 38 | public HealthCheckResponse call() { 39 | return HealthCheckResponse.down("failed-check"); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | smallrye-health-parent 5 | io.smallrye 6 | 4.3.1-SNAPSHOT 7 | 8 | 4.0.0 9 | 10 | smallrye-health-api 11 | 12 | SmallRye Health: API 13 | The feature API for the testing of features to be included in the specification. 14 | 15 | 16 | 17 | org.eclipse.microprofile.health 18 | microprofile-health-api 19 | 20 | 21 | io.smallrye.common 22 | smallrye-common-annotation 23 | 24 | 25 | jakarta.enterprise 26 | jakarta.enterprise.cdi-api 27 | provided 28 | 29 | 30 | jakarta.json 31 | jakarta.json-api 32 | 33 | 34 | io.smallrye.reactive 35 | mutiny 36 | ${version.mutiny} 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/FailedHealthGroup2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2019 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | package io.smallrye.health.deployment; 23 | 24 | import jakarta.enterprise.context.ApplicationScoped; 25 | 26 | import org.eclipse.microprofile.health.HealthCheck; 27 | import org.eclipse.microprofile.health.HealthCheckResponse; 28 | 29 | import io.smallrye.health.api.HealthGroup; 30 | 31 | /** 32 | * @author Antone Sabot-Durand 33 | * @since 2.0 34 | */ 35 | @HealthGroup("health-group-2") 36 | @ApplicationScoped 37 | public class FailedHealthGroup2 implements HealthCheck { 38 | @Override 39 | public HealthCheckResponse call() { 40 | return HealthCheckResponse.down("failed-check"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /provided-checks/src/test/java/io/smallrye/health/checks/SocketHealthCheckTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.checks; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertTrue; 5 | 6 | import java.net.InetAddress; 7 | import java.net.UnknownHostException; 8 | 9 | import org.eclipse.microprofile.health.HealthCheckResponse; 10 | import org.junit.jupiter.api.Test; 11 | 12 | public class SocketHealthCheckTest { 13 | 14 | @Test 15 | public void testSocketHealthCheck() throws UnknownHostException { 16 | final String hostAddress = InetAddress.getByName("www.google.com").getHostAddress(); 17 | SocketHealthCheck socketHealthCheck = new SocketHealthCheck(hostAddress, 80); 18 | 19 | final HealthCheckResponse healthCheckResponse = socketHealthCheck.call(); 20 | 21 | assertEquals(SocketHealthCheck.DEFAULT_NAME, healthCheckResponse.getName()); 22 | assertEquals(hostAddress + ":80", healthCheckResponse.getData().get().get("host")); 23 | assertEquals(HealthCheckResponse.Status.UP, healthCheckResponse.getStatus()); 24 | 25 | } 26 | 27 | @Test 28 | public void testSocketHealthCheckNoneServiceOnPort() { 29 | SocketHealthCheck socketHealthCheck = new SocketHealthCheck("198.51.100.0", 8985); 30 | 31 | final HealthCheckResponse healthCheckResponse = socketHealthCheck.call(); 32 | assertEquals(HealthCheckResponse.Status.DOWN, healthCheckResponse.getStatus()); 33 | assertTrue(((String) healthCheckResponse.getData().get().get("error")).matches("[cC]onnect timed out")); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/FailedStartupAsync.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | package io.smallrye.health.deployment; 23 | 24 | import java.time.Duration; 25 | 26 | import jakarta.enterprise.context.ApplicationScoped; 27 | 28 | import org.eclipse.microprofile.health.HealthCheckResponse; 29 | import org.eclipse.microprofile.health.Startup; 30 | 31 | import io.smallrye.health.api.AsyncHealthCheck; 32 | import io.smallrye.mutiny.Uni; 33 | 34 | @Startup 35 | @ApplicationScoped 36 | public class FailedStartupAsync implements AsyncHealthCheck { 37 | 38 | @Override 39 | public Uni call() { 40 | return Uni.createFrom().item(HealthCheckResponse.down("failed-check")) 41 | .onItem().delayIt().by(Duration.ofMillis(10)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/SuccessfulWellnessAsync.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | package io.smallrye.health.deployment; 23 | 24 | import java.time.Duration; 25 | 26 | import jakarta.enterprise.context.ApplicationScoped; 27 | 28 | import org.eclipse.microprofile.health.HealthCheckResponse; 29 | 30 | import io.smallrye.health.api.AsyncHealthCheck; 31 | import io.smallrye.health.api.Wellness; 32 | import io.smallrye.mutiny.Uni; 33 | 34 | @Wellness 35 | @ApplicationScoped 36 | public class SuccessfulWellnessAsync implements AsyncHealthCheck { 37 | @Override 38 | public Uni call() { 39 | return Uni.createFrom().item(HealthCheckResponse.up("successful-check")) 40 | .onItem().delayIt().by(Duration.ofMillis(10)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/SuccessfulStartupAsync.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | package io.smallrye.health.deployment; 23 | 24 | import java.time.Duration; 25 | 26 | import jakarta.enterprise.context.ApplicationScoped; 27 | 28 | import org.eclipse.microprofile.health.HealthCheckResponse; 29 | import org.eclipse.microprofile.health.Startup; 30 | 31 | import io.smallrye.health.api.AsyncHealthCheck; 32 | import io.smallrye.mutiny.Uni; 33 | 34 | @Startup 35 | @ApplicationScoped 36 | public class SuccessfulStartupAsync implements AsyncHealthCheck { 37 | @Override 38 | public Uni call() { 39 | return Uni.createFrom().item(HealthCheckResponse.up("successful-check")) 40 | .onItem().delayIt().by(Duration.ofMillis(10)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/DeploymentUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | package io.smallrye.health.test; 23 | 24 | import org.jboss.shrinkwrap.api.ShrinkWrap; 25 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 26 | import org.jboss.shrinkwrap.api.spec.WebArchive; 27 | 28 | public class DeploymentUtils { 29 | private DeploymentUtils() { 30 | } 31 | 32 | public static WebArchive createEmptyWarFile(String name) { 33 | return ShrinkWrap.create(WebArchive.class, name + ".war") 34 | .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); 35 | } 36 | 37 | public static WebArchive createWarFileWithClasses(String name, Class>... classes) { 38 | return createEmptyWarFile(name) 39 | .addClasses(classes); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /provided-checks/src/main/java/io/smallrye/health/checks/AbstractHeapMemoryHealthCheck.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.checks; 2 | 3 | import java.lang.management.ManagementFactory; 4 | import java.lang.management.MemoryMXBean; 5 | import java.lang.management.MemoryUsage; 6 | import java.util.function.Function; 7 | 8 | import org.eclipse.microprofile.health.HealthCheck; 9 | import org.eclipse.microprofile.health.HealthCheckResponse; 10 | import org.eclipse.microprofile.health.HealthCheckResponseBuilder; 11 | 12 | public abstract class AbstractHeapMemoryHealthCheck implements HealthCheck { 13 | 14 | double maxPercentage = 0.9; // Default 90% 15 | 16 | public AbstractHeapMemoryHealthCheck() { 17 | } 18 | 19 | public AbstractHeapMemoryHealthCheck(double maxPercentage) { 20 | this.maxPercentage = maxPercentage; 21 | } 22 | 23 | protected HealthCheckResponse getHealthCheckResponse(Function memoryUsageFunction) { 24 | MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); 25 | MemoryUsage memoryUsage = memoryUsageFunction.apply(memoryBean); 26 | long memUsed = memoryUsage.getUsed(); 27 | long memMax = memoryUsage.getMax(); 28 | 29 | HealthCheckResponseBuilder responseBuilder = HealthCheckResponse.named(name()) 30 | .withData("used", memUsed) 31 | .withData("max", memMax) 32 | .withData("max %", String.valueOf(maxPercentage)); 33 | 34 | if (memMax > 0) { 35 | boolean status = (memUsed < memMax * maxPercentage); 36 | return responseBuilder.status(status).build(); 37 | } else { 38 | // Max not available 39 | return responseBuilder.up().build(); 40 | } 41 | } 42 | 43 | abstract String name(); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /provided-checks/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | smallrye-health-parent 6 | io.smallrye 7 | 4.3.1-SNAPSHOT 8 | 9 | 10 | smallrye-health-provided-checks 11 | 12 | SmallRye Health: Provided Health Checks 13 | 14 | 15 | 16 | io.smallrye 17 | smallrye-health 18 | ${project.version} 19 | 20 | 21 | 22 | org.jboss.logging 23 | jboss-logging 24 | 25 | 26 | 27 | org.jboss.logging 28 | jboss-logging-annotations 29 | 30 | 31 | 32 | org.jboss.logging 33 | jboss-logging-processor 34 | 35 | 36 | 37 | org.junit.jupiter 38 | junit-jupiter 39 | 40 | 41 | 42 | 43 | 44 | coverage 45 | 46 | @{jacocoArgLine} 47 | 48 | 49 | 50 | 51 | org.jacoco 52 | jacoco-maven-plugin 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /api/src/main/java/io/smallrye/health/api/HealthGroups.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | package io.smallrye.health.api; 23 | 24 | import static java.lang.annotation.ElementType.FIELD; 25 | import static java.lang.annotation.ElementType.METHOD; 26 | import static java.lang.annotation.ElementType.PARAMETER; 27 | import static java.lang.annotation.ElementType.TYPE; 28 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 29 | 30 | import java.lang.annotation.Documented; 31 | import java.lang.annotation.Retention; 32 | import java.lang.annotation.Target; 33 | 34 | import io.smallrye.common.annotation.Experimental; 35 | 36 | /** 37 | * 38 | * This annotation allow to repeat {@link HealthGroup} qualifier 39 | * 40 | * @author Antoine Sabot-Durand 41 | * 42 | */ 43 | @Target({ PARAMETER, FIELD, METHOD, TYPE }) 44 | @Documented 45 | @Retention(RUNTIME) 46 | @Experimental("Custom health group definitions exposed at /health/group/{group-name}. Not covered by the specification. " + 47 | "Subject to change.") 48 | public @interface HealthGroups { 49 | /** 50 | * @return list of {@link HealthGroup} 51 | */ 52 | HealthGroup[] value(); 53 | } 54 | -------------------------------------------------------------------------------- /provided-checks/src/test/java/io/smallrye/health/checks/UrlHealthCheckTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.checks; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import java.net.HttpURLConnection; 6 | 7 | import org.eclipse.microprofile.health.HealthCheck; 8 | import org.eclipse.microprofile.health.HealthCheckResponse; 9 | import org.junit.jupiter.api.Test; 10 | 11 | public class UrlHealthCheckTest { 12 | 13 | @Test 14 | public void testUrlCheck() { 15 | final UrlHealthCheck urlHealthCheck = new UrlHealthCheck("http://www.google.com"); 16 | final HealthCheckResponse healthCheckResponse = urlHealthCheck.call(); 17 | 18 | assertEquals(UrlHealthCheck.DEFAULT_NAME, healthCheckResponse.getName()); 19 | assertEquals("GET http://www.google.com", healthCheckResponse.getData().get().get("host")); 20 | assertEquals(HealthCheckResponse.Status.UP, healthCheckResponse.getStatus()); 21 | 22 | } 23 | 24 | @Test 25 | public void testUrlCheckIncorrectStatusCode() { 26 | final HealthCheck urlHealthCheck = new UrlHealthCheck("http://www.google.com") 27 | .statusCode(HttpURLConnection.HTTP_CREATED); 28 | final HealthCheckResponse healthCheckResponse = urlHealthCheck.call(); 29 | 30 | assertEquals(HealthCheckResponse.Status.DOWN, healthCheckResponse.getStatus()); 31 | assertEquals("Expected response code 201 but actual is 200", healthCheckResponse.getData().get().get("error")); 32 | } 33 | 34 | @Test 35 | public void testUrlCheckNoneExistingUrl() { 36 | final UrlHealthCheck urlHealthCheck = new UrlHealthCheck("http://www.fdghreer.invalid"); 37 | final HealthCheckResponse healthCheckResponse = urlHealthCheck.call(); 38 | 39 | assertEquals(HealthCheckResponse.Status.DOWN, healthCheckResponse.getStatus()); 40 | assertEquals("java.net.UnknownHostException: www.fdghreer.invalid", healthCheckResponse.getData().get().get("error")); 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/health/ResponseBuilder.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | 6 | import org.eclipse.microprofile.health.HealthCheckResponse; 7 | import org.eclipse.microprofile.health.HealthCheckResponseBuilder; 8 | 9 | class ResponseBuilder extends HealthCheckResponseBuilder { 10 | 11 | @Override 12 | public HealthCheckResponseBuilder name(String name) { 13 | this.name = name; 14 | return this; 15 | } 16 | 17 | @Override 18 | public HealthCheckResponseBuilder withData(String key, String value) { 19 | this.data.put(key, value); 20 | return this; 21 | } 22 | 23 | @Override 24 | public HealthCheckResponseBuilder withData(String key, long value) { 25 | this.data.put(key, value); 26 | return this; 27 | } 28 | 29 | @Override 30 | public HealthCheckResponseBuilder withData(String key, boolean value) { 31 | this.data.put(key, value); 32 | return this; 33 | } 34 | 35 | @Override 36 | public HealthCheckResponseBuilder up() { 37 | this.status = HealthCheckResponse.Status.UP; 38 | return this; 39 | } 40 | 41 | @Override 42 | public HealthCheckResponseBuilder down() { 43 | this.status = HealthCheckResponse.Status.DOWN; 44 | return this; 45 | } 46 | 47 | @Override 48 | public HealthCheckResponseBuilder status(boolean up) { 49 | if (up) { 50 | return up(); 51 | } 52 | 53 | return down(); 54 | } 55 | 56 | @Override 57 | public HealthCheckResponse build() { 58 | if (null == this.name || this.name.trim().length() == 0) { 59 | throw HealthMessages.msg.invalidHealthCheckName(); 60 | } 61 | 62 | return new Response(this.name, this.status, this.data.isEmpty() ? null : this.data); 63 | } 64 | 65 | private String name; 66 | 67 | private HealthCheckResponse.Status status = HealthCheckResponse.Status.DOWN; 68 | 69 | private final Map data = new LinkedHashMap<>(); 70 | } 71 | -------------------------------------------------------------------------------- /testsuite/tck/src/test/java/io/smallrye/health/SmallRyeHealthArchiveProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.smallrye.health; 17 | 18 | import java.io.File; 19 | 20 | import org.eclipse.microprofile.health.tck.TCKBase; 21 | import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor; 22 | import org.jboss.arquillian.test.spi.TestClass; 23 | import org.jboss.shrinkwrap.api.Archive; 24 | import org.jboss.shrinkwrap.api.spec.WebArchive; 25 | import org.jboss.shrinkwrap.resolver.api.maven.Maven; 26 | 27 | public class SmallRyeHealthArchiveProcessor implements ApplicationArchiveProcessor { 28 | 29 | @Override 30 | public void process(Archive> applicationArchive, TestClass testClass) { 31 | if (applicationArchive instanceof WebArchive) { 32 | WebArchive testDeployment = (WebArchive) applicationArchive; 33 | 34 | String[] deps = { 35 | "io.smallrye:smallrye-health", 36 | "io.smallrye.config:smallrye-config", 37 | "io.smallrye:smallrye-health-tck" }; 38 | 39 | File[] dependencies = Maven.resolver().loadPomFromFile(new File("pom.xml")).resolve(deps).withTransitivity() 40 | .asFile(); 41 | 42 | testDeployment.addAsLibraries(dependencies); 43 | // needed because of unnecessary NCDF exceptions in the test runs 44 | testDeployment.addClass(TCKBase.class); 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /doc/modules/ROOT/pages/custom-config-properties.adoc: -------------------------------------------------------------------------------- 1 | [[custom-config-properties]] 2 | = Custom configuration values 3 | 4 | SmallRye Health provides several custom configuration values that are exposing additional features which are currently not a part of the MicroProfile Health specification. The following sections provide an overview of what users can configure to adjust the executions of health check invocations. 5 | 6 | == Disabling Health Checks with configuration 7 | 8 | In SmallRye Health, you can dynamically choose which `HealthCheck` implementation will be included in the final produces responses with configuration values. To disable any included `HealthCheck` implementation dynamically you can use the following configuration property: 9 | 10 | [source,properties] 11 | ---- 12 | io.smallrye.health.check..enabled=false 13 | ---- 14 | 15 | where `health-check-classname` is a fully-qualified class name of the `HealthCheck` implementation that should not be included in the responses. This value can be specified dynamically on the application startup with MicroProfile Config values (see https://github.com/eclipse/microprofile-config[MicroProfile Config specification]). 16 | 17 | For instance, for `HealthCheck` implementation included in class `org.acme.TestHC` the property would look like `-Dio.smallrye.health.check.org.acme.TestHC.enabled=false` or `IO_SMALLRYE_HEALTH_CHECK_ORG_ACME_TESTHC_ENABLED=false`. 18 | 19 | == Adding additional JSON properties 20 | 21 | SmallRye Health provides a feature that allows users to specify additional properties with fixed values that should be included in the top level properties of the outputed JSON. To specify additonal JSON properties, you can use the following configuration values: 22 | 23 | [source,properties] 24 | ---- 25 | io.smallrye.health.additional.property.testProperty1=testValue1 26 | io.smallrye.health.additional.property.testProperty2=testValue2 27 | ---- 28 | 29 | which will output a JSON like this: 30 | 31 | [source,json] 32 | ---- 33 | { 34 | "checks": [], 35 | "status": "UP", 36 | "testProperty1": "testValue1", 37 | "testProperty2": "testValue2" 38 | } 39 | ---- -------------------------------------------------------------------------------- /doc/modules/ROOT/pages/health-registry.adoc: -------------------------------------------------------------------------------- 1 | [[health-registry]] 2 | = Health Registry 3 | 4 | A health registry provides a way to register the health checks programatically. It also allows 5 | to remove the programatically registered health checks when they are no longer needed. This presents 6 | an option to dynamically register and unregister health checks based on the user defined criteria. 7 | 8 | == Health Registry usage 9 | 10 | The `HealthRegistry` can be injected as a CDI bean with `@Liveness`, `@Readiness`, `@Startup`, or `@Wellness` qualifiers: 11 | 12 | [source,java] 13 | ---- 14 | @Inject 15 | @Liveness 16 | HealthRegistry livenessHealthRegistry; 17 | 18 | @Inject 19 | @Readiness 20 | HealthRegistry readinessHealthRegistry; 21 | 22 | @Inject 23 | @Startup 24 | HealthRegistry startupHealthRegistry; 25 | 26 | @Inject 27 | @Wellness 28 | HealthRegistry wellnessHealthRegistry; 29 | ---- 30 | 31 | NOTE: Health group registry have not been requested as of yet but if some applications would find 32 | it useful please raise a new issue in the https://github.com/smallrye/smallrye-health/issues[SmallRye Health issue tracker]. 33 | 34 | You can then register your health check by simple calling the `register` methods: 35 | 36 | [source,java] 37 | ---- 38 | public void register() { 39 | livenessHealthRegistry.register(new TestLiveness()); <1> 40 | } 41 | 42 | public void registerReady() { 43 | readinessHealthRegistry.register("dynamic-readiness", new TestReadiness()); <2> 44 | } 45 | ---- 46 | <1> If no user defined name is provided during registration the health check is registered as 47 | `TestLiveness.class.getName()` 48 | <2> The user provided name `dynamic-readiness` will be used as the check identificator 49 | 50 | To unregister the registered health check you can call the `remove` methods: 51 | 52 | [source,java] 53 | ---- 54 | public void remove() { 55 | livenessHealthRegistry.remove(TestLiveness.class.getName()); 56 | } 57 | 58 | public void removeReady() { 59 | readinessHealthRegistry.remove("dynamic-readiness"); 60 | } 61 | ---- 62 | 63 | == Resources 64 | 65 | * https://github.com/smallrye/smallrye-health/blob/main/api/src/main/java/io/smallrye/health/api/HealthRegistry.java[`HealthRegistry`] 66 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/SmallRyeHealthArchiveProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc, and individual contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.smallrye.health; 17 | 18 | import java.io.File; 19 | 20 | import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor; 21 | import org.jboss.arquillian.test.spi.TestClass; 22 | import org.jboss.shrinkwrap.api.Archive; 23 | import org.jboss.shrinkwrap.api.spec.WebArchive; 24 | import org.jboss.shrinkwrap.resolver.api.maven.Maven; 25 | 26 | import com.beust.jcommander.ParameterException; 27 | 28 | public class SmallRyeHealthArchiveProcessor implements ApplicationArchiveProcessor { 29 | 30 | @Override 31 | public void process(Archive> applicationArchive, TestClass testClass) { 32 | if (applicationArchive instanceof WebArchive) { 33 | WebArchive testDeployment = (WebArchive) applicationArchive; 34 | 35 | String[] deps = { 36 | "io.smallrye:smallrye-health", 37 | "io.smallrye.config:smallrye-config", 38 | "io.smallrye:smallrye-health-tck", 39 | "org.apache.httpcomponents:httpclient" }; 40 | 41 | File[] dependencies = Maven.resolver().loadPomFromFile(new File("pom.xml")).resolve(deps).withTransitivity() 42 | .asFile(); 43 | 44 | testDeployment.addAsLibraries(dependencies); 45 | // needed because of unnecessary NCDF exceptions in the test runs 46 | testDeployment.addClass(ParameterException.class); 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /doc/modules/ROOT/pages/async-checks.adoc: -------------------------------------------------------------------------------- 1 | [[async-checks]] 2 | = Asynchronous health checks 3 | 4 | == Defining asynchronous checks 5 | 6 | SmallRye Health provides a way to define asynchronous checks that can be consumed 7 | in the reactive applications in a non-blocking manner. These checks are defined in 8 | a very similar way to the usual health checks only they implement a different interface: 9 | 10 | [source,java] 11 | ---- 12 | @Liveness <1> 13 | @ApplicationScoped <2> 14 | public class LivenessAsync implements AsyncHealthCheck { <3> 15 | 16 | @Override 17 | public Uni call() { <4> 18 | return Uni.createFrom().item(HealthCheckResponse.up("liveness-async")) 19 | .onItem().delayIt().by(Duration.ofMillis(10)); 20 | } 21 | } 22 | ---- 23 | <1> The MicroProfile Health CDI qualifier is still required 24 | <2> The check still needs to be a CDI bean 25 | <3> The asynchronous checks must implement the `AsyncHealthCheck` interface 26 | <4> The return type of the health check `call()` method is `Uni` 27 | 28 | The `Uni` is one of the main types included in the https://smallrye.io/smallrye-mutiny/[Mutiny project] 29 | on top of which asynchronous checks are built. Mutiny provides several ways to transform the 30 | most common reactive types to `Uni`, so if you are used to work with different reacitve 31 | library it should be an issue. 32 | 33 | == Consuming health checks asynchronously 34 | 35 | The `SmallRyeHealthReporter` class was extended to provide variants of get health methods 36 | that end with `*Async()` (e.g. `getLivenessAsync()`) that return an `Uni` so it can 37 | also be included in any reactive pipeline. Example uses of this API is demonstrated for instance in 38 | the `AsyncHealthTest`. 39 | 40 | == References 41 | 42 | * https://github.com/smallrye/smallrye-health/blob/main/api/src/main/java/io/smallrye/health/api/AsyncHealthCheck.java[`AsyncHealthCheck`] 43 | * https://github.com/smallrye/smallrye-health/blob/main/implementation/src/main/java/io/smallrye/health/SmallRyeHealthReporter.java[`SmallRyeHealthReporter`] 44 | * https://github.com/smallrye/smallrye-health/blob/main/testsuite/experimental/src/test/java/io/smallrye/health/test/AsyncHealthTest.java[`AsyncHealthTest`] 45 | -------------------------------------------------------------------------------- /api/src/main/java/io/smallrye/health/api/Wellness.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | package io.smallrye.health.api; 23 | 24 | import static java.lang.annotation.ElementType.FIELD; 25 | import static java.lang.annotation.ElementType.METHOD; 26 | import static java.lang.annotation.ElementType.PARAMETER; 27 | import static java.lang.annotation.ElementType.TYPE; 28 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 29 | 30 | import java.lang.annotation.Documented; 31 | import java.lang.annotation.Retention; 32 | import java.lang.annotation.Target; 33 | 34 | import jakarta.enterprise.util.AnnotationLiteral; 35 | import jakarta.inject.Qualifier; 36 | 37 | import io.smallrye.common.annotation.Experimental; 38 | 39 | /** 40 | * 41 | * This qualifier is used to define a wellness Health Check procedure 42 | * 43 | * @author Antoine Sabot-Durand 44 | */ 45 | @Target({ TYPE, METHOD, PARAMETER, FIELD }) 46 | @Retention(RUNTIME) 47 | @Documented 48 | @Qualifier 49 | @Experimental("Custom health check type definitions exposed at /health/well. Not covered by the specification. " + 50 | "Subject to change.") 51 | public @interface Wellness { 52 | 53 | /** 54 | * Support inline instantiation of the {@link Wellness} qualifier. 55 | * 56 | * @author Antoine Sabot-Durand 57 | */ 58 | public static final class Literal extends AnnotationLiteral implements Wellness { 59 | public static final Literal INSTANCE = new Literal(); 60 | 61 | private static final long serialVersionUID = 1L; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /implementation/src/test/java/io/smallrye/health/HealthStatusTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import static org.hamcrest.CoreMatchers.is; 4 | import static org.hamcrest.CoreMatchers.startsWith; 5 | import static org.hamcrest.MatcherAssert.assertThat; 6 | 7 | import org.eclipse.microprofile.health.HealthCheck; 8 | import org.eclipse.microprofile.health.HealthCheckResponse; 9 | import org.junit.jupiter.api.Test; 10 | 11 | public class HealthStatusTest { 12 | 13 | @Test 14 | public void testHealthStatusUp() { 15 | 16 | final HealthCheck myHealth = HealthStatus.up("myHealth"); 17 | 18 | final HealthCheckResponse healthCheckResponse = myHealth.call(); 19 | 20 | assertThat(healthCheckResponse.getName(), is("myHealth")); 21 | assertThat(healthCheckResponse.getStatus(), is(HealthCheckResponse.Status.UP)); 22 | } 23 | 24 | @Test 25 | public void testHealthStatusDown() { 26 | 27 | final HealthCheck myHealth = HealthStatus.down("myHealth"); 28 | 29 | final HealthCheckResponse healthCheckResponse = myHealth.call(); 30 | 31 | assertThat(healthCheckResponse.getName(), is("myHealth")); 32 | assertThat(healthCheckResponse.getStatus(), is(HealthCheckResponse.Status.DOWN)); 33 | } 34 | 35 | @Test 36 | public void testRandomNameHealthStatus() { 37 | 38 | final HealthCheck healthCheck = HealthStatus.status(true); 39 | 40 | final HealthCheckResponse healthCheckResponse = healthCheck.call(); 41 | 42 | assertThat(healthCheckResponse.getName(), startsWith("unnamed-health-check-")); 43 | } 44 | 45 | @Test 46 | public void testBooleanSupplierHealthStatus() { 47 | 48 | final HealthCheck myHealth = HealthStatus.status("myHealth", () -> true); 49 | 50 | final HealthCheckResponse healthCheckResponse = myHealth.call(); 51 | 52 | assertThat(healthCheckResponse.getName(), is("myHealth")); 53 | assertThat(healthCheckResponse.getStatus(), is(HealthCheckResponse.Status.UP)); 54 | 55 | } 56 | 57 | @Test 58 | public void testBooleanHealthStatus() { 59 | 60 | final HealthCheck myHealth = HealthStatus.status("myHealth", true); 61 | 62 | final HealthCheckResponse healthCheckResponse = myHealth.call(); 63 | 64 | assertThat(healthCheckResponse.getName(), is("myHealth")); 65 | assertThat(healthCheckResponse.getStatus(), is(HealthCheckResponse.Status.UP)); 66 | 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/NullHealthCheckProducerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.RunAsClient; 30 | import org.jboss.shrinkwrap.api.Archive; 31 | import org.testng.Assert; 32 | import org.testng.annotations.Test; 33 | 34 | import io.smallrye.health.deployment.NullHealthCheckProducer; 35 | 36 | /** 37 | * @author Martin Stefanko 38 | */ 39 | @RunAsClient 40 | public class NullHealthCheckProducerTest extends TCKBase { 41 | 42 | @Deployment 43 | public static Archive getDeployment() { 44 | return DeploymentUtils.createWarFileWithClasses(NullHealthCheckProducerTest.class.getSimpleName(), 45 | NullHealthCheckProducer.class, TCKBase.class); 46 | } 47 | 48 | /** 49 | * Verifies the CDI producer producin a null HealthCheck (with scope @Depedent) does not 50 | * throw NullPointerException 51 | */ 52 | @Test 53 | public void testSuccessResponsePayload() { 54 | Response response = getUrlLiveContents(); 55 | 56 | // status code 57 | Assert.assertEquals(response.getStatus(), 200); 58 | 59 | JsonObject json = readJson(response); 60 | 61 | // response size 62 | JsonArray checks = json.getJsonArray("checks"); 63 | Assert.assertEquals(checks.size(), 0, "Expected a null health check is ignored in the output"); 64 | 65 | assertOverallSuccess(json); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/WellnessFailedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.RunAsClient; 30 | import org.jboss.shrinkwrap.api.Archive; 31 | import org.testng.Assert; 32 | import org.testng.annotations.Test; 33 | 34 | import io.smallrye.health.deployment.FailedWellness; 35 | 36 | /** 37 | * @author Antoine Sabot-Durand 38 | */ 39 | @RunAsClient 40 | public class WellnessFailedTest extends TCKBase { 41 | 42 | @Deployment 43 | public static Archive getDeployment() { 44 | return DeploymentUtils.createWarFileWithClasses(WellnessFailedTest.class.getSimpleName(), 45 | FailedWellness.class, TCKBase.class); 46 | } 47 | 48 | /** 49 | * Verifies the wellness integration with CDI at the scope of a server runtime 50 | */ 51 | @Test 52 | public void testFailedResponsePayload() { 53 | Response response = getUrlWellContents(); 54 | 55 | // status code 56 | Assert.assertEquals(response.getStatus(), 503); 57 | 58 | JsonObject json = readJson(response); 59 | 60 | // response size 61 | JsonArray checks = json.getJsonArray("checks"); 62 | Assert.assertEquals(checks.size(), 1, "Expected a single check response"); 63 | 64 | // single procedure response 65 | assertFailureCheck(checks.getJsonObject(0), "failed-check"); 66 | 67 | assertOverallFailure(json); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/SingleStartupAsyncFailedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2021 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.RunAsClient; 30 | import org.jboss.shrinkwrap.api.Archive; 31 | import org.testng.Assert; 32 | import org.testng.annotations.Test; 33 | 34 | import io.smallrye.health.deployment.FailedStartupAsync; 35 | 36 | /** 37 | * @author Martin Stefanko 38 | */ 39 | @RunAsClient 40 | public class SingleStartupAsyncFailedTest extends TCKBase { 41 | 42 | @Deployment 43 | public static Archive getDeployment() { 44 | return DeploymentUtils.createWarFileWithClasses(SingleStartupAsyncFailedTest.class.getSimpleName(), 45 | FailedStartupAsync.class, TCKBase.class); 46 | } 47 | 48 | /** 49 | * Verifies the startup async integration 50 | */ 51 | @Test 52 | public void testFailedResponsePayload() { 53 | Response response = getUrlStartedContents(); 54 | 55 | // status code 56 | Assert.assertEquals(response.getStatus(), 503); 57 | 58 | JsonObject json = readJson(response); 59 | 60 | // response size 61 | JsonArray checks = json.getJsonArray("checks"); 62 | Assert.assertEquals(checks.size(), 1, "Expected a single check response"); 63 | 64 | // single procedure response 65 | assertFailureCheck(checks.getJsonObject(0), "failed-check"); 66 | 67 | assertOverallFailure(json); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/ContextPropagatedHealthTest.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.test; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | import org.jboss.arquillian.container.test.api.Deployment; 7 | import org.jboss.arquillian.container.test.api.RunAsClient; 8 | import org.jboss.shrinkwrap.api.Archive; 9 | import org.jboss.shrinkwrap.api.spec.WebArchive; 10 | import org.testng.Assert; 11 | import org.testng.annotations.Test; 12 | 13 | import io.smallrye.health.deployment.ContextHealthCheck; 14 | import io.smallrye.health.deployment.ContextInfo; 15 | import io.smallrye.health.deployment.RequestFilter; 16 | import io.smallrye.mutiny.Uni; 17 | import io.smallrye.mutiny.infrastructure.Infrastructure; 18 | 19 | @RunAsClient 20 | class ContextPropagatedHealthTest extends TCKBase { 21 | 22 | @Deployment 23 | public static Archive getDeployment() { 24 | return DeploymentUtils 25 | .createWarFileWithClasses(ContextPropagatedHealthTest.class.getSimpleName(), 26 | ContextHealthCheck.class, ContextInfo.class, RequestFilter.class, TCKBase.class); 27 | } 28 | 29 | // got to repeat this test a couple of times to trigger potential race condition issue at least once. 30 | @Test(invocationCount = 20) 31 | void twoParallelRequests_shouldNotMixupContext() { 32 | String contextValue = "test-value"; 33 | String otherContextValue = "other-test-value"; 34 | Uni response = Uni.createFrom().voidItem().emitOn(Infrastructure.getDefaultExecutor()).onItem() 35 | .transform(v -> getUrlHealthContents(Map.of(RequestFilter.TEST_CONTEXT_HEADER, contextValue))); 36 | Uni otherResponse = Uni.createFrom().voidItem().emitOn(Infrastructure.getDefaultExecutor()).onItem() 37 | .transform(v -> getUrlHealthContents(Map.of(RequestFilter.TEST_CONTEXT_HEADER, otherContextValue))); 38 | 39 | List responses = Uni.join().all(response, otherResponse).andCollectFailures().await().indefinitely(); 40 | 41 | String responseBody = responses.get(0).getBody().orElseThrow(); 42 | String otherResponseBody = responses.get(1).getBody().orElseThrow(); 43 | Assert.assertNotEquals(responseBody, otherResponseBody); 44 | Assert.assertTrue(responseBody.contains(contextValue), responseBody); 45 | Assert.assertTrue(otherResponseBody.contains(otherContextValue), otherResponseBody); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /provided-checks/src/main/java/io/smallrye/health/checks/SystemLoadHealthCheck.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.checks; 2 | 3 | import java.lang.management.ManagementFactory; 4 | import java.lang.management.OperatingSystemMXBean; 5 | 6 | import org.eclipse.microprofile.health.HealthCheck; 7 | import org.eclipse.microprofile.health.HealthCheckResponse; 8 | import org.eclipse.microprofile.health.HealthCheckResponseBuilder; 9 | 10 | /** 11 | * Health check implementation that is checking average load usage against max load 12 | * 13 | * 14 | * {@code 15 | * @Produces 16 | * @ApplicationScoped 17 | * @Liveness 18 | * HealthCheck check1() { 19 | * return new SystemLoadHealthCheck(); 20 | * } 21 | * } 22 | * 23 | */ 24 | public class SystemLoadHealthCheck implements HealthCheck { 25 | 26 | double max = 0.7; 27 | 28 | public SystemLoadHealthCheck() { 29 | } 30 | 31 | public SystemLoadHealthCheck(double max) { 32 | this.max = max; 33 | } 34 | 35 | @Override 36 | public HealthCheckResponse call() { 37 | OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); 38 | 39 | String arch = operatingSystemMXBean.getArch(); 40 | String name = operatingSystemMXBean.getName(); 41 | String version = operatingSystemMXBean.getVersion(); 42 | int availableProcessors = operatingSystemMXBean.getAvailableProcessors(); 43 | 44 | double systemLoadAverage = operatingSystemMXBean.getSystemLoadAverage(); 45 | double systemLoadAveragePerProcessors = systemLoadAverage / availableProcessors; 46 | 47 | HealthCheckResponseBuilder responseBuilder = HealthCheckResponse.named("system-load") 48 | .withData("name", name) 49 | .withData("arch", arch) 50 | .withData("version", version) 51 | .withData("processors", availableProcessors) 52 | .withData("loadAverage", String.valueOf(systemLoadAverage)) 53 | .withData("loadAverage per processor", String.valueOf(systemLoadAveragePerProcessors)) 54 | .withData("loadAverage max", String.valueOf(max)); 55 | 56 | if (systemLoadAverage > 0) { 57 | boolean status = systemLoadAveragePerProcessors < max; 58 | return responseBuilder.status(status).build(); 59 | } else { 60 | // Load average not available 61 | return responseBuilder.up().build(); 62 | } 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/SingleStartupAsyncSuccessfulTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2021 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.RunAsClient; 30 | import org.jboss.shrinkwrap.api.Archive; 31 | import org.testng.Assert; 32 | import org.testng.annotations.Test; 33 | 34 | import io.smallrye.health.deployment.SuccessfulStartupAsync; 35 | 36 | /** 37 | * @author Martin Stefanko 38 | */ 39 | @RunAsClient 40 | public class SingleStartupAsyncSuccessfulTest extends TCKBase { 41 | 42 | @Deployment 43 | public static Archive getDeployment() { 44 | return DeploymentUtils.createWarFileWithClasses(SingleStartupAsyncSuccessfulTest.class.getSimpleName(), 45 | SuccessfulStartupAsync.class, TCKBase.class); 46 | } 47 | 48 | /** 49 | * Verifies the startup async integration 50 | */ 51 | @Test 52 | public void testSuccessResponsePayload() { 53 | Response response = getUrlStartedContents(); 54 | 55 | // status code 56 | Assert.assertEquals(response.getStatus(), 200); 57 | 58 | JsonObject json = readJson(response); 59 | 60 | // response size 61 | JsonArray checks = json.getJsonArray("checks"); 62 | Assert.assertEquals(checks.size(), 1, "Expected a single check response"); 63 | 64 | // single procedure response 65 | assertSuccessfulCheck(checks.getJsonObject(0), "successful-check"); 66 | 67 | assertOverallSuccess(json); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/SingleCustomSuccessfulTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.RunAsClient; 30 | import org.jboss.shrinkwrap.api.Archive; 31 | import org.testng.Assert; 32 | import org.testng.annotations.Test; 33 | 34 | import io.smallrye.health.deployment.HealthGroup12; 35 | 36 | /** 37 | * @author Antoine Sabot-Durand 38 | */ 39 | @RunAsClient 40 | public class SingleCustomSuccessfulTest extends TCKBase { 41 | 42 | @Deployment 43 | public static Archive getDeployment() { 44 | return DeploymentUtils.createWarFileWithClasses(SingleCustomSuccessfulTest.class.getSimpleName(), 45 | HealthGroup12.class, TCKBase.class); 46 | } 47 | 48 | /** 49 | * Verifies the custom health integration with CDI at the scope of a server runtime 50 | */ 51 | @Test 52 | public void testSuccessResponsePayload() { 53 | Response response = getUrlCustomHealthContents("health-group-1"); 54 | 55 | // status code 56 | Assert.assertEquals(response.getStatus(), 200); 57 | 58 | JsonObject json = readJson(response); 59 | 60 | // response size 61 | JsonArray checks = json.getJsonArray("checks"); 62 | Assert.assertEquals(checks.size(), 1, "Expected a single check response"); 63 | 64 | // single procedure response 65 | assertSuccessfulCheck(checks.getJsonObject(0), "health-group-12"); 66 | 67 | assertOverallSuccess(json); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /doc/modules/ROOT/pages/health-groups.adoc: -------------------------------------------------------------------------------- 1 | [[health-groups]] 2 | = Health Groups 3 | 4 | A health group is simply a user defined group of health checks. Namely, liveness and readiness 5 | (and experimental wellness) are predefined health groups. With this feature users are allowed to 6 | define any number of custom health groups and the individual checks that will belong to them. 7 | 8 | == Including a check in a health group 9 | 10 | To include a health check in a custom health group you can use the `HealthGroup` annotations: 11 | 12 | [source,java] 13 | ---- 14 | @HealthGroup("group1") <1> 15 | @HealthGroup("group2") <2> 16 | @ApplicationScoped 17 | public class SuccessfulCustom implements HealthCheck { 18 | @Override 19 | public HealthCheckResponse call() { 20 | return HealthCheckResponse.up("successful-check"); 21 | } 22 | } 23 | ---- 24 | <1> The check will belong to the health group _"group1"_ 25 | <2> The check will also belong to the health group _"group2"_ 26 | 27 | A health check can be included in any number of health groups including the liveness and readiness: 28 | 29 | [source,java] 30 | ---- 31 | @HealthGroup("custom1") 32 | @HealthGroup("different-group") 33 | @Liveness 34 | @ApplicationScoped 35 | public class GroupsCheck implements HealthCheck { ... 36 | ---- 37 | 38 | == Accessing the health groups 39 | 40 | The custom health groups are exposed under the `/health/group` resource tree: 41 | 42 | |=== 43 | | Path | Description 44 | | `/health/group` | All health checks in all groups 45 | | `/health/group/\{group-name}` | All health checks in the group called \{group-name} 46 | |=== 47 | 48 | Please note that is totally valid to define custom health group as a liveness and/or readiness 49 | probe if required. Both liveness and readiness are shorcuts for predefined health groups. 50 | 51 | In the previous example, the `GroupsCheck` will be invoked when accessing: 52 | 53 | * `/health/group` 54 | * `/health/group/custom1` 55 | * `/health/group/different-group` 56 | * `/health/live` 57 | 58 | However, it won't be invoked for instance when accessing: 59 | 60 | * `/health/group/foobar` 61 | * `/health/ready` 62 | 63 | == Default health group 64 | 65 | The configuration property `io.smallrye.health.defaultHealthGroup=\{default-group-name}` can be used to specify the health 66 | group name of a new, default health group that is implicitly added to the all 67 | health checks that don't already belong into any health group. This might be useful to easily categorize the custom health groups. 68 | 69 | == References 70 | 71 | * https://github.com/smallrye/smallrye-health/blob/main/api/src/main/java/io/smallrye/health/api/HealthGroup.java[`HealthGroup`] 72 | 73 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/WellnessSuccessfulTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.RunAsClient; 30 | import org.jboss.shrinkwrap.api.Archive; 31 | import org.testng.Assert; 32 | import org.testng.annotations.Test; 33 | 34 | import io.smallrye.health.deployment.SuccessfulWellness; 35 | import io.smallrye.health.deployment.SuccessfulWellnessAsync; 36 | 37 | /** 38 | * @author Antoine Sabot-Durand 39 | */ 40 | @RunAsClient 41 | public class WellnessSuccessfulTest extends TCKBase { 42 | 43 | @Deployment 44 | public static Archive getDeployment() { 45 | return DeploymentUtils.createWarFileWithClasses(WellnessSuccessfulTest.class.getSimpleName(), 46 | SuccessfulWellness.class, SuccessfulWellnessAsync.class, TCKBase.class); 47 | } 48 | 49 | /** 50 | * Verifies the wellness integration with CDI at the scope of a server runtime 51 | */ 52 | @Test 53 | public void testSuccessResponsePayload() { 54 | Response response = getUrlWellContents(); 55 | 56 | // status code 57 | Assert.assertEquals(response.getStatus(), 200); 58 | 59 | JsonObject json = readJson(response); 60 | 61 | // response size 62 | JsonArray checks = json.getJsonArray("checks"); 63 | Assert.assertEquals(checks.size(), 2, "Expected two check responses"); 64 | 65 | // single procedure response 66 | assertSuccessfulCheck(checks.getJsonObject(0), "successful-check"); 67 | assertSuccessfulCheck(checks.getJsonObject(1), "successful-check"); 68 | 69 | assertOverallSuccess(json); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/health/registry/HealthRegistryImpl.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.registry; 2 | 3 | import java.util.Collection; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.Stream; 8 | 9 | import org.eclipse.microprofile.health.HealthCheck; 10 | import org.eclipse.microprofile.health.HealthCheckResponse; 11 | 12 | import io.smallrye.health.AsyncHealthCheckFactory; 13 | import io.smallrye.health.api.AsyncHealthCheck; 14 | import io.smallrye.health.api.HealthRegistry; 15 | import io.smallrye.mutiny.Uni; 16 | 17 | public class HealthRegistryImpl implements HealthRegistry { 18 | 19 | Map checks = new HashMap<>(); 20 | Map asyncChecks = new HashMap<>(); 21 | private boolean checksChanged = false; 22 | 23 | AsyncHealthCheckFactory asyncHealthCheckFactory = new AsyncHealthCheckFactory(); 24 | 25 | @Override 26 | public HealthRegistry register(String id, HealthCheck healthCheck) { 27 | return register(id, healthCheck, checks); 28 | } 29 | 30 | @Override 31 | public HealthRegistry register(String id, AsyncHealthCheck asyncHealthCheck) { 32 | return register(id, asyncHealthCheck, asyncChecks); 33 | } 34 | 35 | private HealthRegistry register(String id, T check, Map checks) { 36 | checks.put(id, check); 37 | checksChanged = true; 38 | return this; 39 | } 40 | 41 | @Override 42 | public HealthRegistry remove(String id) { 43 | try { 44 | if (checks.remove(id) == null && asyncChecks.remove(id) == null) { 45 | throw new IllegalStateException(String.format("ID '%s' not found", id)); 46 | } 47 | checksChanged = true; 48 | return this; 49 | } catch (Exception e) { 50 | throw new IllegalStateException(e); 51 | } 52 | } 53 | 54 | public Collection> getChecks(Map healthChecksConfigs) { 55 | var enabledChecks = checks.entrySet().stream() 56 | .filter(e -> healthChecksConfigs.getOrDefault(e.getKey(), true)) 57 | .map(e -> asyncHealthCheckFactory.callSync(e.getValue())); 58 | var enabledAsyncChecks = asyncChecks.entrySet().stream() 59 | .filter(e -> healthChecksConfigs.getOrDefault(e.getKey(), true)) 60 | .map(e -> asyncHealthCheckFactory.callAsync(e.getValue())); 61 | return Stream.concat(enabledChecks, enabledAsyncChecks).collect(Collectors.toList()); 62 | } 63 | 64 | public boolean checksChanged() { 65 | return checksChanged; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /provided-checks/src/main/java/io/smallrye/health/checks/SocketHealthCheck.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.checks; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | import java.net.Socket; 6 | import java.net.SocketAddress; 7 | 8 | import org.eclipse.microprofile.health.HealthCheck; 9 | import org.eclipse.microprofile.health.HealthCheckResponse; 10 | import org.eclipse.microprofile.health.HealthCheckResponseBuilder; 11 | 12 | /** 13 | * Health check implementation to check if host is reachable using a socket. 14 | * 15 | * 16 | * {@code 17 | * @Produces 18 | * @ApplicationScoped 19 | * @Liveness 20 | * HealthCheck check1() { 21 | * return new SocketHealthCheck("192.168.0.2", 5432); 22 | * } 23 | * } 24 | * 25 | * 26 | * @see Socket 27 | */ 28 | public class SocketHealthCheck implements HealthCheck { 29 | 30 | static final String DEFAULT_NAME = "Socket Check"; 31 | static final int DEFAULT_TIMEOUT = 2000; 32 | 33 | private String host; 34 | private String name; 35 | private int port; 36 | private int timeout; 37 | 38 | public SocketHealthCheck(String host, int port) { 39 | this.host = host; 40 | this.port = port; 41 | this.name = DEFAULT_NAME; 42 | this.timeout = DEFAULT_TIMEOUT; 43 | } 44 | 45 | @Override 46 | public HealthCheckResponse call() { 47 | HealthCheckResponseBuilder healthCheckResponseBuilder = HealthCheckResponse 48 | .named(name); 49 | healthCheckResponseBuilder.withData("host", String.format("%s:%d", this.host, this.port)); 50 | try (Socket s = new Socket()) { 51 | final SocketAddress socketAddress = new InetSocketAddress(host, port); 52 | s.connect(socketAddress, timeout); 53 | healthCheckResponseBuilder.up(); 54 | } catch (IOException ex) { 55 | HealthChecksLogging.logger.socketHealthCheckError(ex); 56 | 57 | healthCheckResponseBuilder.withData("error", ex.getMessage()); 58 | healthCheckResponseBuilder.down(); 59 | } 60 | return healthCheckResponseBuilder.build(); 61 | } 62 | 63 | /** 64 | * Sets the name of the health check. 65 | * 66 | * @param name of health check. 67 | * @return SocketHealthCheck instance. 68 | */ 69 | public SocketHealthCheck name(String name) { 70 | this.name = name; 71 | return this; 72 | } 73 | 74 | /** 75 | * Sets timeout in millis. 76 | * 77 | * @param timeout in millis. 78 | * @return SocketHealthCheck instance. 79 | */ 80 | public SocketHealthCheck timeout(int timeout) { 81 | this.timeout = timeout; 82 | return this; 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/health/HealthStatus.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import java.security.SecureRandom; 4 | import java.util.function.BooleanSupplier; 5 | 6 | import org.eclipse.microprofile.health.HealthCheck; 7 | import org.eclipse.microprofile.health.HealthCheckResponse; 8 | 9 | public class HealthStatus { 10 | 11 | private static final SecureRandom random = new SecureRandom(); 12 | 13 | /** 14 | * Creates a health check with status up. 15 | * 16 | * @param name of the health check 17 | * @return Health check with status up and given name. 18 | */ 19 | public static HealthCheck up(String name) { 20 | return status(name, true); 21 | } 22 | 23 | /** 24 | * Creates a health check with status down. 25 | * 26 | * @param name of the health check 27 | * @return Health check with status down and given name. 28 | */ 29 | public static HealthCheck down(String name) { 30 | return status(name, false); 31 | } 32 | 33 | /** 34 | * Creates a health check with status set from supplier and default health check name (health-check). 35 | * 36 | * @param supplier to get status. 37 | * @return Health check with given status and default name. 38 | */ 39 | public static HealthCheck status(BooleanSupplier supplier) { 40 | return status(supplier.getAsBoolean()); 41 | } 42 | 43 | /** 44 | * Creates a health check with given status and default health check name (health-check). 45 | * 46 | * @param status 47 | * @return Health check with given status and default name. 48 | */ 49 | public static HealthCheck status(boolean status) { 50 | return status(generateRandomHealthCheckName(), status); 51 | } 52 | 53 | /** 54 | * Creates a health check with given status and health check name. 55 | * 56 | * @param name of the status. 57 | * @param supplier to get status. 58 | * @return Health check with given status and name. 59 | */ 60 | public static HealthCheck status(String name, BooleanSupplier supplier) { 61 | return status(name, supplier.getAsBoolean()); 62 | } 63 | 64 | /** 65 | * Creates a health check with given status and health check name. 66 | * 67 | * @param name of the status. 68 | * @param status 69 | * @return Health check with given status and name. 70 | */ 71 | public static HealthCheck status(String name, boolean status) { 72 | return () -> HealthCheckResponse.named(name).status(status).build(); 73 | } 74 | 75 | private static final String generateRandomHealthCheckName() { 76 | int suffix = random.nextInt(99999); 77 | return String.format("unnamed-health-check-%05d", suffix); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /provided-checks/src/main/java/io/smallrye/health/checks/InetAddressHealthCheck.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.checks; 2 | 3 | import java.io.IOException; 4 | import java.net.InetAddress; 5 | 6 | import org.eclipse.microprofile.health.HealthCheck; 7 | import org.eclipse.microprofile.health.HealthCheckResponse; 8 | import org.eclipse.microprofile.health.HealthCheckResponseBuilder; 9 | 10 | /** 11 | * Health check implementation to check if host is reachable using {@code java.net.InetAddress.isReachable} method. 12 | * 13 | * 14 | * {@code 15 | * @Produces 16 | * @ApplicationScoped 17 | * @Liveness 18 | * HealthCheck check1() { 19 | * return new InetAddressHealthCheck("service.com"); 20 | * } 21 | * } 22 | * 23 | * 24 | * @see InetAddress 25 | */ 26 | public class InetAddressHealthCheck implements HealthCheck { 27 | 28 | static final String DEFAULT_NAME = "Internet Address Check"; 29 | static final int DEFAULT_TIMEOUT = 2000; 30 | 31 | private String host; 32 | private String name; 33 | private int timeout; 34 | 35 | public InetAddressHealthCheck(String host) { 36 | this.host = host; 37 | this.name = DEFAULT_NAME; 38 | this.timeout = DEFAULT_TIMEOUT; 39 | } 40 | 41 | @Override 42 | public HealthCheckResponse call() { 43 | final HealthCheckResponseBuilder healthCheckResponseBuilder = HealthCheckResponse.named(this.name); 44 | healthCheckResponseBuilder.withData("host", this.host); 45 | try { 46 | InetAddress addr = InetAddress.getByName(this.host); 47 | final boolean reachable = addr.isReachable(this.timeout); 48 | if (!reachable) { 49 | healthCheckResponseBuilder.withData("error", String.format("Host %s not reachable.", this.host)); 50 | } 51 | 52 | healthCheckResponseBuilder.status(reachable); 53 | } catch (IOException e) { 54 | HealthChecksLogging.logger.inetAddressHealthCheckError(e); 55 | 56 | healthCheckResponseBuilder.withData("error", e.getMessage()); 57 | healthCheckResponseBuilder.down(); 58 | } 59 | 60 | return healthCheckResponseBuilder.build(); 61 | } 62 | 63 | /** 64 | * Sets timeout in millis. 65 | * 66 | * @param timeout in millis. 67 | * @return InetAddressHealthCheck instance. 68 | */ 69 | public InetAddressHealthCheck timeout(int timeout) { 70 | this.timeout = timeout; 71 | return this; 72 | } 73 | 74 | /** 75 | * Sets the name of the health check. 76 | * 77 | * @param name of health check. 78 | * @return InetAddressHealthCheck instance. 79 | */ 80 | public InetAddressHealthCheck name(String name) { 81 | this.name = name; 82 | return this; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /api/src/main/java/io/smallrye/health/api/HealthGroup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | package io.smallrye.health.api; 23 | 24 | import static java.lang.annotation.ElementType.FIELD; 25 | import static java.lang.annotation.ElementType.METHOD; 26 | import static java.lang.annotation.ElementType.PARAMETER; 27 | import static java.lang.annotation.ElementType.TYPE; 28 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 29 | 30 | import java.lang.annotation.Documented; 31 | import java.lang.annotation.Repeatable; 32 | import java.lang.annotation.Retention; 33 | import java.lang.annotation.Target; 34 | 35 | import jakarta.enterprise.util.AnnotationLiteral; 36 | import jakarta.inject.Qualifier; 37 | 38 | import io.smallrye.common.annotation.Experimental; 39 | 40 | /** 41 | * 42 | * This qualifier is used to define a custom Health Check procedure by applying a group name to it 43 | * 44 | * @author Antoine Sabot-Durand 45 | * 46 | */ 47 | @Target({ TYPE, METHOD, PARAMETER, FIELD }) 48 | @Retention(RUNTIME) 49 | @Documented 50 | @Qualifier 51 | @Repeatable(HealthGroups.class) 52 | @Experimental("Custom health group definitions exposed at /health/group/{group-name}. Not covered by the specification. " + 53 | "Subject to change.") 54 | public @interface HealthGroup { 55 | 56 | /** 57 | * @return name of the custom group 58 | */ 59 | String value(); 60 | 61 | /** 62 | * Support inline instantiation of the {@link HealthGroup} qualifier. 63 | * 64 | * @author Antoine Sabot-Durand 65 | * @since 2.2 66 | */ 67 | final class Literal extends AnnotationLiteral implements HealthGroup { 68 | 69 | private static final long serialVersionUID = 1L; 70 | 71 | private final String value; 72 | 73 | public static Literal of(String value) { 74 | return new Literal(value); 75 | } 76 | 77 | private Literal(String value) { 78 | this.value = value; 79 | } 80 | 81 | @Override 82 | public String value() { 83 | return value; 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/AllCustomFailedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.RunAsClient; 30 | import org.jboss.shrinkwrap.api.Archive; 31 | import org.testng.Assert; 32 | import org.testng.annotations.Test; 33 | 34 | import io.smallrye.health.deployment.FailedHealthGroup2; 35 | import io.smallrye.health.deployment.HealthGroup12; 36 | 37 | @RunAsClient 38 | public class AllCustomFailedTest extends TCKBase { 39 | 40 | @Deployment 41 | public static Archive getDeployment() { 42 | return DeploymentUtils.createWarFileWithClasses(AllCustomFailedTest.class.getSimpleName(), 43 | FailedHealthGroup2.class, HealthGroup12.class, TCKBase.class); 44 | } 45 | 46 | /** 47 | * Verifies the custom health integration with CDI at the scope of a server runtime, by retrieving all the custom checks. 48 | */ 49 | @Test 50 | public void testFailureResponsePayload() { 51 | Response response = getUrlAllCustomHealthContents(); 52 | 53 | // status code 54 | Assert.assertEquals(response.getStatus(), 503); 55 | 56 | JsonObject json = readJson(response); 57 | 58 | // response size 59 | JsonArray checks = json.getJsonArray("checks"); 60 | Assert.assertEquals(checks.size(), 2, "Expected two check responses"); 61 | 62 | for (JsonObject check : checks.getValuesAs(JsonObject.class)) { 63 | String id = check.getString("name"); 64 | switch (id) { 65 | case "health-group-12": 66 | verifySuccessStatus(check); 67 | break; 68 | case "failed-check": 69 | verifyFailureStatus(check); 70 | break; 71 | default: 72 | Assert.fail("Unexpected response payload structure"); 73 | } 74 | } 75 | 76 | assertOverallFailure(json); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /doc/modules/ROOT/pages/static-access.adoc: -------------------------------------------------------------------------------- 1 | [[static-access]] 2 | = Static access to the SmallRye Health 3 | 4 | In some contexts it might have been necessary to access SmallRye health capabilities in the non-CDI environments where CDI injection access typical for MicroProfile application is not available. For this reason, SmallRye Health provides a programmatic non-CDI static access to the `SmallRyeHealthReporter` and all different type of `HealthRegistry` so users can register (and unregister) health checks dynamically and invoke the reporter to get the same JSON objects as from usual `/health` calls. 5 | 6 | == Accessing health registry and reporting health 7 | 8 | The class `HealthRegistries` provides several static methods to access different types of health registry that can be used to register different types of health checks (see <>). The simplest way to report health is then: 9 | 10 | [source,java] 11 | ---- 12 | public static void main(String[] args) { 13 | HealthRegistry livenessRegistry = HealthRegistries.getRegistry(HealthType.LIVENESS); 14 | 15 | livenessRegistry.register("test-hc", () -> HealthCheckResponse.up("test")); 16 | 17 | SmallRyeHealthReporter reporter = new SmallRyeHealthReporter(); 18 | reporter.reportHealth(System.out, reporter.getHealth()); 19 | } 20 | ---- 21 | 22 | == Different types of health registries 23 | 24 | SmallRye Health provides a different health registry for each of the base health types: 25 | 26 | [source,java] 27 | ---- 28 | HealthRegistry livenessRegistry = HealthRegistries.getRegistry(HealthType.LIVENESS); 29 | HealthRegistry readinessRegistry = HealthRegistries.getRegistry(HealthType.READINESS); 30 | HealthRegistry startupRegistry = HealthRegistries.getRegistry(HealthType.STARTUP); 31 | HealthRegistry wellnessRegistry = HealthRegistries.getRegistry(HealthType.WELLNESS); 32 | ---- 33 | 34 | and also a static access to health groups (experimental, see <>): 35 | 36 | [source,java] 37 | ---- 38 | HealthRegistry testGroupRegistry = HealthRegistries.getHealthGroupRegistry("test-group"); 39 | Collection healthGroupRegistries = HealthRegistries.getHealthGroupRegistries(); 40 | ---- 41 | 42 | == Overriding configuration values 43 | 44 | In CDI environment, SmallRye Health uses MicroProfile Config for its configuration. However, in non-CDI environments, MicroProfile Config doesn't work so all configuration values used in SmallRye Health are overridable by methods in the classes that use particular config values: 45 | 46 | `SmallRyeHealthReporter` 47 | 48 | * #setContextPropagated(boolean) 49 | * #setEmptyChecksOutcome(String) 50 | * #setTimeoutSeconds(int) 51 | * #setAdditionalProperties(Map) 52 | 53 | `AsyncHealthCheckFactory` 54 | 55 | * #setUncheckedExceptionDataStyle(String) 56 | 57 | == Resources 58 | 59 | * https://github.com/smallrye/smallrye-health/blob/main/implementation/src/main/java/io/smallrye/health/registry/HealthRegistries.java[`HealthRegistries`] -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/MultipleCustomFailedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.RunAsClient; 30 | import org.jboss.shrinkwrap.api.Archive; 31 | import org.testng.Assert; 32 | import org.testng.annotations.Test; 33 | 34 | import io.smallrye.health.deployment.FailedHealthGroup2; 35 | import io.smallrye.health.deployment.HealthGroup12; 36 | 37 | /** 38 | * @author Antoine Sabot-Durand 39 | */ 40 | @RunAsClient 41 | public class MultipleCustomFailedTest extends TCKBase { 42 | 43 | @Deployment 44 | public static Archive getDeployment() { 45 | return DeploymentUtils.createWarFileWithClasses(MultipleCustomFailedTest.class.getSimpleName(), 46 | FailedHealthGroup2.class, HealthGroup12.class, TCKBase.class); 47 | } 48 | 49 | /** 50 | * Verifies the custom health integration with CDI at the scope of a server runtime 51 | */ 52 | @Test 53 | public void testFailureResponsePayload() { 54 | Response response = getUrlCustomHealthContents("health-group-2"); 55 | 56 | // status code 57 | Assert.assertEquals(response.getStatus(), 503); 58 | 59 | JsonObject json = readJson(response); 60 | 61 | // response size 62 | JsonArray checks = json.getJsonArray("checks"); 63 | Assert.assertEquals(checks.size(), 2, "Expected two check responses"); 64 | 65 | for (JsonObject check : checks.getValuesAs(JsonObject.class)) { 66 | String id = check.getString("name"); 67 | switch (id) { 68 | case "health-group-12": 69 | verifySuccessStatus(check); 70 | break; 71 | case "failed-check": 72 | verifyFailureStatus(check); 73 | break; 74 | default: 75 | Assert.fail("Unexpected response payload structure"); 76 | } 77 | } 78 | 79 | assertOverallFailure(json); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/AsyncHealthTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.RunAsClient; 30 | import org.jboss.shrinkwrap.api.Archive; 31 | import org.testng.Assert; 32 | import org.testng.annotations.Test; 33 | 34 | import io.smallrye.health.deployment.SuccessLivenessAsync; 35 | import io.smallrye.health.deployment.SuccessReadinessAsync; 36 | 37 | @RunAsClient 38 | public class AsyncHealthTest extends TCKBase { 39 | 40 | @Deployment 41 | public static Archive getDeployment() { 42 | return DeploymentUtils.createWarFileWithClasses(AsyncHealthTest.class.getSimpleName(), 43 | SuccessLivenessAsync.class, SuccessReadinessAsync.class, TCKBase.class); 44 | } 45 | 46 | @Test 47 | public void testAsyncLiveness() { 48 | Response response = getUrlLiveContents(); 49 | 50 | // status code 51 | Assert.assertEquals(response.getStatus(), 200); 52 | 53 | JsonObject json = readJson(response); 54 | 55 | // response size 56 | JsonArray checks = json.getJsonArray("checks"); 57 | Assert.assertEquals(checks.size(), 1, "Expected a single check response"); 58 | 59 | // single procedure response 60 | assertSuccessfulCheck(checks.getJsonObject(0), SuccessLivenessAsync.class.getName()); 61 | 62 | assertOverallSuccess(json); 63 | } 64 | 65 | @Test 66 | public void testAsyncReadiness() { 67 | Response response = getUrlReadyContents(); 68 | 69 | // status code 70 | Assert.assertEquals(response.getStatus(), 200); 71 | 72 | JsonObject json = readJson(response); 73 | 74 | // response size 75 | JsonArray checks = json.getJsonArray("checks"); 76 | Assert.assertEquals(checks.size(), 1, "Expected a single check response"); 77 | 78 | // single procedure response 79 | assertSuccessfulCheck(checks.getJsonObject(0), SuccessReadinessAsync.class.getName()); 80 | 81 | assertOverallSuccess(json); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/AsyncFailedHealthTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.RunAsClient; 30 | import org.jboss.shrinkwrap.api.Archive; 31 | import org.testng.Assert; 32 | import org.testng.annotations.Test; 33 | 34 | import io.smallrye.health.deployment.FailedLivenessAsync; 35 | import io.smallrye.health.deployment.FailedReadinessAsync; 36 | 37 | @RunAsClient 38 | public class AsyncFailedHealthTest extends TCKBase { 39 | 40 | @Deployment 41 | public static Archive getDeployment() { 42 | return DeploymentUtils.createWarFileWithClasses(AsyncFailedHealthTest.class.getSimpleName(), 43 | FailedLivenessAsync.class, FailedReadinessAsync.class, TCKBase.class); 44 | } 45 | 46 | @Test 47 | public void testAsyncLiveness() { 48 | Response response = getUrlLiveContents(); 49 | 50 | // status code 51 | Assert.assertEquals(response.getStatus(), 503); 52 | 53 | JsonObject json = readJson(response); 54 | 55 | // response size 56 | JsonArray checks = json.getJsonArray("checks"); 57 | Assert.assertEquals(checks.size(), 1, "Expected a single check response"); 58 | 59 | // single procedure response 60 | assertFailureCheck(checks.getJsonObject(0), FailedLivenessAsync.class.getName()); 61 | 62 | assertOverallFailure(json); 63 | } 64 | 65 | @Test 66 | public void testAsyncReadiness() { 67 | Response response = getUrlReadyContents(); 68 | 69 | // status code 70 | Assert.assertEquals(response.getStatus(), 503); 71 | 72 | JsonObject json = readJson(response); 73 | 74 | // response size 75 | JsonArray checks = json.getJsonArray("checks"); 76 | Assert.assertEquals(checks.size(), 1, "Expected a single check response"); 77 | 78 | // single procedure response 79 | assertFailureCheck(checks.getJsonObject(0), FailedReadinessAsync.class.getName()); 80 | 81 | assertOverallFailure(json); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: SmallRye Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - 3.1.x 8 | - jakarta 9 | paths-ignore: 10 | - '.gitignore' 11 | - 'CODEOWNERS' 12 | - 'LICENSE' 13 | - 'NOTICE' 14 | - 'README*' 15 | pull_request: 16 | paths-ignore: 17 | - '.gitignore' 18 | - 'CODEOWNERS' 19 | - 'LICENSE' 20 | - 'NOTICE' 21 | - 'README*' 22 | 23 | jobs: 24 | build: 25 | runs-on: ubuntu-latest 26 | strategy: 27 | fail-fast: false 28 | matrix: 29 | # To list the available "feature versions" (ignore "tip_version", it's not relevant): 30 | # https://api.adoptium.net/v3/info/available_releases 31 | # To list the available releases for a given "feature version" (example for 16): 32 | # https://api.adoptium.net/v3/assets/latest/16/hotspot 33 | java: 34 | - { name: "17" } 35 | - { name: "21" } 36 | - { name: "25" } 37 | 38 | name: Build with JDK ${{ matrix.java.name }} 39 | 40 | steps: 41 | - uses: actions/checkout@v2 42 | - name: Manually download JDK ${{ matrix.java.name }} 43 | if: matrix.java.download_url != '' 44 | run: wget -O $RUNNER_TEMP/java_package.tar.gz ${{ matrix.java.download_url }} 45 | - name: Set up JDK ${{ matrix.java.name }} (manually downloaded) 46 | if: matrix.java.download_url != '' 47 | uses: actions/setup-java@v4 48 | with: 49 | distribution: 'jdkfile' 50 | jdkFile: ${{ runner.temp }}/java_package.tar.gz 51 | java-version: ${{ matrix.java.name }} 52 | architecture: x64 53 | - name: Set up JDK ${{ matrix.java.name }} (automatically downloaded) 54 | if: matrix.java.download_url == '' 55 | uses: actions/setup-java@v4 56 | with: 57 | java-version: ${{ matrix.java.name }} 58 | distribution: oracle 59 | cache: maven 60 | check-latest: true 61 | - name: Build and Test with Java ${{ matrix.java.name }} 62 | run: mvn -B javadoc:javadoc formatter:validate verify 63 | - uses: actions/upload-artifact@v4 64 | name: TCK report 65 | with: 66 | name: tck-report-jdk-${{ matrix.java.name }} 67 | path: testsuite/tck/target/surefire-reports 68 | overwrite: 'true' 69 | 70 | quality: 71 | needs: [build] 72 | if: github.event_name == 'push' && github.repository == 'smallrye/smallrye-health' 73 | runs-on: ubuntu-latest 74 | name: quality 75 | 76 | steps: 77 | - uses: actions/checkout@v2 78 | - uses: actions/setup-java@v4 79 | with: 80 | java-version: 17 81 | distribution: temurin 82 | 83 | - name: sonar 84 | env: 85 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 86 | SONAR_TOKEN: ${{secrets.SONAR_TOKEN}} 87 | run: mvn -B verify --file pom.xml -Pcoverage javadoc:javadoc sonar:sonar -Dsonar.organization=smallrye -Dsonar.projectKey=smallrye_smallrye-health -Dsonar.login=$SONAR_TOKEN -Dmaven.test.failure.ignore=true 88 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/AdditionalHealthPropertiesTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.RunAsClient; 30 | import org.jboss.shrinkwrap.api.Archive; 31 | import org.jboss.shrinkwrap.api.asset.StringAsset; 32 | import org.testng.Assert; 33 | import org.testng.annotations.Test; 34 | 35 | import io.smallrye.health.deployment.SuccessLiveness; 36 | 37 | @RunAsClient 38 | public class AdditionalHealthPropertiesTest extends TCKBase { 39 | 40 | @Deployment 41 | public static Archive getDeployment() { 42 | return DeploymentUtils.createWarFileWithClasses(AdditionalHealthPropertiesTest.class.getSimpleName(), 43 | SuccessLiveness.class, TCKBase.class) 44 | .addAsManifestResource(new StringAsset("io.smallrye.health.additional.property.testProperty1=testValue1\n" + 45 | "io.smallrye.health.additional.property.testProperty2=testValue2\n" + 46 | "io.smallrye.health.additional.property.testProperty3=testValue3"), 47 | "microprofile-config.properties"); 48 | } 49 | 50 | @Test 51 | public void testAdditionalProperties() { 52 | Response response = getUrlHealthContents(); 53 | 54 | // status code 55 | Assert.assertEquals(response.getStatus(), 200); 56 | 57 | JsonObject json = readJson(response); 58 | 59 | // response size 60 | JsonArray checks = json.getJsonArray("checks"); 61 | Assert.assertEquals(checks.size(), 1, "Expected one check response"); 62 | 63 | JsonObject checkJson = checks.getJsonObject(0); 64 | Assert.assertEquals(SuccessLiveness.class.getName(), checkJson.getString("name")); 65 | verifySuccessStatus(checkJson); 66 | 67 | assertOverallSuccess(json); 68 | 69 | Assert.assertEquals(json.getString("testProperty1", "no value provided"), "testValue1"); 70 | Assert.assertEquals(json.getString("testProperty2", "no value provided"), "testValue2"); 71 | Assert.assertEquals(json.getString("testProperty3", "no value provided"), "testValue3"); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/DependentHealthChecksTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.shrinkwrap.api.Archive; 30 | import org.testng.Assert; 31 | import org.testng.annotations.Test; 32 | 33 | import io.smallrye.health.deployment.AsyncDependentHealthCheck; 34 | import io.smallrye.health.deployment.DependentCallRecorder; 35 | import io.smallrye.health.deployment.DependentHealthCheck; 36 | 37 | public class DependentHealthChecksTest extends TCKBase { 38 | 39 | @Deployment 40 | public static Archive getDeployment() { 41 | return DeploymentUtils.createWarFileWithClasses(DependentHealthChecksTest.class.getSimpleName(), 42 | DependentHealthCheck.class, AsyncDependentHealthCheck.class, DependentCallRecorder.class, TCKBase.class); 43 | } 44 | 45 | @Test 46 | public void testAsyncLiveness() { 47 | Response response = getUrlLiveContents(); 48 | 49 | // status code 50 | Assert.assertEquals(response.getStatus(), 200); 51 | 52 | JsonObject json = readJson(response); 53 | 54 | // response size 55 | JsonArray checks = json.getJsonArray("checks"); 56 | Assert.assertEquals(checks.size(), 2, "Expected two check responses"); 57 | 58 | for (JsonObject check : checks.getValuesAs(JsonObject.class)) { 59 | String id = check.getString("name"); 60 | 61 | if (id.equals(DependentHealthCheck.class.getName())) { 62 | verifySuccessStatus(check); 63 | Assert.assertTrue(DependentCallRecorder.healthCheckPreDestroyCalled, 64 | "HealthCheck - PreDestroy method was not called"); 65 | } else if (id.equals(AsyncDependentHealthCheck.class.getName())) { 66 | verifySuccessStatus(check); 67 | Assert.assertTrue(DependentCallRecorder.asyncHealthCheckPreDestroyCalled, 68 | "AsyncHealthCheck - PreDestroy method was not called"); 69 | } else { 70 | Assert.fail("Unexpected response payload structure"); 71 | } 72 | } 73 | 74 | assertOverallSuccess(json); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/deployment/TestHealthObserver.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.deployment; 2 | 3 | import static org.eclipse.microprofile.health.HealthCheckResponse.Status.UP; 4 | 5 | import jakarta.enterprise.context.ApplicationScoped; 6 | import jakarta.enterprise.event.Observes; 7 | import jakarta.enterprise.inject.Default; 8 | 9 | import org.eclipse.microprofile.health.HealthCheckResponse; 10 | import org.eclipse.microprofile.health.Liveness; 11 | import org.eclipse.microprofile.health.Readiness; 12 | import org.eclipse.microprofile.health.Startup; 13 | 14 | import io.smallrye.health.api.Wellness; 15 | import io.smallrye.health.event.SmallRyeHealthStatusChangeEvent; 16 | 17 | @ApplicationScoped 18 | public class TestHealthObserver { 19 | 20 | private int counterHealth; 21 | private int counterLiveness; 22 | private int counterReadiness; 23 | private int counterWellness; 24 | private int counterStartup; 25 | 26 | private HealthCheckResponse.Status healthStatus = UP; 27 | private HealthCheckResponse.Status livenessStatus = UP; 28 | private HealthCheckResponse.Status readinessStatus = UP; 29 | private HealthCheckResponse.Status wellnessStatus = UP; 30 | private HealthCheckResponse.Status startupStatus = UP; 31 | 32 | public void observeHealth(@Observes @Default SmallRyeHealthStatusChangeEvent event) { 33 | counterHealth++; 34 | healthStatus = event.health().getStatus(); 35 | } 36 | 37 | public void observeLiveness(@Observes @Liveness SmallRyeHealthStatusChangeEvent event) { 38 | counterLiveness++; 39 | livenessStatus = event.health().getStatus(); 40 | } 41 | 42 | public void observeReadiness(@Observes @Readiness SmallRyeHealthStatusChangeEvent event) { 43 | counterReadiness++; 44 | readinessStatus = event.health().getStatus(); 45 | } 46 | 47 | public void observeWellness(@Observes @Wellness SmallRyeHealthStatusChangeEvent event) { 48 | counterWellness++; 49 | wellnessStatus = event.health().getStatus(); 50 | } 51 | 52 | public void observeStartup(@Observes @Startup SmallRyeHealthStatusChangeEvent event) { 53 | counterStartup++; 54 | startupStatus = event.health().getStatus(); 55 | } 56 | 57 | public int getCounterHealth() { 58 | return counterHealth; 59 | } 60 | 61 | public int getCounterLiveness() { 62 | return counterLiveness; 63 | } 64 | 65 | public int getCounterReadiness() { 66 | return counterReadiness; 67 | } 68 | 69 | public int getCounterWellness() { 70 | return counterWellness; 71 | } 72 | 73 | public int getCounterStartup() { 74 | return counterStartup; 75 | } 76 | 77 | public HealthCheckResponse.Status getHealthStatus() { 78 | return healthStatus; 79 | } 80 | 81 | public HealthCheckResponse.Status getLivenessStatus() { 82 | return livenessStatus; 83 | } 84 | 85 | public HealthCheckResponse.Status getReadinessStatus() { 86 | return readinessStatus; 87 | } 88 | 89 | public HealthCheckResponse.Status getWellnessStatus() { 90 | return wellnessStatus; 91 | } 92 | 93 | public HealthCheckResponse.Status getStartupStatus() { 94 | return startupStatus; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/ChangingHealthTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import java.util.function.Supplier; 26 | 27 | import jakarta.json.JsonArray; 28 | import jakarta.json.JsonObject; 29 | 30 | import org.jboss.arquillian.container.test.api.Deployment; 31 | import org.jboss.arquillian.container.test.api.RunAsClient; 32 | import org.jboss.shrinkwrap.api.Archive; 33 | import org.testng.Assert; 34 | import org.testng.annotations.Test; 35 | 36 | import io.smallrye.health.deployment.ChangingLivenessHealthCheck; 37 | import io.smallrye.health.deployment.ChangingReadinessHealthCheckAsync; 38 | 39 | @RunAsClient 40 | public class ChangingHealthTest extends TCKBase { 41 | 42 | @Deployment 43 | public static Archive getDeployment() { 44 | return DeploymentUtils.createWarFileWithClasses(ChangingHealthTest.class.getSimpleName(), 45 | ChangingLivenessHealthCheck.class, ChangingReadinessHealthCheckAsync.class, TCKBase.class); 46 | } 47 | 48 | @Test 49 | public void testChangingHealthCheck() { 50 | testChangingHealth(this::getUrlLiveContents); 51 | } 52 | 53 | @Test 54 | public void testChangingAsyncHealthCheck() { 55 | testChangingHealth(this::getUrlReadyContents); 56 | } 57 | 58 | public void testChangingHealth(Supplier supplier) { 59 | // first invocation -> success 60 | Response response = supplier.get(); 61 | 62 | // status code 63 | Assert.assertEquals(response.getStatus(), 200); 64 | 65 | JsonObject json = readJson(response); 66 | 67 | // response size 68 | JsonArray checks = json.getJsonArray("checks"); 69 | Assert.assertEquals(checks.size(), 1, "Expected one check response"); 70 | 71 | JsonObject check = checks.getJsonObject(0); 72 | Assert.assertEquals(check.getString("name"), "up"); 73 | verifySuccessStatus(check); 74 | 75 | assertOverallSuccess(json); 76 | 77 | // second invocation -> failure 78 | response = supplier.get(); 79 | 80 | // status code 81 | Assert.assertEquals(response.getStatus(), 503); 82 | 83 | json = readJson(response); 84 | 85 | // response size 86 | checks = json.getJsonArray("checks"); 87 | Assert.assertEquals(checks.size(), 1, "Expected one check response"); 88 | 89 | check = checks.getJsonObject(0); 90 | Assert.assertEquals(check.getString("name"), "down"); 91 | verifyFailureStatus(check); 92 | 93 | assertOverallFailure(json); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/health/registry/HealthRegistries.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.registry; 2 | 3 | import java.util.Collection; 4 | import java.util.Collections; 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | import jakarta.enterprise.context.ApplicationScoped; 9 | import jakarta.enterprise.inject.Produces; 10 | 11 | import org.eclipse.microprofile.config.ConfigProvider; 12 | import org.eclipse.microprofile.health.Liveness; 13 | import org.eclipse.microprofile.health.Readiness; 14 | import org.eclipse.microprofile.health.Startup; 15 | 16 | import io.smallrye.health.api.HealthRegistry; 17 | import io.smallrye.health.api.HealthType; 18 | import io.smallrye.health.api.Wellness; 19 | 20 | @ApplicationScoped 21 | public class HealthRegistries { 22 | 23 | private static final int MAX_GROUP_REGISTRIES_COUNT_DEFAULT = 100; 24 | 25 | private static final Map registries = new ConcurrentHashMap<>(); 26 | private static final Map groupRegistries = new ConcurrentHashMap<>(); 27 | 28 | private static int maxGroupRegistriesCount = MAX_GROUP_REGISTRIES_COUNT_DEFAULT; 29 | 30 | static { 31 | try { 32 | maxGroupRegistriesCount = ConfigProvider.getConfig() 33 | .getOptionalValue("io.smallrye.health.maxGroupRegistriesCount", Integer.class) 34 | .orElse(MAX_GROUP_REGISTRIES_COUNT_DEFAULT); 35 | } catch (IllegalStateException illegalStateException) { 36 | // OK, no config provider was found, use default values 37 | } 38 | } 39 | 40 | @Produces 41 | @Liveness 42 | @ApplicationScoped 43 | public HealthRegistry getLivenessRegistry() { 44 | return getRegistry(HealthType.LIVENESS); 45 | } 46 | 47 | @Produces 48 | @Readiness 49 | @ApplicationScoped 50 | public HealthRegistry getReadinessRegistry() { 51 | return getRegistry(HealthType.READINESS); 52 | } 53 | 54 | @Produces 55 | @Startup 56 | @ApplicationScoped 57 | public HealthRegistry getStartupRegistry() { 58 | return getRegistry(HealthType.STARTUP); 59 | } 60 | 61 | @Produces 62 | @Wellness 63 | @ApplicationScoped 64 | public HealthRegistry getWellnessRegistry() { 65 | return getRegistry(HealthType.WELLNESS); 66 | } 67 | 68 | public static HealthRegistry getRegistry(HealthType type) { 69 | return registries.computeIfAbsent(type, t -> new HealthRegistryImpl()); 70 | } 71 | 72 | public static HealthRegistry getHealthGroupRegistry(String groupName) { 73 | if (groupName == null) { 74 | throw new IllegalArgumentException("Health group name cannot be null"); 75 | } 76 | 77 | HealthRegistry healthRegistry = groupRegistries.get(groupName); 78 | if (healthRegistry == null) { 79 | if (groupRegistries.keySet().size() >= maxGroupRegistriesCount) { 80 | throw new IllegalStateException( 81 | "Attempted to create more custom health group registries than allowed: " + maxGroupRegistriesCount); 82 | } 83 | 84 | healthRegistry = groupRegistries.computeIfAbsent(groupName, s -> new HealthRegistryImpl()); 85 | } 86 | 87 | return healthRegistry; 88 | } 89 | 90 | public static Collection getHealthGroupRegistries() { 91 | return Collections.unmodifiableCollection(groupRegistries.values()); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /implementation/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 4.0.0 21 | 22 | 23 | io.smallrye 24 | smallrye-health-parent 25 | 4.3.1-SNAPSHOT 26 | 27 | 28 | smallrye-health 29 | 30 | SmallRye Health: Implementation 31 | 32 | 33 | 34 | org.eclipse.microprofile.health 35 | microprofile-health-api 36 | 37 | 38 | 39 | io.smallrye 40 | smallrye-health-api 41 | 42 | 43 | 44 | io.smallrye.config 45 | smallrye-config 46 | 47 | 48 | 49 | org.jboss.logging 50 | jboss-logging 51 | 52 | 53 | 54 | org.jboss.logging 55 | jboss-logging-annotations 56 | 57 | 58 | 59 | org.jboss.logging 60 | jboss-logging-processor 61 | 62 | 63 | 64 | jakarta.enterprise 65 | jakarta.enterprise.cdi-api 66 | 67 | 68 | jakarta.json 69 | jakarta.json-api 70 | 71 | 72 | org.eclipse.parsson 73 | jakarta.json 74 | ${version.eclipse.parsson} 75 | 76 | 77 | 78 | org.junit.jupiter 79 | junit-jupiter 80 | 81 | 82 | io.smallrye.testing 83 | smallrye-testing-utilities 84 | 85 | 86 | org.hamcrest 87 | hamcrest 88 | test 89 | 3.0 90 | 91 | 92 | 93 | 94 | 95 | coverage 96 | 97 | @{jacocoArgLine} 98 | 99 | 100 | 101 | 102 | org.jacoco 103 | jacoco-maven-plugin 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/AsyncSyncHealthTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.RunAsClient; 30 | import org.jboss.shrinkwrap.api.Archive; 31 | import org.testng.Assert; 32 | import org.testng.annotations.Test; 33 | 34 | import io.smallrye.health.deployment.SuccessLiveness; 35 | import io.smallrye.health.deployment.SuccessLivenessAsync; 36 | import io.smallrye.health.deployment.SuccessReadiness; 37 | import io.smallrye.health.deployment.SuccessReadinessAsync; 38 | 39 | @RunAsClient 40 | public class AsyncSyncHealthTest extends TCKBase { 41 | 42 | @Deployment 43 | public static Archive getDeployment() { 44 | return DeploymentUtils.createWarFileWithClasses(AsyncSyncHealthTest.class.getSimpleName(), 45 | SuccessLiveness.class, SuccessReadiness.class, 46 | SuccessLivenessAsync.class, SuccessReadinessAsync.class, TCKBase.class); 47 | } 48 | 49 | @Test 50 | public void testLiveness() { 51 | Response response = getUrlLiveContents(); 52 | 53 | // status code 54 | Assert.assertEquals(response.getStatus(), 200); 55 | 56 | JsonObject json = readJson(response); 57 | 58 | // response size 59 | JsonArray checks = json.getJsonArray("checks"); 60 | Assert.assertEquals(checks.size(), 2, "Expected two checks in the response"); 61 | 62 | for (JsonObject check : checks.getValuesAs(JsonObject.class)) { 63 | String id = check.getString("name"); 64 | 65 | if (id.equals(SuccessLiveness.class.getName()) || id.equals(SuccessLivenessAsync.class.getName())) { 66 | verifySuccessStatus(check); 67 | } else { 68 | Assert.fail("Unexpected response payload structure"); 69 | } 70 | } 71 | 72 | assertOverallSuccess(json); 73 | } 74 | 75 | @Test 76 | public void testReadiness() { 77 | Response response = getUrlReadyContents(); 78 | 79 | // status code 80 | Assert.assertEquals(response.getStatus(), 200); 81 | 82 | JsonObject json = readJson(response); 83 | 84 | // response size 85 | JsonArray checks = json.getJsonArray("checks"); 86 | Assert.assertEquals(checks.size(), 2, "Expected two checks in the response"); 87 | 88 | for (JsonObject check : checks.getValuesAs(JsonObject.class)) { 89 | String id = check.getString("name"); 90 | 91 | if (id.equals(SuccessReadiness.class.getName()) || id.equals(SuccessReadinessAsync.class.getName())) { 92 | verifySuccessStatus(check); 93 | } else { 94 | Assert.fail("Unexpected response payload structure"); 95 | } 96 | } 97 | 98 | assertOverallSuccess(json); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/health/AsyncHealthCheckFactory.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health; 2 | 3 | import java.io.PrintWriter; 4 | import java.io.StringWriter; 5 | import java.util.Objects; 6 | 7 | import jakarta.enterprise.context.ApplicationScoped; 8 | 9 | import org.eclipse.microprofile.config.ConfigProvider; 10 | import org.eclipse.microprofile.health.HealthCheck; 11 | import org.eclipse.microprofile.health.HealthCheckResponse; 12 | import org.eclipse.microprofile.health.HealthCheckResponseBuilder; 13 | 14 | import io.smallrye.health.api.AsyncHealthCheck; 15 | import io.smallrye.mutiny.Uni; 16 | 17 | @ApplicationScoped 18 | public class AsyncHealthCheckFactory { 19 | 20 | private static final String EXCEPTION_CLASS = "exceptionClass"; 21 | private static final String EXCEPTION_MESSAGE = "exceptionMessage"; 22 | private static final String ROOT_CAUSE = "rootCause"; 23 | private static final String STACK_TRACE = "stackTrace"; 24 | 25 | String uncheckedExceptionDataStyle = ROOT_CAUSE; 26 | 27 | public AsyncHealthCheckFactory() { 28 | try { 29 | uncheckedExceptionDataStyle = ConfigProvider.getConfig() 30 | .getOptionalValue("io.smallrye.health.uncheckedExceptionDataStyle", String.class) 31 | .orElse(ROOT_CAUSE); 32 | } catch (IllegalStateException illegalStateException) { 33 | // OK, no config provider was found, use default values 34 | } 35 | } 36 | 37 | public Uni callAsync(AsyncHealthCheck asyncHealthCheck) { 38 | return withRecovery(asyncHealthCheck.getClass().getName(), Uni.createFrom().deferred(asyncHealthCheck::call)); 39 | } 40 | 41 | public Uni callSync(HealthCheck healthCheck) { 42 | return withRecovery(healthCheck.getClass().getName(), Uni.createFrom().item(healthCheck::call)); 43 | } 44 | 45 | private Uni withRecovery(String name, Uni uni) { 46 | return uni.onFailure().recoverWithItem(e -> handleFailure(name, e)) 47 | .onItem().ifNull() 48 | .continueWith(() -> handleFailure(name, HealthMessages.msg.healthCheckNull())); 49 | } 50 | 51 | private HealthCheckResponse handleFailure(String name, Throwable e) { 52 | // Log Stacktrace to server log so an error is not just in Health Check response 53 | HealthLogging.logger.healthCheckError(e); 54 | 55 | HealthCheckResponseBuilder response = HealthCheckResponse.named(name).down(); 56 | 57 | if (!uncheckedExceptionDataStyle.equals("none")) { 58 | response.withData(EXCEPTION_CLASS, e.getClass().getName()); 59 | response.withData(EXCEPTION_MESSAGE, e.getMessage()); 60 | 61 | switch (uncheckedExceptionDataStyle) { 62 | case ROOT_CAUSE: 63 | response.withData(ROOT_CAUSE, getRootCause(e).getMessage()); 64 | break; 65 | case STACK_TRACE: 66 | response.withData(STACK_TRACE, getStackTrace(e)); 67 | break; 68 | default: 69 | // don't add anything 70 | } 71 | } 72 | 73 | return response.build(); 74 | } 75 | 76 | private static String getStackTrace(Throwable t) { 77 | StringWriter string = new StringWriter(); 78 | 79 | try (PrintWriter pw = new PrintWriter(string)) { 80 | t.printStackTrace(pw); 81 | } 82 | 83 | return string.toString(); 84 | } 85 | 86 | private static Throwable getRootCause(Throwable t) { 87 | Throwable cause = t.getCause(); 88 | 89 | if (cause == null || cause == t) { 90 | return t; 91 | } 92 | 93 | return getRootCause(cause); 94 | } 95 | 96 | // Manual config overrides 97 | 98 | public void setUncheckedExceptionDataStyle(String uncheckedExceptionDataStyle) { 99 | Objects.requireNonNull(uncheckedExceptionDataStyle); 100 | this.uncheckedExceptionDataStyle = uncheckedExceptionDataStyle; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /testsuite/experimental/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | io.smallrye 5 | smallrye-health-testsuite-parent 6 | 4.3.1-SNAPSHOT 7 | 8 | 4.0.0 9 | 10 | smallrye-health-experimental-test 11 | 12 | SmallRye Health: Experimental Test Suite 13 | The test module for features to be included in the specification. 14 | 15 | 16 | 17 | io.smallrye 18 | smallrye-health-tck 19 | ${project.version} 20 | 21 | 22 | 23 | org.eclipse.microprofile.health 24 | microprofile-health-tck 25 | test 26 | 27 | 28 | 29 | org.apache.httpcomponents 30 | httpclient 31 | ${version.httpclient} 32 | compile 33 | 34 | 35 | 36 | jakarta.servlet 37 | jakarta.servlet-api 38 | provided 39 | 40 | 41 | 42 | 43 | 44 | 45 | wildfly 46 | 47 | 48 | 49 | !noWildfly 50 | 51 | 52 | 53 | 54 | org.wildfly.arquillian 55 | wildfly-arquillian-container-managed 56 | test 57 | 58 | 59 | 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-surefire-plugin 64 | 65 | 66 | ${jboss.extra.opts} 67 | 68 | 69 | ${project.build.directory}/wildfly-${version.wildfly} 70 | 71 | 72 | 73 | 74 | org.apache.maven.plugins 75 | maven-dependency-plugin 76 | 77 | 78 | unpack 79 | process-test-classes 80 | 81 | unpack 82 | 83 | 84 | 85 | 86 | org.wildfly 87 | wildfly-dist 88 | ${version.wildfly} 89 | zip 90 | false 91 | ${project.build.directory} 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | jdk11plus 103 | 104 | [11,) 105 | 106 | 107 | --add-modules java.se --add-opens=java.base/java.util=ALL-UNNAMED 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /provided-checks/src/main/java/io/smallrye/health/checks/UrlHealthCheck.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.health.checks; 2 | 3 | import java.net.HttpURLConnection; 4 | import java.net.Socket; 5 | import java.net.URL; 6 | 7 | import org.eclipse.microprofile.health.HealthCheck; 8 | import org.eclipse.microprofile.health.HealthCheckResponse; 9 | import org.eclipse.microprofile.health.HealthCheckResponseBuilder; 10 | 11 | /** 12 | * Health check implementation to check if host is reachable using a Http URL connection. 13 | * 14 | * 15 | * {@code 16 | * @Produces 17 | * @ApplicationScoped 18 | * @Liveness 19 | * HealthCheck check1() { 20 | * return new UrlHealthCheck("www.google.com"); 21 | * } 22 | * } 23 | * 24 | * 25 | * @see Socket 26 | */ 27 | public class UrlHealthCheck implements HealthCheck { 28 | 29 | static final String DEFAULT_NAME = "Url Check"; 30 | static final int DEFAULT_TIMEOUT = 2000; 31 | static final String DEFAULT_REQUEST_METHOD = "GET"; 32 | static final int DEFAULT_EXPECTED_STATUS_CODE = HttpURLConnection.HTTP_OK; 33 | 34 | private String url; 35 | private String name; 36 | private int timeout; 37 | private String requestMethod; 38 | private int statusCode; 39 | 40 | public UrlHealthCheck(String url) { 41 | this.url = url; 42 | this.requestMethod = DEFAULT_REQUEST_METHOD; 43 | this.statusCode = DEFAULT_EXPECTED_STATUS_CODE; 44 | this.name = DEFAULT_NAME; 45 | this.timeout = DEFAULT_TIMEOUT; 46 | } 47 | 48 | @Override 49 | public HealthCheckResponse call() { 50 | final HealthCheckResponseBuilder healthCheckResponseBuilder = HealthCheckResponse 51 | .named(name); 52 | healthCheckResponseBuilder.withData("host", String.format("%s %s", this.requestMethod, this.url)); 53 | HttpURLConnection httpUrlConn = null; 54 | try { 55 | httpUrlConn = (HttpURLConnection) new URL(this.url) 56 | .openConnection(); 57 | 58 | httpUrlConn.setRequestMethod(requestMethod); 59 | 60 | httpUrlConn.setConnectTimeout(timeout); 61 | httpUrlConn.setReadTimeout(timeout); 62 | 63 | final boolean isUp = httpUrlConn.getResponseCode() == statusCode; 64 | 65 | if (!isUp) { 66 | healthCheckResponseBuilder.withData("error", String.format("Expected response code %d but actual is %d", 67 | statusCode, httpUrlConn.getResponseCode())); 68 | } 69 | 70 | healthCheckResponseBuilder.status(isUp); 71 | 72 | } catch (Exception e) { 73 | HealthChecksLogging.logger.urlHealthCheckError(e); 74 | 75 | healthCheckResponseBuilder.withData("error", 76 | String.format("%s: %s", e.getClass().getCanonicalName(), e.getMessage())); 77 | healthCheckResponseBuilder.down(); 78 | } finally { 79 | if (httpUrlConn != null) { 80 | httpUrlConn.disconnect(); 81 | } 82 | } 83 | 84 | return healthCheckResponseBuilder.build(); 85 | } 86 | 87 | /** 88 | * Sets the name of the health check. 89 | * 90 | * @param name of health check. 91 | * @return UrlHealthCheck instance. 92 | */ 93 | public UrlHealthCheck name(String name) { 94 | this.name = name; 95 | return this; 96 | } 97 | 98 | /** 99 | * Sets timeout in millis. 100 | * 101 | * @param timeout in millis. 102 | * @return UrlHealthCheck instance. 103 | */ 104 | public UrlHealthCheck timeout(int timeout) { 105 | this.timeout = timeout; 106 | return this; 107 | } 108 | 109 | /** 110 | * Sets the expected status code to be returned as valid. 111 | * 112 | * @param statusCode expected. 113 | * @return UrlHealthCheck instance. 114 | */ 115 | public UrlHealthCheck statusCode(int statusCode) { 116 | this.statusCode = statusCode; 117 | return this; 118 | } 119 | 120 | /** 121 | * Sets the request method to be used (ie GET, POST, PUT, ...) 122 | * 123 | * @param requestMethod to use. 124 | * @return UrlHealthCheck instance. 125 | */ 126 | public UrlHealthCheck requestMethod(String requestMethod) { 127 | this.requestMethod = requestMethod; 128 | return this; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/HealthContentFilterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.OperateOnDeployment; 30 | import org.jboss.arquillian.container.test.api.RunAsClient; 31 | import org.jboss.shrinkwrap.api.Archive; 32 | import org.testng.Assert; 33 | import org.testng.annotations.Test; 34 | 35 | import io.smallrye.health.deployment.SuccessLiveness; 36 | import io.smallrye.health.deployment.TestHealthContentFilter; 37 | import io.smallrye.health.deployment.TestHealthContentFilter2; 38 | 39 | @RunAsClient 40 | public class HealthContentFilterTest extends TCKBase { 41 | 42 | private static final String DEPLOYMENT_1 = "deployment1"; 43 | private static final String DEPLOYMENT_2 = "deployment2"; 44 | 45 | @Deployment(name = DEPLOYMENT_1) 46 | public static Archive getDeployment() { 47 | return DeploymentUtils.createWarFileWithClasses(HealthContentFilterTest.class.getSimpleName(), 48 | TestHealthContentFilter.class, SuccessLiveness.class, TCKBase.class); 49 | } 50 | 51 | @Deployment(name = DEPLOYMENT_2) 52 | public static Archive getDeployment2() { 53 | return DeploymentUtils.createWarFileWithClasses(HealthContentFilterTest.class.getSimpleName() + "2", 54 | TestHealthContentFilter.class, TestHealthContentFilter2.class, SuccessLiveness.class, TCKBase.class); 55 | } 56 | 57 | /** 58 | * Verifies that the filter implementations process the payload before its returned to the caller. 59 | */ 60 | @Test 61 | @OperateOnDeployment(DEPLOYMENT_1) 62 | public void testHealthContentFilterFiltersReturnedJson() { 63 | Response response = getUrlHealthContents(); 64 | 65 | // status code 66 | Assert.assertEquals(response.getStatus(), 200); 67 | 68 | JsonObject json = readJson(response); 69 | 70 | // response size 71 | JsonArray checks = json.getJsonArray("checks"); 72 | Assert.assertEquals(checks.size(), 1, "Expected one check response"); 73 | 74 | JsonObject checkJson = checks.getJsonObject(0); 75 | Assert.assertEquals(SuccessLiveness.class.getName(), checkJson.getString("name")); 76 | verifySuccessStatus(checkJson); 77 | 78 | assertOverallSuccess(json); 79 | 80 | System.out.println(json); 81 | Assert.assertEquals("bar", json.getString("foo")); 82 | } 83 | 84 | /** 85 | * Verifies that the filter implementations process the payload before its returned to the caller. 86 | */ 87 | @Test 88 | @OperateOnDeployment(DEPLOYMENT_2) 89 | public void testMultipleHealthContentFiltersFilterReturnedJson() { 90 | Response response = getUrlHealthContents(); 91 | 92 | // status code 93 | Assert.assertEquals(response.getStatus(), 200); 94 | 95 | JsonObject json = readJson(response); 96 | 97 | // response size 98 | JsonArray checks = json.getJsonArray("checks"); 99 | Assert.assertEquals(checks.size(), 1, "Expected one check response"); 100 | 101 | JsonObject checkJson = checks.getJsonObject(0); 102 | Assert.assertEquals(SuccessLiveness.class.getName(), checkJson.getString("name")); 103 | verifySuccessStatus(checkJson); 104 | 105 | assertOverallSuccess(json); 106 | 107 | System.out.println(json); 108 | Assert.assertEquals("bar", json.getString("foo")); 109 | Assert.assertEquals("bar2", json.getString("foo2")); 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /testsuite/experimental/src/test/java/io/smallrye/health/test/DisableHealthCheckTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICES file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * SPDX-License-Identifier: Apache-2.0 20 | * 21 | */ 22 | 23 | package io.smallrye.health.test; 24 | 25 | import jakarta.json.JsonArray; 26 | import jakarta.json.JsonObject; 27 | 28 | import org.jboss.arquillian.container.test.api.Deployment; 29 | import org.jboss.arquillian.container.test.api.OperateOnDeployment; 30 | import org.jboss.arquillian.container.test.api.RunAsClient; 31 | import org.jboss.shrinkwrap.api.Archive; 32 | import org.jboss.shrinkwrap.api.asset.StringAsset; 33 | import org.testng.Assert; 34 | import org.testng.annotations.Test; 35 | 36 | import io.smallrye.health.deployment.SuccessLiveness; 37 | import io.smallrye.health.deployment.SuccessLivenessAsync; 38 | import io.smallrye.health.deployment.SuccessReadiness; 39 | import io.smallrye.health.deployment.SuccessReadinessAsync; 40 | 41 | @RunAsClient 42 | public class DisableHealthCheckTest extends TCKBase { 43 | 44 | private static final String SYNC_DEPLOYMENT = "syncDeployment"; 45 | private static final String ASYNC_DEPLOYMENT = "asyncDeployment"; 46 | 47 | @Deployment(name = SYNC_DEPLOYMENT) 48 | public static Archive getSyncDeployment() { 49 | return DeploymentUtils.createWarFileWithClasses(DisableHealthCheckTest.class.getSimpleName() + "-sync", 50 | SuccessLiveness.class, SuccessReadiness.class, TCKBase.class) 51 | .addAsManifestResource( 52 | new StringAsset("io.smallrye.health.check." + SuccessLiveness.class.getName() + ".enabled=false"), 53 | "microprofile-config.properties"); 54 | } 55 | 56 | @Deployment(name = ASYNC_DEPLOYMENT) 57 | public static Archive getAsyncDeployment() { 58 | return DeploymentUtils.createWarFileWithClasses(DisableHealthCheckTest.class.getSimpleName() + "-async", 59 | SuccessLivenessAsync.class, SuccessReadinessAsync.class, TCKBase.class) 60 | .addAsManifestResource( 61 | new StringAsset("io.smallrye.health.check." + SuccessLivenessAsync.class.getName() + ".enabled=false"), 62 | "microprofile-config.properties"); 63 | } 64 | 65 | @Test 66 | @OperateOnDeployment(SYNC_DEPLOYMENT) 67 | public void testAdditionalProperties() { 68 | Response response = getUrlHealthContents(); 69 | 70 | Assert.assertEquals(response.getStatus(), 200); 71 | 72 | JsonObject json = readJson(response); 73 | 74 | // response size, SuccessLiveness is in the deployment but it should not be included in the response 75 | JsonArray checks = json.getJsonArray("checks"); 76 | Assert.assertEquals(checks.size(), 1, "Expected one check response"); 77 | 78 | JsonObject checkJson = checks.getJsonObject(0); 79 | Assert.assertEquals(SuccessReadiness.class.getName(), checkJson.getString("name")); 80 | verifySuccessStatus(checkJson); 81 | 82 | assertOverallSuccess(json); 83 | } 84 | 85 | @Test 86 | @OperateOnDeployment(ASYNC_DEPLOYMENT) 87 | public void testAdditionalPropertiesAsync() { 88 | Response response = getUrlHealthContents(); 89 | 90 | Assert.assertEquals(response.getStatus(), 200); 91 | 92 | JsonObject json = readJson(response); 93 | 94 | // response size, SuccessLivenessAsync is in the deployment but it should not be included in the response 95 | JsonArray checks = json.getJsonArray("checks"); 96 | Assert.assertEquals(checks.size(), 1, "Expected one check response"); 97 | 98 | JsonObject checkJson = checks.getJsonObject(0); 99 | Assert.assertEquals(SuccessReadinessAsync.class.getName(), checkJson.getString("name")); 100 | verifySuccessStatus(checkJson); 101 | 102 | assertOverallSuccess(json); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /ui/src/main/webapp/health-ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | SmallRye Health (v${project.version}) 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Health UI 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | Settings 48 | 49 | × 50 | 51 | 52 | 53 | 54 | 55 | 56 | Title 57 | 58 | 59 | 60 | 61 | Health URL 62 | 63 | 64 | 65 | 66 | Poll 67 | 68 | off 69 | every 5 seconds 70 | every 10 seconds 71 | every 30 seconds 72 | every minute 73 | every 5 minutes 74 | every 10 minutes 75 | 76 | 77 | 78 | 79 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | Loading health probes... 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /.github/workflows/review-release.yml: -------------------------------------------------------------------------------- 1 | name: SmallRye Pre Release 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '.github/project.yml' 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | name: pre release 12 | 13 | steps: 14 | - uses: radcortez/project-metadata-action@main 15 | name: retrieve project metadata 16 | id: metadata 17 | with: 18 | github-token: ${{secrets.GITHUB_TOKEN}} 19 | metadata-file-path: '.github/project.yml' 20 | 21 | - name: Validate version 22 | if: contains(steps.metadata.outputs.current-version, 'SNAPSHOT') 23 | run: | 24 | echo '::error::Cannot release a SNAPSHOT version.' 25 | exit 1 26 | 27 | - uses: radcortez/milestone-review-action@main 28 | name: milestone review 29 | with: 30 | github-token: ${{secrets.GITHUB_TOKEN}} 31 | milestone-title: ${{steps.metadata.outputs.current-version}} 32 | 33 | integration-build-smallrye-health: 34 | runs-on: ubuntu-latest 35 | name: Integration - Build SmallRye Health 36 | if: contains(github.event.pull_request.body, 'Breaking change') == false 37 | outputs: 38 | SNAPSHOT_VERSION: ${{ steps.version-step.outputs.SNAPSHOT_VERSION }} 39 | 40 | steps: 41 | - uses: actions/checkout@v2 42 | 43 | - uses: actions/setup-java@v4 44 | with: 45 | java-version: 17 46 | distribution: temurin 47 | cache: maven 48 | 49 | - name: Build with Maven 50 | run: mvn -B javadoc:javadoc formatter:validate install 51 | 52 | - id: version-step 53 | name: Save version for integration builds 54 | run: | 55 | VERSION=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec) 56 | echo "::set-output name=SNAPSHOT_VERSION::$VERSION" 57 | 58 | - uses: actions/upload-artifact@v4 59 | with: 60 | name: smallrye-health 61 | path: ~/.m2/repository/io/smallrye 62 | 63 | integration-verification-quarkus: 64 | runs-on: ubuntu-latest 65 | name: Integration verification for Quarkus 66 | if: contains(github.event.pull_request.body, 'Breaking change') == false 67 | needs: integration-build-smallrye-health 68 | 69 | steps: 70 | - uses: actions/checkout@v2 71 | 72 | - uses: actions/download-artifact@v4 73 | with: 74 | name: smallrye-health 75 | path: ~/.m2/repository/io/smallrye 76 | 77 | - uses: actions/setup-java@v4 78 | with: 79 | java-version: 17 80 | distribution: temurin 81 | cache: maven 82 | 83 | - uses: actions/checkout@v2 84 | name: Checkout Quarkus 85 | with: 86 | repository: quarkusio/quarkus 87 | 88 | - name: Quarkus integration 89 | env: 90 | SNAPSHOT_VERSION: ${{ needs.integration-build-smallrye-health.outputs.SNAPSHOT_VERSION }} 91 | run: | 92 | ./mvnw -Dquickly -Dsmallrye-health.version="$SNAPSHOT_VERSION" 93 | ./mvnw clean verify -pl extensions/smallrye-health/deployment -Dsmallrye-health.version="$SNAPSHOT_VERSION" 94 | ./mvnw clean verify -pl tcks/microprofile-health -Dtcks -Dsmallrye-health.version="$SNAPSHOT_VERSION" 95 | 96 | integration-verification-wildfly: 97 | runs-on: ubuntu-latest 98 | name: Integration verification for WildFly 99 | if: contains(github.event.pull_request.body, 'Breaking change') == false 100 | needs: integration-build-smallrye-health 101 | 102 | steps: 103 | - uses: actions/checkout@v2 104 | 105 | - uses: actions/download-artifact@v4 106 | with: 107 | name: smallrye-health 108 | path: ~/.m2/repository/io/smallrye 109 | 110 | - uses: actions/setup-java@v4 111 | with: 112 | java-version: 17 113 | distribution: temurin 114 | cache: maven 115 | 116 | - uses: actions/checkout@v2 117 | name: Checkout WildFly 118 | with: 119 | repository: wildfly/wildfly 120 | 121 | - name: WildFly integration 122 | env: 123 | SNAPSHOT_VERSION: ${{ needs.integration-build-smallrye-health.outputs.SNAPSHOT_VERSION }} 124 | run: | 125 | ./mvnw clean install -DallTests -DskipTests -DskipITs -Denforcer.skip -Dversion.io.smallrye.smallrye-health="$SNAPSHOT_VERSION" 126 | ./mvnw clean verify -pl microprofile/health-smallrye -Dversion.io.smallrye.smallrye-health="$SNAPSHOT_VERSION" 127 | ./mvnw clean verify -pl testsuite/integration/expansion -Dts.standalone.microprofile -Dtest="org.wildfly.test.integration.microprofile.health.*TestCase" -Dversion.io.smallrye.smallrye-health="$SNAPSHOT_VERSION" 128 | ./mvnw clean verify -pl testsuite/integration/microprofile-tck/health -Dts.standalone.microprofile -Dversion.io.smallrye.smallrye-health="$SNAPSHOT_VERSION" 129 | ./mvnw clean verify -pl testsuite/integration/manualmode-expansion -DallTests -Dtest="org.wildfly.test.manual.microprofile.health.*TestCase" -Dversion.io.smallrye.smallrye-health="$SNAPSHOT_VERSION" 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /ui/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.smallrye 7 | smallrye-health-parent 8 | 4.3.1-SNAPSHOT 9 | 10 | 11 | smallrye-health-ui 12 | 13 | SmallRye Health: UI 14 | 15 | 16 | 4.5.0 17 | 3.5.1 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ${basedir}/src/main/resources 26 | 27 | 28 | ${basedir}/src/main/webapp 29 | ${project.build.directory}/classes/META-INF/resources 30 | true 31 | 32 | **/*.css 33 | **/*.html 34 | 35 | 36 | 37 | ${basedir}/src/main/webapp 38 | ${project.build.directory}/classes/META-INF/resources 39 | false 40 | 41 | **/*.css 42 | **/*.html 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | com.googlecode.maven-download-plugin 51 | download-maven-plugin 52 | 1.13.0 53 | 54 | 55 | install-bootstrap-css 56 | generate-sources 57 | 58 | wget 59 | 60 | 61 | https://unpkg.com/bootstrap@${bootstrap.version}/dist/css/bootstrap.min.css 62 | false 63 | ${project.build.directory}/classes/META-INF/resources/health-ui 64 | 3afe15e976734d9daac26310110c4594 65 | true 66 | true 67 | 10000 68 | 69 | 70 | 71 | install-bootstrap-js 72 | generate-sources 73 | 74 | wget 75 | 76 | 77 | https://unpkg.com/bootstrap@${bootstrap.version}/dist/js/bootstrap.min.js 78 | false 79 | ${project.build.directory}/classes/META-INF/resources/health-ui 80 | 6bea60c34c5db6797150610dacdc6bce 81 | true 82 | true 83 | 10000 84 | 85 | 86 | 87 | install-query 88 | generate-sources 89 | 90 | wget 91 | 92 | 93 | https://unpkg.com/jquery@${jquery.version}/dist/jquery.min.js 94 | false 95 | ${project.build.directory}/classes/META-INF/resources/health-ui 96 | dc5e7f18c8d36ac1d3d4753a87c98d0a 97 | true 98 | true 99 | 10000 100 | 101 | 102 | 103 | 104 | 105 | 106 | --------------------------------------------------------------------------------
11 | * {@code 12 | * @Produces 13 | * @ApplicationScoped 14 | * @Liveness 15 | * HealthCheck check1() { 16 | * return new HeapMemoryHealthCheck(); 17 | * } 18 | * } 19 | *
11 | * {@code 12 | * @Produces 13 | * @ApplicationScoped 14 | * @Liveness 15 | * HealthCheck check1() { 16 | * return new NonHeapMemoryHealthCheck(); 17 | * } 18 | * } 19 | *
17 | * public void observeLiveness(@Observes @Liveness SmallRyeHealthStatusChangeEvent event) { 18 | * ... 19 | * } 20 | *
14 | * {@code 15 | * @Produces 16 | * @ApplicationScoped 17 | * @Liveness 18 | * HealthCheck check1() { 19 | * return new SystemLoadHealthCheck(); 20 | * } 21 | * } 22 | *
16 | * {@code 17 | * @Produces 18 | * @ApplicationScoped 19 | * @Liveness 20 | * HealthCheck check1() { 21 | * return new SocketHealthCheck("192.168.0.2", 5432); 22 | * } 23 | * } 24 | *
14 | * {@code 15 | * @Produces 16 | * @ApplicationScoped 17 | * @Liveness 18 | * HealthCheck check1() { 19 | * return new InetAddressHealthCheck("service.com"); 20 | * } 21 | * } 22 | *
15 | * {@code 16 | * @Produces 17 | * @ApplicationScoped 18 | * @Liveness 19 | * HealthCheck check1() { 20 | * return new UrlHealthCheck("www.google.com"); 21 | * } 22 | * } 23 | *