Author: ghenzler
Date: Fri Jan  4 08:54:11 2019
New Revision: 1850329

URL: http://svn.apache.org/viewvc?rev=1850329&view=rev
Log:
FELIX-6005 Introduce result status TEMPORARILY_UNAVAILABLE for health checks

Modified:
    
felix/trunk/healthcheck/api/src/main/java/org/apache/felix/hc/api/Result.java
    
felix/trunk/healthcheck/api/src/main/java/org/apache/felix/hc/util/FormattingResultLog.java
    
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/JmxAdjustableStatusHealthCheck.java
    
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/executor/HealthCheckResultCache.java
    
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServlet.java
    
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServletConfiguration.java
    
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/ResultHtmlSerializerConfiguration.java
    
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/ResultTxtVerboseSerializerConfiguration.java
    
felix/trunk/healthcheck/core/src/test/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServletTest.java
    felix/trunk/healthcheck/docs/felix-health-checks.md

Modified: 
felix/trunk/healthcheck/api/src/main/java/org/apache/felix/hc/api/Result.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/api/src/main/java/org/apache/felix/hc/api/Result.java?rev=1850329&r1=1850328&r2=1850329&view=diff
==============================================================================
--- 
felix/trunk/healthcheck/api/src/main/java/org/apache/felix/hc/api/Result.java 
(original)
+++ 
felix/trunk/healthcheck/api/src/main/java/org/apache/felix/hc/api/Result.java 
Fri Jan  4 08:54:11 2019
@@ -25,10 +25,11 @@ public class Result implements Iterable<
     protected final ResultLog resultLog;
 
     public enum Status {
-        OK, // no problem
-        WARN, // health check detected something wrong but not critical
-        CRITICAL, // health check detected a critical problem
-        HEALTH_CHECK_ERROR // health check did not execute properly
+        OK, // system is fully operational
+        WARN, // attention required but system is operational 
+        TEMPORARILY_UNAVAILABLE, // system is not operational, it may become 
available soon
+        CRITICAL, // critical problem exists, system should not be used
+        HEALTH_CHECK_ERROR // health check itself did not execute properly (no 
reliable status is known)
     }
 
     /** Build a single-value Result

Modified: 
felix/trunk/healthcheck/api/src/main/java/org/apache/felix/hc/util/FormattingResultLog.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/api/src/main/java/org/apache/felix/hc/util/FormattingResultLog.java?rev=1850329&r1=1850328&r2=1850329&view=diff
==============================================================================
--- 
felix/trunk/healthcheck/api/src/main/java/org/apache/felix/hc/util/FormattingResultLog.java
 (original)
+++ 
felix/trunk/healthcheck/api/src/main/java/org/apache/felix/hc/util/FormattingResultLog.java
 Fri Jan  4 08:54:11 2019
@@ -52,6 +52,10 @@ public class FormattingResultLog extends
         add(createEntry(Result.Status.CRITICAL, format, args));
     }
 
+    public void temporarilyUnavailable(String format, Object... args) {
+        add(createEntry(Result.Status.TEMPORARILY_UNAVAILABLE, format, args));
+    }
+    
     public void healthCheckError(String format, Object... args) {
         add(createEntry(Result.Status.HEALTH_CHECK_ERROR, format, args));
     }

Modified: 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/JmxAdjustableStatusHealthCheck.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/JmxAdjustableStatusHealthCheck.java?rev=1850329&r1=1850328&r2=1850329&view=diff
==============================================================================
--- 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/JmxAdjustableStatusHealthCheck.java
 (original)
+++ 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/JmxAdjustableStatusHealthCheck.java
 Fri Jan  4 08:54:11 2019
@@ -96,7 +96,7 @@ public class JmxAdjustableStatusHealthCh
         unregisterDynamicHealthCheck();
         HealthCheck healthCheck = new AdhocStatusOnlyHealthCheck(status);
         Dictionary<String, Object> props = new Hashtable<String, Object>();
-        props.put(HealthCheck.NAME, "JMX-adjustable Check");
+        props.put(HealthCheck.NAME, "JMX Adhoc Result");
         props.put(HealthCheck.TAGS, tags);
 
         healthCheckRegistration = 
bundleContext.registerService(HealthCheck.class.getName(), healthCheck, props);
@@ -134,6 +134,7 @@ public class JmxAdjustableStatusHealthCh
 
         private static final String OP_RESET = "reset";
         private static final String OP_ADD_WARN_RESULT_FOR_TAGS = 
"addWarnResultForTags";
+        private static final String 
OP_ADD_TEMPORARILY_UNAVAILABLE_RESULT_FOR_TAGS = 
"addTemporarilyUnavailableResultForTags";
         private static final String OP_ADD_CRITICAL_RESULT_FOR_TAGS = 
"addCriticalResultForTags";
 
         private static final String ATT_TAGS = "tags";
@@ -188,9 +189,11 @@ public class JmxAdjustableStatusHealthCh
             final List<MBeanOperationInfo> ops = new 
ArrayList<MBeanOperationInfo>();
             ops.add(new MBeanOperationInfo(OP_RESET, "Resets this testing 
mechanism and removes the failing HC",
                     new MBeanParameterInfo[0], "java.lang.String", 
MBeanOperationInfo.ACTION));
-            ops.add(new MBeanOperationInfo(OP_ADD_CRITICAL_RESULT_FOR_TAGS, 
"Adds a critical result for the given tags",
+            ops.add(new 
MBeanOperationInfo(OP_ADD_TEMPORARILY_UNAVAILABLE_RESULT_FOR_TAGS, "Adds a 
TEMPORARILY_UNAVAILABLE result for the given tags",
                     params, "java.lang.String", MBeanOperationInfo.ACTION));
-            ops.add(new MBeanOperationInfo(OP_ADD_WARN_RESULT_FOR_TAGS, "Adds 
a warn result for the given tags",
+            ops.add(new MBeanOperationInfo(OP_ADD_CRITICAL_RESULT_FOR_TAGS, 
"Adds a CRITICAL result for the given tags",
+                    params, "java.lang.String", MBeanOperationInfo.ACTION));
+            ops.add(new MBeanOperationInfo(OP_ADD_WARN_RESULT_FOR_TAGS, "Adds 
a WARN result for the given tags",
                     params, "java.lang.String", MBeanOperationInfo.ACTION));
 
             return new MBeanInfo(this.getClass().getName(),
@@ -206,32 +209,32 @@ public class JmxAdjustableStatusHealthCh
         @Override
         public Object invoke(final String actionName, final Object[] params, 
final String[] signature)
                 throws MBeanException, ReflectionException {
+            
+            Status newStatus = null;
+            
+            tags = params.length > 0 ? 
Arrays.asList(params[0].toString().split("[,; ]+")) : Arrays.asList("");
+            
             if (OP_RESET.equals(actionName)) {
-                tags = Arrays.asList("");
-                status = STATUS_INACTIVE;
                 unregisterDynamicHealthCheck();
                 LOG.info("JMX-adjustable Health Check was reset");
+                status = STATUS_INACTIVE;
                 return "Reset successful";
+            } else if 
(OP_ADD_TEMPORARILY_UNAVAILABLE_RESULT_FOR_TAGS.equals(actionName)) {
+                newStatus =  Result.Status.TEMPORARILY_UNAVAILABLE;
             } else if (OP_ADD_CRITICAL_RESULT_FOR_TAGS.equals(actionName)) {
-                String[] newTags = params[0].toString().split("[,; ]+");
-                tags = Arrays.asList(newTags);
-                Status critical = Result.Status.CRITICAL;
-                status = critical.toString();
-                registerDynamicHealthCheck(critical, newTags);
-                LOG.info("Activated JMX-adjustable Health Check with status 
CRITICAL and tags " + StringUtils.join(tags, ","));
-                return "Added check with result CRITICAL";
+                newStatus =  Result.Status.CRITICAL;
             } else if (OP_ADD_WARN_RESULT_FOR_TAGS.equals(actionName)) {
-                String[] newTags = params[0].toString().split("[,; ]+");
-                tags = Arrays.asList(newTags);
-                Status warn = Result.Status.WARN;
-                status = warn.toString();
-                registerDynamicHealthCheck(warn, newTags);
-                LOG.info("Activated JMX-adjustable Health Check with status 
WARN and tags " + StringUtils.join(tags, ","));
-                return "Added check with result WARN";
+                newStatus =  Result.Status.WARN;
             } else {
                 throw new MBeanException(
                         new 
UnsupportedOperationException(getClass().getSimpleName() + " does not support 
operation " + actionName));
             }
+            
+            status = newStatus.toString();
+            registerDynamicHealthCheck(newStatus, tags.toArray(new 
String[tags.size()]));
+            LOG.info("Activated JMX-adjustable Health Check with status 
"+newStatus+" and tags " + StringUtils.join(tags, ","));
+            return "Added check with result "+newStatus;
+        
         }
 
         @Override

Modified: 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/executor/HealthCheckResultCache.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/executor/HealthCheckResultCache.java?rev=1850329&r1=1850328&r2=1850329&view=diff
==============================================================================
--- 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/executor/HealthCheckResultCache.java
 (original)
+++ 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/executor/HealthCheckResultCache.java
 Fri Jan  4 08:54:11 2019
@@ -44,19 +44,10 @@ public class HealthCheckResultCache {
 
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
-    private static final List<Status> NOT_OK_STATUS_VALUES = 
Arrays.asList(Status.WARN, Status.CRITICAL, Status.HEALTH_CHECK_ERROR);
-
     /** The map holding the cached results. */
     private final Map<Long, HealthCheckExecutionResult> cache = new 
