diff --git a/src/main/java/org/rundeck/client/api/model/ExecLog.java b/src/main/java/org/rundeck/client/api/model/ExecLog.java index cbff6893..34cc57e3 100644 --- a/src/main/java/org/rundeck/client/api/model/ExecLog.java +++ b/src/main/java/org/rundeck/client/api/model/ExecLog.java @@ -18,6 +18,9 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.HashMap; +import java.util.Map; + @JsonIgnoreProperties(ignoreUnknown = true) public class ExecLog { @@ -28,4 +31,14 @@ public class ExecLog { public String command; public String node; + public Map toMap() { + HashMap map = new HashMap<>(); + map.put("time", time); + map.put("level", level); + map.put("log", log); + map.put("user", user); + map.put("command", command); + map.put("node", node); + return map; + } } diff --git a/src/main/java/org/rundeck/client/tool/commands/Executions.java b/src/main/java/org/rundeck/client/tool/commands/Executions.java index 1cbc7292..bf9ea628 100644 --- a/src/main/java/org/rundeck/client/tool/commands/Executions.java +++ b/src/main/java/org/rundeck/client/tool/commands/Executions.java @@ -33,6 +33,7 @@ import java.io.IOException; import java.util.*; import java.util.function.BooleanSupplier; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @@ -103,9 +104,19 @@ public boolean follow(Follow options, CommandOutput out) throws IOException, Inp ); - return followOutput(getClient(), output, options.isProgress(), options.isQuiet(), options.getId(), max, out); + return followOutput( + getClient(), + output, + options.isProgress(), + options.isQuiet(), + options.getId(), + max, + out, + options.isOutputFormat() ? Format.formatter(options.getOutputFormat(), ExecLog::toMap, "%", "") : null + ); } + public static Call startFollowOutput( final Client client, final long max, @@ -133,6 +144,7 @@ public static Call startFollowOutput( * @param max max lines * @param out output * + * @param formatter * @return true if successful * */ @@ -143,10 +155,26 @@ public static boolean followOutput( final boolean quiet, final String id, long max, - CommandOutput out + CommandOutput out, + final Function formatter ) throws IOException { - return followOutput(client, output, progress, quiet, id, max, out, () -> { + return followOutput(client, output, id, max, entries -> { + if (progress && !entries.isEmpty()) { + out.output("."); + } else if (!quiet) { + for (ExecLog entry : entries) { + String outval = formatter != null ? formatter.apply(entry) : entry.log; + if ("WARN".equals(entry.level)) { + out.warning(outval); + } else if ("ERROR".equals(entry.level)) { + out.error(outval); + } else { + out.output(outval); + } + } + } + }, () -> { try { Thread.sleep(2000); return true; @@ -159,10 +187,9 @@ public static boolean followOutput( /** * Follow output until execution completes and output is fully read, or interrupted - * @param progress show progress - * @param quiet quell log output * @param id execution id * @param max max lines to retrieve with each request + * @param receiver receive log events * @param waitFunc function for waiting, return false to halt * * @return true if execution is successful @@ -171,11 +198,9 @@ public static boolean followOutput( public static boolean followOutput( final Client client, final Call output, - final boolean progress, - final boolean quiet, final String id, long max, - CommandOutput out, + Consumer> receiver, BooleanSupplier waitFunc ) throws IOException { @@ -184,7 +209,7 @@ public static boolean followOutput( Call callOutput = output; while (!done) { ExecOutput execOutput = client.checkError(callOutput); - printLogOutput(execOutput.entries, progress, quiet, out); + receiver.accept(execOutput.entries); status = execOutput.execState; done = execOutput.execCompleted && execOutput.completed; if (!done) { @@ -197,30 +222,6 @@ public static boolean followOutput( return "succeeded".equals(status); } - private static void printLogOutput( - final List entries, - final boolean progress, - final boolean quiet, - CommandOutput out - ) - { - - if (!quiet && !progress) { - for (ExecLog entry : entries) { - if ("WARN".equals(entry.level)) { - out.warning(entry.log); - } else if ("ERROR".equals(entry.level)) { - out.error(entry.log); - } else { - out.output(entry.log); - } - } - } else if (progress && entries.size() > 0) { - out.output("."); - } - } - - @CommandLineInterface(application = "info") interface Info extends ExecutionIdOption, ExecutionResultOptions { } @@ -543,7 +544,8 @@ public static boolean maybeFollow( options.isQuiet(), id, 500, - output + output, + options.isOutputFormat() ? Format.formatter(options.getOutputFormat(), ExecLog::toMap, "%", "") : null ); } } diff --git a/src/main/java/org/rundeck/client/tool/options/FollowOptions.java b/src/main/java/org/rundeck/client/tool/options/FollowOptions.java index 81cb2b43..3f383fbb 100644 --- a/src/main/java/org/rundeck/client/tool/options/FollowOptions.java +++ b/src/main/java/org/rundeck/client/tool/options/FollowOptions.java @@ -38,4 +38,12 @@ public interface FollowOptions extends RunOptions{ long getTail(); boolean isTail(); + + @Option(shortName = "%", + longName = "outformat", + description = "Output format specifier for execution logs. You can use \"%key\" where key is one of:" + + "time,level,log,user,command,node. E.g. \"%user@%node/%level: %log\"") + String getOutputFormat(); + + boolean isOutputFormat(); }