Skip to content

Commit

Permalink
3.x: Support built-in health check config at health.checks (retaini…
Browse files Browse the repository at this point in the history
…ng now-deprecated `helidon.health` for compatibility) (#9337)

* Add support for built-in health check config at health.checks while maintaining bw compat at helidon.health

Signed-off-by: Tim Quinn <[email protected]>
  • Loading branch information
tjquinno authored Nov 7, 2024
1 parent 9d2752d commit 4899076
Show file tree
Hide file tree
Showing 13 changed files with 347 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2024 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.config.mp;

import java.util.Optional;
import java.util.logging.Logger;

import org.eclipse.microprofile.config.Config;

/**
* A utility class to handle MicroProfile configuration properties that should no longer be used.
* <p>
* For one major release, the property is retrieved through this class, to warn about the usage.
* In next major release, the deprecated property is removed (as is use of this class).
* <p>
* This class is closely patterned after {@code io.helidon.config.DeprecatedConfig} and works whether the MP config object
* is proxied by CDI or not. That other class can be used in conjunction with
* {@link io.helidon.config.mp.MpConfig#toHelidonConfig(org.eclipse.microprofile.config.Config)} for MP
* config objects that <em>are not</em> injected but that does work for MP config objects proxied by CDI. This one does work for
* those use cases.
*/
public final class DeprecatedMpConfig {
private static final Logger LOGGER = Logger.getLogger(DeprecatedMpConfig.class.getName());

private DeprecatedMpConfig() {
}

/**
* Get a value from config, attempting to read both the keys.
* Warning is logged if either the current key is not defined, or both the keys are defined.
*
* @param config configuration instance
* @param type type of the retrieved value
* @param currentKey key that should be used
* @param deprecatedKey key that should not be used
* @param <T> type of the retrieved value
* @return config value of the current key if exists, or the deprecated key if it does not, an empty {@code Optional}
* otherwise
*/
public static <T> Optional<T> getConfigValue(Config config, Class<T> type, String currentKey, String deprecatedKey) {
Optional<T> deprecatedConfig = config.getOptionalValue(deprecatedKey, type);
Optional<T> currentConfig = config.getOptionalValue(currentKey, type);

if (deprecatedConfig.isPresent()) {
if (currentConfig.isPresent()) {
LOGGER.warning("You are using both a deprecated configuration and a current one. "
+ "Deprecated key: \"" + deprecatedKey + "\", "
+ "current key: \"" + currentKey + "\", "
+ "only the current key will be used, and deprecated will be ignored.");
return currentConfig;
} else {
LOGGER.warning("You are using a deprecated configuration key. "
+ "Deprecated key: \"" + deprecatedKey + "\", "
+ "current key: \"" + currentKey + "\".");
return deprecatedConfig;
}
} else {
return currentConfig;
}
}
}
9 changes: 4 additions & 5 deletions docs/se/health.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
:rootdir: {docdir}/..
include::{rootdir}/includes/se.adoc[]
:built-in-health-check-config-prefix: health.checks
== Contents
Expand Down Expand Up @@ -216,16 +217,14 @@ common health check statuses:
|available disk space
|`diskSpace`
| link:{health-javadoc-base-url}/io/helidon/health/checks/DiskSpaceHealthCheck.html[`DiskSpaceHealthCheck`]
|`helidon.healthCheck.diskSpace.thresholdPercent` +
+
`helidon.healthCheck.diskSpace.path`
|`{built-in-health-check-config-prefix}.diskSpace.thresholdPercent` +
`{built-in-health-check-config-prefix}.diskSpace.path`
| `99.999` +
+
`/`
|available heap memory
| `heapMemory`
| link:{health-javadoc-base-url}/io/helidon/health/checks/HeapMemoryHealthCheck.html[`HeapMemoryHealthCheck`]
|`helidon.healthCheck.heapMemory.thresholdPercent`
|`{built-in-health-check-config-prefix}.heapMemory.thresholdPercent`
|`98`
|=======
Expand Down
4 changes: 4 additions & 0 deletions health/health-checks/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
<groupId>io.helidon.config</groupId>
<artifactId>helidon-config</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.config</groupId>
<artifactId>helidon-config-mp</artifactId>
</dependency>
<dependency>
<!-- only needed for compilation, not required in runtime -->
<groupId>jakarta.enterprise</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,22 @@

package io.helidon.health.checks;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileStore;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Formatter;
import java.util.Locale;
import java.util.function.Consumer;

import io.helidon.config.Config;
import io.helidon.config.mp.DeprecatedMpConfig;
import io.helidon.health.HealthCheckException;
import io.helidon.health.common.BuiltInHealthCheck;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;
import org.eclipse.microprofile.health.Liveness;
Expand All @@ -43,7 +43,8 @@
* <p>
* By default, this health check has a threshold of 100%, meaning that it will never fail the threshold check.
* Also, by default, it will check the root path {@code /}. These defaults can be modified using the
* {@value CONFIG_KEY_PATH} property (default {@value DEFAULT_PATH}), and the {@value CONFIG_KEY_THRESHOLD_PERCENT}
* {@value CURRENT_CONFIG_KEY_PATH} property (default {@value DEFAULT_PATH}), and the
* {@value CURRENT_CONFIG_KEY_THRESHOLD_PERCENT}
* property (default {@value DEFAULT_THRESHOLD}, virtually 100). The threshold should be set to a percent, such as 50 for 50% or
* 99 for 99%. If disk usage
* exceeds this threshold, then the health check will fail.
Expand All @@ -69,7 +70,7 @@ public class DiskSpaceHealthCheck implements HealthCheck {
* directory as application path), use
* {@link io.helidon.health.checks.DiskSpaceHealthCheck.Builder#path(java.nio.file.Path)}.
* When running within a MicroProfile server, you can configure path using a configuration key
* {@value #CONFIG_KEY_PATH}
* {@value #CURRENT_CONFIG_KEY_PATH}
* Defaults to {@value}
*/
public static final String DEFAULT_PATH = ".";
Expand All @@ -82,19 +83,34 @@ public class DiskSpaceHealthCheck implements HealthCheck {
static final String CONFIG_KEY_DISKSPACE_PREFIX = "diskSpace";

static final String CONFIG_KEY_PATH_SUFFIX = "path";
static final String CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX = "thresholdPercent";

/**
* Full configuration key for path, when configured through MicroProfile config.
*
* @deprecated The value will change to {@value CURRENT_CONFIG_KEY_PATH} in a future release
*/
public static final String CONFIG_KEY_PATH = HealthChecks.CONFIG_KEY_HEALTH_PREFIX
@Deprecated(since = "3.2.11")
public static final String CONFIG_KEY_PATH = HealthChecks.DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX
+ "." + CONFIG_KEY_DISKSPACE_PREFIX
+ "." + CONFIG_KEY_PATH_SUFFIX;

static final String CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX = "thresholdPercent";
/**
* Full configuration key for threshold percent, when configured through Microprofile config.
*
* @deprecated The value will change to {@value CURRENT_CONFIG_KEY_THRESHOLD_PERCENT} in future release
*/
public static final String CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.CONFIG_KEY_HEALTH_PREFIX
@Deprecated(since = "3.2.11")
public static final String CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX
+ "." + CONFIG_KEY_DISKSPACE_PREFIX
+ "." + CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX;

// The following two constants are used in the Javadoc to nudge users toward using the config key prefix "health.checks"
// rather than the obsolete "helidon.health". Because the original public constants above have always referred to the
// now-deprecated config prefixes, those values are unchanged to preserve backward compatibility.
private static final String CURRENT_CONFIG_KEY_PATH = HealthChecks.CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX
+ "." + CONFIG_KEY_DISKSPACE_PREFIX
+ "." + CONFIG_KEY_PATH_SUFFIX;

private static final String CURRENT_CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX
+ "." + CONFIG_KEY_DISKSPACE_PREFIX
+ "." + CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX;

Expand All @@ -114,16 +130,8 @@ public class DiskSpaceHealthCheck implements HealthCheck {
}

@Inject
DiskSpaceHealthCheck(
@ConfigProperty(name = CONFIG_KEY_PATH, defaultValue = DEFAULT_PATH) File path,
@ConfigProperty(name = CONFIG_KEY_THRESHOLD_PERCENT, defaultValue = "99.999") double thresholdPercent
) {
try {
this.fileStore = Files.getFileStore(path.toPath());
} catch (IOException e) {
throw new HealthCheckException("Failed to obtain file store for path " + path.getAbsolutePath(), e);
}
this.thresholdPercent = thresholdPercent;
DiskSpaceHealthCheck(org.eclipse.microprofile.config.Config mpConfig) {
this(builder().update(applyConfig(mpConfig)));
}

private DiskSpaceHealthCheck(Builder builder) {
Expand Down Expand Up @@ -174,6 +182,29 @@ public static DiskSpaceHealthCheck create() {
return builder().build();
}

private static Consumer<Builder> applyConfig(org.eclipse.microprofile.config.Config mpConfig) {
return builder -> {
DeprecatedMpConfig.getConfigValue(mpConfig,
Path.class,
configKey(HealthChecks.CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX,
CONFIG_KEY_PATH_SUFFIX),
configKey(HealthChecks.DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX,
CONFIG_KEY_PATH_SUFFIX))
.ifPresent(builder::path);
DeprecatedMpConfig.getConfigValue(mpConfig,
Double.class,
configKey(HealthChecks.CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX,
CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX),
configKey(HealthChecks.DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX,
CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX))
.ifPresent(builder::thresholdPercent);
};
}

private static String configKey(String prefix, String suffix) {
return prefix + "." + CONFIG_KEY_DISKSPACE_PREFIX + "." + suffix;
}

@Override
public HealthCheckResponse call() {
long diskFreeInBytes;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021 Oracle and/or its affiliates.
* Copyright (c) 2018, 2024 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.
Expand Down Expand Up @@ -31,7 +31,8 @@
*/
public final class HealthChecks {

static final String CONFIG_KEY_HEALTH_PREFIX = "helidon.health";
static final String CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX = "health.checks";
static final String DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX = "helidon.health";

private HealthChecks() {
}
Expand Down Expand Up @@ -114,9 +115,10 @@ public static HealthCheck[] healthChecks() {
}

/**
* Built-in health checks, set up using "helidon.health" configuration.
* Built-in health checks, set up using configuration at {@value CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX} or the deprecated
* {@value DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX}.
*
* @param config configuration rooted at "helidon.health"
* @param config configuration at the node containing health checks config
* @return built-in health checks, set up using the provided configuration
* @see io.helidon.health.HealthSupport.Builder#addLiveness(org.eclipse.microprofile.health.HealthCheck...)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@
import java.util.Formatter;
import java.util.Locale;

import io.helidon.config.Config;
import io.helidon.config.mp.DeprecatedMpConfig;
import io.helidon.health.common.BuiltInHealthCheck;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;
import org.eclipse.microprofile.health.Liveness;
Expand All @@ -36,7 +35,7 @@
* By default, this health check has a threshold of {@value DEFAULT_THRESHOLD} ({@value DEFAULT_THRESHOLD}%).
* If heap usage exceeds this level, then the server
* is considered to be unhealthy. This default can be modified using the
* {@value CONFIG_KEY_THRESHOLD_PERCENT} property. The threshold should be set as a percent, such as
* {@value CURRENT_CONFIG_KEY_THRESHOLD_PERCENT} property. The threshold should be set as a percent, such as
* 50 for 50% or 99 for 99%.
* </p>
* <p>
Expand All @@ -62,8 +61,18 @@ public class HeapMemoryHealthCheck implements HealthCheck {

/**
* Config property key for heap memory threshold.
*
* @deprecated The value will change to {@value #CURRENT_CONFIG_KEY_THRESHOLD_PERCENT} in a future release
*/
public static final String CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.CONFIG_KEY_HEALTH_PREFIX
@Deprecated(since = "3.2.11")
public static final String CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX
+ "." + CONFIG_KEY_HEAP_PREFIX
+ "." + CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX;

// The following constant is used in the Javadoc to nudge users toward using the current config key prefix "health.checks"
// rather than the deprecated "helidon.health". The public constant above has always used the now-deprecated prefix so that
// value is unchanged to preserve backward compatibility.
private static final String CURRENT_CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX
+ "." + CONFIG_KEY_HEAP_PREFIX
+ "." + CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX;

Expand All @@ -72,11 +81,18 @@ public class HeapMemoryHealthCheck implements HealthCheck {

// this will be ignored if not within CDI
@Inject
HeapMemoryHealthCheck(
Runtime runtime,
@ConfigProperty(name = CONFIG_KEY_THRESHOLD_PERCENT, defaultValue = "98") double threshold) {
this.thresholdPercent = threshold;
HeapMemoryHealthCheck(Runtime runtime, org.eclipse.microprofile.config.Config mpConfig) {
// Cannot use
this(runtime, DeprecatedMpConfig.getConfigValue(mpConfig,
Double.class,
thresholdPercentKey(HealthChecks.CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX),
thresholdPercentKey(HealthChecks.DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX))
.orElse(DEFAULT_THRESHOLD));
}

HeapMemoryHealthCheck(Runtime runtime, double thresholdPercent) {
this.rt = runtime;
this.thresholdPercent = thresholdPercent;
}

private HeapMemoryHealthCheck(Builder builder) {
Expand Down Expand Up @@ -104,6 +120,12 @@ public static HeapMemoryHealthCheck create() {
return builder().build();
}

private static String thresholdPercentKey(String prefix) {
return prefix + "."
+ CONFIG_KEY_HEAP_PREFIX + "."
+ CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX;
}

@Override
public HealthCheckResponse call() {
//Formatter ensures that returned delimiter will be always the same
Expand Down Expand Up @@ -174,7 +196,7 @@ public Builder thresholdPercent(double threshold) {
* @param config {@code Config} node for heap memory
* @return updated builder instance
*/
public Builder config(Config config) {
public Builder config(io.helidon.config.Config config) {
config.get(CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX)
.asDouble()
.ifPresent(this::thresholdPercent);
Expand Down
3 changes: 2 additions & 1 deletion health/health-checks/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021 Oracle and/or its affiliates.
* Copyright (c) 2018, 2024 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.
Expand All @@ -26,6 +26,7 @@

requires io.helidon.common;
requires io.helidon.config;
requires io.helidon.config.mp;
requires io.helidon.health;
requires io.helidon.health.common;
requires static microprofile.config.api;
Expand Down
Loading

0 comments on commit 4899076

Please sign in to comment.