ConcurrentHashMap<Long, HealthCheckExecutionResult>();
 
-    @SuppressWarnings("serial")
-    private final Map<Result.Status, Map<Long, HealthCheckExecutionResult>> 
cacheOfNotOkResults = new ConcurrentHashMap<Result.Status, Map<Long, 
HealthCheckExecutionResult>>() {
-        {
-            for (Status status : NOT_OK_STATUS_VALUES) {
-                put(status, new ConcurrentHashMap<Long, 
HealthCheckExecutionResult>());
-            }
-        }
-    };
+    private final Map<Result.Status, Map<Long, HealthCheckExecutionResult>> 
cacheOfNotOkResults = new ConcurrentHashMap<Result.Status, Map<Long, 
HealthCheckExecutionResult>>();
 
     /** Update the cache with the result */
     public void updateWith(HealthCheckExecutionResult result) {
@@ -64,9 +55,14 @@ public class HealthCheckResultCache {
         cache.put(executionResult.getServiceId(), result);
 
         Status status = executionResult.getHealthCheckResult().getStatus();
-        if (status.ordinal() >= Result.Status.WARN.ordinal()) {
+        if (status != Result.Status.OK) {
             logger.debug("Caching {} result for HC {}", status, 
executionResult.getServiceId());
-            
cacheOfNotOkResults.get(status).put(executionResult.getServiceId(), result);
+            Map<Long, HealthCheckExecutionResult> nonOkResultsForStatus = 
cacheOfNotOkResults.get(status);
+            if(nonOkResultsForStatus==null) {
+                nonOkResultsForStatus = new ConcurrentHashMap<Long, 
HealthCheckExecutionResult>();
+                cacheOfNotOkResults.put(status, nonOkResultsForStatus);
+            }
+            nonOkResultsForStatus.put(executionResult.getServiceId(), result);
         }
     }
 
@@ -155,7 +151,7 @@ public class HealthCheckResultCache {
                     healthCheckMetadata.getName());
             List<HealthCheckExecutionResult> nonOkResultsFromPast = new 
ArrayList<HealthCheckExecutionResult>();
             long cutOffTime = System.currentTimeMillis() - 
(warningsStickForMinutes * 60 * 1000);
-            for (Status status : NOT_OK_STATUS_VALUES) {
+            for (Status status : cacheOfNotOkResults.keySet()) {
                 long hcServiceId = ((ExecutionResult) 
origResult).getServiceId();
                 HealthCheckExecutionResult nonOkResultFromPast = 
cacheOfNotOkResults.get(status).get(hcServiceId);
                 if (nonOkResultFromPast == null) {
@@ -201,16 +197,14 @@ public class HealthCheckResultCache {
     /** Clear the whole cache */
     public void clear() {
         this.cache.clear();
-        for (Status status : NOT_OK_STATUS_VALUES) {
-            cacheOfNotOkResults.get(status).clear();
-        }
+        this.cacheOfNotOkResults.clear();
     }
 
     /** Remove entry from cache */
     public void removeCachedResult(final Long serviceId) {
         this.cache.remove(serviceId);
-        for (Status status : NOT_OK_STATUS_VALUES) {
-            cacheOfNotOkResults.get(status).remove(serviceId);
+        for (Map<Long, HealthCheckExecutionResult> 
cacheOfNotOkResultsForStatus : cacheOfNotOkResults.values()) {
+            cacheOfNotOkResultsForStatus.remove(serviceId);
         }
     }
 

Modified: 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServlet.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServlet.java?rev=1850329&r1=1850328&r2=1850329&view=diff
==============================================================================
--- 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServlet.java
 (original)
+++ 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServlet.java
 Fri Jan  4 08:54:11 2019
@@ -21,10 +21,10 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.TreeMap;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -55,7 +55,7 @@ import org.slf4j.LoggerFactory;
  * Parameters:
  * <ul>
  * <li>tags: The health check tags to take into account
- * <li>format: html|json|jsonp
+ * <li>format: html|json|jsonp|txt|verbose.txt
  * <li>includeDebug: If true, debug messages from result log are included.
  * <li>callback: For jsonp, the JS callback function name (defaults to 
"processHealthCheckResults")
  * <li>httpStatus: health check status to http status mapping in format 
httpStatus=WARN:418,CRITICAL:503,HEALTH_CHECK_ERROR:500.
@@ -123,6 +123,7 @@ public class HealthCheckExecutorServlet
 
     private static final String CACHE_CONTROL_KEY = "Cache-control";
     private static final String CACHE_CONTROL_VALUE = "no-cache";
+    private static final String CORS_ORIGIN_HEADER_NAME = 
"Access-Control-Allow-Origin";
 
     private String[] servletPaths;
 
@@ -132,8 +133,8 @@ public class HealthCheckExecutorServlet
 
     private String corsAccessControlAllowOrigin;
 
-    private static final String CORS_ORIGIN_HEADER_NAME = 
"Access-Control-Allow-Origin";
-
+    private Map<Result.Status, Integer> defaultStatusMapping;
+    
     @Reference
     private HttpService httpService;
 
@@ -157,11 +158,18 @@ public class HealthCheckExecutorServlet
         this.servletPath = configuration.servletPath();
         this.disabled = configuration.disabled();
         this.corsAccessControlAllowOrigin = 
configuration.cors_accessControlAllowOrigin();
+        this.defaultStatusMapping = 
getStatusMapping(configuration.httpStatusMapping());
 
         LOG.info("servletPath={}", servletPath);
         LOG.info("disabled={}", disabled);
         LOG.info("corsAccessControlAllowOrigin={}", 
corsAccessControlAllowOrigin);
+        LOG.info("defaultStatusMapping={}", defaultStatusMapping);
 
+        if (disabled) {
+            LOG.info("Health Check Servlet is disabled by configuration");
+            return;
+        }
+        
         Map<String, HttpServlet> servletsToRegister = new 
LinkedHashMap<String, HttpServlet>();
         servletsToRegister.put(this.servletPath, this);
         servletsToRegister.put(this.servletPath + "." + FORMAT_HTML, new 
ProxyServlet(FORMAT_HTML));
@@ -170,11 +178,6 @@ public class HealthCheckExecutorServlet
         servletsToRegister.put(this.servletPath + "." + FORMAT_TXT, new 
ProxyServlet(FORMAT_TXT));
         servletsToRegister.put(this.servletPath + "." + FORMAT_VERBOSE_TXT, 
new ProxyServlet(FORMAT_VERBOSE_TXT));
 
-        if (disabled) {
-            LOG.info("Health Check Servlet is disabled by configuration");
-            return;
-        }
-
         for (final Map.Entry<String, HttpServlet> servlet : 
servletsToRegister.entrySet()) {
             try {
                 LOG.info("Registering HC servlet {} to path {}", 
getClass().getSimpleName(), servlet.getKey());
@@ -237,8 +240,9 @@ public class HealthCheckExecutorServlet
         selector.withNames(names.toArray(new String[0]));
 
         final Boolean includeDebug = 
Boolean.valueOf(request.getParameter(PARAM_INCLUDE_DEBUG.name));
-        final Map<Result.Status, Integer> statusMapping = 
request.getParameter(PARAM_HTTP_STATUS.name) != null ? getStatusMapping(request
-                .getParameter(PARAM_HTTP_STATUS.name)) : null;
+        
+        String httpStatusMappingParameterVal = 
request.getParameter(PARAM_HTTP_STATUS.name);
+        final Map<Result.Status, Integer> statusMapping = 
httpStatusMappingParameterVal!=null ? 
getStatusMapping(httpStatusMappingParameterVal) : defaultStatusMapping;
 
         HealthCheckExecutionOptions executionOptions = new 
HealthCheckExecutionOptions();
         executionOptions.setCombineTagsWithOr(
@@ -263,10 +267,8 @@ public class HealthCheckExecutorServlet
         sendNoCacheHeaders(response);
         sendCorsHeaders(response);
 
-        if (statusMapping != null) {
-            Integer httpStatus = statusMapping.get(overallResult.getStatus());
-            response.setStatus(httpStatus);
-        }
+        Integer httpStatus = statusMapping.get(overallResult.getStatus());
+        response.setStatus(httpStatus);
 
         if (FORMAT_HTML.equals(format)) {
             sendHtmlResponse(overallResult, executionResults, request, 
response, includeDebug);
@@ -361,8 +363,9 @@ public class HealthCheckExecutorServlet
         return sb.toString();
     }
 
-    Map<Result.Status, Integer> getStatusMapping(String mappingStr) throws 
ServletException {
-        Map<Result.Status, Integer> statusMapping = new HashMap<Result.Status, 
Integer>();
+    Map<Result.Status, Integer> getStatusMapping(String mappingStr) {
+        Map<Result.Status, Integer> statusMapping = new TreeMap<Result.Status, 
Integer>();
+        
         try {
             String[] bits = mappingStr.split("[,]");
             for (String bit : bits) {
@@ -370,7 +373,7 @@ public class HealthCheckExecutorServlet
                 statusMapping.put(Result.Status.valueOf(tuple[0]), 
Integer.parseInt(tuple[1]));
             }
         } catch (Exception e) {
-            throw new ServletException("Invalid parameter httpStatus=" + 
mappingStr + " " + e, e);
+            throw new IllegalArgumentException("Invalid parameter httpStatus=" 
+ mappingStr + " " + e, e);
         }
 
         if (!statusMapping.containsKey(Result.Status.OK)) {
@@ -379,16 +382,20 @@ public class HealthCheckExecutorServlet
         if (!statusMapping.containsKey(Result.Status.WARN)) {
             statusMapping.put(Result.Status.WARN, 
statusMapping.get(Result.Status.OK));
         }
+        if (!statusMapping.containsKey(Result.Status.TEMPORARILY_UNAVAILABLE)) 
{
+            statusMapping.put(Result.Status.TEMPORARILY_UNAVAILABLE, 503);
+        }
         if (!statusMapping.containsKey(Result.Status.CRITICAL)) {
-            statusMapping.put(Result.Status.CRITICAL, 
statusMapping.get(Result.Status.WARN));
+            statusMapping.put(Result.Status.CRITICAL, 503);
         }
         if (!statusMapping.containsKey(Result.Status.HEALTH_CHECK_ERROR)) {
-            statusMapping.put(Result.Status.HEALTH_CHECK_ERROR, 
statusMapping.get(Result.Status.CRITICAL));
+            statusMapping.put(Result.Status.HEALTH_CHECK_ERROR, 500);
         }
         return statusMapping;
     }
 
     private class ProxyServlet extends HttpServlet {
+        private static final long serialVersionUID = 1L;
 
         private final String format;
 

Modified: 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServletConfiguration.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServletConfiguration.java?rev=1850329&r1=1850328&r2=1850329&view=diff
==============================================================================
--- 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServletConfiguration.java
 (original)
+++ 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServletConfiguration.java
 Fri Jan  4 08:54:11 2019
@@ -35,4 +35,6 @@ import org.osgi.service.metatype.annotat
     @AttributeDefinition(name = "CORS Access-Control-Allow-Origin", 
description = "Sets the Access-Control-Allow-Origin CORS header. If blank no 
header is sent.")
     String cors_accessControlAllowOrigin() default "*";
 
+    @AttributeDefinition(name = "Http Status Mapping", description = "Maps HC 
result status values to http response codes. Can be overwritten via request 
parameter 'httpStatus'")
+    String httpStatusMapping() default 
"OK:200,WARN:200,CRITICAL:503,TEMPORARILY_UNAVAILABLE:503,HEALTH_CHECK_ERROR:500";
 }

Modified: 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/ResultHtmlSerializerConfiguration.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/ResultHtmlSerializerConfiguration.java?rev=1850329&r1=1850328&r2=1850329&view=diff
==============================================================================
--- 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/ResultHtmlSerializerConfiguration.java
 (original)
+++ 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/ResultHtmlSerializerConfiguration.java
 Fri Jan  4 08:54:11 2019
@@ -30,6 +30,7 @@ import org.osgi.service.metatype.annotat
             + "table td { padding:5px; border-top: 1px solid #ffffff; 
border-bottom:1px solid #e0e0e0; border-left: 1px solid #e0e0e0; }\n"
             + ".statusOK { background-color:#CCFFCC;}\n"
             + ".statusWARN { background-color:#FFE569;}\n"
+            + ".statusTEMPORARILY_UNAVAILABLE { background-color:#dab6fc;}\n"
             + ".statusCRITICAL { background-color:#F0975A;}\n"
             + ".statusHEALTH_CHECK_ERROR { background-color:#F16D4E;}\n"
             + ".helpText { color:grey; font-size:80%; }\n";

Modified: 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/ResultTxtVerboseSerializerConfiguration.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/ResultTxtVerboseSerializerConfiguration.java?rev=1850329&r1=1850328&r2=1850329&view=diff
==============================================================================
--- 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/ResultTxtVerboseSerializerConfiguration.java
 (original)
+++ 
felix/trunk/healthcheck/core/src/main/java/org/apache/felix/hc/core/impl/servlet/ResultTxtVerboseSerializerConfiguration.java
 Fri Jan  4 08:54:11 2019
@@ -30,7 +30,7 @@ import org.osgi.service.metatype.annotat
     int colWidthName() default 30;
 
     @AttributeDefinition(name = "Result Column Width", description = "Column 
width of health check result (in characters)")
-    int colWidthResult() default 9;
+    int colWidthResult() default 25;
 
     @AttributeDefinition(name = "Timing Column Width", description = "Column 
width of health check timing (in characters)")
     int colWidthTiming() default 22;

Modified: 
felix/trunk/healthcheck/core/src/test/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServletTest.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/core/src/test/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServletTest.java?rev=1850329&r1=1850328&r2=1850329&view=diff
==============================================================================
--- 
felix/trunk/healthcheck/core/src/test/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServletTest.java
 (original)
+++ 
felix/trunk/healthcheck/core/src/test/java/org/apache/felix/hc/core/impl/servlet/HealthCheckExecutorServletTest.java
 Fri Jan  4 08:54:11 2019
@@ -89,12 +89,19 @@ public class HealthCheckExecutorServletT
     @Mock
     private PrintWriter writer;
 
+    @Mock
+    private HealthCheckExecutorServletConfiguration 
healthCheckExecutorServletConfig;
+    
     @Before
     public void setup() throws IOException {
         initMocks(this);
 
         doReturn(500L).when(hcServiceRef).getProperty(Constants.SERVICE_ID);
         doReturn(writer).when(response).getWriter();
+        
+        doReturn(true).when(healthCheckExecutorServletConfig).disabled();
+        
doReturn("OK:200").when(healthCheckExecutorServletConfig).httpStatusMapping();
+        healthCheckExecutorServlet.activate(healthCheckExecutorServletConfig);
     }
 
     @Test
@@ -222,43 +229,47 @@ public class HealthCheckExecutorServletT
     @Test
     public void testGetStatusMapping() throws ServletException {
 
-        Map<Status, Integer> statusMapping = 
healthCheckExecutorServlet.getStatusMapping("CRITICAL:503");
+        Map<Status, Integer> statusMapping = 
healthCheckExecutorServlet.getStatusMapping("CRITICAL:500");
         assertEquals(statusMapping.get(Result.Status.OK), (Integer) 200);
         assertEquals(statusMapping.get(Result.Status.WARN), (Integer) 200);
-        assertEquals(statusMapping.get(Result.Status.CRITICAL), (Integer) 503);
-        assertEquals(statusMapping.get(Result.Status.HEALTH_CHECK_ERROR), 
(Integer) 503);
+        assertEquals(statusMapping.get(Result.Status.TEMPORARILY_UNAVAILABLE), 
(Integer) 503);
+        assertEquals(statusMapping.get(Result.Status.CRITICAL), (Integer) 500);
+        assertEquals(statusMapping.get(Result.Status.HEALTH_CHECK_ERROR), 
(Integer) 500);
 
         statusMapping = healthCheckExecutorServlet.getStatusMapping("OK:333");
         assertEquals(statusMapping.get(Result.Status.OK), (Integer) 333);
         assertEquals(statusMapping.get(Result.Status.WARN), (Integer) 333);
-        assertEquals(statusMapping.get(Result.Status.CRITICAL), (Integer) 333);
-        assertEquals(statusMapping.get(Result.Status.HEALTH_CHECK_ERROR), 
(Integer) 333);
+        assertEquals(statusMapping.get(Result.Status.TEMPORARILY_UNAVAILABLE), 
(Integer) 503);
+        assertEquals(statusMapping.get(Result.Status.CRITICAL), (Integer) 503);
+        assertEquals(statusMapping.get(Result.Status.HEALTH_CHECK_ERROR), 
(Integer) 500);
 
-        statusMapping = 
healthCheckExecutorServlet.getStatusMapping("OK:200,WARN:418,CRITICAL:503,HEALTH_CHECK_ERROR:500");
+        statusMapping = 
healthCheckExecutorServlet.getStatusMapping("OK:200,WARN:418,CRITICAL:503,TEMPORARILY_UNAVAILABLE:503,HEALTH_CHECK_ERROR:500");
         assertEquals(statusMapping.get(Result.Status.OK), (Integer) 200);
         assertEquals(statusMapping.get(Result.Status.WARN), (Integer) 418);
+        assertEquals(statusMapping.get(Result.Status.TEMPORARILY_UNAVAILABLE), 
(Integer) 503);
         assertEquals(statusMapping.get(Result.Status.CRITICAL), (Integer) 503);
         assertEquals(statusMapping.get(Result.Status.HEALTH_CHECK_ERROR), 
(Integer) 500);
 
-        statusMapping = 
healthCheckExecutorServlet.getStatusMapping("CRITICAL:503,HEALTH_CHECK_ERROR:500");
+        statusMapping = 
healthCheckExecutorServlet.getStatusMapping("WARN:418,HEALTH_CHECK_ERROR:503");
         assertEquals(statusMapping.get(Result.Status.OK), (Integer) 200);
-        assertEquals(statusMapping.get(Result.Status.WARN), (Integer) 200);
+        assertEquals(statusMapping.get(Result.Status.WARN), (Integer) 418);
+        assertEquals(statusMapping.get(Result.Status.TEMPORARILY_UNAVAILABLE), 
(Integer) 503);
         assertEquals(statusMapping.get(Result.Status.CRITICAL), (Integer) 503);
-        assertEquals(statusMapping.get(Result.Status.HEALTH_CHECK_ERROR), 
(Integer) 500);
+        assertEquals(statusMapping.get(Result.Status.HEALTH_CHECK_ERROR), 
(Integer) 503);
 
     }
 
-    @Test(expected = ServletException.class)
+    @Test(expected = IllegalArgumentException.class)
     public void testGetStatusMappingInvalidToken() throws ServletException {
         healthCheckExecutorServlet.getStatusMapping("CRITICAL");
     }
 
-    @Test(expected = ServletException.class)
+    @Test(expected = IllegalArgumentException.class)
     public void testGetStatusMappingInvalidStatus() throws ServletException {
         healthCheckExecutorServlet.getStatusMapping("INVALID:200");
     }
 
-    @Test(expected = ServletException.class)
+    @Test(expected = IllegalArgumentException.class)
     public void testGetStatusMappingInvalidStatusCode() throws 
ServletException {
         healthCheckExecutorServlet.getStatusMapping("CRITICAL:xxx");
     }

Modified: felix/trunk/healthcheck/docs/felix-health-checks.md
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/docs/felix-health-checks.md?rev=1850329&r1=1850328&r2=1850329&view=diff
==============================================================================
--- felix/trunk/healthcheck/docs/felix-health-checks.md (original)
+++ felix/trunk/healthcheck/docs/felix-health-checks.md Fri Jan  4 08:54:11 2019
@@ -82,6 +82,18 @@ A simple health check implementation mig
 The `Result` is a simple immutable class that provides a `Status` via 
`getStatus()` (OK, WARN, CRITICAL etc.) and one or more log-like messages that
 can provide more info about what, if anything, went wrong.
 
+### Semantic meaning of health check results
+In order to make health check results aggregatable in a reasonable way, it is 
important that result status values are used in a consistent way across 
different checks. When implementing custom health checks, comply to the 
following table:
+
+Status | System is functional | Meaning | Actions possible for machine clients 
| Actions possible for human clients  
+--- | --- | --- | --- | ---  
+OK | yes | Everything is ok. | <ul><li>If system is not actively used yet, a 
load balancer might decide to take the system to production after receiving 
this status for the first time.</li><li>Otherwise no action needed</li></ul> | 
Response logs might still provide information to a human on why the system 
currently is healthy. E.g. it might show 30% disk used which indicates that no 
action will be required for a long time  
+WARN | yes | **Tendency to CRITICAL** <br>System is fully functional but 
actions are needed to avoid a CRITICAL status in the future | <ul><li>Certain 
actions can be configured for known, actionable warnings, e.g. if disk space is 
low, it could be dynamically extended using infrastructure APIs if on virtual 
infrastructure)</li><li>Pass on information to monitoring system to be 
available to humans (in other aggregator UIs)</li></ul> | Any manual steps that 
a human can perform based on their knowledge to avoid the system to get to 
CRITICAL state
+TEMPORARILY_UNAVAILABLE | no | **Tendency to OK** <br>System is not functional 
at the moment but is expected to become OK (or at least WARN) without action. 
An health check using this status is expected to turn CRITICAL after a certain 
period returning TEMPORARILY_UNAVAILABLE | <ul><li>Take out system from load 
balancing</li><li>Wait until TEMPORARILY_UNAVAILABLE status turns into either 
OK or CRITICAL</li></ul> | Wait and monitor result logs of health check 
returning TEMPORARILY_UNAVAILABLE
+CRITICAL | no | System is not functional and must not be used | <ul><li>Take 
out system from load balancing</li><li>Decommission system entirely and 
re-provision from scratch</li></ul>  | Any manual steps that a human can 
perform based on their knowledge to bring the system back to state OK
+HEALTH\_CHECK\_ERROR | no | **Actual status unknown** <br>There was an error 
in correctly calculating one of the status values above. Like CRITICAL but with 
the hint that the health check probe itself might be the problem (and the 
system could well be in state OK) | <ul><li>Treat exactly the same as 
CRITICAL</li></ul>  | Fix health check implementation or configuration to 
ensure a correct status can be calculated
+
+
 ### Configuring Health Checks
 
 `HealthCheck` services are created via OSGi configurations. Generic health 
check service properties are interpreted by the health check executor service. 
Custom health check service properties can be used by the health check 
implementation itself to configure its behaviour.
@@ -127,7 +139,7 @@ domain `org.apache.felix.healthcheck` wi
 The MBean gives access to the `Result` and the log, as shown on the screenshot 
below.   
 
 ### Health Check Servlet
-Starting with version 1.2.4 of the `org.apache.felix.healthcheck.core` bundle, 
a flexible Health Checks execution servlet is available. It provides
+The health check servlet allows to query the checks via http. It provides
 similar features to the Web Console plugin described above, with output in 
HTML, JSON (plain or jsonp) and TXT (concise or verbose) formats (see HTML 
format rendering page for more documentation).
 
 The Health Checks Servlet is disabled by default, to enable it create an OSGi 
configuration like


Reply via email to