2323import io.opentelemetry.javaagent.instrumentation.hypertrace.com.google.protobuf.Descriptors.FileDescriptor;
2424import io.opentelemetry.javaagent.instrumentation.hypertrace.com.google.protobuf.DynamicMessage;
2525import 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;
2630import org.slf4j.Logger;
2731import org.slf4j.LoggerFactory;
2832
2933public class ProtobufMessageConverter {
3034 private static final Logger log = LoggerFactory.getLogger(ProtobufMessageConverter.class);
35+ private static final Map<String, FileDescriptor> fileDescriptorCache = new HashMap<>();
36+
3137 /**
3238 * Converts an unrelocated protobuf message into a relocated DynamicMessage via a byte-array
3339 * round-trip.
@@ -43,31 +49,64 @@ public static DynamicMessage convertToRelocatedDynamicMessage(Message message) t
4349 // 2. Obtain the original (unrelocated) message descriptor.
4450 Descriptors.Descriptor originalDescriptor = message.getDescriptorForType();
4551
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 {
4772 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
48100 com.google.protobuf.DescriptorProtos.FileDescriptorProto unrelocatedFileProto =
49101 unrelocatedFileDescriptor.toProto();
50102 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.
54103 FileDescriptorProto relocatedFileProto = FileDescriptorProto.parseFrom(fileProtoBytes);
55104
56- // 5. Build the relocated FileDescriptor.
57105 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);
67108
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());
71110 }
72111
73112 /**
@@ -77,17 +116,25 @@ public static DynamicMessage convertToRelocatedDynamicMessage(Message message) t
77116 * @param message The incoming (unrelocated) protobuf message.
78117 */
79118 public static String getMessage(Message message) {
119+ if (message == null) {
120+ log.debug("Cannot convert null message to JSON");
121+ return "";
122+ }
123+
80124 try {
81125 // Convert the unrelocated message into a relocated DynamicMessage.
82126 DynamicMessage relocatedMessage = convertToRelocatedDynamicMessage(message);
83127
84128 // 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);
89132 } 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+ }
91138 }
92139 return "";
93140 }
0 commit comments