Skip to content

Commit 78a9097

Browse files
jbachorikclaude
andcommitted
feat(profiling): Add optional pretty-printing for JSON output
Add --pretty flag to control JSON pretty-printing in the CLI converter. By default, JSON output is compact for efficient processing. Use --pretty for human-readable output with indentation. Usage: # Compact JSON (default) ./gradlew convertJfr --args="--json input.jfr output.json" # Pretty-printed JSON ./gradlew convertJfr --args="--json --pretty input.jfr output.json" The pretty-printer is a simple, dependency-free implementation that adds newlines and 2-space indentation without external libraries. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent ed61c40 commit 78a9097

File tree

3 files changed

+117
-9
lines changed

3 files changed

+117
-9
lines changed

dd-java-agent/agent-profiling/profiling-otel/doc/CLI.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ Convert to JSON for human inspection:
2424

2525
### Options
2626

27-
- `--json` - Output JSON format instead of protobuf (useful for inspection)
27+
- `--json` - Output JSON format instead of protobuf (compact by default)
28+
- `--pretty` - Pretty-print JSON output with indentation (use with `--json`)
2829
- `--include-payload` - Include original JFR payload in output (increases size significantly)
2930
- `--help` - Show help message
3031

@@ -41,11 +42,18 @@ Convert single JFR to protobuf:
4142

4243
#### JSON Output for Inspection
4344

44-
Output JSON format to examine the structure:
45+
Output compact JSON for processing:
4546

