Add Marshalers for profiling signal type (#6565)

This commit is contained in:
Jonathan Halliday 2024-07-23 15:28:12 +01:00 committed by GitHub
parent 468b528956
commit 26b3d41d72
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 1352 additions and 0 deletions

View File

@ -81,6 +81,11 @@ final class JsonSerializer extends Serializer {
generator.writeString(Long.toString(value));
}
@Override
public void writeUInt64(ProtoFieldInfo field, long value) throws IOException {
generator.writeStringField(field.getJsonName(), Long.toString(value));
}
@Override
protected void writeFixed32(ProtoFieldInfo field, int value) throws IOException {
generator.writeNumberField(field.getJsonName(), value);

View File

@ -129,6 +129,26 @@ public final class MarshalerUtil {
return field.getTagSize() + CodedOutputStream.computeUInt32SizeNoTag(payloadSize) + payloadSize;
}
/**
* Returns the size of a repeated uint64 field.
*
* <p>Packed repeated fields contain the tag, an integer representing the incoming payload size,
* and an actual payload of repeated varints.
*/
public static int sizeRepeatedUInt64(ProtoFieldInfo field, List<Long> values) {
if (values.isEmpty()) {
return 0;
}
int payloadSize = 0;
for (long v : values) {
payloadSize += CodedOutputStream.computeUInt64SizeNoTag(v);
}
// tag size + payload indicator size + actual payload size
return field.getTagSize() + CodedOutputStream.computeUInt32SizeNoTag(payloadSize) + payloadSize;
}
/**
* Returns the size of a repeated uint64 field.
*
@ -154,6 +174,46 @@ public final class MarshalerUtil {
return field.getTagSize() + CodedOutputStream.computeUInt32SizeNoTag(payloadSize) + payloadSize;
}
/**
* Returns the size of a repeated int64 field.
*
* <p>Packed repeated fields contain the tag, an integer representing the incoming payload size,
* and an actual payload of repeated varints.
*/
public static int sizeRepeatedInt64(ProtoFieldInfo field, long[] values) {
if (values.length == 0) {
return 0;
}
int payloadSize = 0;
for (long v : values) {
payloadSize += CodedOutputStream.computeInt64SizeNoTag(v);
}
// tag size + payload indicator size + actual payload size
return field.getTagSize() + CodedOutputStream.computeUInt32SizeNoTag(payloadSize) + payloadSize;
}
/**
* Returns the size of a repeated int64 field.
*
* <p>Packed repeated fields contain the tag, an integer representing the incoming payload size,
* and an actual payload of repeated varints.
*/
public static int sizeRepeatedInt64(ProtoFieldInfo field, List<Long> values) {
if (values.isEmpty()) {
return 0;
}
int payloadSize = 0;
for (long v : values) {
payloadSize += CodedOutputStream.computeInt64SizeNoTag(v);
}
// tag size + payload indicator size + actual payload size
return field.getTagSize() + CodedOutputStream.computeUInt32SizeNoTag(payloadSize) + payloadSize;
}
/** Returns the size of a repeated double field. */
public static int sizeRepeatedDouble(ProtoFieldInfo field, List<Double> values) {
// Same as fixed64.
@ -207,6 +267,14 @@ public final class MarshalerUtil {
return field.getTagSize() + CodedOutputStream.computeInt64SizeNoTag(message);
}
/** Returns the size of a uint64 field. */
public static int sizeUInt64(ProtoFieldInfo field, long message) {
if (message == 0) {
return 0;
}
return field.getTagSize() + CodedOutputStream.computeUInt64SizeNoTag(message);
}
/** Returns the size of a uint32 field. */
public static int sizeUInt32(ProtoFieldInfo field, int message) {
if (message == 0) {

View File

@ -108,6 +108,12 @@ final class ProtoSerializer extends Serializer implements AutoCloseable {
output.writeInt64NoTag(value);
}
@Override
public void writeUInt64(ProtoFieldInfo field, long value) throws IOException {
output.writeUInt32NoTag(field.getTag());
output.writeUInt64NoTag(value);
}
@Override
protected void writeFixed64(ProtoFieldInfo field, long value) throws IOException {
output.writeUInt32NoTag(field.getTag());

View File

@ -139,9 +139,20 @@ public abstract class Serializer implements AutoCloseable {
writeInt64(field, value);
}
/** Serializes a protobuf {@code uint64} field. */
public void serializeUInt64(ProtoFieldInfo field, long value) throws IOException {
if (value == 0) {
return;
}
writeUInt64(field, value);
}
/** Writes a protobuf {@code int64} field, even if it matches the default value. */
public abstract void writeInt64(ProtoFieldInfo field, long value) throws IOException;
/** Writes a protobuf {@code uint64} field, even if it matches the default value. */
public abstract void writeUInt64(ProtoFieldInfo field, long value) throws IOException;
/** Serializes a protobuf {@code fixed64} field. */
public void serializeFixed64(ProtoFieldInfo field, long value) throws IOException {
if (value == 0) {
@ -340,6 +351,24 @@ public abstract class Serializer implements AutoCloseable {
writeEndRepeatedVarint();
}
/** Serializes a {@code repeated uint64} field. */
public void serializeRepeatedUInt64(ProtoFieldInfo field, List<Long> values) throws IOException {
if (values.isEmpty()) {
return;
}
int payloadSize = 0;
for (long v : values) {
payloadSize += CodedOutputStream.computeUInt64SizeNoTag(v);
}
writeStartRepeatedVarint(field, payloadSize);
for (long value : values) {
writeUInt64Value(value);
}
writeEndRepeatedVarint();
}
/**
* Serializes a {@code repeated uint64} field.
*
@ -366,6 +395,24 @@ public abstract class Serializer implements AutoCloseable {
writeEndRepeatedVarint();
}
/** Serializes a {@code repeated int64} field. */
public void serializeRepeatedInt64(ProtoFieldInfo field, List<Long> values) throws IOException {
if (values.isEmpty()) {
return;
}
int payloadSize = 0;
for (long v : values) {
payloadSize += CodedOutputStream.computeInt64SizeNoTag(v);
}
writeStartRepeatedVarint(field, payloadSize);
for (long value : values) {
writeUInt64Value(value);
}
writeEndRepeatedVarint();
}
/** Serializes a {@code repeated double} field. */
public void serializeRepeatedDouble(ProtoFieldInfo field, List<Double> values)
throws IOException {

View File

@ -42,6 +42,7 @@ wire {
"opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest",
"opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest",
"opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest",
"opentelemetry.proto.collector.profiles.v1experimental.ExportProfilesServiceRequest"
)
custom {

View File

@ -9,8 +9,15 @@ plugins {
description = "OpenTelemetry - Profiles Exporter"
otelJava.moduleName.set("io.opentelemetry.exporter.otlp.profiles")
val versions: Map<String, String> by project
dependencies {
api(project(":sdk:common"))
api(project(":exporters:common"))
implementation(project(":exporters:otlp:common"))
annotationProcessor("com.google.auto.value:auto-value")
testImplementation("com.fasterxml.jackson.core:jackson-databind")
testImplementation("com.google.protobuf:protobuf-java-util")
testImplementation("io.opentelemetry.proto:opentelemetry-proto")
}

View File

@ -0,0 +1,66 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.otlp.profiles;
import io.opentelemetry.exporter.internal.marshal.MarshalerUtil;
import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize;
import io.opentelemetry.exporter.internal.marshal.Serializer;
import io.opentelemetry.proto.profiles.v1experimental.internal.AttributeUnit;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
final class AttributeUnitMarshaler extends MarshalerWithSize {
private static final AttributeUnitMarshaler[] EMPTY_REPEATED = new AttributeUnitMarshaler[0];
private final long attributeKey;
private final long unitIndex;
static AttributeUnitMarshaler create(AttributeUnitData attributeUnitData) {
return new AttributeUnitMarshaler(
attributeUnitData.getAttributeKey(), attributeUnitData.getUnitIndex());
}
static AttributeUnitMarshaler[] createRepeated(List<AttributeUnitData> items) {
if (items.isEmpty()) {
return EMPTY_REPEATED;
}
AttributeUnitMarshaler[] attributeUnitMarshalers = new AttributeUnitMarshaler[items.size()];
items.forEach(
item ->
new Consumer<AttributeUnitData>() {
int index = 0;
@Override
public void accept(AttributeUnitData attributeUnitData) {
attributeUnitMarshalers[index++] = AttributeUnitMarshaler.create(attributeUnitData);
}
});
return attributeUnitMarshalers;
}
private AttributeUnitMarshaler(long attributeKey, long unitIndex) {
super(calculateSize(attributeKey, unitIndex));
this.attributeKey = attributeKey;
this.unitIndex = unitIndex;
}
@Override
protected void writeTo(Serializer output) throws IOException {
output.serializeInt64(AttributeUnit.ATTRIBUTE_KEY, attributeKey);
output.serializeInt64(AttributeUnit.UNIT, unitIndex);
}
private static int calculateSize(long attributeKey, long unitIndex) {
int size;
size = 0;
size += MarshalerUtil.sizeInt64(AttributeUnit.ATTRIBUTE_KEY, attributeKey);
size += MarshalerUtil.sizeInt64(AttributeUnit.UNIT, unitIndex);
return size;
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.otlp.profiles;
import io.opentelemetry.exporter.internal.marshal.MarshalerUtil;
import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize;
import io.opentelemetry.exporter.internal.marshal.Serializer;
import io.opentelemetry.proto.profiles.v1experimental.internal.Function;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
final class FunctionMarshaler extends MarshalerWithSize {
private static final FunctionMarshaler[] EMPTY_REPEATED = new FunctionMarshaler[0];
private final long nameIndex;
private final long systemNameIndex;
private final long filenameIndex;
private final long startLine;
static FunctionMarshaler create(FunctionData functionData) {
return new FunctionMarshaler(
functionData.getNameIndex(),
functionData.getSystemNameIndex(),
functionData.getFilenameIndex(),
functionData.getStartLine());
}
static FunctionMarshaler[] createRepeated(List<FunctionData> items) {
if (items.isEmpty()) {
return EMPTY_REPEATED;
}
FunctionMarshaler[] functionMarshalers = new FunctionMarshaler[items.size()];
items.forEach(
item ->
new Consumer<FunctionData>() {
int index = 0;
@Override
public void accept(FunctionData functionData) {
functionMarshalers[index++] = FunctionMarshaler.create(functionData);
}
});
return functionMarshalers;
}
private FunctionMarshaler(
long nameIndex, long systemNameIndex, long filenameIndex, long startLine) {
super(calculateSize(nameIndex, systemNameIndex, filenameIndex, startLine));
this.nameIndex = nameIndex;
this.systemNameIndex = systemNameIndex;
this.filenameIndex = filenameIndex;
this.startLine = startLine;
}
@Override
protected void writeTo(Serializer output) throws IOException {
output.serializeInt64(Function.NAME, nameIndex);
output.serializeInt64(Function.SYSTEM_NAME, systemNameIndex);
output.serializeInt64(Function.FILENAME, filenameIndex);
output.serializeInt64(Function.START_LINE, startLine);
}
private static int calculateSize(
long nameIndex, long systemNameIndex, long filenameIndex, long startLine) {
int size = 0;
size += MarshalerUtil.sizeInt64(Function.NAME, nameIndex);
size += MarshalerUtil.sizeInt64(Function.SYSTEM_NAME, systemNameIndex);
size += MarshalerUtil.sizeInt64(Function.FILENAME, filenameIndex);
size += MarshalerUtil.sizeInt64(Function.START_LINE, startLine);
return size;
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.otlp.profiles;
import io.opentelemetry.exporter.internal.marshal.MarshalerUtil;
import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize;
import io.opentelemetry.exporter.internal.marshal.Serializer;
import io.opentelemetry.proto.profiles.v1experimental.internal.Line;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
final class LineMarshaler extends MarshalerWithSize {
private static final LineMarshaler[] EMPTY_REPEATED = new LineMarshaler[0];
private final long functionIndex;
private final long line;
private final long column;
static LineMarshaler create(LineData lineData) {
return new LineMarshaler(lineData.getFunctionIndex(), lineData.getLine(), lineData.getColumn());
}
static LineMarshaler[] createRepeated(List<LineData> items) {
if (items.isEmpty()) {
return EMPTY_REPEATED;
}
LineMarshaler[] lineMarshalers = new LineMarshaler[items.size()];
items.forEach(
item ->
new Consumer<LineData>() {
int index = 0;
@Override
public void accept(LineData lineData) {
lineMarshalers[index++] = LineMarshaler.create(lineData);
}
});
return lineMarshalers;
}
private LineMarshaler(long functionIndex, long line, long column) {
super(calculateSize(functionIndex, line, column));
this.functionIndex = functionIndex;
this.line = line;
this.column = column;
}
@Override
protected void writeTo(Serializer output) throws IOException {
output.serializeUInt64(Line.FUNCTION_INDEX, functionIndex);
output.serializeInt64(Line.LINE, line);
output.serializeInt64(Line.COLUMN, column);
}
private static int calculateSize(long functionIndex, long line, long column) {
int size = 0;
size += MarshalerUtil.sizeUInt64(Line.FUNCTION_INDEX, functionIndex);
size += MarshalerUtil.sizeInt64(Line.LINE, line);
size += MarshalerUtil.sizeInt64(Line.COLUMN, column);
return size;
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.otlp.profiles;
import io.opentelemetry.api.internal.OtelEncodingUtils;
import io.opentelemetry.api.trace.SpanId;
import io.opentelemetry.api.trace.TraceId;
import io.opentelemetry.exporter.internal.marshal.MarshalerUtil;
import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize;
import io.opentelemetry.exporter.internal.marshal.Serializer;
import io.opentelemetry.proto.profiles.v1experimental.internal.Link;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
final class LinkMarshaler extends MarshalerWithSize {
private static final LinkMarshaler[] EMPTY_REPEATED = new LinkMarshaler[0];
private final byte[] traceId;
private final byte[] spanId;
static LinkMarshaler create(LinkData linkData) {
// in tracing this conversion is handled by utility methods on SpanContext,
// but we don't have a SpanContext here...
byte[] traceId = OtelEncodingUtils.bytesFromBase16(linkData.getTraceId(), TraceId.getLength());
byte[] spanId = OtelEncodingUtils.bytesFromBase16(linkData.getSpanId(), SpanId.getLength());
return new LinkMarshaler(traceId, spanId);
}
static LinkMarshaler[] createRepeated(List<LinkData> items) {
if (items.isEmpty()) {
return EMPTY_REPEATED;
}
LinkMarshaler[] linkMarshalers = new LinkMarshaler[items.size()];
items.forEach(
item ->
new Consumer<LinkData>() {
int index = 0;
@Override
public void accept(LinkData linkData) {
linkMarshalers[index++] = LinkMarshaler.create(linkData);
}
});
return linkMarshalers;
}
private LinkMarshaler(byte[] traceId, byte[] spanId) {
super(calculateSize(traceId, spanId));
this.traceId = traceId;
this.spanId = spanId;
}
@Override
protected void writeTo(Serializer output) throws IOException {
output.serializeBytes(Link.TRACE_ID, traceId);
output.serializeBytes(Link.SPAN_ID, spanId);
}
private static int calculateSize(byte[] traceId, byte[] spanId) {
int size = 0;
size += MarshalerUtil.sizeBytes(Link.TRACE_ID, traceId);
size += MarshalerUtil.sizeBytes(Link.SPAN_ID, spanId);
return size;
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.otlp.profiles;
import io.opentelemetry.exporter.internal.marshal.MarshalerUtil;
import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize;
import io.opentelemetry.exporter.internal.marshal.Serializer;
import io.opentelemetry.proto.profiles.v1experimental.internal.Location;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
final class LocationMarshaler extends MarshalerWithSize {
private static final LocationMarshaler[] EMPTY_REPEATED = new LocationMarshaler[0];
private final long mappingIndex;
private final long address;
private final LineMarshaler[] lineMarshalers;
private final boolean isFolded;
private final int typeIndex;
private final List<Long> attributes;
static LocationMarshaler create(LocationData locationData) {
return new LocationMarshaler(
locationData.getMappingIndex(),
locationData.getAddress(),
LineMarshaler.createRepeated(locationData.getLines()),
locationData.isFolded(),
locationData.getTypeIndex(),
locationData.getAttributes());
}
static LocationMarshaler[] createRepeated(List<LocationData> items) {
if (items.isEmpty()) {
return EMPTY_REPEATED;
}
LocationMarshaler[] locationMarshalers = new LocationMarshaler[items.size()];
items.forEach(
item ->
new Consumer<LocationData>() {
int index = 0;
@Override
public void accept(LocationData locationData) {
locationMarshalers[index++] = LocationMarshaler.create(locationData);
}
});
return locationMarshalers;
}
private LocationMarshaler(
long mappingIndex,
long address,
LineMarshaler[] lineMarshalers,
boolean isFolded,
int typeIndex,
List<Long> attributes) {
super(calculateSize(mappingIndex, address, lineMarshalers, isFolded, typeIndex, attributes));
this.mappingIndex = mappingIndex;
this.address = address;
this.lineMarshalers = lineMarshalers;
this.isFolded = isFolded;
this.typeIndex = typeIndex;
this.attributes = attributes;
}
@Override
protected void writeTo(Serializer output) throws IOException {
output.serializeUInt64(Location.MAPPING_INDEX, mappingIndex);
output.serializeUInt64(Location.ADDRESS, address);
output.serializeRepeatedMessage(Location.LINE, lineMarshalers);
output.serializeBool(Location.IS_FOLDED, isFolded);
output.serializeUInt32(Location.TYPE_INDEX, typeIndex);
output.serializeRepeatedUInt64(Location.ATTRIBUTES, attributes);
}
private static int calculateSize(
long mappingIndex,
long address,
LineMarshaler[] lineMarshalers,
boolean isFolded,
int typeIndex,
List<Long> attributes) {
int size = 0;
size += MarshalerUtil.sizeUInt64(Location.MAPPING_INDEX, mappingIndex);
size += MarshalerUtil.sizeUInt64(Location.ADDRESS, address);
size += MarshalerUtil.sizeRepeatedMessage(Location.LINE, lineMarshalers);
size += MarshalerUtil.sizeBool(Location.IS_FOLDED, isFolded);
size += MarshalerUtil.sizeUInt32(Location.TYPE_INDEX, typeIndex);
size += MarshalerUtil.sizeRepeatedUInt64(Location.ATTRIBUTES, attributes);
return size;
}
}

View File

@ -0,0 +1,156 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.otlp.profiles;
import io.opentelemetry.exporter.internal.marshal.MarshalerUtil;
import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize;
import io.opentelemetry.exporter.internal.marshal.ProtoEnumInfo;
import io.opentelemetry.exporter.internal.marshal.Serializer;
import io.opentelemetry.proto.profiles.v1experimental.internal.BuildIdKind;
import io.opentelemetry.proto.profiles.v1experimental.internal.Mapping;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
final class MappingMarshaler extends MarshalerWithSize {
private static final MappingMarshaler[] EMPTY_REPEATED = new MappingMarshaler[0];
private final long memoryStart;
private final long memoryLimit;
private final long fileOffset;
private final long filenameIndex;
private final long buildIdIndex;
private final ProtoEnumInfo buildIdKind;
private final List<Long> attributeIndices;
private final boolean hasFunctions;
private final boolean hasFilenames;
private final boolean hasLineNumbers;
private final boolean hasInlineFrames;
static MappingMarshaler create(MappingData mappingData) {
ProtoEnumInfo buildKind = BuildIdKind.BUILD_ID_LINKER;
switch (mappingData.getBuildIdKind()) {
case LINKER:
buildKind = BuildIdKind.BUILD_ID_LINKER;
break;
case BINARY_HASH:
buildKind = BuildIdKind.BUILD_ID_BINARY_HASH;
break;
}
return new MappingMarshaler(
mappingData.getMemoryStart(),
mappingData.getMemoryLimit(),
mappingData.getFileOffset(),
mappingData.getFilenameIndex(),
mappingData.getBuildIdIndex(),
buildKind,
mappingData.getAttributeIndices(),
mappingData.hasFunctions(),
mappingData.hasFilenames(),
mappingData.hasLineNumbers(),
mappingData.hasInlineFrames());
}
static MappingMarshaler[] createRepeated(List<MappingData> items) {
if (items.isEmpty()) {
return EMPTY_REPEATED;
}
MappingMarshaler[] mappingMarshalers = new MappingMarshaler[items.size()];
items.forEach(
item ->
new Consumer<MappingData>() {
int index = 0;
@Override
public void accept(MappingData mappingData) {
mappingMarshalers[index++] = MappingMarshaler.create(mappingData);
}
});
return mappingMarshalers;
}
private MappingMarshaler(
long memoryStart,
long memoryLimit,
long fileOffset,
long filenameIndex,
long buildIdIndex,
ProtoEnumInfo buildIdKind,
List<Long> attributeIndices,
boolean hasFunctions,
boolean hasFilenames,
boolean hasLineNumbers,
boolean hasInlineFrames) {
super(
calculateSize(
memoryStart,
memoryLimit,
fileOffset,
filenameIndex,
buildIdIndex,
buildIdKind,
attributeIndices,
hasFunctions,
hasFilenames,
hasLineNumbers,
hasInlineFrames));
this.memoryStart = memoryStart;
this.memoryLimit = memoryLimit;
this.fileOffset = fileOffset;
this.filenameIndex = filenameIndex;
this.buildIdIndex = buildIdIndex;
this.buildIdKind = buildIdKind;
this.attributeIndices = attributeIndices;
this.hasFunctions = hasFunctions;
this.hasFilenames = hasFilenames;
this.hasLineNumbers = hasLineNumbers;
this.hasInlineFrames = hasInlineFrames;
}
@Override
protected void writeTo(Serializer output) throws IOException {
output.serializeUInt64(Mapping.MEMORY_START, memoryStart);
output.serializeUInt64(Mapping.MEMORY_LIMIT, memoryLimit);
output.serializeUInt64(Mapping.FILE_OFFSET, fileOffset);
output.serializeInt64(Mapping.FILENAME, filenameIndex);
output.serializeInt64(Mapping.BUILD_ID, buildIdIndex);
output.serializeEnum(Mapping.BUILD_ID_KIND, buildIdKind);
output.serializeRepeatedUInt64(Mapping.ATTRIBUTES, attributeIndices);
output.serializeBool(Mapping.HAS_FUNCTIONS, hasFunctions);
output.serializeBool(Mapping.HAS_FILENAMES, hasFilenames);
output.serializeBool(Mapping.HAS_LINE_NUMBERS, hasLineNumbers);
output.serializeBool(Mapping.HAS_INLINE_FRAMES, hasInlineFrames);
}
private static int calculateSize(
long memoryStart,
long memoryLimit,
long fileOffset,
long filenameIndex,
long buildIdIndex,
ProtoEnumInfo buildIdKind,
List<Long> attributeIndices,
boolean hasFunctions,
boolean hasFilenames,
boolean hasLineNumbers,
boolean hasInlineFrames) {
int size = 0;
size += MarshalerUtil.sizeUInt64(Mapping.MEMORY_START, memoryStart);
size += MarshalerUtil.sizeUInt64(Mapping.MEMORY_LIMIT, memoryLimit);
size += MarshalerUtil.sizeUInt64(Mapping.FILE_OFFSET, fileOffset);
size += MarshalerUtil.sizeInt64(Mapping.FILENAME, filenameIndex);
size += MarshalerUtil.sizeInt64(Mapping.BUILD_ID, buildIdIndex);
size += MarshalerUtil.sizeEnum(Mapping.BUILD_ID_KIND, buildIdKind);
size += MarshalerUtil.sizeRepeatedUInt64(Mapping.ATTRIBUTES, attributeIndices);
size += MarshalerUtil.sizeBool(Mapping.HAS_FUNCTIONS, hasFunctions);
size += MarshalerUtil.sizeBool(Mapping.HAS_FILENAMES, hasFilenames);
size += MarshalerUtil.sizeBool(Mapping.HAS_LINE_NUMBERS, hasLineNumbers);
size += MarshalerUtil.sizeBool(Mapping.HAS_INLINE_FRAMES, hasInlineFrames);
return size;
}
}

View File

@ -0,0 +1,208 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.otlp.profiles;
import io.opentelemetry.exporter.internal.marshal.MarshalerUtil;
import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize;
import io.opentelemetry.exporter.internal.marshal.Serializer;
import io.opentelemetry.exporter.internal.otlp.KeyValueMarshaler;
import io.opentelemetry.proto.profiles.v1experimental.internal.Profile;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
final class ProfileMarshaler extends MarshalerWithSize {
private final ValueTypeMarshaler[] sampleTypeMarshalers;
private final SampleMarshaler[] sampleMarshalers;
private final MappingMarshaler[] mappingMarshalers;
private final LocationMarshaler[] locationMarshalers;
private final List<Long> locationIndices;
private final FunctionMarshaler[] functionMarshalers;
private final KeyValueMarshaler[] attributeMarshalers;
private final AttributeUnitMarshaler[] attributeUnitMarshalers;
private final LinkMarshaler[] linkMarshalers;
private final byte[][] stringTable;
private final long dropFrames;
private final long keepFrames;
private final long timeNanos;
private final long durationNanos;
private final ValueTypeMarshaler periodTypeMarshaler;
private final long period;
private final List<Long> comment;
private final long defaultSampleType;
static ProfileMarshaler create(ProfileData profileData) {
ValueTypeMarshaler[] sampleTypeMarshalers =
ValueTypeMarshaler.createRepeated(profileData.getSampleTypes());
SampleMarshaler[] sampleMarshalers = SampleMarshaler.createRepeated(profileData.getSamples());
MappingMarshaler[] mappingMarshalers =
MappingMarshaler.createRepeated(profileData.getMappings());
LocationMarshaler[] locationMarshalers =
LocationMarshaler.createRepeated(profileData.getLocations());
FunctionMarshaler[] functionMarshalers =
FunctionMarshaler.createRepeated(profileData.getFunctions());
KeyValueMarshaler[] attributeMarshalers =
KeyValueMarshaler.createForAttributes(profileData.getAttributes());
AttributeUnitMarshaler[] attributeUnitsMarshalers =
AttributeUnitMarshaler.createRepeated(profileData.getAttributeUnits());
LinkMarshaler[] linkMarshalers = LinkMarshaler.createRepeated(profileData.getLinks());
ValueTypeMarshaler periodTypeMarshaler = ValueTypeMarshaler.create(profileData.getPeriodType());
byte[][] convertedStrings = new byte[profileData.getStringTable().size()][];
for (int i = 0; i < profileData.getStringTable().size(); i++) {
convertedStrings[i] = profileData.getStringTable().get(i).getBytes(StandardCharsets.UTF_8);
}
return new ProfileMarshaler(
sampleTypeMarshalers,
sampleMarshalers,
mappingMarshalers,
locationMarshalers,
profileData.getLocationIndices(),
functionMarshalers,
attributeMarshalers,
attributeUnitsMarshalers,
linkMarshalers,
convertedStrings,
profileData.getDropFrames(),
profileData.getKeepFrames(),
profileData.getTimeNanos(),
profileData.getDurationNanos(),
periodTypeMarshaler,
profileData.getPeriod(),
profileData.getComment(),
profileData.getDefaultSampleType());
}
private ProfileMarshaler(
ValueTypeMarshaler[] sampleTypeMarshalers,
SampleMarshaler[] sampleMarshalers,
MappingMarshaler[] mappingMarshalers,
LocationMarshaler[] locationMarshalers,
List<Long> locationIndices,
FunctionMarshaler[] functionMarshalers,
KeyValueMarshaler[] attributeMarshalers,
AttributeUnitMarshaler[] attributeUnitMarshalers,
LinkMarshaler[] linkMarshalers,
byte[][] stringTableUtf8,
long dropFrames,
long keepFrames,
long timeNanos,
long durationNanos,
ValueTypeMarshaler periodTypeMarshaler,
long period,
List<Long> comment,
long defaultSampleType) {
super(
calculateSize(
sampleTypeMarshalers,
sampleMarshalers,
mappingMarshalers,
locationMarshalers,
locationIndices,
functionMarshalers,
attributeMarshalers,
attributeUnitMarshalers,
linkMarshalers,
stringTableUtf8,
dropFrames,
keepFrames,
timeNanos,
durationNanos,
periodTypeMarshaler,
period,
comment,
defaultSampleType));
this.sampleTypeMarshalers = sampleTypeMarshalers;
this.sampleMarshalers = sampleMarshalers;
this.mappingMarshalers = mappingMarshalers;
this.locationMarshalers = locationMarshalers;
this.locationIndices = locationIndices;
this.functionMarshalers = functionMarshalers;
this.attributeMarshalers = attributeMarshalers;
this.attributeUnitMarshalers = attributeUnitMarshalers;
this.linkMarshalers = linkMarshalers;
this.stringTable = stringTableUtf8;
this.dropFrames = dropFrames;
this.keepFrames = keepFrames;
this.timeNanos = timeNanos;
this.durationNanos = durationNanos;
this.periodTypeMarshaler = periodTypeMarshaler;
this.period = period;
this.comment = comment;
this.defaultSampleType = defaultSampleType;
}
@Override
protected void writeTo(Serializer output) throws IOException {
output.serializeRepeatedMessage(Profile.SAMPLE_TYPE, sampleTypeMarshalers);
output.serializeRepeatedMessage(Profile.SAMPLE, sampleMarshalers);
output.serializeRepeatedMessage(Profile.MAPPING, mappingMarshalers);
output.serializeRepeatedMessage(Profile.LOCATION, locationMarshalers);
output.serializeRepeatedInt64(Profile.LOCATION_INDICES, locationIndices);
output.serializeRepeatedMessage(Profile.FUNCTION, functionMarshalers);
output.serializeRepeatedMessage(Profile.ATTRIBUTE_TABLE, attributeMarshalers);
output.serializeRepeatedMessage(Profile.ATTRIBUTE_UNITS, attributeUnitMarshalers);
output.serializeRepeatedMessage(Profile.LINK_TABLE, linkMarshalers);
for (byte[] i : stringTable) {
output.serializeString(Profile.STRING_TABLE, i);
}
output.serializeInt64(Profile.DROP_FRAMES, dropFrames);
output.serializeInt64(Profile.KEEP_FRAMES, keepFrames);
output.serializeInt64(Profile.TIME_NANOS, timeNanos);
output.serializeInt64(Profile.DURATION_NANOS, durationNanos);
output.serializeMessage(Profile.PERIOD_TYPE, periodTypeMarshaler);
output.serializeInt64(Profile.PERIOD, period);
output.serializeRepeatedInt64(Profile.COMMENT, comment);
output.serializeInt64(Profile.DEFAULT_SAMPLE_TYPE, defaultSampleType);
}
private static int calculateSize(
ValueTypeMarshaler[] sampleTypeMarshalers,
SampleMarshaler[] sampleMarshalers,
MappingMarshaler[] mappingMarshalers,
LocationMarshaler[] locationMarshalers,
List<Long> locationIndices,
FunctionMarshaler[] functionMarshalers,
KeyValueMarshaler[] attributeMarshalers,
AttributeUnitMarshaler[] attributeUnitMarshalers,
LinkMarshaler[] linkMarshalers,
byte[][] stringTable,
long dropFrames,
long keepFrames,
long timeNanos,
long durationNanos,
ValueTypeMarshaler periodTypeMarshaler,
long period,
List<Long> comment,
long defaultSampleType) {
int size;
size = 0;
size += MarshalerUtil.sizeRepeatedMessage(Profile.SAMPLE_TYPE, sampleTypeMarshalers);
size += MarshalerUtil.sizeRepeatedMessage(Profile.SAMPLE, sampleMarshalers);
size += MarshalerUtil.sizeRepeatedMessage(Profile.MAPPING, mappingMarshalers);
size += MarshalerUtil.sizeRepeatedMessage(Profile.LOCATION, locationMarshalers);
size += MarshalerUtil.sizeRepeatedInt64(Profile.LOCATION_INDICES, locationIndices);
size += MarshalerUtil.sizeRepeatedMessage(Profile.FUNCTION, functionMarshalers);
size += MarshalerUtil.sizeRepeatedMessage(Profile.ATTRIBUTE_TABLE, attributeMarshalers);
size += MarshalerUtil.sizeRepeatedMessage(Profile.ATTRIBUTE_UNITS, attributeUnitMarshalers);
size += MarshalerUtil.sizeRepeatedMessage(Profile.LINK_TABLE, linkMarshalers);
for (byte[] i : stringTable) {
size += MarshalerUtil.sizeBytes(Profile.STRING_TABLE, i);
}
size += MarshalerUtil.sizeInt64(Profile.DROP_FRAMES, dropFrames);
size += MarshalerUtil.sizeInt64(Profile.KEEP_FRAMES, keepFrames);
size += MarshalerUtil.sizeInt64(Profile.TIME_NANOS, timeNanos);
size += MarshalerUtil.sizeInt64(Profile.DURATION_NANOS, durationNanos);
size += MarshalerUtil.sizeMessage(Profile.PERIOD_TYPE, periodTypeMarshaler);
size += MarshalerUtil.sizeInt64(Profile.PERIOD, period);
size += MarshalerUtil.sizeRepeatedInt64(Profile.COMMENT, comment);
size += MarshalerUtil.sizeInt64(Profile.DEFAULT_SAMPLE_TYPE, defaultSampleType);
return size;
}
}

View File

@ -0,0 +1,115 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.otlp.profiles;
import io.opentelemetry.exporter.internal.marshal.MarshalerUtil;
import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize;
import io.opentelemetry.exporter.internal.marshal.Serializer;
import io.opentelemetry.proto.profiles.v1experimental.internal.Sample;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
final class SampleMarshaler extends MarshalerWithSize {
private static final SampleMarshaler[] EMPTY_REPEATED = new SampleMarshaler[0];
private final long locationsStartIndex;
private final long locationsLength;
private final int stacktraceIdIndex;
private final List<Long> values;
private final List<Long> attributes;
private final long link;
private final List<Long> timestamps;
static SampleMarshaler create(SampleData sampleData) {
return new SampleMarshaler(
sampleData.getLocationsStartIndex(),
sampleData.getLocationsLength(),
sampleData.getStacktraceIdIndex(),
sampleData.getValues(),
sampleData.getAttributes(),
sampleData.getLink(),
sampleData.getTimestamps());
}
static SampleMarshaler[] createRepeated(List<SampleData> items) {
if (items.isEmpty()) {
return EMPTY_REPEATED;
}
SampleMarshaler[] sampleMarshalers = new SampleMarshaler[items.size()];
items.forEach(
item ->
new Consumer<SampleData>() {
int index = 0;
@Override
public void accept(SampleData sampleData) {
sampleMarshalers[index++] = SampleMarshaler.create(sampleData);
}
});
return sampleMarshalers;
}
private SampleMarshaler(
long locationsStartIndex,
long locationsLength,
int stacktraceIdIndex,
List<Long> values,
List<Long> attributes,
long link,
List<Long> timestamps) {
super(
calculateSize(
locationsStartIndex,
locationsLength,
stacktraceIdIndex,
values,
attributes,
link,
timestamps));
this.locationsStartIndex = locationsStartIndex;
this.locationsLength = locationsLength;
this.stacktraceIdIndex = stacktraceIdIndex;
this.values = values;
this.attributes = attributes;
this.link = link;
this.timestamps = timestamps;
}
@Override
protected void writeTo(Serializer output) throws IOException {
output.serializeUInt64(Sample.LOCATIONS_START_INDEX, locationsStartIndex);
output.serializeUInt64(Sample.LOCATIONS_LENGTH, locationsLength);
output.serializeUInt32(Sample.STACKTRACE_ID_INDEX, stacktraceIdIndex);
output.serializeRepeatedInt64(Sample.VALUE, values);
output.serializeRepeatedUInt64(Sample.ATTRIBUTES, attributes);
output.serializeUInt64(Sample.LINK, link);
output.serializeRepeatedUInt64(Sample.TIMESTAMPS_UNIX_NANO, timestamps);
}
private static int calculateSize(
long locationsStartIndex,
long locationsLength,
int stacktraceIdIndex,
List<Long> values,
List<Long> attributes,
long link,
List<Long> timestamps) {
int size;
size = 0;
size += MarshalerUtil.sizeUInt64(Sample.LOCATIONS_START_INDEX, locationsStartIndex);
size += MarshalerUtil.sizeUInt64(Sample.LOCATIONS_LENGTH, locationsLength);
size += MarshalerUtil.sizeUInt32(Sample.STACKTRACE_ID_INDEX, stacktraceIdIndex);
size += MarshalerUtil.sizeRepeatedInt64(Sample.VALUE, values);
size += MarshalerUtil.sizeRepeatedUInt64(Sample.ATTRIBUTES, attributes);
size += MarshalerUtil.sizeUInt64(Sample.LINK, link);
size += MarshalerUtil.sizeRepeatedUInt64(Sample.TIMESTAMPS_UNIX_NANO, timestamps);
return size;
}
}

View File

@ -0,0 +1,84 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.otlp.profiles;
import io.opentelemetry.exporter.internal.marshal.MarshalerUtil;
import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize;
import io.opentelemetry.exporter.internal.marshal.ProtoEnumInfo;
import io.opentelemetry.exporter.internal.marshal.Serializer;
import io.opentelemetry.proto.profiles.v1experimental.internal.AggregationTemporality;
import io.opentelemetry.proto.profiles.v1experimental.internal.ValueType;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
final class ValueTypeMarshaler extends MarshalerWithSize {
private static final ValueTypeMarshaler[] EMPTY_REPEATED = new ValueTypeMarshaler[0];
private final long type;
private final long unit;
private final ProtoEnumInfo aggregationTemporality;
static ValueTypeMarshaler create(ValueTypeData valueTypeData) {
ProtoEnumInfo aggregationTemporality =
AggregationTemporality.AGGREGATION_TEMPORALITY_UNSPECIFIED;
if (valueTypeData.aggregationTemporality() != null) {
switch (valueTypeData.aggregationTemporality()) {
case DELTA:
aggregationTemporality = AggregationTemporality.AGGREGATION_TEMPORALITY_DELTA;
break;
case CUMULATIVE:
aggregationTemporality = AggregationTemporality.AGGREGATION_TEMPORALITY_CUMULATIVE;
break;
}
}
return new ValueTypeMarshaler(
valueTypeData.type(), valueTypeData.unit(), aggregationTemporality);
}
static ValueTypeMarshaler[] createRepeated(List<ValueTypeData> items) {
if (items.isEmpty()) {
return EMPTY_REPEATED;
}
ValueTypeMarshaler[] valueTypeMarshalers = new ValueTypeMarshaler[items.size()];
items.forEach(
item ->
new Consumer<ValueTypeData>() {
int index = 0;
@Override
public void accept(ValueTypeData valueTypeData) {
valueTypeMarshalers[index++] = ValueTypeMarshaler.create(valueTypeData);
}
});
return valueTypeMarshalers;
}
private ValueTypeMarshaler(long type, long unit, ProtoEnumInfo aggregationTemporality) {
super(calculateSize(type, unit, aggregationTemporality));
this.type = type;
this.unit = unit;
this.aggregationTemporality = aggregationTemporality;
}
@Override
protected void writeTo(Serializer output) throws IOException {
output.serializeInt64(ValueType.TYPE, type);
output.serializeInt64(ValueType.UNIT, unit);
output.serializeEnum(ValueType.AGGREGATION_TEMPORALITY, aggregationTemporality);
}
private static int calculateSize(long type, long unit, ProtoEnumInfo aggregationTemporality) {
int size;
size = 0;
size += MarshalerUtil.sizeInt64(ValueType.TYPE, type);
size += MarshalerUtil.sizeInt64(ValueType.UNIT, unit);
size += MarshalerUtil.sizeEnum(ValueType.AGGREGATION_TEMPORALITY, aggregationTemporality);
return size;
}
}

View File

@ -0,0 +1,273 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.otlp.profiles;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import com.google.protobuf.util.JsonFormat;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.exporter.internal.marshal.Marshaler;
import io.opentelemetry.exporter.otlp.internal.data.ImmutableAttributeUnitData;
import io.opentelemetry.exporter.otlp.internal.data.ImmutableFunctionData;
import io.opentelemetry.exporter.otlp.internal.data.ImmutableLineData;
import io.opentelemetry.exporter.otlp.internal.data.ImmutableLinkData;
import io.opentelemetry.exporter.otlp.internal.data.ImmutableLocationData;
import io.opentelemetry.exporter.otlp.internal.data.ImmutableMappingData;
import io.opentelemetry.exporter.otlp.internal.data.ImmutableProfileData;
import io.opentelemetry.exporter.otlp.internal.data.ImmutableSampleData;
import io.opentelemetry.exporter.otlp.internal.data.ImmutableValueTypeData;
import io.opentelemetry.proto.profiles.v1experimental.AttributeUnit;
import io.opentelemetry.proto.profiles.v1experimental.Function;
import io.opentelemetry.proto.profiles.v1experimental.Line;
import io.opentelemetry.proto.profiles.v1experimental.Link;
import io.opentelemetry.proto.profiles.v1experimental.Location;
import io.opentelemetry.proto.profiles.v1experimental.Mapping;
import io.opentelemetry.proto.profiles.v1experimental.Profile;
import io.opentelemetry.proto.profiles.v1experimental.Sample;
import io.opentelemetry.proto.profiles.v1experimental.ValueType;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
public class ProfilesRequestMarshalerTest {
@Test
void compareAttributeUnitMarshaling() {
AttributeUnitData input = ImmutableAttributeUnitData.create(1, 2);
AttributeUnit builderResult = AttributeUnit.newBuilder().setAttributeKey(1).setUnit(2).build();
AttributeUnit roundTripResult =
parse(AttributeUnit.getDefaultInstance(), AttributeUnitMarshaler.create(input));
assertThat(roundTripResult).isEqualTo(builderResult);
}
@Test
void compareFunctionMarshaling() {
FunctionData input = ImmutableFunctionData.create(1, 2, 3, 4);
Function builderResult =
Function.newBuilder().setName(1).setSystemName(2).setFilename(3).setStartLine(4).build();
Function roundTripResult =
parse(Function.getDefaultInstance(), FunctionMarshaler.create(input));
assertThat(roundTripResult).isEqualTo(builderResult);
}
@Test
void compareLineMarshaling() {
LineData input = ImmutableLineData.create(1, 2, 3);
Line builderResult = Line.newBuilder().setFunctionIndex(1).setLine(2).setColumn(3).build();
Line roundTripResult = parse(Line.getDefaultInstance(), LineMarshaler.create(input));
assertThat(roundTripResult).isEqualTo(builderResult);
}
@Test
void compareLinkMarshaling() {
String traceId = "0123456789abcdef0123456789abcdef";
String spanId = "fedcba9876543210";
LinkData input = ImmutableLinkData.create(traceId, spanId);
Link builderResult =
Link.newBuilder()
.setTraceId(ByteString.fromHex(traceId))
.setSpanId(ByteString.fromHex(spanId))
.build();
Link roundTripResult = parse(Link.getDefaultInstance(), LinkMarshaler.create(input));
assertThat(roundTripResult).isEqualTo(builderResult);
}
@Test
void compareLocationMarshaling() {
LocationData input =
ImmutableLocationData.create(1, 2, Collections.emptyList(), true, 3, listOf(5L, 6L));
Location builderResult =
Location.newBuilder()
.setMappingIndex(1)
.setAddress(2)
.setIsFolded(true)
.setTypeIndex(3)
.addAllAttributes(listOf(5L, 6L))
.build();
Location roundTripResult =
parse(Location.getDefaultInstance(), LocationMarshaler.create(input));
assertThat(roundTripResult).isEqualTo(builderResult);
}
@Test
void compareMappingMarshaling() {
MappingData input =
ImmutableMappingData.create(
1, 2, 3, 4, 5, BuildIdKind.LINKER, listOf(6L, 7L), true, true, true, true);
Mapping builderResult =
Mapping.newBuilder()
.setMemoryStart(1)
.setMemoryLimit(2)
.setFileOffset(3)
.setFilename(4)
.setBuildId(5)
.setBuildIdKind(
io.opentelemetry.proto.profiles.v1experimental.BuildIdKind.BUILD_ID_LINKER)
.addAllAttributes(listOf(6L, 7L))
.setHasFunctions(true)
.setHasFilenames(true)
.setHasLineNumbers(true)
.setHasInlineFrames(true)
.build();
Mapping roundTripResult = parse(Mapping.getDefaultInstance(), MappingMarshaler.create(input));
assertThat(roundTripResult).isEqualTo(builderResult);
}
@Test
void compareProfileMarshaling() {
ProfileData input =
ImmutableProfileData.create(
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
listOf(1L, 2L),
Collections.emptyList(),
Attributes.empty(),
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
3,
4,
5,
6,
ImmutableValueTypeData.create(1, 2, AggregationTemporality.CUMULATIVE),
7,
listOf(8L, 9L),
10);
Profile builderResult =
Profile.newBuilder()
.addAllLocationIndices(listOf(1L, 2L))
.setDropFrames(3)
.setKeepFrames(4)
.setTimeNanos(5)
.setDurationNanos(6)
.setPeriod(7)
.setPeriodType(
ValueType.newBuilder()
.setType(1)
.setUnit(2)
.setAggregationTemporality(
io.opentelemetry.proto.profiles.v1experimental.AggregationTemporality
.AGGREGATION_TEMPORALITY_CUMULATIVE)
.build())
.addAllComment(listOf(8L, 9L))
.setDefaultSampleType(10)
.build();
Profile roundTripResult = parse(Profile.getDefaultInstance(), ProfileMarshaler.create(input));
assertThat(roundTripResult).isEqualTo(builderResult);
}
@Test
void compareSampleMarshaling() {
SampleData input =
ImmutableSampleData.create(1, 2, 3, listOf(4L, 5L), listOf(6L, 7L), 8L, listOf(9L, 10L));
Sample builderResult =
Sample.newBuilder()
.setLocationsStartIndex(1)
.setLocationsLength(2)
.setStacktraceIdIndex(3)
.addAllValue(listOf(4L, 5L))
.addAllAttributes(listOf(6L, 7L))
.setLink(8)
.addAllTimestampsUnixNano(listOf(9L, 10L))
.build();
Sample roundTripResult = parse(Sample.getDefaultInstance(), SampleMarshaler.create(input));
assertThat(roundTripResult).isEqualTo(builderResult);
}
@Test
void compareValueTypeMarshaling() {
ValueTypeData input = ImmutableValueTypeData.create(1, 2, AggregationTemporality.CUMULATIVE);
ValueType builderResult =
ValueType.newBuilder()
.setType(1)
.setUnit(2)
.setAggregationTemporality(
io.opentelemetry.proto.profiles.v1experimental.AggregationTemporality
.AGGREGATION_TEMPORALITY_CUMULATIVE)
.build();
ValueType roundTripResult =
parse(ValueType.getDefaultInstance(), ValueTypeMarshaler.create(input));
assertThat(roundTripResult).isEqualTo(builderResult);
}
private static <T> List<T> listOf(T a, T b) {
ArrayList<T> list = new ArrayList<>();
list.add(a);
list.add(b);
return Collections.unmodifiableList(list);
}
@SuppressWarnings("unchecked")
private static <T extends Message> T parse(T prototype, Marshaler marshaler) {
byte[] serialized = toByteArray(marshaler);
T result;
try {
result = (T) prototype.newBuilderForType().mergeFrom(serialized).build();
} catch (InvalidProtocolBufferException e) {
throw new UncheckedIOException(e);
}
// Our marshaler should produce the exact same length of serialized output (for example, field
// default values are not outputted), so we check that here. The output itself may have slightly
// different ordering, mostly due to the way we don't output oneof values in field order all the
// tieme. If the lengths are equal and the resulting protos are equal, the marshaling is
// guaranteed to be valid.
assertThat(result.getSerializedSize()).isEqualTo(serialized.length);
// We don't compare JSON strings due to some differences (particularly serializing enums as
// numbers instead of names). This may improve in the future but what matters is what we produce
// can be parsed.
String json = toJson(marshaler);
Message.Builder builder = prototype.newBuilderForType();
try {
JsonFormat.parser().merge(json, builder);
} catch (InvalidProtocolBufferException e) {
throw new UncheckedIOException(e);
}
assertThat(builder.build()).isEqualTo(result);
return result;
}
private static byte[] toByteArray(Marshaler marshaler) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
marshaler.writeBinaryTo(bos);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return bos.toByteArray();
}
private static String toJson(Marshaler marshaler) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
marshaler.writeJsonTo(bos);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return new String(bos.toByteArray(), StandardCharsets.UTF_8);
}
}