23
23
import io .opentelemetry .javaagent .instrumentation .hypertrace .com .google .protobuf .Descriptors .FileDescriptor ;
24
24
import io .opentelemetry .javaagent .instrumentation .hypertrace .com .google .protobuf .DynamicMessage ;
25
25
import io .opentelemetry .javaagent .instrumentation .hypertrace .com .google .protobuf .util .JsonFormat ;
26
+ import java .util .ArrayList ;
27
+ import java .util .HashMap ;
28
+ import java .util .List ;
29
+ import java .util .Map ;
26
30
import org .slf4j .Logger ;
27
31
import org .slf4j .LoggerFactory ;
28
32
29
33
public class ProtobufMessageConverter {
30
34
private static final Logger log = LoggerFactory .getLogger (ProtobufMessageConverter .class );
35
+ private static final Map <String , FileDescriptor > fileDescriptorCache = new HashMap <>();
36
+
31
37
/**
32
38
* Converts an unrelocated protobuf message into a relocated DynamicMessage via a byte-array
33
39
* round-trip.
@@ -43,31 +49,64 @@ public static DynamicMessage convertToRelocatedDynamicMessage(Message message) t
43
49
// 2. Obtain the original (unrelocated) message descriptor.
44
50
Descriptors .Descriptor originalDescriptor = message .getDescriptorForType ();
45
51
46
- // 3. Get the unrelocated file descriptor and its proto representation.
52
+ // 3. Build the relocated descriptor with all dependencies
53
+ Descriptor relocatedDescriptor = getRelocatedDescriptor (originalDescriptor );
54
+ if (relocatedDescriptor == null ) {
55
+ throw new IllegalStateException (
56
+ "Could not find relocated descriptor for message type: "
57
+ + originalDescriptor .getFullName ());
58
+ }
59
+
60
+ // 4. Parse the original message bytes using the relocated descriptor.
61
+ try {
62
+ return DynamicMessage .parseFrom (relocatedDescriptor , messageBytes );
63
+ } catch (Exception e ) {
64
+ log .debug ("Failed to parse message bytes using relocated descriptor: {}" , e .getMessage ());
65
+ throw e ;
66
+ }
67
+ }
68
+
69
+ /** Recursively builds relocated file descriptors with all dependencies. */
70
+ private static Descriptor getRelocatedDescriptor (Descriptors .Descriptor originalDescriptor )
71
+ throws Exception {
47
72
Descriptors .FileDescriptor unrelocatedFileDescriptor = originalDescriptor .getFile ();
73
+
74
+ // Check if we've already processed this file descriptor
75
+ String fileKey = unrelocatedFileDescriptor .getName ();
76
+ if (fileDescriptorCache .containsKey (fileKey )) {
77
+ FileDescriptor relocatedFileDescriptor = fileDescriptorCache .get (fileKey );
78
+ return relocatedFileDescriptor .findMessageTypeByName (originalDescriptor .getName ());
79
+ }
80
+
81
+ // Process all dependencies first
82
+ List <FileDescriptor > dependencies = new ArrayList <>();
83
+ for (Descriptors .FileDescriptor dependency : unrelocatedFileDescriptor .getDependencies ()) {
84
+ String depKey = dependency .getName ();
85
+ if (!fileDescriptorCache .containsKey (depKey )) {
86
+ // Convert the dependency file descriptor
87
+ com .google .protobuf .DescriptorProtos .FileDescriptorProto depProto = dependency .toProto ();
88
+ byte [] depBytes = depProto .toByteArray ();
89
+ FileDescriptorProto relocatedDepProto = FileDescriptorProto .parseFrom (depBytes );
90
+
91
+ // Build with empty dependencies first (we'll fill them in later)
92
+ FileDescriptor relocatedDep =
93
+ FileDescriptor .buildFrom (relocatedDepProto , new FileDescriptor [] {});
94
+ fileDescriptorCache .put (depKey , relocatedDep );
95
+ }
96
+ dependencies .add (fileDescriptorCache .get (depKey ));
97
+ }
98
+
99
+ // Now build the current file descriptor with its dependencies
48
100
com .google .protobuf .DescriptorProtos .FileDescriptorProto unrelocatedFileProto =
49
101
unrelocatedFileDescriptor .toProto ();
50
102
byte [] fileProtoBytes = unrelocatedFileProto .toByteArray ();
51
-
52
- // 4. Parse the file descriptor proto using relocated classes.
53
- // This converts the unrelocated FileDescriptorProto into your relocated FileDescriptorProto.
54
103
FileDescriptorProto relocatedFileProto = FileDescriptorProto .parseFrom (fileProtoBytes );
55
104
56
- // 5. Build the relocated FileDescriptor.
57
105
FileDescriptor relocatedFileDescriptor =
58
- FileDescriptor .buildFrom (relocatedFileProto , new FileDescriptor [] {});
59
-
60
- // 6. Find the relocated message descriptor by name.
61
- Descriptor relocatedDescriptor =
62
- relocatedFileDescriptor .findMessageTypeByName (originalDescriptor .getName ());
63
- if (relocatedDescriptor == null ) {
64
- throw new IllegalStateException (
65
- "Could not find relocated descriptor for message type: " + originalDescriptor .getName ());
66
- }
106
+ FileDescriptor .buildFrom (relocatedFileProto , dependencies .toArray (new FileDescriptor [0 ]));
107
+ fileDescriptorCache .put (fileKey , relocatedFileDescriptor );
67
108
68
- // 7. Parse the original message bytes using the relocated descriptor.
69
- DynamicMessage relocatedMessage = DynamicMessage .parseFrom (relocatedDescriptor , messageBytes );
70
- return relocatedMessage ;
109
+ return relocatedFileDescriptor .findMessageTypeByName (originalDescriptor .getName ());
71
110
}
72
111
73
112
/**
@@ -77,17 +116,25 @@ public static DynamicMessage convertToRelocatedDynamicMessage(Message message) t
77
116
* @param message The incoming (unrelocated) protobuf message.
78
117
*/
79
118
public static String getMessage (Message message ) {
119
+ if (message == null ) {
120
+ log .debug ("Cannot convert null message to JSON" );
121
+ return "" ;
122
+ }
123
+
80
124
try {
81
125
// Convert the unrelocated message into a relocated DynamicMessage.
82
126
DynamicMessage relocatedMessage = convertToRelocatedDynamicMessage (message );
83
127
84
128
// Use the relocated JsonFormat to print the message as JSON.
85
- JsonFormat .Printer relocatedPrinter = JsonFormat .printer ();
86
- String jsonOutput = relocatedPrinter .print (relocatedMessage );
87
-
88
- return jsonOutput ;
129
+ JsonFormat .Printer relocatedPrinter =
130
+ JsonFormat .printer ().includingDefaultValueFields ().preservingProtoFieldNames ();
131
+ return relocatedPrinter .print (relocatedMessage );
89
132
} catch (Exception e ) {
90
- log .error ("Failed to convert message with relocated protobuf message: {}" , e .getMessage ());
133
+ log .error ("Failed to convert message to JSON: {}" , e .getMessage (), e );
134
+ if (log .isDebugEnabled ()) {
135
+ log .debug ("Message type: {}" , message .getClass ().getName ());
136
+ log .debug ("Message descriptor: {}" , message .getDescriptorForType ().getFullName ());
137
+ }
91
138
}
92
139
return "" ;
93
140
}
0 commit comments