All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.runtime.health.api.Health Maven / Gradle / Ivy

/**
 * Copyright 2016 Netflix, Inc.
 *
 * 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 com.netflix.runtime.health.api;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
/**
 * Immutable health check instance returned from a {@link HealthIndicator}
 * 
 * This may be one of {@link Health}.healthy() or {@link Health}.unhealthy().
 * Additional details may be provided (ex. {@link Health}.unhealthy(exception).withDetails(...) 
 */
public final class Health {
	
    public static final String ERROR_KEY = "error";
    public static final String CACHE_KEY = "cached";
    public static final String NAME_KEY = "className";
    
	private final Map details;
	private final boolean isHealthy;
	
	private Health(boolean isHealthy) {
		this.isHealthy=isHealthy;
		this.details = new LinkedHashMap<>();
	}
	
	private Health(boolean isHealthy, Map details) {
		this.isHealthy = isHealthy;
		this.details = new LinkedHashMap<>(details);
	}
	
	private Health(Health health) {
		this.isHealthy = health.isHealthy();
		this.details = health.getDetails();
	}

	/**
     * @return Map of named attributes that provide additional information regarding the health.
     * For example, a CPU health check may return Unhealthy with attribute "usage"="90%"
     */
    public Map getDetails() {
    	return this.details;
    }
    
    /**
     * @return True if healthy or false otherwise.
     */
    public boolean isHealthy() {
    	return this.isHealthy;
    }

	public Optional getErrorMessage() {
		return Optional.ofNullable((String) getDetails().get(ERROR_KEY));
	}

	/**
	 * Create a new {@link Builder} instance with a {@link Health} of "healthy".
	 * @return a new {@link Builder} instance
	 */
	public static Builder healthy() {
		return from(new Health(true));
	}

	/**
	 * Create a new {@link Builder} instance with a {@link Health} of "unhealthy"
	 * which includes the provided exception details.
	 * @param ex the exception
	 * @return a new {@link Builder} instance
	 */
	public static Builder unhealthy(Throwable ex) {
		return unhealthy().withException(ex);
	}

	/**
	 * Create a new {@link Builder} instance with a {@link Health} of "unhealthy".
	 * @return a new {@link Builder} instance
	 */
	public static Builder unhealthy() {
		return from(new Health(false));
	}

	/**
	 * Create a new {@link Builder} instance with a specific {@link Health}.
	 * @param health the health
	 * @return a new {@link Builder} instance
	 */
	public static Builder from(Health health) {
		return new Builder(health);
	}

	/**
	 * Builder for creating immutable {@link Health} instances.
	 */
	public static class Builder {

		private final boolean isHealthy;
		private final Map details;

		/**
		 * Create new Builder instance using a {@link Health}
		 * @param health the {@link Health} to use
		 */
		private Builder(Health health) {
			assertNotNull(health, "Health must not be null");
			this.isHealthy = health.isHealthy();
			this.details = health.getDetails();
		}

		/**
		 * Record detail for given {@link Exception}.
		 * @param ex the exception
		 * @return this {@link Builder} instance
		 */
		public Builder withException(Throwable ex) {
			assertNotNull(ex, "Exception must not be null");
			this.details.put(ERROR_KEY, ex.getClass().getName() + ": " + ex.getMessage());
			return this;
		}

		/**
		 * Record detail using {@code key} and {@code value}.
		 * @param key the detail key
		 * @param data the detail data
		 * @return this {@link Builder} instance
		 */
		public Builder withDetail(String key, Object data) {
			assertNotNull(key, "Key must not be null");
			assertNotNull(data, "Data must not be null");
			assertNotReservedKey(key, "\""+key+"\" is a reserved key and may not be overridden");
			this.details.put(key, data);
			return this;
		}

		/**
		 * Create a new {@link Health} from the provided information. 
		 * @return a new {@link Health} instance
		 */
		public Health build() {
			return new Health(this.isHealthy, this.details);
		}
	}
	
	private static void assertNotNull(Object test, String message) {
		if(test == null){
			throw new IllegalArgumentException(message);
		}
	}
	
	private static void assertNotReservedKey(Object key, String message) {
		if(ERROR_KEY.equals(key)){
			throw new IllegalArgumentException(message);
		}
	}

    @Override
    public String toString() {
        return "Health [details=" + details + ", isHealthy=" + isHealthy + "]";
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy