This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 7c55523d99e CAMEL-21481: camel-jbang - Capture reload error when doing
route reloads (#16399)
7c55523d99e is described below
commit 7c55523d99ebbbf0fee379228c4a030e8029b13c
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Nov 28 18:09:28 2024 +0100
CAMEL-21481: camel-jbang - Capture reload error when doing route reloads
(#16399)
* CAMEL-21481: camel-jbang - Capture reload error when doing route reloads
---
.../java/org/apache/camel/spi/ReloadStrategy.java | 5 +++
.../camel/impl/console/ContextDevConsole.java | 39 ++++++++++++++++----
.../camel/impl/console/ReloadDevConsole.java | 20 ++++++++++
.../support/DefaultContextReloadStrategy.java | 8 ++++
.../support/FileWatcherResourceReloadStrategy.java | 2 +
.../support/ResourceReloadStrategySupport.java | 18 +++++++++
.../camel/support/RouteOnDemandReloadStrategy.java | 2 +
.../core/commands/process/CamelContextStatus.java | 43 +++++++++++++++++++---
.../jbang/core/commands/process/ListProcess.java | 31 +++++++++++++++-
9 files changed, 153 insertions(+), 15 deletions(-)
diff --git
a/core/camel-api/src/main/java/org/apache/camel/spi/ReloadStrategy.java
b/core/camel-api/src/main/java/org/apache/camel/spi/ReloadStrategy.java
index c390f732172..ca32988afb2 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/ReloadStrategy.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/ReloadStrategy.java
@@ -48,4 +48,9 @@ public interface ReloadStrategy extends StaticService,
CamelContextAware {
* Reset the counters.
*/
void resetCounters();
+
+ /**
+ * Gets the last error if reloading failed
+ */
+ Exception getLastError();
}
diff --git
a/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java
b/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java
index 5981c5d7a8d..9f6b5ae2d67 100644
---
a/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java
+++
b/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java
@@ -16,6 +16,7 @@
*/
package org.apache.camel.impl.console;
+import java.util.Collections;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
@@ -26,8 +27,10 @@ import
org.apache.camel.api.management.mbean.ManagedCamelContextMBean;
import org.apache.camel.spi.ReloadStrategy;
import org.apache.camel.spi.annotations.DevConsole;
import org.apache.camel.support.CamelContextHelper;
+import org.apache.camel.support.ExceptionHelper;
import org.apache.camel.support.console.AbstractDevConsole;
import org.apache.camel.util.TimeUtils;
+import org.apache.camel.util.json.JsonArray;
import org.apache.camel.util.json.JsonObject;
@DevConsole(name = "context", displayName = "CamelContext", description =
"Overall information about the CamelContext")
@@ -57,9 +60,11 @@ public class ContextDevConsole extends AbstractDevConsole {
ManagedCamelContextMBean mb = mcc.getManagedCamelContext();
if (mb != null) {
int reloaded = 0;
+ int reloadedFailed = 0;
Set<ReloadStrategy> rs =
getCamelContext().hasServices(ReloadStrategy.class);
for (ReloadStrategy r : rs) {
reloaded += r.getReloadCounter();
+ reloadedFailed += r.getFailedCounter();
}
String load1 = getLoad1(mb);
String load5 = getLoad5(mb);
@@ -80,7 +85,7 @@ public class ContextDevConsole extends AbstractDevConsole {
} else {
sb.append(String.format("\n Idle Since: %s", ""));
}
- sb.append(String.format("\n Reloaded: %s", reloaded));
+ sb.append(String.format("\n Reloaded: %s/%s", reloaded,
reloadedFailed));
sb.append(String.format("\n Mean Time: %s",
TimeUtils.printDuration(mb.getMeanProcessingTime(), true)));
sb.append(String.format("\n Max Time: %s",
TimeUtils.printDuration(mb.getMaxProcessingTime(), true)));
sb.append(String.format("\n Min Time: %s",
TimeUtils.printDuration(mb.getMinProcessingTime(), true)));
@@ -131,11 +136,6 @@ public class ContextDevConsole extends AbstractDevConsole {
if (mb != null) {
JsonObject stats = new JsonObject();
- int reloaded = 0;
- Set<ReloadStrategy> rs =
getCamelContext().hasServices(ReloadStrategy.class);
- for (ReloadStrategy r : rs) {
- reloaded += r.getReloadCounter();
- }
String load1 = getLoad1(mb);
String load5 = getLoad5(mb);
String load15 = getLoad15(mb);
@@ -155,7 +155,6 @@ public class ContextDevConsole extends AbstractDevConsole {
stats.put("remoteExchangesTotal",
mb.getRemoteExchangesTotal());
stats.put("remoteExchangesFailed",
mb.getRemoteExchangesFailed());
stats.put("remoteExchangesInflight",
mb.getRemoteExchangesInflight());
- stats.put("reloaded", reloaded);
stats.put("meanProcessingTime", mb.getMeanProcessingTime());
stats.put("maxProcessingTime", mb.getMaxProcessingTime());
stats.put("minProcessingTime", mb.getMinProcessingTime());
@@ -175,6 +174,32 @@ public class ContextDevConsole extends AbstractDevConsole {
if (last != null) {
stats.put("lastFailedExchangeTimestamp", last.getTime());
}
+ // reload stats
+ int reloaded = 0;
+ int reloadedFailed = 0;
+ Exception reloadCause = null;
+ Set<ReloadStrategy> rs =
getCamelContext().hasServices(ReloadStrategy.class);
+ for (ReloadStrategy r : rs) {
+ reloaded += r.getReloadCounter();
+ reloadedFailed += r.getFailedCounter();
+ if (reloadCause == null) {
+ reloadCause = r.getLastError();
+ }
+ }
+ JsonObject ro = new JsonObject();
+ ro.put("reloaded", reloaded);
+ ro.put("failed", reloadedFailed);
+ if (reloadCause != null) {
+ JsonObject eo = new JsonObject();
+ eo.put("message", reloadCause.getMessage());
+ JsonArray arr2 = new JsonArray();
+ final String trace =
ExceptionHelper.stackTraceToString(reloadCause);
+ eo.put("stackTrace", arr2);
+ Collections.addAll(arr2, trace.split("\n"));
+ ro.put("lastError", eo);
+ }
+ stats.put("reload", ro);
+
root.put("statistics", stats);
}
}
diff --git
a/core/camel-console/src/main/java/org/apache/camel/impl/console/ReloadDevConsole.java
b/core/camel-console/src/main/java/org/apache/camel/impl/console/ReloadDevConsole.java
index 4c899caccb4..a9f6e21a597 100644
---
a/core/camel-console/src/main/java/org/apache/camel/impl/console/ReloadDevConsole.java
+++
b/core/camel-console/src/main/java/org/apache/camel/impl/console/ReloadDevConsole.java
@@ -16,6 +16,7 @@
*/
package org.apache.camel.impl.console;
+import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -24,6 +25,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.camel.spi.ReloadStrategy;
import org.apache.camel.spi.annotations.DevConsole;
+import org.apache.camel.support.ExceptionHelper;
import org.apache.camel.support.console.AbstractDevConsole;
import org.apache.camel.util.json.JsonArray;
import org.apache.camel.util.json.JsonObject;
@@ -71,6 +73,14 @@ public class ReloadDevConsole extends AbstractDevConsole {
sb.append(String.format("\nReloadStrategy: %s",
r.getClass().getName()));
sb.append(String.format("\n Reloaded: %s",
r.getReloadCounter()));
sb.append(String.format("\n Failed: %s",
r.getFailedCounter()));
+ Exception cause = r.getLastError();
+ if (cause != null) {
+ sb.append(String.format("\n Error Message: %s",
cause.getMessage()));
+ final String stackTrace =
ExceptionHelper.stackTraceToString(cause);
+ sb.append("\n\n");
+ sb.append(stackTrace);
+ sb.append("\n\n");
+ }
}
}
if (trigger) {
@@ -117,6 +127,16 @@ public class ReloadDevConsole extends AbstractDevConsole {
jo.put("className", r.getClass().getName());
jo.put("reloaded", r.getReloadCounter());
jo.put("failed", r.getFailedCounter());
+ Throwable cause = r.getLastError();
+ if (cause != null) {
+ JsonObject eo = new JsonObject();
+ eo.put("message", cause.getMessage());
+ JsonArray arr2 = new JsonArray();
+ final String trace =
ExceptionHelper.stackTraceToString(cause);
+ eo.put("stackTrace", arr2);
+ Collections.addAll(arr2, trace.split("\n"));
+ jo.put("lastError", eo);
+ }
}
}
diff --git
a/core/camel-support/src/main/java/org/apache/camel/support/DefaultContextReloadStrategy.java
b/core/camel-support/src/main/java/org/apache/camel/support/DefaultContextReloadStrategy.java
index 068060ad069..54ec13fa789 100644
---
a/core/camel-support/src/main/java/org/apache/camel/support/DefaultContextReloadStrategy.java
+++
b/core/camel-support/src/main/java/org/apache/camel/support/DefaultContextReloadStrategy.java
@@ -37,6 +37,7 @@ public class DefaultContextReloadStrategy extends
ServiceSupport implements Cont
private CamelContext camelContext;
private int succeeded;
private int failed;
+ private Exception lastError;
@Override
public CamelContext getCamelContext() {
@@ -57,12 +58,14 @@ public class DefaultContextReloadStrategy extends
ServiceSupport implements Cont
public void onReload(Object source) {
LOG.info("Reloading CamelContext ({}) triggered by: {}",
camelContext.getName(), source);
try {
+ lastError = null;
EventHelper.notifyContextReloading(getCamelContext(), source);
reloadProperties(source);
reloadRoutes(source);
incSucceededCounter();
EventHelper.notifyContextReloaded(getCamelContext(), source);
} catch (Exception e) {
+ lastError = e;
incFailedCounter();
LOG.warn("Error reloading CamelContext ({}) due to: {}",
camelContext.getName(), e.getMessage(), e);
EventHelper.notifyContextReloadFailure(getCamelContext(), source,
e);
@@ -106,6 +109,11 @@ public class DefaultContextReloadStrategy extends
ServiceSupport implements Cont
failed = 0;
}
+ @Override
+ public Exception getLastError() {
+ return lastError;
+ }
+
protected void incSucceededCounter() {
succeeded++;
}
diff --git
a/core/camel-support/src/main/java/org/apache/camel/support/FileWatcherResourceReloadStrategy.java
b/core/camel-support/src/main/java/org/apache/camel/support/FileWatcherResourceReloadStrategy.java
index 554c02b92d2..9415307fe7f 100644
---
a/core/camel-support/src/main/java/org/apache/camel/support/FileWatcherResourceReloadStrategy.java
+++
b/core/camel-support/src/main/java/org/apache/camel/support/FileWatcherResourceReloadStrategy.java
@@ -305,12 +305,14 @@ public class FileWatcherResourceReloadStrategy extends
ResourceReloadStrategySup
if (accept) {
LOG.debug("Accepted Modified/Created file: {}",
name);
try {
+ setLastError(null);
// must use file resource loader as we cannot
load from classpath
Resource resource
=
PluginHelper.getResourceLoader(getCamelContext()).resolveResource("file:" +
name);
getResourceReload().onReload(name, resource);
incSucceededCounter();
} catch (Exception e) {
+ setLastError(e);
incFailedCounter();
LOG.warn("Error reloading routes from file: {}
due to: {}. This exception is ignored.", name,
e.getMessage(), e);
diff --git
a/core/camel-support/src/main/java/org/apache/camel/support/ResourceReloadStrategySupport.java
b/core/camel-support/src/main/java/org/apache/camel/support/ResourceReloadStrategySupport.java
index 73c55f78f48..75a2ea44a5d 100644
---
a/core/camel-support/src/main/java/org/apache/camel/support/ResourceReloadStrategySupport.java
+++
b/core/camel-support/src/main/java/org/apache/camel/support/ResourceReloadStrategySupport.java
@@ -32,6 +32,7 @@ public abstract class ResourceReloadStrategySupport extends
ServiceSupport imple
private CamelContext camelContext;
private int succeeded;
private int failed;
+ private Exception lastError;
@Override
public CamelContext getCamelContext() {
@@ -77,6 +78,23 @@ public abstract class ResourceReloadStrategySupport extends
ServiceSupport imple
failed = 0;
}
+ public void setLastError(Exception throwable) {
+ this.lastError = throwable;
+ }
+
+ @Override
+ public Exception getLastError() {
+ return lastError;
+ }
+
+ @ManagedOperation(description = "Last error message")
+ public String lastErrorMessage() {
+ if (lastError != null) {
+ return lastError.getMessage();
+ }
+ return null;
+ }
+
protected void incSucceededCounter() {
succeeded++;
}
diff --git
a/core/camel-support/src/main/java/org/apache/camel/support/RouteOnDemandReloadStrategy.java
b/core/camel-support/src/main/java/org/apache/camel/support/RouteOnDemandReloadStrategy.java
index 552b9a64760..a178c48da8e 100644
---
a/core/camel-support/src/main/java/org/apache/camel/support/RouteOnDemandReloadStrategy.java
+++
b/core/camel-support/src/main/java/org/apache/camel/support/RouteOnDemandReloadStrategy.java
@@ -66,6 +66,7 @@ public class RouteOnDemandReloadStrategy extends
RouteWatcherReloadStrategy {
public void onReload(Object source) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
+ setLastError(null);
// use bootstrap classloader from camel so its consistent
ClassLoader acl =
getCamelContext().getApplicationContextClassLoader();
if (acl != null) {
@@ -74,6 +75,7 @@ public class RouteOnDemandReloadStrategy extends
RouteWatcherReloadStrategy {
doOnReload(source);
incSucceededCounter();
} catch (Exception e) {
+ setLastError(e);
incFailedCounter();
LOG.warn("Error reloading routes due to {}. This exception is
ignored.", e.getMessage(), e);
} finally {
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java
index 706b2f6c541..0833ea3214f 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java
@@ -104,7 +104,6 @@ public class CamelContextStatus extends ProcessWatchCommand
{
if (num != null) {
row.inflightRemote = num.toString();
}
- row.reloaded = stats.get("reloaded").toString();
Object last = stats.get("lastProcessingTime");
if (last != null) {
row.last = last.toString();
@@ -128,6 +127,16 @@ public class CamelContextStatus extends
ProcessWatchCommand {
long time = Long.parseLong(last.toString());
row.sinceLastFailed =
TimeUtils.printSince(time);
}
+ row.reloaded = (String) stats.get("reloaded"); //
backwards compatible
+ stats = (Map<String, ?>) stats.get("reload");
+ if (stats != null) {
+ row.reloaded =
stats.get("reloaded").toString();
+ row.reloadedFailed =
stats.get("failed").toString();
+ stats = (Map<String, ?>)
stats.get("lastError");
+ if (stats != null) {
+ row.reloadedError =
stats.get("message").toString();
+ }
+ }
}
JsonArray array = (JsonArray) root.get("routes");
for (int i = 0; i < array.size(); i++) {
@@ -163,9 +172,8 @@ public class CamelContextStatus extends ProcessWatchCommand
{
new
Column().header("PROFILE").dataAlign(HorizontalAlign.LEFT).with(this::getProfile),
new
Column().header("READY").dataAlign(HorizontalAlign.CENTER).with(r -> r.ready),
new
Column().header("STATUS").headerAlign(HorizontalAlign.CENTER)
- .with(r -> extractState(r.state)),
- new
Column().header("RELOAD").headerAlign(HorizontalAlign.CENTER)
- .with(r -> r.reloaded),
+ .with(this::getStatus),
+ new Column().header("RELOAD").with(this::getReloaded),
new
Column().header("AGE").headerAlign(HorizontalAlign.CENTER).with(r -> r.age),
new Column().header("ROUTE").with(this::getRoutes),
new Column().header("MSG/S").with(this::getThroughput),
@@ -174,8 +182,11 @@ public class CamelContextStatus extends
ProcessWatchCommand {
new Column().header("FAIL").with(this::getFailed),
new Column().header("INFLIGHT").with(this::getInflight),
new Column().header("LAST").with(r -> r.last),
- new Column().header("DELTA").with(this::getDelta),
- new
Column().header("SINCE-LAST").with(this::getSinceLast))));
+ new Column().header("SINCE-LAST").with(this::getSinceLast),
+ new Column().header("") // empty header as we only show
info when there is an error
+
.headerAlign(HorizontalAlign.LEFT).dataAlign(HorizontalAlign.LEFT)
+ .maxWidth(70, OverflowBehaviour.NEWLINE)
+ .with(this::getDescription))));
}
return 0;
@@ -221,6 +232,20 @@ public class CamelContextStatus extends
ProcessWatchCommand {
}
}
+ private String getStatus(Row r) {
+ if (r.reloadedError != null) {
+ return "Error";
+ }
+ return extractState(r.state);
+ }
+
+ private String getDescription(Row r) {
+ if (r.reloadedError != null) {
+ return "Reload failed due to: " + r.reloadedError;
+ }
+ return null;
+ }
+
private String getTotal(Row r) {
return r.total;
}
@@ -289,6 +314,10 @@ public class CamelContextStatus extends
ProcessWatchCommand {
return s;
}
+ protected String getReloaded(Row row) {
+ return row.reloaded + "/" + row.reloadedFailed;
+ }
+
protected String getRoutes(Row r) {
return r.routeStarted + "/" + r.routeTotal;
}
@@ -305,6 +334,8 @@ public class CamelContextStatus extends ProcessWatchCommand
{
int routeTotal;
int state;
String reloaded;
+ String reloadedFailed;
+ String reloadedError;
String age;
long uptime;
String throughput;
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProcess.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProcess.java
index 9a5d0f73ef8..db486d1ea33 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProcess.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProcess.java
@@ -96,7 +96,15 @@ public class ListProcess extends ProcessWatchCommand {
if (num != null) {
row.inflightRemote = num.toString();
}
+ stats = (Map<String, ?>) stats.get("reload");
+ if (stats != null) {
+ stats = (Map<String, ?>)
stats.get("lastError");
+ }
+ if (stats != null) {
+ row.reloadError = (String)
stats.get("message");
+ }
}
+
rows.add(row);
}
});
@@ -115,18 +123,36 @@ public class ListProcess extends ProcessWatchCommand {
.with(r -> r.name),
new
Column().header("READY").dataAlign(HorizontalAlign.CENTER).with(r -> r.ready),
new
Column().header("STATUS").headerAlign(HorizontalAlign.CENTER)
- .with(r -> extractState(r.state)),
+ .with(this::getStatus),
new
Column().header("AGE").headerAlign(HorizontalAlign.CENTER).with(r -> r.ago),
new Column().header("TOTAL").with(this::getTotal),
new
Column().header("REMOTE").with(this::getTotalRemote),
new Column().header("FAIL").with(this::getFailed),
- new
Column().header("INFLIGHT").with(this::getInflight))));
+ new
Column().header("INFLIGHT").with(this::getInflight),
+ new Column().header("") // empty header as we only
show info when there is an error
+
.headerAlign(HorizontalAlign.LEFT).dataAlign(HorizontalAlign.LEFT)
+ .maxWidth(70, OverflowBehaviour.NEWLINE)
+ .with(this::getDescription))));
}
}
return 0;
}
+ private String getStatus(Row r) {
+ if (r.reloadError != null) {
+ return "Error";
+ }
+ return extractState(r.state);
+ }
+
+ private String getDescription(Row r) {
+ if (r.reloadError != null) {
+ return "Reload failed due to: " + r.reloadError;
+ }
+ return null;
+ }
+
private String getTotal(Row r) {
return r.total;
}
@@ -184,6 +210,7 @@ public class ListProcess extends ProcessWatchCommand {
String failedRemote;
String inflight;
String inflightRemote;
+ String reloadError;
}
}