diff --git a/plugins/tasks/log/pom.xml b/plugins/tasks/log/pom.xml
index 64e47352a2..e69802916c 100644
--- a/plugins/tasks/log/pom.xml
+++ b/plugins/tasks/log/pom.xml
@@ -24,6 +24,27 @@
provided
+
+ com.fasterxml.jackson.core
+ jackson-core
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-yaml
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jdk8
+
+
javax.inject
javax.inject
diff --git a/plugins/tasks/log/src/main/java/com/walmartlabs/concord/plugins/log/LoggingTaskV2.java b/plugins/tasks/log/src/main/java/com/walmartlabs/concord/plugins/log/LoggingTaskV2.java
index 87b2e54ca1..3884f0473d 100644
--- a/plugins/tasks/log/src/main/java/com/walmartlabs/concord/plugins/log/LoggingTaskV2.java
+++ b/plugins/tasks/log/src/main/java/com/walmartlabs/concord/plugins/log/LoggingTaskV2.java
@@ -20,39 +20,48 @@
* =====
*/
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.walmartlabs.concord.runtime.v2.sdk.Task;
import com.walmartlabs.concord.runtime.v2.sdk.TaskResult;
import com.walmartlabs.concord.runtime.v2.sdk.Variables;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import javax.inject.Named;
@Named("log")
public class LoggingTaskV2 implements Task {
+ private static final ObjectMapper yamlObjectMapper = createYamlObjectMapper();
+
@Override
public TaskResult execute(Variables variables) {
Object msg = variables.get("msg");
+ String format = variables.getString("format");
String logLevel = variables.getString("level", "INFO");
switch (logLevel.toUpperCase()) {
case "DEBUG": {
- LogUtils.debug(msg);
+ LogUtils.debug(formatMessage(format, msg));
break;
}
case "INFO": {
- LogUtils.info(msg);
+ LogUtils.info(formatMessage(format, msg));
break;
}
case "WARN": {
- LogUtils.warn(msg);
+ LogUtils.warn(formatMessage(format, msg));
break;
}
case "ERROR": {
- LogUtils.error(msg);
+ LogUtils.error(formatMessage(format, msg));
break;
}
default:
- LogUtils.info(msg);
+ LogUtils.info(formatMessage(format, msg));
}
return TaskResult.success();
@@ -93,4 +102,34 @@ public static void error(Object o) {
public void call(String s) {
LogUtils.info(s);
}
+
+ private static Object formatMessage(String format, Object msg) {
+ if (format == null || format.trim().isEmpty()) {
+ return msg;
+ }
+
+ if ("yaml".equalsIgnoreCase(format)) {
+ try {
+ return "\n" + yamlObjectMapper.writerWithDefaultPrettyPrinter()
+ .writeValueAsString(msg);
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid yaml:" + e.getMessage());
+ }
+ }
+
+ throw new IllegalArgumentException("Unknown format '" + format + "'");
+ }
+
+ private static ObjectMapper createYamlObjectMapper() {
+ return defaultObjectMapper(new YAMLFactory()
+ .disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER)
+ .disable(YAMLGenerator.Feature.SPLIT_LINES));
+ }
+
+ private static ObjectMapper defaultObjectMapper(JsonFactory jf) {
+ ObjectMapper om = new ObjectMapper(jf);
+ om.registerModule(new Jdk8Module());
+ om.registerModule(new JavaTimeModule());
+ return om;
+ }
}
diff --git a/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/parser/GrammarV2.java b/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/parser/GrammarV2.java
index 78d2ece4d9..96e9850957 100644
--- a/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/parser/GrammarV2.java
+++ b/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/parser/GrammarV2.java
@@ -47,6 +47,7 @@
import static com.walmartlabs.concord.runtime.v2.parser.GrammarMisc.*;
import static com.walmartlabs.concord.runtime.v2.parser.GroupOfStepsGrammar.group;
import static com.walmartlabs.concord.runtime.v2.parser.LogGrammar.logStep;
+import static com.walmartlabs.concord.runtime.v2.parser.LogGrammar.logYamlStep;
import static com.walmartlabs.concord.runtime.v2.parser.ParallelGrammar.parallelBlock;
import static com.walmartlabs.concord.runtime.v2.parser.ReturnGrammar.returnStep;
import static com.walmartlabs.concord.runtime.v2.parser.ScriptGrammar.script;
@@ -181,7 +182,7 @@ private static Parser _val(JsonToken t) {
private static final Parser stepObject =
betweenTokens(JsonToken.START_OBJECT, JsonToken.END_OBJECT,
choice(choice(parallelBlock, group, exprFull), choice(taskFull, script, callFull, callForm),
- choice(checkpoint, ifExpr, switchExpr), setVars, logStep, throwStep, suspendStep));
+ choice(checkpoint, ifExpr, switchExpr, setVars), logStep, logYamlStep, throwStep, suspendStep));
// step := exit | exprShort | parallelBlock | stepObject
private static final Parser step = orError(choice(exit, returnStep, exprShort, stepObject), YamlValueType.STEP);
diff --git a/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/parser/LogGrammar.java b/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/parser/LogGrammar.java
index 5350bf4aae..75b5f872fb 100644
--- a/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/parser/LogGrammar.java
+++ b/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/parser/LogGrammar.java
@@ -26,18 +26,26 @@
import static com.walmartlabs.concord.runtime.v2.parser.GrammarMisc.namedStep;
import static com.walmartlabs.concord.runtime.v2.parser.GrammarOptions.namedOptions;
import static com.walmartlabs.concord.runtime.v2.parser.GrammarV2.anyVal;
-import static com.walmartlabs.concord.runtime.v2.parser.TaskGrammar.optionsWithStepName;
public final class LogGrammar {
public static final Parser logStep =
namedStep("log", YamlValueType.TASK, (stepName, a) ->
anyVal.bind(msg ->
- namedOptions.map(options -> new TaskCall(a.location, "log", optionsWithStepName(stepName)
+ namedOptions.map(options -> new TaskCall(a.location, "log", TaskGrammar.optionsWithStepName(stepName)
.putInput("msg", msg)
.putAllMeta(options.meta())
.build()))));
+ public static final Parser logYamlStep =
+ namedStep("logYaml", YamlValueType.TASK, (stepName, a) ->
+ anyVal.bind(msg ->
+ namedOptions.map(options -> new TaskCall(a.location, "log", TaskGrammar.optionsWithStepName(stepName)
+ .putInput("msg", msg)
+ .putInput("format", "yaml")
+ .putAllMeta(options.meta())
+ .build()))));
+
private LogGrammar() {
}
}
diff --git a/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/schema/LogYamlStepMixIn.java b/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/schema/LogYamlStepMixIn.java
new file mode 100644
index 0000000000..d77018eccc
--- /dev/null
+++ b/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/schema/LogYamlStepMixIn.java
@@ -0,0 +1,38 @@
+package com.walmartlabs.concord.runtime.v2.schema;
+
+/*-
+ * *****
+ * Concord
+ * -----
+ * Copyright (C) 2017 - 2020 Walmart Inc.
+ * -----
+ * Licensed 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.
+ * =====
+ */
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.kjetland.jackson.jsonSchema.annotations.JsonSchemaTitle;
+
+import java.util.Map;
+
+@JsonTypeName("LogYamlStep")
+public interface LogYamlStepMixIn extends NamedStep {
+
+ @JsonProperty(value = "logYaml", required = true)
+ @JsonSchemaTitle("Log yaml step")
+ String logYaml();
+
+ @JsonProperty("meta")
+ Map meta();
+}
diff --git a/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/schema/StepMixIn.java b/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/schema/StepMixIn.java
index 8e475bc430..d8100fba99 100644
--- a/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/schema/StepMixIn.java
+++ b/runtime/v2/model/src/main/java/com/walmartlabs/concord/runtime/v2/schema/StepMixIn.java
@@ -36,6 +36,7 @@
@JsonSubTypes.Type(value = ExpressionShortMixIn.class, name = "Expression (short form)"),
@JsonSubTypes.Type(value = ExpressionFullMixIn.class, name = "Expression (full form)"),
@JsonSubTypes.Type(value = LogStepMixIn.class, name = "Log"),
+ @JsonSubTypes.Type(value = LogYamlStepMixIn.class, name = "LogYaml"),
@JsonSubTypes.Type(value = FlowCallStepMixIn.class, name = "Flow call"),
@JsonSubTypes.Type(value = FormCallStepMixIn.class, name = "Form call"),
@JsonSubTypes.Type(value = IfStepMixIn.class, name = "IF step"),
diff --git a/runtime/v2/runner/src/test/java/com/walmartlabs/concord/runtime/v2/runner/MainTest.java b/runtime/v2/runner/src/test/java/com/walmartlabs/concord/runtime/v2/runner/MainTest.java
index 61db3ca3a1..c93fd6e595 100644
--- a/runtime/v2/runner/src/test/java/com/walmartlabs/concord/runtime/v2/runner/MainTest.java
+++ b/runtime/v2/runner/src/test/java/com/walmartlabs/concord/runtime/v2/runner/MainTest.java
@@ -229,6 +229,7 @@ public void test() throws Exception {
byte[] log = run();
assertLog(log, ".*Hello, Concord!.*");
assertLog(log, ".*" + Pattern.quote("defaultsMap:{a=a-value}") + ".*");
+ assertLog(log, ".*k: \"value\".*");
verify(processStatusCallback, times(1)).onRunning(instanceId);
}
diff --git a/runtime/v2/runner/src/test/resources/com/walmartlabs/concord/runtime/v2/runner/hello/concord.yml b/runtime/v2/runner/src/test/resources/com/walmartlabs/concord/runtime/v2/runner/hello/concord.yml
index b3237fdb4b..f3a35ae0a0 100644
--- a/runtime/v2/runner/src/test/resources/com/walmartlabs/concord/runtime/v2/runner/hello/concord.yml
+++ b/runtime/v2/runner/src/test/resources/com/walmartlabs/concord/runtime/v2/runner/hello/concord.yml
@@ -1,4 +1,6 @@
flows:
default:
- log: "Hello, ${name}!"
- - task: testDefaults
\ No newline at end of file
+ - task: testDefaults
+ - logYaml:
+ k: "value"
\ No newline at end of file