diff --git a/docs/mp/guides/health.adoc b/docs/mp/guides/health.adoc index cb5739ea38b..a806d52bc93 100644 --- a/docs/mp/guides/health.adoc +++ b/docs/mp/guides/health.adoc @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// - Copyright (c) 2019, 2022 Oracle and/or its affiliates. + Copyright (c) 2019, 2023 Oracle and/or its affiliates. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -51,8 +51,7 @@ mvn -U archetype:generate -DinteractiveMode=false \ === Using the Built-In Health Checks -Helidon has a set of built-in health checks that are automatically enabled to report various -health check statuses that are commonly used: +Helidon has a set of built-in health checks: * deadlock detection * available disk space @@ -61,10 +60,14 @@ health check statuses that are commonly used: The following example will demonstrate how to use the built-in health checks. These examples are all executed from the root directory of your project (helidon-quickstart-mp). +[source,xml] +.Include dependency for the built-in health checks +include::{rootdir}/mp/health.adoc[tag=built-in-health-checks-depc] + [source,bash] -.Build the application, skipping unit tests, then run it: +.Build the application then run it: ---- -mvn package -DskipTests=true +mvn package java -jar target/helidon-quickstart-mp.jar ---- @@ -488,9 +491,9 @@ The example below will change the root path. .Create a file named `application.yaml` in the `resources` directory with the following contents: ---- health: - web-context: "myhealth" // <1> + endpoint: "/myhealth" // <1> ---- -<1> The web-context specifies a new root path for the health endpoint. +<1> The `endpoint` settings specifies the root path for the health endpoint. [source,bash] .Build and run the application, then verify that the health endpoint is using the new `/myhealth` root: @@ -507,20 +510,21 @@ The following example will change the root path and the health port. .Update application.yaml to use a different port and root path for the health endpoint: ---- server: - port: 8080 // <1> - host: "localhost" + port: 8080 // <1> sockets: - health: // <2> - port: 8081 // <3> - bind-address: "localhost" + - name: "admin" // <2> + port: 8081 // <3> + features: + observe: + sockets: "admin" // <4> health: - routing: "health" // <4> - web-context: "myhealth" + endpoint: "/myhealth" // <5> + ---- <1> The default port for the application. -<2> The name of the new socket, it can be any name, this example uses `health`. -<3> The port for the new health socket. -<4> The health endpoint routing uses the new socket `health`. +<2> The name of the new socket, it can be any name, this example uses `admin`. +<3> The port for the `admin` socket. +<4> The health endpoint, as part of Helidon's observability support, uses the socket `admin`. [source,bash] diff --git a/docs/mp/health.adoc b/docs/mp/health.adoc index 892f302f607..353ac8dbefc 100644 --- a/docs/mp/health.adoc +++ b/docs/mp/health.adoc @@ -79,6 +79,7 @@ If full control over the dependencies is required, and you want to minimize the To enable built-in health checks add the following dependency (or use the xref:introduction/microprofile.adoc[helidon-microprofile bundle] ) +//tag::built-in-health-checks-depc[] [source,xml] ---- @@ -86,7 +87,7 @@ To enable built-in health checks add the following dependency helidon-health-checks ---- - +//end::built-in-health-checks-depc[] == Usage @@ -154,7 +155,7 @@ The class responsible for configuration is: include::{rootdir}/config/io_helidon_webserver_observe_health_HealthObserver.adoc[leveloffset=+1,tag=config] -Current properties may be set in `application.yaml` or in `microprofile-config.properties` with `health` prefix. +Properties may be set in `application.yaml` or in `microprofile-config.properties`, in both cases using the `health` prefix. For example, you can specify a custom port and root context for the root health endpoint path. However, you cannot use different ports, such as http://localhost:8080/myhealth and http://localhost:8081/myhealth/live. @@ -163,18 +164,18 @@ The example below will change the root path. [source,properties] .Create a file named `microprofile-config.properties` in the `resources/META-INF` directory with the following contents: ---- -health.web-context=myhealth #<1> +health.endpoint=/myhealth #<1> ---- -<1> The web-context specifies a new root path for the health endpoint. +<1> The `endpoint` setting specifies the root path for the health endpoint. == Examples -Generate Helidon MP Quickstart project following these xref:guides/quickstart.adoc[Instruction] +Generate Helidon MP Quickstart project following these xref:guides/quickstart.adoc[instructions]. === Using the Built-In Health Checks -Helidon has a set of built-in health checks that are enabled to report various -health check statuses that are commonly used: +Helidon has a set of built-in health checks that can report various +conditions: * deadlock detection * available disk space @@ -183,6 +184,10 @@ health check statuses that are commonly used: The following example will demonstrate how to use the built-in health checks. These examples are all executed from the root directory of your project (helidon-quickstart-mp). +[source,xml] +.Include the built-in health checks dependency in your `pom.xml`: +include::{rootdir}/mp/health.adoc[tag=built-in-health-checks-depc] + [source,bash] .Build the application, then run it: ---- @@ -282,9 +287,6 @@ curl http://localhost:8080/health/live } ---- -Full example code is available link:{helidon-github-tree-url}/examples/microprofile[here]. - - === Custom Readiness Health Checks You can add a readiness check to indicate that the application is ready to be used. In this diff --git a/docs/se/guides/health.adoc b/docs/se/guides/health.adoc index 1d3b763855e..869d42f4169 100644 --- a/docs/se/guides/health.adoc +++ b/docs/se/guides/health.adoc @@ -51,8 +51,7 @@ mvn -U archetype:generate -DinteractiveMode=false \ === Using the Built-In Health Checks -Helidon has a set of built-in health checks that can be optionally enabled to report various - health check statuses that are commonly used: +Helidon has a set of built-in health checks: * deadlock detection * available disk space @@ -70,391 +69,199 @@ from the root directory of your project (helidon-quickstart-se). ---- +Handling health checks is part of Helidon's observability support. +By default, when you add the dependency for the built-in health checks, Helidon automatically registers the built-in checks. +But the generated project explicitly suppresses the build-in health checks, thereby highlighting the custom health checks it adds. + +[source,java] +.Excerpt from `Main.main`: +---- +ObserveFeature observe = ObserveFeature.builder() + .config(config.get("server.features.observe")) // <1> + .addObserver(HealthObserver.builder() // <2> + .details(true) // <3> + .useSystemServices(false) // <4> + .addCheck(() -> HealthCheckResponse.builder() // <5> + .status(HealthCheckResponse.Status.UP) + .detail("time", System.currentTimeMillis()) + .build(), HealthCheckType.READINESS) + .addCheck(() -> HealthCheckResponse.builder() // <6> + .status(isStarted()) + .detail("time", System.currentTimeMillis()) + .build(), HealthCheckType.STARTUP) + .build()) // <7> + .build(); + +---- +<1> Finds and applies configuration for observability. +<2> Begins preparing the `HealthObserver` according to this app's specific needs. +<3> Turns on detailed output in HTTP responses to the health endpoint. +<4> Suppresses automatic registration of built-in health checks. +<5> Adds a custom readiness health check which always reports `UP`'. +<6> Adds a custom start-up health check. +<7> Builds the `HealthObserver` for addition to the `ObserveFeature`. + +To see the built-in health checks, temporarily change `useSystemServices` to `true`: [source,java] -.Have a look at `Main.java`, and the `createRouting` method: +.Temporarily enable all built-in health checks ---- -private static Routing createRouting(Config config) { - - HealthSupport health = HealthSupport.builder() - .add(HealthChecks.healthChecks()) // <1> - .build(); - - return Routing.builder() - .register(health) // <2> - .build(); -} + .useSystemServices(true) ---- -<1> Add built-in health checks (requires the `helidon-health-checks` - dependency). -<2> Register the created health support with web server routing (adds the -`/health` endpoint). - [source,bash] -.Build the application, skipping unit tests, then run it: +.Build the application then run it: ---- -mvn package -DskipTests=true +mvn package java -jar target/helidon-quickstart-se.jar ---- [source,bash] .Verify the health endpoint in a new terminal window: ---- -curl http://localhost:8080/health +curl http://localhost:8080/observe/health ---- [source,json] -.JSON response: +.Built-in health checks in the JSON response: ---- { - "status": "UP", + "status": "DOWN", "checks": [ - { - "name": "deadlock", - "status": "UP" - }, + ... { "name": "diskSpace", "status": "UP", "data": { - "free": "319.58 GB", - "freeBytes": 343144304640, - "percentFree": "68.63%", "total": "465.63 GB", - "totalBytes": 499963174912 + "percentFree": "15.77%", + "totalBytes": 499963174912, + "free": "73.42 GB", + "freeBytes": 78837497856 } }, { "name": "heapMemory", "status": "UP", "data": { - "free": "196.84 MB", - "freeBytes": 206404016, - "max": "3.56 GB", - "maxBytes": 3817865216, - "percentFree": "98.66%", - "total": "245.50 MB", - "totalBytes": 257425408 + "total": "516.00 MB", + "percentFree": "99.81%", + "max": "8.00 GB", + "totalBytes": 541065216, + "maxBytes": 8589934592, + "free": "500.80 MB", + "freeBytes": 525126760 } + }, + { + "name": "deadlock", + "status": "UP" } ] } ----- -=== Custom Liveness Health Checks - -You can create application specific custom health checks and integrate them with Helidon -using the `HealthSupport` class, which is a WebServer service that contains -a collection of registered `HealthCheck` instances. When queried, it invokes the registered -health check and returns a response with a status code representing the overall -state of the application. - -[source,xml] -.Notice the custom health checks dependency is already in the project's pom.xml file: ----- - - io.helidon.health - helidon-health - ---- -[source,java] -.Replace the `HealthSupport` builder in the `Main.createRouting` method: ----- -HealthSupport health = HealthSupport.builder() - .addLiveness(() -> HealthCheckResponse.named("LivenessCheck") - .up() - .withData("time", System.currentTimeMillis()) - .build()) // <1> - .build(); ----- -<1> Add a custom liveness health check. This example returns `UP` and current time. -[source,bash] -.Build and run the application, then verify the custom health endpoint: ----- -curl http://localhost:8080/health ----- +=== Adding Custom Health Checks -[source,json] -.JSON response: ----- -{ - "status": "UP", - "checks": [ - { - "name": "LivenessCheck", - "status": "UP", - "data": { - "time": 1546958376613 - } - } - ] -} ----- +As illustrated above, the generated `Main` class in the QuickStart project adds two custom health checks. +Your own checks typically assess the conditions in and around your application and report whether the service should be considered started, live, and/or ready. -=== Custom Readiness Health Checks +As a trivial but illustrative example, the custom start-up health check in the generated `Main` class reports that the app is _not_ started until eight seconds after the server has started. After that, the start-up check reports that the app _is_ started. -You can add readiness checks to indicate that the application is ready to be used. In this -example, the server will wait five seconds before it becomes ready. +To see this start-up check in action, stop your running server (press ^C), then rerun it. -[source,java] -.Add a `readyTime` variable to the `Main` class, then set it five seconds after the application starts: +[source,bash] +.Stop the application: ---- -import java.util.concurrent.atomic.AtomicLong; // <1> - -public final class Main { - - private static AtomicLong readyTime = new AtomicLong(0); // <2> - - static WebServer startServer() throws IOException { - - server.start(); - - // Server threads are not daemon. No need to block. Just react. - try { - Thread.sleep(5000); // <3> - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - readyTime.set(System.currentTimeMillis()); // <4> - return server; +^C ---- -<1> Import AtomicLong. -<2> Declare the `readyTime` variable. -<3> Sleep five seconds. -<4> Set the `readyTime` to the time when the server became ready. - - -[source,java] -.Add a readiness check to the `HealhSupport` builder in the `Main.createRouting` method: +and note the output from the server +[listing] ---- -HealthSupport health = HealthSupport.builder() - .addLiveness(() -> HealthCheckResponse.named("LivenessCheck") - .up() - .withData("time", System.currentTimeMillis()) - .build()) - .addReadiness(() -> HealthCheckResponse.named("ReadinessCheck") - .status(readyTime.get() != 0 ) - .withData( "time", readyTime.get()) - .build()) // <1> - .build(); +Shutdown requested by JVM shutting down +[0x4fdb2ff3] @default socket closed. +Shutdown finished ---- -<1> Add the readiness check. - +then restart the server [source,bash] -.Build and run the application. Issue the `curl` command with -v within five seconds and you see the application is not ready: ----- -curl -v http://localhost:8080/health/ready ----- - -[source,json] -.HTTP response: ---- -... -< HTTP/1.1 503 Service Unavailable // <1> -... -{ - "status": "DOWN", - "checks": [ - { - "name": "ReadinessCheck", - "status": "DOWN", - "data": { - "time,": 0 - } - } - ] -} +java -jar target/helidon-quickstart-se.jar ---- -<1> The HTTP status is `503` since the application is not ready. -[source,bash] -.After five seconds you will see the application is ready: +In another terminal window, within eight seconds access the health endpoint [source,bash] +.Verify the health endpoint in a new terminal window: ---- -curl -v http://localhost:8080/health/ready +curl http://localhost:8080/observe/health ---- - +and notice the output. [source,json] -.JSON response: ---- -... -< HTTP/1.1 200 OK // <1> -... { - "status": "UP", + "status": "DOWN", // <1> "checks": [ { - "name": "ReadinessCheck", + "name": "Main$$Lambda/0x00000001310a8dc8", // <2> "status": "UP", "data": { - "time,": 1566243562097 + "time": 1697584867358 } - } - ] -} ----- -<1> The HTTP status is `200` indicating that the application is ready. - -=== Custom Startup Health Checks - -You can create custom startup health checks to indicate when the application has fully started and, therefore, when the readiness and liveness checks are meaningful. - -This example reuses the `readyTime` field added above for the custom readiness check and adds a startup check that waits three additional seconds past the "ready" time before declaring the application started. - -[source,java] -.Add a startup check to the `HealhSupport` builder in the `Main.createRouting` method: ----- -HealthSupport health = HealthSupport.builder() - .addLiveness(() -> HealthCheckResponse.named("LivenessCheck") - .up() - .withData("time", System.currentTimeMillis()) - .build()) - .addReadiness(() -> HealthCheckResponse.named("ReadinessCheck") - .status(readyTime.get() != 0 ) - .withData("time", readyTime.get()) - .build()) - .addStartup(() -> HealthCheckResponse.named("StartupCheck") // <1> - .status(readyTime.get() != 0 - && Duration.ofMillis(System.currentTimeMillis() - readyTime.get()).getSeconds() >= 3) - .withData("time", readyTime.get()) - .build()) - .build(); ----- -<1> Add the startup check. - -[source,bash] -.Build and run the application. Issue the `curl` command with -v within eight seconds and you see the application is not reported as started: ----- -curl -v http://localhost:8080/health/started ----- - -[source,json] -.HTTP response: ----- -... -< HTTP/1.1 503 Service Unavailable // <1> -... -{ - "status": "DOWN", - "checks": [ + }, { - "name": "StartupCheck", + "name": "Main$$Lambda/0x00000001310a9a78", // <3> "status": "DOWN", "data": { - "time": 1566243562097 + "time": 1697584867358 } - } - ] -} ----- -<1> The HTTP status is `503` since the application is not started. - -[source,bash] -.After eight seconds you will see the application is started: ----- -curl -v http://localhost:8080/health/started ----- - -[source,json] -.JSON response: ----- -... -< HTTP/1.1 200 OK // <1> + }, ... -{ - "status": "UP", - "checks": [ - { - "name": "StartupCheck", - "status": "UP", - "data": { - "time": 1566243562097 - } - } - ] } ---- -<1> The HTTP status is `200` indicating that the application is started. - - -When using the health check URLs, you can get the following health check data +<1> Overall health (`DOWN` because at least one check reports `DOWN`). +<2> The custom readiness check (hard-coded as `UP`). +<3> The custom start-up check (`DOWN` because the server has not been up for at least eight seconds yet). -* liveness only - http://localhost:8080/health/live -* readiness only - http://localhost:8080/health/ready -* startup only - http://localhost:8080/health/started -* all - http://localhost:8080/health - - -[source,bash] -.Get all of liveness, readiness, and startup data from a single query: ----- -curl http://localhost:8080/health ----- +Now wait eight seconds and access the endpoint again. [source,json] -.JSON response: ---- { - "status": "UP", + "status": "UP", // <1> "checks": [ { - "name": "LivenessCheck", + "name": "Main$$Lambda/0x00000001310a8dc8", "status": "UP", "data": { - "time": 1566244094548 + "time": 1697584869478 } }, { - "name": "ReadinessCheck", + "name": "Main$$Lambda/0x00000001310a9a78", // <2> "status": "UP", "data": { - "time,": 1566244093012 + "time": 1697584869478 } }, - { - "name": "StartupCheck", - "status": "UP", - "data": { - "time": 1566244093012 - } - } - ] +... } ---- +<1> Overall status (now `UP` because all checks report `UP`). +<2> The custom start-up check (now `UP` because the server has been up at least eight seconds). -=== Combine Built-In and Custom Health Checks +=== Accessing Specific Health Check Types +You can choose which category of health check to retrieve when you access the health endpoint by adding the health check type as an additional part of the resource path: -You can combine built-in and custom health checks using the same `HealthSupport` builder. +* liveness only - http://localhost:8080/observe/health/live +* readiness only - http://localhost:8080/observe/health/ready +* startup only - http://localhost:8080/observe/health/started +* all - http://localhost:8080/observe/health -[source,java] -.Register a custom health check in the `Main.createRouting` method: ----- -HealthSupport health = HealthSupport.builder() - .add(HealthChecks.healthChecks()) // <1> - .addLiveness(() -> HealthCheckResponse.named("LivenessCheck") - .up() - .withData("time", System.currentTimeMillis()) - .build()) - .addReadiness(() -> HealthCheckResponse.named("ReadinessCheck") - .status(readyTime.get() != 0) - .withData("time", readyTime.get()) - .build()) - .addStartup(() -> HealthCheckResponse.named("StartupCheck") - .status(readyTime.get() != 0 - && Duration.ofMillis(System.currentTimeMillis() - readyTime.get()).getSeconds() >= 3) - .withData("time", readyTime.get()) - .build()) - .build(); ----- -<1> Add the built-in health checks back to `HealthSupport` builder. [source,bash] -.Build and run the application, then verify the health endpoint. You will see both the built-in and custom health check data: +.Get only start-up health checks ---- -curl http://localhost:8080/health +curl http://localhost:8080/observe/started ---- [source,json] @@ -464,100 +271,38 @@ curl http://localhost:8080/health "status": "UP", "checks": [ { - "name": "LivenessCheck", + "name": "Main$$Lambda/0x00000001360a9a78", "status": "UP", "data": { - "time": 1566245527673 - } - }, - { - "name": "ReadinessCheck", - "status": "UP", - "data": { - "time,": 1566245527620 - }, - { - "name": "StartupCheck", - "status": "UP", - "data": { - "time,": 1566245527620 - } - }, - { - "name": "deadlock", - "status": "UP" - }, - { - "name": "diskSpace", - "status": "UP", - "data": { - "free": "326.17 GB", - "freeBytes": 350224424960, - "percentFree": "70.05%", - "total": "465.63 GB", - "totalBytes": 499963174912 - } - }, - { - "name": "heapMemory", - "status": "UP", - "data": { - "free": "247.76 MB", - "freeBytes": 259791680, - "max": "4.00 GB", - "maxBytes": 4294967296, - "percentFree": "99.80%", - "total": "256.00 MB", - "totalBytes": 268435456 + "time": 1697585727515 } } ] } ---- - === Custom Health Check URL Path -You can use a custom URL path for heath checks by setting the `WebContext`. In the following example, only -the liveness URL is changed, but you can do the same for the readiness, startup, and default -health checks. +You can use a custom URL path for heath checks by setting the `endpoint` for the `HealthObserver`. [source,java] -.Register a custom URL path with the custom health check in the `Main.createRouting` method: +.Set a custom endpoint path: ---- -HealthSupport health = HealthSupport.builder() - .webContext("/probe/live")// <1> - .addLiveness(() -> HealthCheckResponse.named("livenessProbe") - .up() - .withData("time", System.currentTimeMillis()) - .build()) - .build(); - +ObserveFeature observe = ObserveFeature.builder() + .config(config.get("server.features.observe")) + .addObserver(HealthObserver.builder() + .endpoint("/myhealth") // <1> + .details(true) +... ---- -<1> Change the liveness URL path using a `WebContext`. +<1> Changes the health endpoint path to `/myhealth`. [source,bash] -.Build and run the application, then verify that the liveness endpoint is using the `/probe/live`: +.Build and run the application, then verify that the health check endpoint responds at `/myhealth`: ---- -curl http://localhost:8080/probe/live +curl http://localhost:8080/myhealth ---- -[source,json] -.JSON response: ----- -{ - "status": "UP", - "checks": [ - { - "name": "livenessProbe", - "status": "UP", - "data": { - "time": 1546958376613 - } - } - ] -} ----- === Using Liveness, Readiness, and Startup Health Checks with Kubernetes @@ -565,29 +310,41 @@ The following example shows how to integrate the Helidon health API in an applic health endpoints for the Kubernetes liveness, readiness, and startup probes. [source,java] -.Change the `HealthSupport` builder in the `Main.createRouting` method to use the built-in liveness checks and custom liveness, readiness, and startup checks: ----- -HealthSupport health = HealthSupport.builder() - .add(HealthChecks.healthChecks()) // <1> - .addLiveness(() -> HealthCheckResponse.named("LivenessCheck") // <2> - .up() - .withData("time", System.currentTimeMillis()) - .build()) - .addReadiness(() -> HealthCheckResponse.named("ReadinessCheck") // <3> - .status(readyTime.get() != 0 ) - .withData("time", readyTime.get()) - .build()) - .addStartup(() -> HealthCheckResponse.named("StartupCheck") // <4> - .status(readyTime.get() != 0 - && Duration.ofMillis(System.currentTimeMillis() - readyTime.get()).getSeconds() >= 3) - .withData("time", readyTime.get()) - .build()) - .build(); +.Add a `readyTime` variable to the `Main` class: +---- +private static AtomicLong readyTime = new AtomicLong(0); +---- + +[source,java] +.Change the `HealthObserver` builder in the `Main.main` method to use new built-in liveness checks and custom liveness, readiness, and startup checks: +---- +ObserveFeature observe = ObserveFeature.builder() + .config(config.get("server.features.observe")) + .addObserver(HealthObserver.builder() + .useSystemServices(true) // <1> + .addCheck(() -> HealthCheckResponse.builder() + .status(readyTime.get() != 0) + .detail("time", readyTime.get()) + .build(), HealthCheckType.READINESS) // <2> + .addCheck(() -> HealthCheckResponse.builder() + .status(readyTime.get() != 0 + && Duration.ofMillis(System.currentTimeMillis() + - readyTime.get()) + .getSeconds() >= 3) + .detail("time", readyTime.get()) + .build(), HealthCheckType.STARTUP) // <3> + .addCheck(() -> HealthCheckResponse.builder() + .status(HealthCheckResponse.Status.UP) + .detail("time", System.currentTimeMillis()) + .build(), HealthCheckType.LIVENESS) // <4> + .build()) +.build(); + ---- <1> Add built-in health checks. -<2> Add a custom liveness check. -<3> Add a custom readiness check. -<4> Add a custom startup check. +<2> Add a custom readiness check. +<3> Add a custom start-up check. +<4> Add a custom liveness check. [source,bash] @@ -711,9 +468,9 @@ kubectl delete -f ./health.yaml ---- === Summary -This guide demonstrated how to use health checks in a Helidon SE application as follows: +This guide demonstrates how to use health checks in a Helidon SE application as follows: -* Access the default health check +* Access the default health checks * Create and use custom readiness, liveness, and startup checks * Customize the health check root path * Integrate Helidon health check with Kubernetes diff --git a/docs/se/health.adoc b/docs/se/health.adoc index 3b765b463a8..a1ee873b738 100644 --- a/docs/se/health.adoc +++ b/docs/se/health.adoc @@ -76,36 +76,51 @@ Optional dependency to use built-in health checks: ---- == API +To add custom health checks to your application, you need to + +* write the code which performs the health checks, and +* make those custom health checks known to Helidon. + +=== Writing Custom Health Checks A health check is a Java functional interface that returns a -`HealthCheckResponse` instance. You can choose to implement a health check -inline with a lambda expression or you can reference a method with the double -colon operator `::`. +`HealthCheckResponse` instance. You can create custom health checks in several ways, among them: + +* write a class which implements the `HealthCheck` interface, +* write an in-line lambda expression, or +* use a method reference a method with the double colon operator `::`. [source,java] .Health check with a lambda expression: ---- HealthCheck hc = () -> HealthCheckResponse - .named("exampleHealthCheck") - .up() - .build(); + .builder() + .detail("exampleCheck", "looking-good") + .status(HealthCheckResponse.Status.UP) // always "up" + .build(); ---- [source,java] -.Health check with method reference: +.Health check with method reference (in class `Main`): ---- -HealthCheckResponse exampleHealthCheck() { - return HealthCheckResponse - .named("exampleHealthCheck") - .up() - .build(); -} -HealthCheck hc = this::exampleHealthCheck; +static HealthCheckResponse exampleHealthCheck() { + return HealthCheckResponse + .builder() + .detail("exampleHealthCheck", "looking-good") + .status(HealthCheckResponse.Status.UP) // always "up" + .build(); + } + +HealthCheck hc = Main::exampleHealthCheck; ---- +A real health check would compute its status dynamically based on the conditions in the server rather than hard-coding a fixed value. + +=== Adding Custom Health Checks to Helidon -`HealthSupport` is a WebServer service that contains a collection of -registered `HealthCheck` instances. When queried, it invokes the registered -health check and returns a response with a status code representing the overall +Health support in Helidon is part of Helidon's observability feature. +`HealthObserver` is a Helidon-provided observability implementation that contains a collection of +registered `HealthCheck` instances and, when queried, invokes the registered +health checks and returns a response with a status code representing the overall status of the application. [cols="1,5",role="flex, sm7"] @@ -117,41 +132,34 @@ status of the application. | `500` | An error occurred while reporting the health. |======= -HTTP `GET` responses include JSON content showing the detailed results of all the health checks which the server executed after receiving the request. -HTTP `HEAD` requests return only the status with no payload. +You control, either using configuration or adding code to your application, whether the HTTP responses to `GET` requests contain detailed information about each health check. +With details enabled, HTTP `GET` responses include JSON content showing the detailed results of all the health checks which the server executed after receiving the request. +With details disabled, HTTP `GET` responses have no payload. +HTTP `HEAD` requests always return only the status with no payload. -The following code snippets show how to register health checks while building an -instance of `HealthSupport`: +If you add the Helidon health dependency to your `pom.xml` file, Helidon automatically registers the `HelidonObserver` service and responds to the default `/observe/health` endpoint. +Further, if you add the built-in health checks dependency, Helidon automatically finds them and adds those checks to the `HealthObserver`. -[source,java] -.Create the health support service: ----- -HealthSupport health = HealthSupport.builder() - .addLiveness(hc) // hc created above - .build(); ----- +The following example shows how to register your own custom health checks while building and registering an +instance of `HealthObserver`: [source,java] -.Create a custom health check: +.Create and register the health observer feature with a custom health check ---- -HealthSupport health = HealthSupport.builder() - .addLiveness(() -> HealthCheckResponse.named("exampleHealthCheck") - .up() - .withData("time", System.currentTimeMillis()) - .build()) - .build(); ----- - -The custom health check above returns a status of `UP` and the current time. -After creating the `HealthCheck` and registering it in a `HealthSupport`, we -must add the latter to the WebServer routes as follows: - -[source,java] ----- -Routing.builder() - .register(health) - .build(); +WebServer server = WebServer.builder() + .config(config.get("server")) + .addFeature(ObserveFeature.create(HealthObserver.builder() // <1> + .addCheck(hc) // <2> + .details(true) // <3> + .build())) // <4> + .routing(Main::routing) + .build() + .start(); ---- +<1> Create a builder for the `HealthObserver`. +<2> Add the custom health check to the `HealthObserver.Builder`. Invoke `addCheck` multiple times to add multiple custom health checks. +<3> Set detailed HTTP response output to `true`. +<4> Build the `HealthObserver` so it can be added to the observability feature that is registered with the webserver. Here is a sample response to the custom health check registered above: @@ -159,16 +167,16 @@ Here is a sample response to the custom health check registered above: .JSON response: ---- { - "status": "UP", - "checks": [ - { - "name": "exampleHealthCheck", - "status": "UP", - "data": { - "time": 1546958376613 - } - } - ] + "status": "UP", + "checks": [ + { + "name": "Main$$Lambda/0x00000001320ac800", + "status": "UP", + "data": { + "exampleHealthCheck": "looking-good" + } + }, +... } ---- @@ -187,7 +195,7 @@ The following table provides a summary of the Health Check API classes. | Result of a health check invocation that contains a status | `io.helidon.webserver.observe.health.HealthObserver` -| WebServer service that exposes `/health` and invokes the registered health +| WebServer service that exposes `/observe/health` and invokes the registered health checks |======= @@ -223,23 +231,29 @@ common health check statuses: |`98` |======= -The following code adds the default built-in health checks to your application: +Simply adding the built-in health check dependency is sufficient to register all the built-in health checks automatically. +If you want to use only some of the built-in checks in your application, you can disable automatic discovery of the built-in health checks and register only the ones you want. + +The following code adds only selected built-in health checks to your application: [source,java] +.Adding selected built-in health checks ---- -HealthObserver health = HealthObserver.builder() - .addChecks(HealthChecks.healthChecks()) // <1> - .build(); - -Routing.builder() - .addFeature(ObserveFeature.builder() - .addObserver(health)) // <2> - .build(); +WebServer server = WebServer.builder() + .config(config.get("server")) + .addFeature(ObserveFeature.create(HealthObserver.builder() + .useSystemServices(false) // <1> + .addCheck(HealthChecks.deadlockCheck()) // <2> + .addCheck(hc) // <3> + .details(true) + .build())) + .routing(Main::routing) + .build() + .start(); ---- -<1> Add built-in health checks using defaults (requires the `helidon-health-checks` -dependency). -<2> Add the created `HealthObserver` to the `ObserveFeature` registered in the web server routing (adds the -`/observe/health` endpoint). +<1> Disables automatic registration of the built-in health checks. +<2> Adds the specific built-in check(s) you want. +<3> Adds a custom check. You can control the thresholds for built-in health checks in either of two ways: