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

commit 903c066453a6dc1bbb11c2c1c5b6518c7649354f
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Jan 4 18:03:54 2023 +0100

    CAMEL-18538: camel-jbang - Log command
---
 .../modules/ROOT/pages/camel-jbang.adoc            |  16 +++
 .../dsl/jbang/core/commands/CamelJBangMain.java    |   2 +
 .../jbang/core/commands/action/CamelLogAction.java | 138 +++++++++++++++++++++
 .../src/main/resources/log4j2.properties           |   3 +-
 4 files changed, 158 insertions(+), 1 deletion(-)

diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
index c84bad7e13c..9f1d67efa00 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
@@ -779,6 +779,22 @@ camel top route
 
 TIP: Use `camel top --help` to display all the available commands as 
additional will be added in upcoming releases.
 
+==== Tailing logs
+
+When you run Camel integrations then they will by default run in the 
foreground and output logs.
+
+You can from another terminal access the logs from any Camel integration with 
the `log` command, as follows:
+
+[source,bash]
+----
+camel log chuck
+2023-01-04 17:59:19.288  INFO 44619 --- [           main] 
org.apache.camel.main.MainSupport        : Apache Camel (JBang) 3.21.0 is 
starting
+2023-01-04 17:59:19.395  INFO 44619 --- [           main] 
org.apache.camel.main.MainSupport        : Using Java 17.0.5 with PID 44619. 
Started by davsclaus in /Users/davsclaus/workspace/
+...
+----
+
+You can also watch logs for all Camel integrations by `camel log`, or you can 
specify by name/pids (separate by comma) `camel log bar,chuck`.
+
 ==== Starting and Stopping routes
 
 The `camel cmd` is intended for executing miscellaneous commands in the 
running Camel integrations.
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
index d35972a8fe7..5176926abe2 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
@@ -22,6 +22,7 @@ import org.apache.camel.catalog.CamelCatalog;
 import org.apache.camel.catalog.DefaultCamelCatalog;
 import org.apache.camel.dsl.jbang.core.commands.action.CamelAction;
 import org.apache.camel.dsl.jbang.core.commands.action.CamelGCAction;
+import org.apache.camel.dsl.jbang.core.commands.action.CamelLogAction;
 import org.apache.camel.dsl.jbang.core.commands.action.CamelReloadAction;
 import org.apache.camel.dsl.jbang.core.commands.action.CamelResetStatsAction;
 import org.apache.camel.dsl.jbang.core.commands.action.CamelRouteStartAction;
@@ -72,6 +73,7 @@ public class CamelJBangMain implements Callable<Integer> {
         commandLine = new CommandLine(main)
                 .addSubcommand("init", new CommandLine(new Init(main)))
                 .addSubcommand("run", new CommandLine(new Run(main)))
+                .addSubcommand("log", new CommandLine(new 
CamelLogAction(main)))
                 .addSubcommand("ps", new CommandLine(new ListProcess(main)))
                 .addSubcommand("stop", new CommandLine(new StopProcess(main)))
                 .addSubcommand("get", new CommandLine(new CamelStatus(main))
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java
new file mode 100644
index 00000000000..39d00a28829
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.action;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.common.RuntimeUtil;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.json.JsonObject;
+import org.fusesource.jansi.Ansi;
+import picocli.CommandLine;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.LineNumberReader;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ArrayBlockingQueue;
+
[email protected](name = "log",
+                     description = "Tail logs from running Camel integrations")
+public class CamelLogAction extends ActionBaseCommand {
+
+    private static final char FIRST_ESC_CHAR = 27;
+    private static final char SECOND_ESC_CHAR = '[';
+
+//    private static final String ANSI_ESCAPE = ("" + FIRST_ESC_CHAR) + ("" + 
SECOND_ESC_CHAR) + ("" + '\\') + ("" + 'd') + ("" + '+') + ("" + 'm');
+
+    private static final String ANSI_ESCAPE = "0x1b\\[\\d*m";
+
+    @CommandLine.Parameters(description = "Name or pid of running Camel 
integration. (default selects all)", arity = "0..1")
+    String name = "*";
+
+    @CommandLine.Option(names = { "--logging-color" }, defaultValue = "true", 
description = "Use colored logging")
+    boolean loggingColor = true;
+
+    @CommandLine.Option(names = { "--tail" },
+            description = "The number of lines from the end of the logs to 
show. Defaults to showing all logs.")
+    int tail;
+
+    public CamelLogAction(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer call() throws Exception {
+        List<Long> pids = findPids(name);
+
+        if (pids.size() == 1) {
+            // single log file then no need to interleave logs
+            File log = logFile(pids.get(0));
+            if (log.exists()) {
+                LineNumberReader lnr = new LineNumberReader(new 
FileReader(log));
+                String line;
+
+                // dump only last N lines
+                if (tail > 0) {
+                    Queue<String> fifo = new ArrayBlockingQueue<>(tail);
+                    do {
+                        line = lnr.readLine();
+                        if (line != null) {
+                            while (!fifo.offer(line)) {
+                                fifo.poll();
+                            }
+                        }
+                    } while (line != null);
+                    fifo.forEach(this::printLine);
+                }
+
+                // continue read new log lines
+                do {
+                    line = lnr.readLine();
+                    if (line != null) {
+                        printLine(line);
+                    } else {
+                        Thread.sleep(50);
+                    }
+                } while (true);
+            }
+        } else {
+            // TODO: interleave logs based on PID + timestamp
+            System.out.println("Logs from multiple Camel integrations is 
currently not yet implemented");
+        }
+        return 0;
+    }
+
+    protected void printLine(String line) {
+        if (loggingColor) {
+            System.out.println(line);
+        } else {
+            // unescape ANSI colors
+            StringBuilder sb = new StringBuilder();
+            boolean escaping = false;
+            char[] arr = line.toCharArray();
+            for (int i = 0; i < arr.length; i++) {
+                char ch = arr[i];
+                if (escaping) {
+                    if (ch == 'm') {
+                        escaping = false;
+                    }
+                    continue;
+                }
+                char ch2 = i < arr.length - 1 ? arr[i + 1] : 0;
+                if (ch == 27 && ch2 == '[') {
+                    escaping = true;
+                    continue;
+                }
+
+                sb.append(ch);
+            }
+            line = sb.toString();
+            System.out.println(line);
+        }
+    }
+
+    private static File logFile(long pid) {
+        File dir = new File(System.getProperty("user.home"), ".camel");
+        String name = pid + ".log";
+        return new File(dir, name);
+    }
+
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2.properties 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2.properties
index e92faa54332..6da5d257de8 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2.properties
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2.properties
@@ -30,7 +30,8 @@ appender.file.createOnDemand = true
 appender.file.append = false
 appender.file.layout.type = PatternLayout
 # logging style that is similar to spring boot (no color)
-appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- 
[%15.15t] %-40.40c : %m%n
+#appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- 
[%15.15t] %-40.40c : %m%n
+appender.file.layout.pattern = %style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{Dim} 
%highlight{%5p} %style{%pid}{Magenta} %style{---}{Dim} %style{[%15.15t]}{Dim} 
%style{%-40.40c}{Cyan} : %m%n
 
 # log to console and file
 rootLogger = INFO,out,file

Reply via email to