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