Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
refactor code
  • Loading branch information
thugrock7 committed Feb 12, 2025
commit 6817c8bad80d87019415d6eb7472d0130dd83a34
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.opentelemetry.javaagent.instrumentation.hypertrace.grpc.v1_6;

import com.google.protobuf.Message;
import io.grpc.Metadata;
import io.grpc.Metadata.Key;
import io.opentelemetry.api.common.AttributeKey;
Expand All @@ -37,12 +38,16 @@ private GrpcSpanDecorator() {}
private static final JsonFormat.Printer PRINTER = JsonFormat.printer();

public static void addMessageAttribute(Object message, Span span, AttributeKey<String> key) {
if (isProtobufMessage(message)) {
if (message instanceof Message) {
Message mb = (Message) message;
try {
ProtobufRoundTripConverter.addConvertedMessageAttribute(message, span, key);
String jsonOutput = ProtobufMessageConverter.getMessage(mb);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to do this? What was happening while we were directly trying to get it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the object we are getting is of com.google.protobuf.Message, this cannot directly be taken as instance of our relocated Message class.

Type Incompatibility: Relocated classes are essentially different types, so couldn’t simply cast one into the other without conversion.
Version Mismatch: two versions (e.g., 3.2.0 vs. 3.25.5) have incompatible internal representations. Like application is using protobuf version 3.2.0, but our bundled dependency of protobuf is 3.25.5.
Different Metadata: The unrelocated message carries descriptors/metadata) that the relocated version doesn't recognize directly.

span.setAttribute(key, jsonOutput);
} catch (Exception e) {
log.error("Failed to print message as JSON", e);
log.error("Failed to decode message as JSON", e);
}
} else {
log.debug("message is not an instance of com.google.protobuf.Message");
}
}

Expand Down Expand Up @@ -83,21 +88,4 @@ public static Map<String, String> metadataToMap(Metadata metadata) {
}
return mapHeaders;
}

private static boolean isProtobufMessage(Object message) {
if (message == null) {
return false;
}
// Check the interfaces on the class and its superclasses
Class<?> cls = message.getClass();
while (cls != null) {
for (Class<?> iface : cls.getInterfaces()) {
if ("com.google.protobuf.Message".equals(iface.getName())) {
return true;
}
}
cls = cls.getSuperclass();
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@

import com.google.protobuf.Descriptors;
import com.google.protobuf.Message;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.javaagent.instrumentation.hypertrace.com.google.protobuf.DescriptorProtos.FileDescriptorProto;
import io.opentelemetry.javaagent.instrumentation.hypertrace.com.google.protobuf.Descriptors.Descriptor;
import io.opentelemetry.javaagent.instrumentation.hypertrace.com.google.protobuf.Descriptors.FileDescriptor;
import io.opentelemetry.javaagent.instrumentation.hypertrace.com.google.protobuf.DynamicMessage;
import io.opentelemetry.javaagent.instrumentation.hypertrace.com.google.protobuf.util.JsonFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ProtobufRoundTripConverter {

public class ProtobufMessageConverter {
private static final Logger log = LoggerFactory.getLogger(ProtobufMessageConverter.class);
/**
* Converts an unrelocated protobuf message into a relocated DynamicMessage via a byte-array
* round-trip.
Expand All @@ -36,16 +36,12 @@ public class ProtobufRoundTripConverter {
* @return A relocated DynamicMessage built from your relocated protobuf classes.
* @throws Exception if conversion fails.
*/
public static DynamicMessage convertToRelocatedDynamicMessage(Object message) throws Exception {
if (!(message instanceof Message)) {
throw new IllegalArgumentException("message is not a protobuf Message");
}
public static DynamicMessage convertToRelocatedDynamicMessage(Message message) throws Exception {
// 1. Serialize the original message to bytes.
Message originalMessage = (Message) message;
byte[] messageBytes = originalMessage.toByteArray();
byte[] messageBytes = message.toByteArray();

// 2. Obtain the original (unrelocated) message descriptor.
Descriptors.Descriptor originalDescriptor = originalMessage.getDescriptorForType();
Descriptors.Descriptor originalDescriptor = message.getDescriptorForType();

// 3. Get the unrelocated file descriptor and its proto representation.
Descriptors.FileDescriptor unrelocatedFileDescriptor = originalDescriptor.getFile();
Expand All @@ -58,12 +54,10 @@ public static DynamicMessage convertToRelocatedDynamicMessage(Object message) th
FileDescriptorProto relocatedFileProto = FileDescriptorProto.parseFrom(fileProtoBytes);

// 5. Build the relocated FileDescriptor.
// Note: This example assumes there are no dependencies.
FileDescriptor relocatedFileDescriptor =
FileDescriptor.buildFrom(relocatedFileProto, new FileDescriptor[] {});

// 6. Find the relocated message descriptor by name.
// We assume the message name is the same in both relocated and unrelocated files.
Descriptor relocatedDescriptor =
relocatedFileDescriptor.findMessageTypeByName(originalDescriptor.getName());
if (relocatedDescriptor == null) {
Expand All @@ -77,15 +71,12 @@ public static DynamicMessage convertToRelocatedDynamicMessage(Object message) th
}

/**
* Example method that takes an incoming message, converts it to a relocated one, prints it as
* JSON using the relocated JsonFormat, and attaches it as a span attribute.
* Method that takes an incoming message, converts it to a relocated one, prints it as JSON using
* the relocated JsonFormat
*
* @param message The incoming (unrelocated) protobuf message.
* @param span The span to which to attach the attribute.
* @param key The attribute key.
*/
public static void addConvertedMessageAttribute(
Object message, Span span, AttributeKey<String> key) {
public static String getMessage(Message message) {
try {
// Convert the unrelocated message into a relocated DynamicMessage.
DynamicMessage relocatedMessage = convertToRelocatedDynamicMessage(message);
Expand All @@ -94,11 +85,10 @@ public static void addConvertedMessageAttribute(
JsonFormat.Printer relocatedPrinter = JsonFormat.printer();
String jsonOutput = relocatedPrinter.print(relocatedMessage);

// Set the JSON output as a span attribute.
span.setAttribute(key, jsonOutput);
return jsonOutput;
} catch (Exception e) {
System.err.println("Failed to convert message via byte-array round-trip: " + e.getMessage());
e.printStackTrace();
log.error("Failed to convert message with relocated protobuf message: {}", e.getMessage());
}
return "";
}
}