17
17
18
18
package com .uber .cadence .internal .common ;
19
19
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 ;
20
26
import com .uber .cadence .ActivityType ;
21
27
import com .uber .cadence .BadRequestError ;
22
28
import com .uber .cadence .Decision ;
54
60
import java .util .Iterator ;
55
61
import java .util .List ;
56
62
import java .util .Map ;
63
+ import java .util .Map .Entry ;
57
64
import java .util .Optional ;
58
65
import java .util .concurrent .CancellationException ;
59
66
import java .util .concurrent .CompletableFuture ;
69
76
*/
70
77
public class WorkflowExecutionUtils {
71
78
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 = " " ;
72
86
private static RetryOptions retryParameters =
73
87
new RetryOptions .Builder ()
74
88
.setBackoffCoefficient (2 )
@@ -642,7 +656,8 @@ public static String prettyPrintHistory(
642
656
} else {
643
657
result .append ("," );
644
658
}
645
- result .append ("\n " );
659
+ result .append ("\n " );
660
+ result .append (INDENTATION );
646
661
result .append (prettyPrintHistoryEvent (event , firstTimestamp ));
647
662
}
648
663
result .append ("\n }" );
@@ -659,7 +674,8 @@ public static String prettyPrintDecisions(Iterable<Decision> decisions) {
659
674
} else {
660
675
result .append ("," );
661
676
}
662
- result .append ("\n " );
677
+ result .append ("\n " );
678
+ result .append (INDENTATION );
663
679
result .append (prettyPrintDecision (decision ));
664
680
}
665
681
result .append ("\n }" );
@@ -688,7 +704,8 @@ private static String prettyPrintHistoryEvent(HistoryEvent event, long firstTime
688
704
}
689
705
result .append (" " );
690
706
result .append (
691
- prettyPrintObject (getEventAttributes (event ), "getFieldValue" , true , " " , false , false ));
707
+ prettyPrintObject (
708
+ getEventAttributes (event ), "getFieldValue" , true , INDENTATION , false , false ));
692
709
return result .toString ();
693
710
}
694
711
@@ -707,7 +724,7 @@ private static Object getEventAttributes(HistoryEvent event) {
707
724
* @param decision decision to pretty print
708
725
*/
709
726
public static String prettyPrintDecision (Decision decision ) {
710
- return prettyPrintObject (decision , "getFieldValue" , true , " " , true , true );
727
+ return prettyPrintObject (decision , "getFieldValue" , true , INDENTATION , true , true );
711
728
}
712
729
713
730
/**
@@ -810,15 +827,26 @@ private static String prettyPrintObject(
810
827
}
811
828
result .append ("\n " );
812
829
result .append (indentation );
813
- result .append (" " );
830
+ result .append (INDENTATION );
814
831
result .append (name .substring (3 ));
815
832
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
+ }
816
844
result .append (
817
845
prettyPrintObject (
818
846
value ,
819
847
methodToSkip ,
820
848
skipNullsAndEmptyCollections ,
821
- indentation + " " ,
849
+ indentation + INDENTATION ,
822
850
false ,
823
851
false ));
824
852
} else {
@@ -848,4 +876,36 @@ public static boolean containsEvent(List<HistoryEvent> history, EventType eventT
848
876
}
849
877
return false ;
850
878
}
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
+ }
851
911
}
0 commit comments