davsclaus commented on code in PR #27399:
URL: https://github.com/apache/camel/pull/27399#discussion_r4194085706
##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/IntegrationLauncher.java:
##########
@@ -218,6 +238,61 @@ private static RuntimeHelper.ProcessInfo findByPid(long
pid) {
return null;
}
+ /**
+ * The console output of a run that failed to start, as camel_get_log
shows a log (CAMEL-25364): each record keeps
+ * its message, an error its root cause and the first line of the user's
code, and the stack frames are left out.
+ * The end of the raw output is mostly frames of the runtime, and the line
that says what went wrong is above them.
+ */
+ static String failureOutput(Path output) {
+ List<String> lines;
+ try {
+ lines = Files.readAllLines(output, StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ return readTail(output);
+ }
+ if (lines.size() > 5000) {
+ lines = lines.subList(lines.size() - 5000, lines.size());
+ }
+ lines = lines.stream().filter(l -> !l.isBlank()).toList();
+ JsonObject log = LogFileReader.build(lines, FAILURE_RECORDS, null,
null, false, new JsonObject());
Review Comment:
Thanks, the javac case is exactly the one that matters. Fixed in 57b420404b:
the frames (`at ...` and `... N more`) are taken out of the lines before they
are folded a second time, so each record keeps its exception lines: the
exception, its `Caused by:` lines and a message over several lines such as the
javac diagnostics. The first frame of the user's code still comes from the
folded view, and the output ends with "(stack frames left out)". Output with no
log records goes back to `readTail`, so the end is kept. New tests:
`failureOutputKeepsAMessageOverSeveralLines` (a `ReflectException` with
`OrderNumber.java:12: error: cannot find symbol`) and
`failureOutputWithoutLogRecordsKeepsTheEnd`.
_Claude Code on behalf of davsclaus_
##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/IntegrationLauncher.java:
##########
@@ -218,6 +238,61 @@ private static RuntimeHelper.ProcessInfo findByPid(long
pid) {
return null;
}
+ /**
+ * The console output of a run that failed to start, as camel_get_log
shows a log (CAMEL-25364): each record keeps
+ * its message, an error its root cause and the first line of the user's
code, and the stack frames are left out.
+ * The end of the raw output is mostly frames of the runtime, and the line
that says what went wrong is above them.
+ */
+ static String failureOutput(Path output) {
+ List<String> lines;
+ try {
+ lines = Files.readAllLines(output, StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ return readTail(output);
+ }
+ if (lines.size() > 5000) {
+ lines = lines.subList(lines.size() - 5000, lines.size());
+ }
+ lines = lines.stream().filter(l -> !l.isBlank()).toList();
+ JsonObject log = LogFileReader.build(lines, FAILURE_RECORDS, null,
null, false, new JsonObject());
+ JsonArray rows = (JsonArray) log.get("lines");
+ if (rows == null || rows.isEmpty()) {
+ return readTail(output);
+ }
+ StringBuilder sb = new StringBuilder();
+ // newest first in the log tool; oldest first here, so it reads as the
console did
+ for (int i = rows.size() - 1; i >= 0; i--) {
+ JsonObject r = (JsonObject) rows.get(i);
+ String level = r.getStringOrDefault("time", "").isEmpty() ? "" :
r.getStringOrDefault("level", "") + " ";
+ sb.append(level).append(r.getStringOrDefault("message", ""));
+ if (r.get("cause") != null) {
+ sb.append("\n cause: ").append(r.getString("cause"));
+ }
+ if (r.get("at") != null) {
+ sb.append("\n at: ").append(r.getString("at"));
+ }
+ if (r.get("detailLines") != null) {
+ sb.append("\n (").append(r.get("detailLines")).append(" lines
of stack trace left out)");
+ } else if (r.get("detail") != null) {
+ sb.append("\n").append(r.getString("detail"));
+ }
+ sb.append("\n");
+ }
+ return sb.toString().strip();
+ }
+
+ /** The integration that runs with this directory as its working
directory, or null. */
+ private static RuntimeHelper.ProcessInfo runningFrom(Path directory) {
+ Path wanted = directory.toAbsolutePath().normalize();
+ for (RuntimeHelper.ProcessInfo p : RuntimeHelper.discoverProcesses()) {
+ Path dir = workingDirectory(p.pid());
+ if (dir != null &&
dir.toAbsolutePath().normalize().equals(wanted)) {
Review Comment:
Fixed in 57b420404b: the directories are compared with `Files.isSameFile`,
falling back to the normalized paths on an `IOException`.
`IntegrationLauncherGuardTest.theRunningIntegrationIsFoundThroughASymlink` pins
it.
_Claude Code on behalf of davsclaus_
##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/IntegrationLauncher.java:
##########
@@ -72,6 +76,22 @@ public static JsonObject run(Path directory, List<String>
files, String name, bo
return result;
}
result.put("directory", directory.toString());
+ if (sourceDir) {
+ // the whole directory is the app: one already running from it is
that app, and a second copy only fights
+ // it for ports and files and makes its name ambiguous to the
other tools
+ RuntimeHelper.ProcessInfo running = runningFrom(directory);
Review Comment:
Fixed in 57b420404b: the launcher remembers the processes it started with
`--source-dir` (a map from the real path of the directory to the
`ProcessHandle`). The guard returns `status: starting` with the pid while that
process is alive and has no status file yet. The check and the start happen
under one lock, so two calls in flight do not both start a copy.
_Claude Code on behalf of davsclaus_
##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/IntegrationLauncher.java:
##########
@@ -72,6 +76,22 @@ public static JsonObject run(Path directory, List<String>
files, String name, bo
return result;
}
result.put("directory", directory.toString());
+ if (sourceDir) {
+ // the whole directory is the app: one already running from it is
that app, and a second copy only fights
+ // it for ports and files and makes its name ambiguous to the
other tools
+ RuntimeHelper.ProcessInfo running = runningFrom(directory);
+ if (running != null) {
+ String runningName = running.contextName() != null &&
!running.contextName().isBlank()
+ ? running.contextName() : running.name();
+ result.put("status", "running");
+ result.put("pid", running.pid());
+ result.put("name", runningName);
+ result.put("message", runningName + " (pid " + running.pid() +
") already runs from this directory;"
+ + " a second copy was not started. In
dev mode a changed or added file is reloaded;"
+ + " camel_control restart restarts it,
for example after adding a Java class.");
Review Comment:
Fixed in 57b420404b: the guard reads the process arguments. With
`--source-dir` and `--dev` it says an added file is reloaded and restart picks
up a Java class; with `--source-dir` and no dev mode it says restart picks up
the change; and an integration started with its own files is reported as such,
with the advice to stop it and run the whole directory. It is still returned
rather than starting a second copy next to it. The guard test checks that an
app without `--source-dir` (the test JVM) is not said to reload added files.
_Claude Code on behalf of davsclaus_
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]