4647
```bash
4748
./gradlew :dd-java-agent:agent-profiling:profiling-otel:convertJfr \
4849
--args="--json recording.jfr output.json"
50+
```
51+
52+
Output pretty-printed JSON for human inspection:
53+
54+
```bash
55+
./gradlew :dd-java-agent:agent-profiling:profiling-otel:convertJfr \
56+
--args="--json --pretty recording.jfr output.json"
4957

5058
# Inspect with jq
5159
cat output.json | jq '.dictionary.string_table | length'

dd-java-agent/agent-profiling/profiling-otel/src/main/java/com/datadog/profiling/otel/JfrToOtlpConverter.java

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ public final class JfrToOtlpConverter {
5959
public enum Kind {
6060
/** Protobuf binary format (default). */
6161
PROTO,
62-
/** JSON text format. */
63-
JSON
62+
/** JSON text format (compact). */
63+
JSON,
64+
/** JSON text format with pretty-printing. */
65+
JSON_PRETTY
6466
}
6567

6668
private static final class PathEntry {
@@ -233,7 +235,9 @@ public byte[] convert(Kind kind) throws IOException {
233235

234236
switch (kind) {
235237
case JSON:
236-
return encodeProfilesDataAsJson();
238+
return encodeProfilesDataAsJson(false);
239+
case JSON_PRETTY:
240+
return encodeProfilesDataAsJson(true);
237241
case PROTO:
238242
default:
239243
return encodeProfilesData();
@@ -762,7 +766,7 @@ private byte[] generateProfileId() {
762766

763767
// JSON encoding methods
764768

765-
private byte[] encodeProfilesDataAsJson() {
769+
private byte[] encodeProfilesDataAsJson(boolean prettyPrint) {
766770
JsonWriter json = new JsonWriter();
767771
json.beginObject();
768772

@@ -776,7 +780,86 @@ private byte[] encodeProfilesDataAsJson() {
776780
encodeDictionaryJson(json);
777781

778782
json.endObject();
779-
return json.toByteArray();
783+
byte[] compactJson = json.toByteArray();
784+
785+
// Pretty-print if requested
786+
return prettyPrint ? prettyPrintJson(compactJson) : compactJson;
787+
}
788+
789+
/**
790+
* Pretty-prints compact JSON with indentation.
791+
*
792+
* <p>Simple pretty-printer that adds newlines and indentation without external dependencies.
793+
*/
794+
private byte[] prettyPrintJson(byte[] compactJson) {
795+
String compact = new String(compactJson, java.nio.charset.StandardCharsets.UTF_8);
796+
StringBuilder pretty = new StringBuilder(compact.length() + compact.length() / 4);
797+
int indent = 0;
798+
boolean inString = false;
799+
boolean escape = false;
800+
801+
for (int i = 0; i < compact.length(); i++) {
802+
char c = compact.charAt(i);
803+
804+
if (escape) {
805+
pretty.append(c);
806+
escape = false;
807+
continue;
808+
}
809+
810+
if (c == '\\') {
811+
pretty.append(c);
812+
escape = true;
813+
continue;
814+
}
815+
816+
if (c == '"') {
817+
pretty.append(c);
818+
inString = !inString;
819+
continue;
820+
}
821+
822+
if (inString) {
823+
pretty.append(c);
824+
continue;
825+
}
826+
827+
switch (c) {
828+
case '{':
829+
case '[':
830+
pretty.append(c).append('\n');
831+
indent++;
832+
appendIndent(pretty, indent);
833+
break;
834+
case '}':
835+
case ']':
836+
pretty.append('\n');
837+
indent--;
838+
appendIndent(pretty, indent);
839+
pretty.append(c);
840+
break;
841+
case ',':
842+
pretty.append(c).append('\n');
843+
appendIndent(pretty, indent);
844+
break;
845+
case ':':
846+
pretty.append(c).append(' ');
847+
break;
848+
default:
849+
if (!Character.isWhitespace(c)) {
850+
pretty.append(c);
851+
}
852+
break;
853+
}
854+
}
855+
856+
return pretty.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8);
857+
}
858+
859+
private void appendIndent(StringBuilder sb, int indent) {
860+
for (int i = 0; i < indent * 2; i++) {
861+
sb.append(' ');
862+
}
780863
}
781864

782865
private void encodeResourceProfilesJson(JsonWriter json) {

dd-java-agent/agent-profiling/profiling-otel/src/main/java/com/datadog/profiling/otel/JfrToOtlpConverterCLI.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
* # Convert single JFR file to protobuf (default)
1616
* java -cp ... com.datadog.profiling.otel.JfrToOtlpConverterCLI input.jfr output.pb
1717
*
18-
* # Convert to JSON format
18+
* # Convert to JSON format (compact)
1919
* java -cp ... com.datadog.profiling.otel.JfrToOtlpConverterCLI --json input.jfr output.json
2020
*
21+
* # Convert to pretty-printed JSON
22+
* java -cp ... com.datadog.profiling.otel.JfrToOtlpConverterCLI --json --pretty input.jfr output.json
23+
*
2124
* # Include original JFR payload
2225
* java -cp ... com.datadog.profiling.otel.JfrToOtlpConverterCLI --include-payload input.jfr output.pb
2326
*
@@ -45,6 +48,7 @@ public static void main(String[] args) {
4548
private void run(String[] args) throws IOException {
4649
JfrToOtlpConverter.Kind outputKind = JfrToOtlpConverter.Kind.PROTO;
4750
boolean includePayload = false;
51+
boolean prettyPrint = false;
4852
int firstInputIndex = 0;
4953

5054
// Parse flags
@@ -55,6 +59,10 @@ private void run(String[] args) throws IOException {
5559
outputKind = JfrToOtlpConverter.Kind.JSON;
5660
firstInputIndex++;
5761
break;
62+
case "--pretty":
63+
prettyPrint = true;
64+
firstInputIndex++;
65+
break;
5866
case "--include-payload":
5967
includePayload = true;
6068
firstInputIndex++;
@@ -67,6 +75,11 @@ private void run(String[] args) throws IOException {
6775
}
6876
}
6977

78+
// Apply pretty-printing to JSON output
79+
if (prettyPrint && outputKind == JfrToOtlpConverter.Kind.JSON) {
80+
outputKind = JfrToOtlpConverter.Kind.JSON_PRETTY;
81+
}
82+
7083
// Remaining args: input1.jfr [input2.jfr ...] output.pb/json
7184
if (args.length - firstInputIndex < 2) {
7285
throw new IllegalArgumentException(
@@ -140,6 +153,7 @@ private static void printUsage() {
140153
System.out.println();
141154
System.out.println("Options:");
142155
System.out.println(" --json Output JSON format instead of protobuf");
156+
System.out.println(" --pretty Pretty-print JSON output (use with --json)");
143157
System.out.println(
144158
" --include-payload Include original JFR payload in output (increases size)");
145159
System.out.println(" --help Show this help message");
@@ -148,9 +162,12 @@ private static void printUsage() {
148162
System.out.println(" # Convert to protobuf (default)");
149163
System.out.println(" JfrToOtlpConverterCLI recording.jfr output.pb");
150164
System.out.println();
151-
System.out.println(" # Convert to JSON for inspection");
165+
System.out.println(" # Convert to compact JSON");
152166
System.out.println(" JfrToOtlpConverterCLI --json recording.jfr output.json");
153167
System.out.println();
168+
System.out.println(" # Convert to pretty-printed JSON");
169+
System.out.println(" JfrToOtlpConverterCLI --json --pretty recording.jfr output.json");
170+
System.out.println();
154171
System.out.println(" # Merge multiple recordings");
155172
System.out.println(" JfrToOtlpConverterCLI file1.jfr file2.jfr file3.jfr merged.pb");
156173
System.out.println();

0 commit comments

Comments
 (0)