Skip to content

Commit adfc1bd

Browse files
authored
Pretty printing of stack traces (#142)
1 parent 4963a40 commit adfc1bd

File tree

1 file changed

+66
-6
lines changed

1 file changed

+66
-6
lines changed

src/main/java/com/uber/cadence/internal/common/WorkflowExecutionUtils.java

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717

1818
package com.uber.cadence.internal.common;
1919

20+
import com.google.gson.Gson;
21+
import com.google.gson.GsonBuilder;
22+
import com.google.gson.JsonElement;
23+
import com.google.gson.JsonObject;
24+
import com.google.gson.JsonParser;
25+
import com.google.gson.JsonPrimitive;
2026
import com.uber.cadence.ActivityType;
2127
import com.uber.cadence.BadRequestError;
2228
import com.uber.cadence.Decision;
@@ -54,6 +60,7 @@
5460
import java.util.Iterator;
5561
import java.util.List;
5662
import java.util.Map;
63+
import java.util.Map.Entry;
5764
import java.util.Optional;
5865
import java.util.concurrent.CancellationException;
5966
import java.util.concurrent.CompletableFuture;
@@ -69,6 +76,13 @@
6976
*/
7077
public class WorkflowExecutionUtils {
7178

79+
80+
/**
81+
* Indentation for history and decisions pretty printing.
82+
* Do not change it from 2 spaces. The gson pretty printer has it hardcoded and changing it
83+
* breaks the indentation of exception stack traces.
84+
*/
85+
private static final String INDENTATION = " ";
7286
private static RetryOptions retryParameters =
7387
new RetryOptions.Builder()
7488
.setBackoffCoefficient(2)
@@ -642,7 +656,8 @@ public static String prettyPrintHistory(
642656
} else {
643657
result.append(",");
644658
}
645-
result.append("\n ");
659+
result.append("\n");
660+
result.append(INDENTATION);
646661
result.append(prettyPrintHistoryEvent(event, firstTimestamp));
647662
}
648663
result.append("\n}");
@@ -659,7 +674,8 @@ public static String prettyPrintDecisions(Iterable<Decision> decisions) {
659674
} else {
660675
result.append(",");
661676
}
662-
result.append("\n ");
677+
result.append("\n");
678+
result.append(INDENTATION);
663679
result.append(prettyPrintDecision(decision));
664680
}
665681
result.append("\n}");
@@ -688,7 +704,8 @@ private static String prettyPrintHistoryEvent(HistoryEvent event, long firstTime
688704
}
689705
result.append(" ");
690706
result.append(
691-
prettyPrintObject(getEventAttributes(event), "getFieldValue", true, " ", false, false));
707+
prettyPrintObject(
708+
getEventAttributes(event), "getFieldValue", true, INDENTATION, false, false));
692709
return result.toString();
693710
}
694711

@@ -707,7 +724,7 @@ private static Object getEventAttributes(HistoryEvent event) {
707724
* @param decision decision to pretty print
708725
*/
709726
public static String prettyPrintDecision(Decision decision) {
710-
return prettyPrintObject(decision, "getFieldValue", true, " ", true, true);
727+
return prettyPrintObject(decision, "getFieldValue", true, INDENTATION, true, true);
711728
}
712729

713730
/**
@@ -810,15 +827,26 @@ private static String prettyPrintObject(
810827
}
811828
result.append("\n");
812829
result.append(indentation);
813-
result.append(" ");
830+
result.append(INDENTATION);
814831
result.append(name.substring(3));
815832
result.append(" = ");
833+
// Pretty print JSON serialized exceptions.
834+
if (name.equals("getDetails") && value instanceof byte[]) {
835+
String details = new String((byte[]) value, StandardCharsets.UTF_8);
836+
details = prettyPrintJson(details, INDENTATION + INDENTATION);
837+
// GSON pretty prints, but doesn't let to set an initial indentation.
838+
// Thus indenting the pretty printed JSON through regexp :(.
839+
String replacement = "\n" + indentation + INDENTATION;
840+
details = details.replaceAll("\\n|\\\\n", replacement);
841+
result.append(details);
842+
continue;
843+
}
816844
result.append(
817845
prettyPrintObject(
818846
value,
819847
methodToSkip,
820848
skipNullsAndEmptyCollections,
821-
indentation + " ",
849+
indentation + INDENTATION,
822850
false,
823851
false));
824852
} else {
@@ -848,4 +876,36 @@ public static boolean containsEvent(List<HistoryEvent> history, EventType eventT
848876
}
849877
return false;
850878
}
879+
880+
/**
881+
* Pretty prints JSON. Not a generic utility. Used to prettify Details fields that contain
882+
* serialized exceptions.
883+
*/
884+
private static String prettyPrintJson(String jsonValue, String stackIndentation) {
885+
JsonParser parser = new JsonParser();
886+
try {
887+
JsonObject json = parser.parse(jsonValue).getAsJsonObject();
888+
fixStackTrace(json, stackIndentation);
889+
Gson gson = new GsonBuilder().setPrettyPrinting().create();
890+
return gson.toJson(json);
891+
} catch (Exception e) {
892+
return jsonValue;
893+
}
894+
}
895+
896+
private static void fixStackTrace(JsonElement json, String stackIndentation) {
897+
if (!json.isJsonObject()) {
898+
return;
899+
}
900+
for (Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
901+
if ("stackTrace".equals(entry.getKey())) {
902+
String value = entry.getValue().getAsString();
903+
String replacement = "\n" + stackIndentation;
904+
String fixed = value.replaceAll("\\n", replacement);
905+
entry.setValue(new JsonPrimitive(fixed));
906+
continue;
907+
}
908+
fixStackTrace(entry.getValue(), stackIndentation + INDENTATION);
909+
}
910+
}
851911
}

0 commit comments

Comments
 (0)