You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/12/16 16:38:30 UTC
(camel) 05/07: CAMEL-20242: camel-main - Health check should not be as verbose by default.
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch rc
in repository https://gitbox.apache.org/repos/asf/camel.git
commit 7caafe2cc6f0601c048fb10596a86b279f5acf6d
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sat Dec 16 16:47:22 2023 +0100
CAMEL-20242: camel-main - Health check should not be as verbose by default.
---
.../platform/http/main/MainHttpServer.java | 55 ++++++++++-------
.../camel/impl/console/HealthDevConsole.java | 19 +++---
.../impl/health/RouteControllerHealthCheck.java | 70 ++++++++++++++++++++++
3 files changed, 115 insertions(+), 29 deletions(-)
diff --git a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
index 32e1ff68f8e..840eb824bd0 100644
--- a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
+++ b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
@@ -323,28 +323,30 @@ public class MainHttpServer extends ServiceSupport implements CamelContextAware,
public void handle(RoutingContext ctx) {
ctx.response().putHeader("content-type", "application/json");
+ HealthCheckRegistry registry = HealthCheckRegistry.get(camelContext);
+ String level = ctx.request().getParam("exposureLevel");
+ if (level == null) {
+ level = registry.getExposureLevel();
+ }
+ String includeStackTrace = ctx.request().getParam("stackTrace");
+ String includeData = ctx.request().getParam("data");
+
boolean all = ctx.currentRoute() == health;
boolean liv = ctx.currentRoute() == live;
boolean rdy = ctx.currentRoute() == ready;
Collection<HealthCheck.Result> res;
if (all) {
- res = HealthCheckHelper.invoke(camelContext);
+ res = HealthCheckHelper.invoke(camelContext, level);
} else if (liv) {
- res = HealthCheckHelper.invokeLiveness(camelContext);
+ res = HealthCheckHelper.invokeLiveness(camelContext, level);
} else {
- res = HealthCheckHelper.invokeReadiness(camelContext);
+ res = HealthCheckHelper.invokeReadiness(camelContext, level);
}
StringBuilder sb = new StringBuilder();
sb.append("{\n");
- HealthCheckRegistry registry = HealthCheckRegistry.get(camelContext);
- String level = ctx.request().getParam("exposureLevel");
- if (level == null) {
- level = registry.getExposureLevel();
- }
-
// are we UP
boolean up = HealthCheckHelper.isResultsUp(res, rdy);
@@ -354,12 +356,12 @@ public class MainHttpServer extends ServiceSupport implements CamelContextAware,
} else if ("full".equals(level)) {
// include all details
List<HealthCheck.Result> list = new ArrayList<>(res);
- healthCheckDetails(sb, list, up);
+ healthCheckDetails(sb, list, up, level, includeStackTrace, includeData);
} else {
// include only DOWN details
List<HealthCheck.Result> downs = res.stream().filter(r -> r.getState().equals(HealthCheck.State.DOWN))
.collect(Collectors.toList());
- healthCheckDetails(sb, downs, up);
+ healthCheckDetails(sb, downs, up, level, includeStackTrace, includeData);
}
sb.append("}\n");
@@ -391,7 +393,9 @@ public class MainHttpServer extends ServiceSupport implements CamelContextAware,
}
}
- private static void healthCheckDetails(StringBuilder sb, List<HealthCheck.Result> checks, boolean up) {
+ private static void healthCheckDetails(
+ StringBuilder sb, List<HealthCheck.Result> checks, boolean up, String level, String includeStackTrace,
+ String includeData) {
healthCheckStatus(sb, up);
if (!checks.isEmpty()) {
@@ -400,7 +404,7 @@ public class MainHttpServer extends ServiceSupport implements CamelContextAware,
for (int i = 0; i < checks.size(); i++) {
HealthCheck.Result d = checks.get(i);
sb.append(" {\n");
- reportHealthCheck(sb, d);
+ reportHealthCheck(sb, d, level, includeStackTrace, includeData);
if (i < checks.size() - 1) {
sb.append(" },\n");
} else {
@@ -411,20 +415,29 @@ public class MainHttpServer extends ServiceSupport implements CamelContextAware,
}
}
- private static void reportHealthCheck(StringBuilder sb, HealthCheck.Result d) {
+ private static void reportHealthCheck(
+ StringBuilder sb, HealthCheck.Result d, String level, String includeStackTrace, String includeData) {
sb.append(" \"name\": \"").append(d.getCheck().getId()).append("\",\n");
- sb.append(" \"status\": \"").append(d.getState()).append("\",\n");
- if (d.getError().isPresent()) {
+ sb.append(" \"status\": \"").append(d.getState()).append("\"");
+ if (("full".equals(level) || "true".equals(includeStackTrace)) && d.getError().isPresent()) {
+ // include error message in full exposure
+ sb.append(",\n");
String msg = allCausedByErrorMessages(d.getError().get());
sb.append(" \"error-message\": \"").append(msg)
- .append("\",\n");
- sb.append(" \"error-stacktrace\": \"").append(errorStackTrace(d.getError().get()))
- .append("\",\n");
+ .append("\"");
+ if ("true".equals(includeStackTrace)) {
+ sb.append(",\n");
+ sb.append(" \"error-stacktrace\": \"").append(errorStackTrace(d.getError().get()))
+ .append("\"");
+ }
}
if (d.getMessage().isPresent()) {
- sb.append(" \"message\": \"").append(d.getMessage().get()).append("\",\n");
+ sb.append(",\n");
+ sb.append(" \"message\": \"").append(d.getMessage().get()).append("\"");
}
- if (d.getDetails() != null && !d.getDetails().isEmpty()) {
+ // only include data if was enabled
+ if (("true".equals(includeData)) && d.getDetails() != null && !d.getDetails().isEmpty()) {
+ sb.append(",\n");
// lets use sorted keys
Iterator<String> it = new TreeSet<>(d.getDetails().keySet()).iterator();
sb.append(" \"data\": {\n");
diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/HealthDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/HealthDevConsole.java
index 175849de7c2..85e2ab46327 100644
--- a/core/camel-console/src/main/java/org/apache/camel/impl/console/HealthDevConsole.java
+++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/HealthDevConsole.java
@@ -53,17 +53,20 @@ public class HealthDevConsole extends AbstractDevConsole {
sb.append(String.format("\n %s: %s", res.getCheck().getId(), res.getState()));
} else {
if (res.getMessage().isPresent()) {
- sb.append(String.format("\n %s: %s (%s)", res.getCheck().getId(), res.getState(), res.getMessage()));
+ sb.append(String.format("\n %s: %s (%s)", res.getCheck().getId(), res.getState(), res.getMessage().get()));
} else {
sb.append(String.format("\n %s: %s", res.getCheck().getId(), res.getState()));
}
- Throwable cause = res.getError().orElse(null);
- if (cause != null) {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- cause.printStackTrace(pw);
- sb.append(pw);
- sb.append("\n\n");
+ if ("full".equals(exposureLevel)) {
+ if (res.getError().isPresent()) {
+ Throwable cause = res.getError().get();
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ cause.printStackTrace(pw);
+ sb.append("\n\n");
+ sb.append(sw);
+ sb.append("\n\n");
+ }
}
}
});
diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/RouteControllerHealthCheck.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/RouteControllerHealthCheck.java
index 16b9b08caed..00639f256b6 100644
--- a/core/camel-health/src/main/java/org/apache/camel/impl/health/RouteControllerHealthCheck.java
+++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/RouteControllerHealthCheck.java
@@ -16,11 +16,18 @@
*/
package org.apache.camel.impl.health;
+import java.util.Comparator;
import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
import org.apache.camel.Ordered;
+import org.apache.camel.Route;
import org.apache.camel.health.HealthCheckResultBuilder;
import org.apache.camel.spi.RouteController;
+import org.apache.camel.spi.SupervisingRouteController;
+import org.apache.camel.util.URISupport;
+import org.apache.camel.util.backoff.BackOffTimer;
/**
* Readiness {@link org.apache.camel.health.HealthCheck} for route controller.
@@ -46,6 +53,19 @@ public class RouteControllerHealthCheck extends AbstractHealthCheck {
if (rc != null) {
// should only be up if there are no unhealthy routes
up = !rc.isUnhealthyRoutes();
+ // do we have any details about why we are not up
+ if (!up && rc instanceof SupervisingRouteController src) {
+ Set<Route> routes = new TreeSet<>(Comparator.comparing(Route::getId));
+ routes.addAll(src.getRestartingRoutes());
+ for (Route route : routes) {
+ builderDetails(builder, src, route, false);
+ }
+ routes = new TreeSet<>(Comparator.comparing(Route::getId));
+ routes.addAll(src.getExhaustedRoutes());
+ for (Route route : routes) {
+ builderDetails(builder, src, route, true);
+ }
+ }
}
if (up) {
@@ -56,4 +76,54 @@ public class RouteControllerHealthCheck extends AbstractHealthCheck {
}
}
+ private void builderDetails(HealthCheckResultBuilder builder, SupervisingRouteController src, Route route, boolean exhausted) {
+ String routeId = route.getRouteId();
+ Throwable cause = src.getRestartException(routeId);
+ if (cause != null) {
+ String status = src.getRouteStatus(routeId).name();
+ String uri = route.getEndpoint().getEndpointBaseUri();
+ uri = URISupport.sanitizeUri(uri);
+
+ BackOffTimer.Task state = src.getRestartingRouteState(routeId);
+ long attempts = state != null ? state.getCurrentAttempts() : 0;
+ long elapsed;
+ long last;
+ long next;
+ // we can only track elapsed/time for active supervised routes
+ elapsed = state != null && BackOffTimer.Task.Status.Active == state.getStatus()
+ ? state.getCurrentElapsedTime() : 0;
+ last = state != null && BackOffTimer.Task.Status.Active == state.getStatus()
+ ? state.getLastAttemptTime() : 0;
+ next = state != null && BackOffTimer.Task.Status.Active == state.getStatus()
+ ? state.getNextAttemptTime() : 0;
+
+ String key = "route." + routeId;
+ builder.detail(key + ".id", routeId);
+ builder.detail(key + ".status", status);
+ builder.detail(key + ".phase", exhausted ? "Exhausted" : "Restarting");
+ builder.detail(key + ".uri", uri);
+ builder.detail(key + ".attempts", attempts);
+ builder.detail(key + ".lastAttempt", last);
+ builder.detail(key + ".nextAttempt", next);
+ builder.detail(key + ".elapsed", elapsed);
+ if (cause.getMessage() != null) {
+ builder.detail(key + ".error", cause.getMessage());
+ // only one exception can be stored so lets just store first found
+ if (builder.error() == null) {
+ builder.error(cause);
+ String msg;
+ if (exhausted) {
+ msg = String.format("Restarting route: %s is exhausted after %s attempts due %s."
+ + " No more attempts will be made and the route is no longer supervised by this route controller and remains as stopped.", routeId, attempts,
+ cause.getMessage());
+ } else {
+ msg = String.format("Failed restarting route: %s attempt: %s due: %s", routeId, attempts,
+ cause.getMessage());
+ }
+ builder.message(msg);
+ }
+ }
+ }
+ }
+
}