io.micronaut.management.endpoint.health.HealthEndpoint Maven / Gradle / Ivy
 The newest version!
        
        /*
 * Copyright 2017-2020 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micronaut.management.endpoint.health;
import io.micronaut.context.annotation.ConfigurationProperties;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.async.annotation.SingleResult;
import io.micronaut.health.HealthStatus;
import io.micronaut.http.HttpStatus;
import io.micronaut.management.endpoint.EndpointConfiguration;
import io.micronaut.management.endpoint.annotation.Endpoint;
import io.micronaut.management.endpoint.annotation.Read;
import io.micronaut.management.endpoint.annotation.Selector;
import io.micronaut.management.health.aggregator.HealthAggregator;
import io.micronaut.management.health.indicator.HealthCheckType;
import io.micronaut.management.health.indicator.HealthIndicator;
import io.micronaut.management.health.indicator.HealthResult;
import io.micronaut.management.health.indicator.annotation.Liveness;
import jakarta.inject.Inject;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import java.security.Principal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
 * Exposes an {@link Endpoint} to provide information about the health of the application.
 *
 * @author James Kleeh
 * @since 1.0
 */
@Endpoint(value = HealthEndpoint.NAME, defaultSensitive = HealthEndpoint.DEFAULT_SENSITIVE)
public class HealthEndpoint {
    /**
     * If the endpoint is sensitive if no configuration is provided.
     */
    public static final boolean DEFAULT_SENSITIVE = false;
    /**
     * Constant for health.
     */
    public static final String NAME = "health";
    /**
     * Prefix for health endpoint.
     */
    public static final String PREFIX = EndpointConfiguration.PREFIX + "." + NAME;
    private HealthAggregator healthAggregator;
    private HealthIndicator[] healthIndicators;
    private HealthIndicator[] livenessHealthIndicators;
    private HealthIndicator[] readinessHealthIndicators;
    private DetailsVisibility detailsVisible = DetailsVisibility.AUTHENTICATED;
    private StatusConfiguration statusConfiguration;
    private boolean serviceReadyIndicatorEnabled = true;
    /**
     * @param healthAggregator The {@link HealthAggregator}
     * @param healthIndicators The {@link HealthIndicator}
     * @param livenessHealthIndicators The {@link HealthIndicator} qualified by {@link Liveness}
     */
    public HealthEndpoint(HealthAggregator healthAggregator,
                          HealthIndicator[] healthIndicators,
                          @Liveness HealthIndicator[] livenessHealthIndicators) {
        this.healthAggregator = healthAggregator;
        this.healthIndicators = healthIndicators;
        this.livenessHealthIndicators = livenessHealthIndicators;
        this.readinessHealthIndicators = getReadinessHealthIndicators(healthIndicators, livenessHealthIndicators);
    }
    protected final HealthIndicator[] getReadinessHealthIndicators(HealthIndicator[] allHealthIndicators,
                                                                   HealthIndicator[] livenessHealthIndicators) {
        List liveness = Arrays.asList(livenessHealthIndicators);
        return Arrays.stream(allHealthIndicators).
            filter(healthIndicator -> !liveness.contains(healthIndicator)).
            toArray(HealthIndicator[]::new);
    }
    /**
     * Return all health indicators.
     *
     * @param principal Authenticated user
     * @return The health information as a {@link Mono}
     */
    @Read
    @SingleResult
    public Publisher getHealth(@Nullable Principal principal) {
        HealthLevelOfDetail detail = levelOfDetail(principal);
        return Mono.from(
            healthAggregator.aggregate(healthIndicators, detail)
        );
    }
    /**
     * Return health indicators based on the selector.
     *
     * @param principal Authenticated user
     * @param selector HealthEndpointSelector
     * @return The health information as a {@link Mono}
     */
    @Read
    @SingleResult
    public Publisher getHealth(@Nullable Principal principal, @Selector HealthCheckType selector) {
        HealthLevelOfDetail detail = levelOfDetail(principal);
        HealthIndicator[] indicators = switch (selector) {
            case LIVENESS -> livenessHealthIndicators;
            default -> readinessHealthIndicators;
        };
        return Mono.from(
            healthAggregator.aggregate(indicators, detail)
        );
    }
    /**
     * Whether the {@link io.micronaut.management.health.indicator.service.ServiceReadyHealthIndicator} is enabled. Defaults to {@code true}.
     *
     * @return True if it is enabled.
     */
    public boolean isServiceReadyIndicatorEnabled() {
        return serviceReadyIndicatorEnabled;
    }
    /**
     * Set whether the {@link io.micronaut.management.health.indicator.service.ServiceReadyHealthIndicator} is enabled. Defaults to {@code true}.
     *
     * @param serviceReadyIndicatorEnabled True if the service ready indicator should be enabled.
     */
    public void setServiceReadyIndicatorEnabled(boolean serviceReadyIndicatorEnabled) {
        this.serviceReadyIndicatorEnabled = serviceReadyIndicatorEnabled;
    }
    /**
     * @return The visibility policy for health information.
     */
    public DetailsVisibility getDetailsVisible() {
        return detailsVisible;
    }
    /**
     * Sets the visibility policy for health information.
     *
     * @param detailsVisible The {@link DetailsVisibility}
     */
    public void setDetailsVisible(DetailsVisibility detailsVisible) {
        this.detailsVisible = detailsVisible;
    }
    /**
     * @return The status configuration
     */
    public StatusConfiguration getStatusConfiguration() {
        return statusConfiguration;
    }
    /**
     * Sets the status configuration.
     *
     * @param statusConfiguration The status configuration
     */
    @Inject
    public void setStatusConfiguration(StatusConfiguration statusConfiguration) {
        if (statusConfiguration != null) {
            this.statusConfiguration = statusConfiguration;
        }
    }
    /**
     * Returns the level of detail that should be returned by the endpoint.
     *
     * @param principal Authenticated user
     * @return The {@link HealthLevelOfDetail}
     */
    protected HealthLevelOfDetail levelOfDetail(@Nullable Principal principal) {
        boolean showDetails = false;
        switch (detailsVisible) {
            case AUTHENTICATED:
                showDetails = principal != null;
                break;
            case ANONYMOUS:
                showDetails = true;
                break;
            default:
                // no-op
        }
        if (showDetails) {
            return HealthLevelOfDetail.STATUS_DESCRIPTION_DETAILS;
        } else {
            return HealthLevelOfDetail.STATUS;
        }
    }
    /**
     * Configuration related to handling of the {@link HealthStatus}.
     *
     * @author graemerocher
     * @since 1.0
     */
    @ConfigurationProperties("status")
    public static class StatusConfiguration {
        private Map httpMapping = new HashMap<>(5);
        /**
         * Default constructor.
         */
        public StatusConfiguration() {
            httpMapping.put(HealthStatus.NAME_DOWN, HttpStatus.SERVICE_UNAVAILABLE);
            httpMapping.put(HealthStatus.NAME_UP, HttpStatus.OK);
            httpMapping.put(HealthStatus.UNKNOWN.getName(), HttpStatus.OK);
        }
        /**
         * @return How {@link HealthStatus} map to {@link io.micronaut.http.HttpStatus} codes.
         */
        public Map getHttpMapping() {
            return httpMapping;
        }
        /**
         * Set how {@link HealthStatus} map to {@link io.micronaut.http.HttpStatus} codes.
         *
         * @param httpMapping The http mappings
         */
        public void setHttpMapping(Map httpMapping) {
            if (httpMapping != null) {
                for (Map.Entry entry : httpMapping.entrySet()) {
                    this.httpMapping.put(
                        entry.getKey().toUpperCase(Locale.ENGLISH),
                        entry.getValue()
                    );
                }
            }
        }
    }
}
             © 2015 - 2025 Weber Informatics LLC | Privacy Policy