From 8c1d24ad473cf459fb73e1321936b7b8a4775f79 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 28 Mar 2024 19:22:15 +0200 Subject: [PATCH 01/15] Low allocation OTLP marshaler --- .../api/internal/OtelEncodingUtils.java | 9 +- .../internal/marshal/CodedOutputStream.java | 4 +- .../internal/marshal/JsonSerializer.java | 48 +++- .../internal/marshal/MarshalerContext.java | 218 +++++++++++++++ .../internal/marshal/MarshalerUtil.java | 152 ++++++++++ .../internal/marshal/ProtoSerializer.java | 72 ++++- .../exporter/internal/marshal/Serializer.java | 82 +++++- .../internal/marshal/MarshalerUtilTest.java | 51 ++++ .../otlp/http/trace/OtlpHttpSpanExporter.java | 35 ++- .../trace/OtlpHttpSpanExporterBuilder.java | 6 +- exporters/otlp/common/build.gradle.kts | 1 + .../otlp/RequestMarshalBenchmarks.java | 45 ++- .../internal/otlp/RequestMarshalState.java | 4 + .../internal/otlp/BoolAnyValueMarshaler.java | 2 +- .../otlp/DoubleAnyValueMarshaler.java | 2 +- .../internal/otlp/IntAnyValueMarshaler.java | 2 +- .../internal/otlp/KeyValueMarshaler.java | 260 ++++++++++++++++++ .../otlp/StringAnyValueMarshaler.java | 15 + .../InstrumentationScopeSpansMarshaler.java | 32 +++ .../LowAllocationTraceRequestMarshaler.java | 153 +++++++++++ .../otlp/traces/ResourceSpansMarshaler.java | 110 ++++++++ .../otlp/traces/SpanEventMarshaler.java | 38 +++ .../otlp/traces/SpanLinkMarshaler.java | 39 +++ .../internal/otlp/traces/SpanMarshaler.java | 112 ++++++++ .../otlp/traces/SpanStatusMarshaler.java | 39 ++- ...owAllocationTraceRequestMarshalerTest.java | 71 +++++ .../otlp/traces/RequestMarshalState.java | 105 +++++++ 27 files changed, 1680 insertions(+), 27 deletions(-) create mode 100644 exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java create mode 100644 exporters/common/src/test/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtilTest.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java create mode 100644 exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshalerTest.java create mode 100644 exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/RequestMarshalState.java diff --git a/api/all/src/main/java/io/opentelemetry/api/internal/OtelEncodingUtils.java b/api/all/src/main/java/io/opentelemetry/api/internal/OtelEncodingUtils.java index ba8e99fe1c3..bb6a5484488 100644 --- a/api/all/src/main/java/io/opentelemetry/api/internal/OtelEncodingUtils.java +++ b/api/all/src/main/java/io/opentelemetry/api/internal/OtelEncodingUtils.java @@ -89,10 +89,15 @@ public static void longToBase16String(long value, char[] dest, int destOffset) { /** Returns the {@code byte[]} decoded from the given hex {@link CharSequence}. */ public static byte[] bytesFromBase16(CharSequence value, int length) { byte[] result = new byte[length / 2]; + bytesFromBase16(value, length, result); + return result; + } + + /** Fills {@code bytes} with bytes decoded from the given hex {@link CharSequence}. */ + public static void bytesFromBase16(CharSequence value, int length, byte[] bytes) { for (int i = 0; i < length; i += 2) { - result[i / 2] = byteFromBase16(value.charAt(i), value.charAt(i + 1)); + bytes[i / 2] = byteFromBase16(value.charAt(i), value.charAt(i + 1)); } - return result; } /** Fills {@code dest} with the hex encoding of {@code bytes}. */ diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/CodedOutputStream.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/CodedOutputStream.java index 8cc17a7834b..5c728e6817c 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/CodedOutputStream.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/CodedOutputStream.java @@ -213,7 +213,7 @@ static int computeInt32SizeNoTag(final int value) { } /** Compute the number of bytes that would be needed to encode a {@code uint32} field. */ - static int computeUInt32SizeNoTag(final int value) { + public static int computeUInt32SizeNoTag(final int value) { if ((value & (~0 << 7)) == 0) { return 1; } @@ -329,7 +329,7 @@ public static int computeByteArraySizeNoTag(final byte[] value) { return computeLengthDelimitedFieldSize(value.length); } - static int computeLengthDelimitedFieldSize(int fieldLength) { + public static int computeLengthDelimitedFieldSize(int fieldLength) { return computeUInt32SizeNoTag(fieldLength) + fieldLength; } diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java index f4745e68cba..654b09238a0 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java @@ -108,18 +108,24 @@ public void writeString(ProtoFieldInfo field, byte[] utf8Bytes) throws IOExcepti generator.writeString(new String(utf8Bytes, StandardCharsets.UTF_8)); } + @Override + public void writeString(ProtoFieldInfo field, String string, int utf8Length) throws IOException { + generator.writeFieldName(field.getJsonName()); + generator.writeString(string); + } + @Override public void writeBytes(ProtoFieldInfo field, byte[] value) throws IOException { generator.writeBinaryField(field.getJsonName(), value); } @Override - protected void writeStartMessage(ProtoFieldInfo field, int protoMessageSize) throws IOException { + public void writeStartMessage(ProtoFieldInfo field, int protoMessageSize) throws IOException { generator.writeObjectFieldStart(field.getJsonName()); } @Override - protected void writeEndMessage() throws IOException { + public void writeEndMessage() throws IOException { generator.writeEndObject(); } @@ -165,6 +171,44 @@ public void serializeRepeatedMessage( generator.writeEndArray(); } + @Override + public void serializeRepeatedMessage( + ProtoFieldInfo field, + List messages, + MarshalerContext context, + MessageConsumer consumer) + throws IOException { + generator.writeArrayFieldStart(field.getJsonName()); + for (int i = 0; i < messages.size(); i++) { + T message = messages.get(i); + generator.writeStartObject(); + consumer.accept(this, message, context); + generator.writeEndObject(); + } + generator.writeEndArray(); + } + + @Override + public void writeStartRepeated(ProtoFieldInfo field) throws IOException { + generator.writeArrayFieldStart(field.getJsonName()); + } + + @Override + public void writeEndRepeated() throws IOException { + generator.writeEndArray(); + } + + @Override + public void writeStartRepeatedElement(ProtoFieldInfo field, int protoMessageSize) + throws IOException { + generator.writeStartObject(); + } + + @Override + public void writeEndRepeatedElement() throws IOException { + generator.writeEndObject(); + } + // Not a field. void writeMessageValue(Marshaler message) throws IOException { generator.writeStartObject(); diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java new file mode 100644 index 00000000000..5e7a59d488e --- /dev/null +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java @@ -0,0 +1,218 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.marshal; + +import io.opentelemetry.api.trace.SpanId; +import io.opentelemetry.api.trace.TraceId; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javax.annotation.Nullable; + +/** + * Class for keeping marshaling state. The state consists of integers, that we call sizes, and + * objects, that we call data. Both integers and objects can be read from the state in the order + * they were added (first in, first out). Additionally, this class provides various pools and caches + * for objects that can be reused between marshalling attempts. + */ +public final class MarshalerContext { + public static final boolean MARSHAL_STRING_NO_ALLOCATION = true; + + private int[] sizes = new int[1024]; + private int sizeReadIndex; + private int sizeWriteIndex; + private Object[] data = new Object[1024]; + private int dataReadIndex; + private int dataWriteIndex; + + public boolean marshalStringNoAllocation() { + return MARSHAL_STRING_NO_ALLOCATION; + } + + public void addSize(int size) { + growSizeIfNeeded(); + sizes[sizeWriteIndex++] = size; + } + + public int addSize() { + growSizeIfNeeded(); + return sizeWriteIndex++; + } + + private void growSizeIfNeeded() { + if (sizeWriteIndex == sizes.length) { + int[] newSizes = new int[sizes.length * 2]; + sizes = newSizes; + } + } + + public void setSize(int index, int size) { + sizes[index] = size; + } + + public int getSize() { + return sizes[sizeReadIndex++]; + } + + public int addData() { + growDataIfNeeded(); + return dataWriteIndex++; + } + + public void addData(@Nullable Object o) { + growDataIfNeeded(); + data[dataWriteIndex++] = o; + } + + private void growDataIfNeeded() { + if (dataWriteIndex == data.length) { + Object[] newData = new Object[data.length * 2]; + System.arraycopy(data, 0, newData, 0, data.length); + data = newData; + } + } + + public byte[] getByteArray() { + return (byte[]) data[dataReadIndex++]; + } + + public String getString() { + return (String) data[dataReadIndex++]; + } + + public T getObject(Class type) { + return type.cast(data[dataReadIndex++]); + } + + public void setData(int index, Object value) { + data[index] = value; + } + + private final IdPool traceIdPool = new IdPool(TraceId.getLength() / 2); + + /** Returns a buffer that can be used to hold a trace id. */ + public byte[] getTraceIdBuffer() { + return traceIdPool.get(); + } + + private final IdPool spanIdPool = new IdPool(SpanId.getLength() / 2); + + /** Returns a buffer that can be used to hold a span id. */ + public byte[] getSpanIdBuffer() { + return spanIdPool.get(); + } + + private static class IdPool { + private final List pool = new ArrayList<>(); + int index; + final int idSize; + + IdPool(int idSize) { + this.idSize = idSize; + } + + byte[] get() { + if (index < pool.size()) { + return pool.get(index++); + } + byte[] result = new byte[idSize]; + pool.add(result); + index++; + + return result; + } + + void reset() { + index = 0; + } + } + + private final Pool> mapPool = new Pool<>(IdentityHashMap::new, Map::clear); + + /** Returns a pooled identity map. */ + @SuppressWarnings("unchecked") + public Map getIdentityMap() { + return (Map) mapPool.get(); + } + + private final Pool> listPool = new Pool<>(ArrayList::new, List::clear); + + /** Returns a pooled list. */ + @SuppressWarnings("unchecked") + public List getList() { + return (List) listPool.get(); + } + + private static class Pool { + private final List pool = new ArrayList<>(); + private int index; + private final Supplier factory; + private final Consumer clean; + + Pool(Supplier factory, Consumer clean) { + this.factory = factory; + this.clean = clean; + } + + T get() { + if (index < pool.size()) { + return pool.get(index++); + } + T result = factory.get(); + pool.add(result); + index++; + + return result; + } + + void reset() { + for (int i = 0; i < index; i++) { + clean.accept(pool.get(i)); + } + index = 0; + } + } + + /** Reset context so that serialization could be re-run. */ + public void resetReadIndex() { + sizeReadIndex = 0; + dataReadIndex = 0; + } + + /** Reset context so that it could be reused. */ + public void reset() { + sizeReadIndex = 0; + sizeWriteIndex = 0; + for (int i = 0; i < dataWriteIndex; i++) { + data[i] = null; + } + dataReadIndex = 0; + dataWriteIndex = 0; + + traceIdPool.reset(); + spanIdPool.reset(); + + mapPool.reset(); + listPool.reset(); + } + + private final Map, Object> instanceMap = new HashMap<>(); + + /** Returns cached instance produced by the given supplier. */ + @SuppressWarnings("unchecked") + public T getInstance(Class key, Supplier supplier) { + T result = (T) instanceMap.get(key); + if (result == null) { + result = supplier.get(); + instanceMap.put(key, result); + } + return result; + } +} diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java index 5abd24925a5..708bddeb488 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java @@ -20,6 +20,8 @@ import java.util.List; import java.util.Map; import java.util.function.Function; +import java.util.function.ToIntBiFunction; +import java.util.function.ToIntFunction; import javax.annotation.Nullable; /** @@ -70,6 +72,34 @@ Map>> groupByResourceAndScope( return result; } + /** Groups SDK items by resource and instrumentation scope. */ + public static + Map>> groupByResourceAndScope( + Collection dataList, + Function getResource, + Function getInstrumentationScope, + Function createMarshaler, + MarshalerContext context) { + Map>> result = context.getIdentityMap(); + for (T data : dataList) { + Resource resource = getResource.apply(data); + Map> scopeInfoListMap = result.get(resource); + if (scopeInfoListMap == null) { + scopeInfoListMap = context.getIdentityMap(); + result.put(resource, scopeInfoListMap); + } + InstrumentationScopeInfo instrumentationScopeInfo = getInstrumentationScope.apply(data); + List marshalerList = scopeInfoListMap.get(instrumentationScopeInfo); + if (marshalerList == null) { + marshalerList = context.getList(); + scopeInfoListMap.put(instrumentationScopeInfo, marshalerList); + } + marshalerList.add(createMarshaler.apply(data)); + } + + return result; + } + /** Preserialize into JSON format. */ public static String preserializeJsonFields(Marshaler marshaler) { if (!MarshalerUtil.JSON_AVAILABLE) { @@ -185,9 +215,51 @@ public static int sizeRepeatedMessage( return size; } + /** Returns the size of a repeated message field. */ + public static int sizeRepeatedMessage( + ProtoFieldInfo field, + ToIntBiFunction consumer, + List messages, + MarshalerContext context) { + if (messages.isEmpty()) { + return 0; + } + + int size = 0; + int fieldTagSize = field.getTagSize(); + for (int i = 0; i < messages.size(); i++) { + T message = messages.get(i); + int fieldSize = consumer.applyAsInt(context, message); + size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; + } + return size; + } + + /** Returns the size of a repeated message field. */ + public static int sizeRepeatedMessage( + ProtoFieldInfo field, ToIntFunction consumer, List messages) { + if (messages.isEmpty()) { + return 0; + } + + int size = 0; + int fieldTagSize = field.getTagSize(); + for (int i = 0; i < messages.size(); i++) { + T message = messages.get(i); + int fieldSize = consumer.applyAsInt(message); + size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; + } + return size; + } + /** Returns the size of a message field. */ public static int sizeMessage(ProtoFieldInfo field, Marshaler message) { int fieldSize = message.getBinarySerializedSize(); + return sizeMessage(field, fieldSize); + } + + /** Returns the size of a message field. */ + public static int sizeMessage(ProtoFieldInfo field, int fieldSize) { return field.getTagSize() + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; } @@ -278,6 +350,14 @@ public static int sizeBytes(ProtoFieldInfo field, byte[] message) { return field.getTagSize() + CodedOutputStream.computeByteArraySizeNoTag(message); } + /** Returns the size of a bytes field. */ + public static int sizeBytes(ProtoFieldInfo field, int length) { + if (length == 0) { + return 0; + } + return field.getTagSize() + CodedOutputStream.computeLengthDelimitedFieldSize(length); + } + /** Returns the size of a enum field. */ // Assumes OTLP always defines the first item in an enum with number 0, which it does and will. public static int sizeEnum(ProtoFieldInfo field, ProtoEnumInfo enumValue) { @@ -312,5 +392,77 @@ public static byte[] toBytes(@Nullable String value) { return value.getBytes(StandardCharsets.UTF_8); } + /** Returns the size of utf8 encoded string in bytes. */ + public static int getUtf8Size(String string) { + // return string.length(); + int size = 0; + for (int i = 0; i < string.length(); i++) { + char c = string.charAt(i); + if (c < 0x80) { + // 1 byte, 7 bits + size += 1; + } else if (c < 0x800) { + // 2 bytes, 11 bits + size += 2; + } else if (!Character.isSurrogate(c)) { + // 3 bytes, 16 bits + size += 3; + } else { + // 4 bytes, 21 bits + if (Character.isHighSurrogate(c) && i + 1 < string.length()) { + char d = string.charAt(i + 1); + if (Character.isLowSurrogate(d)) { + i += 1; + size += 4; + continue; + } + } + // invalid characters are replaced with ? + size += 1; + } + } + + return size; + } + + /** Write utf8 encoded string to output stream. */ + public static void writeUtf8(CodedOutputStream output, String string) throws IOException { + for (int i = 0; i < string.length(); i++) { + char c = string.charAt(i); + if (c < 0x80) { + // 1 byte, 7 bits + output.write((byte) c); + } else if (c < 0x800) { + // 2 bytes, 11 bits + output.write((byte) (0xc0 | (c >> 6))); + output.write((byte) (0x80 | (c & 0x3f))); + } else if (!Character.isSurrogate(c)) { + // 3 bytes, 16 bits + output.write((byte) (0xe0 | (c >> 12))); + output.write((byte) (0x80 | ((c >> 6) & 0x3f))); + output.write((byte) (0x80 | (c & 0x3f))); + } else { + // 4 bytes, 21 bits + int codePoint = -1; + if (Character.isHighSurrogate(c) && i + 1 < string.length()) { + char d = string.charAt(i + 1); + if (Character.isLowSurrogate(d)) { + codePoint = Character.toCodePoint(c, d); + } + } + // invalid character + if (codePoint == -1) { + output.write((byte) '?'); + } else { + output.write((byte) (0xf0 | (codePoint >> 18))); + output.write((byte) (0x80 | ((codePoint >> 12) & 0x3f))); + output.write((byte) (0x80 | ((codePoint >> 6) & 0x3f))); + output.write((byte) (0x80 | (codePoint & 0x3f))); + i++; + } + } + } + } + private MarshalerUtil() {} } diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java index 16015fe6bbf..085aeb64d58 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java @@ -40,6 +40,18 @@ protected void writeTraceId(ProtoFieldInfo field, String traceId) throws IOExcep writeBytes(field, traceIdBytes); } + @Override + protected void writeTraceId(ProtoFieldInfo field, String traceId, MarshalerContext context) + throws IOException { + byte[] traceIdBytes = idCache.get(traceId); + if (traceIdBytes == null) { + traceIdBytes = context.getTraceIdBuffer(); + OtelEncodingUtils.bytesFromBase16(traceId, TraceId.getLength(), traceIdBytes); + idCache.put(traceId, traceIdBytes); + } + writeBytes(field, traceIdBytes); + } + @Override protected void writeSpanId(ProtoFieldInfo field, String spanId) throws IOException { byte[] spanIdBytes = @@ -48,6 +60,18 @@ protected void writeSpanId(ProtoFieldInfo field, String spanId) throws IOExcepti writeBytes(field, spanIdBytes); } + @Override + protected void writeSpanId(ProtoFieldInfo field, String spanId, MarshalerContext context) + throws IOException { + byte[] spanIdBytes = idCache.get(spanId); + if (spanIdBytes == null) { + spanIdBytes = context.getSpanIdBuffer(); + OtelEncodingUtils.bytesFromBase16(spanId, SpanId.getLength(), spanIdBytes); + idCache.put(spanId, spanIdBytes); + } + writeBytes(field, spanIdBytes); + } + @Override public void writeBool(ProtoFieldInfo field, boolean value) throws IOException { output.writeUInt32NoTag(field.getTag()); @@ -122,6 +146,14 @@ public void writeString(ProtoFieldInfo field, byte[] utf8Bytes) throws IOExcepti writeBytes(field, utf8Bytes); } + @Override + public void writeString(ProtoFieldInfo field, String string, int utf8Length) throws IOException { + output.writeUInt32NoTag(field.getTag()); + output.writeUInt32NoTag(utf8Length); + + MarshalerUtil.writeUtf8(output, string); + } + @Override public void writeBytes(ProtoFieldInfo field, byte[] value) throws IOException { output.writeUInt32NoTag(field.getTag()); @@ -129,13 +161,13 @@ public void writeBytes(ProtoFieldInfo field, byte[] value) throws IOException { } @Override - protected void writeStartMessage(ProtoFieldInfo field, int protoMessageSize) throws IOException { + public void writeStartMessage(ProtoFieldInfo field, int protoMessageSize) throws IOException { output.writeUInt32NoTag(field.getTag()); output.writeUInt32NoTag(protoMessageSize); } @Override - protected void writeEndMessage() { + public void writeEndMessage() { // Do nothing } @@ -179,6 +211,42 @@ public void serializeRepeatedMessage( } } + @Override + public void serializeRepeatedMessage( + ProtoFieldInfo field, + List messages, + MarshalerContext context, + MessageConsumer consumer) + throws IOException { + for (int i = 0; i < messages.size(); i++) { + T message = messages.get(i); + writeStartMessage(field, context.getSize()); + consumer.accept(this, message, context); + writeEndMessage(); + } + } + + @Override + public void writeStartRepeated(ProtoFieldInfo field) { + // Do nothing + } + + @Override + public void writeEndRepeated() { + // Do nothing + } + + @Override + public void writeStartRepeatedElement(ProtoFieldInfo field, int protoMessageSize) + throws IOException { + writeStartMessage(field, protoMessageSize); + } + + @Override + public void writeEndRepeatedElement() { + writeEndMessage(); + } + @Override public void writeSerializedMessage(byte[] protoSerialized, String jsonSerialized) throws IOException { diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java index ba182316add..4c1a4425d2e 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java @@ -34,8 +34,21 @@ public void serializeTraceId(ProtoFieldInfo field, @Nullable String traceId) thr writeTraceId(field, traceId); } + public void serializeTraceId( + ProtoFieldInfo field, @Nullable String traceId, MarshalerContext context) throws IOException { + if (traceId == null) { + return; + } + writeTraceId(field, traceId, context); + } + protected abstract void writeTraceId(ProtoFieldInfo field, String traceId) throws IOException; + protected void writeTraceId(ProtoFieldInfo field, String traceId, MarshalerContext context) + throws IOException { + writeTraceId(field, traceId); + } + /** Serializes a span ID field. */ public void serializeSpanId(ProtoFieldInfo field, @Nullable String spanId) throws IOException { if (spanId == null) { @@ -44,8 +57,21 @@ public void serializeSpanId(ProtoFieldInfo field, @Nullable String spanId) throw writeSpanId(field, spanId); } + public void serializeSpanId( + ProtoFieldInfo field, @Nullable String spanId, MarshalerContext context) throws IOException { + if (spanId == null) { + return; + } + writeSpanId(field, spanId, context); + } + protected abstract void writeSpanId(ProtoFieldInfo field, String spanId) throws IOException; + protected void writeSpanId(ProtoFieldInfo field, String spanId, MarshalerContext context) + throws IOException { + writeSpanId(field, spanId); + } + /** Serializes a protobuf {@code bool} field. */ public void serializeBool(ProtoFieldInfo field, boolean value) throws IOException { if (!value) { @@ -175,9 +201,24 @@ public void serializeString(ProtoFieldInfo field, byte[] utf8Bytes) throws IOExc writeString(field, utf8Bytes); } + /** + * Serializes a protobuf {@code string} field. {@code string} is the value to be serialized and + * {@code utf8Length} is the length of the string after it is encoded in UTF8. + */ + public void serializeString(ProtoFieldInfo field, String string, int utf8Length) + throws IOException { + if (string.isEmpty()) { + return; + } + writeString(field, string, utf8Length); + } + /** Writes a protobuf {@code string} field, even if it matches the default value. */ public abstract void writeString(ProtoFieldInfo field, byte[] utf8Bytes) throws IOException; + public abstract void writeString(ProtoFieldInfo field, String string, int utf8Length) + throws IOException; + /** Serializes a protobuf {@code bytes} field. */ public void serializeBytes(ProtoFieldInfo field, byte[] value) throws IOException { if (value.length == 0) { @@ -188,10 +229,10 @@ public void serializeBytes(ProtoFieldInfo field, byte[] value) throws IOExceptio public abstract void writeBytes(ProtoFieldInfo field, byte[] value) throws IOException; - protected abstract void writeStartMessage(ProtoFieldInfo field, int protoMessageSize) + public abstract void writeStartMessage(ProtoFieldInfo field, int protoMessageSize) throws IOException; - protected abstract void writeEndMessage() throws IOException; + public abstract void writeEndMessage() throws IOException; /** Serializes a protobuf embedded {@code message}. */ public void serializeMessage(ProtoFieldInfo field, Marshaler message) throws IOException { @@ -200,6 +241,17 @@ public void serializeMessage(ProtoFieldInfo field, Marshaler message) throws IOE writeEndMessage(); } + public void serializeMessage( + ProtoFieldInfo field, + T message, + MarshalerContext context, + MessageConsumer consumer) + throws IOException { + writeStartMessage(field, context.getSize()); + consumer.accept(this, message, context); + writeEndMessage(); + } + @SuppressWarnings("SameParameterValue") protected abstract void writeStartRepeatedPrimitive( ProtoFieldInfo field, int protoSizePerElement, int numElements) throws IOException; @@ -301,10 +353,36 @@ public abstract void serializeRepeatedMessage(ProtoFieldInfo field, Marshaler[] public abstract void serializeRepeatedMessage( ProtoFieldInfo field, List repeatedMessage) throws IOException; + /** Serializes {@code repeated message} field. */ + public abstract void serializeRepeatedMessage( + ProtoFieldInfo field, + List messages, + MarshalerContext context, + MessageConsumer consumer) + throws IOException; + + /** Writes start of repeated messages. */ + public abstract void writeStartRepeated(ProtoFieldInfo field) throws IOException; + + /** Writes end of repeated messages. */ + public abstract void writeEndRepeated() throws IOException; + + /** Writes start of a repeated message element. */ + public abstract void writeStartRepeatedElement(ProtoFieldInfo field, int protoMessageSize) + throws IOException; + + /** Writes end of a repeated message element. */ + public abstract void writeEndRepeatedElement() throws IOException; + /** Writes the value for a message field that has been pre-serialized. */ public abstract void writeSerializedMessage(byte[] protoSerialized, String jsonSerialized) throws IOException; @Override public abstract void close() throws IOException; + + @FunctionalInterface + public interface MessageConsumer { + void accept(O output, D data, C context) throws IOException; + } } diff --git a/exporters/common/src/test/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtilTest.java b/exporters/common/src/test/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtilTest.java new file mode 100644 index 00000000000..5e7c37f03f9 --- /dev/null +++ b/exporters/common/src/test/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtilTest.java @@ -0,0 +1,51 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.marshal; + +import static io.opentelemetry.exporter.internal.marshal.MarshalerUtil.getUtf8Size; +import static io.opentelemetry.exporter.internal.marshal.MarshalerUtil.writeUtf8; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; + +class MarshalerUtilTest { + + @Test + @SuppressWarnings("AvoidEscapedUnicodeCharacters") + void encodeUtf8() { + assertThat(getUtf8Size("")).isEqualTo(0); + assertThat(testUtf8("")).isEqualTo(""); + + assertThat(getUtf8Size("a")).isEqualTo(1); + assertThat(testUtf8("a")).isEqualTo("a"); + + assertThat(getUtf8Size("©")).isEqualTo(2); + assertThat(testUtf8("©")).isEqualTo("©"); + + assertThat(getUtf8Size("∆")).isEqualTo(3); + assertThat(testUtf8("∆")).isEqualTo("∆"); + + assertThat(getUtf8Size("😀")).isEqualTo(4); + assertThat(testUtf8("😀")).isEqualTo("😀"); + + // test that invalid characters are replaced with ? + assertThat(getUtf8Size("\uD83D😀\uDE00")).isEqualTo(6); + assertThat(testUtf8("\uD83D😀\uDE00")).isEqualTo("?😀?"); + } + + private static String testUtf8(String string) { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(outputStream); + writeUtf8(codedOutputStream, string); + codedOutputStream.flush(); + return new String(outputStream.toByteArray(), StandardCharsets.UTF_8); + } catch (Exception exception) { + throw new IllegalArgumentException(exception); + } + } +} diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporter.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporter.java index d693090e316..bcb894bdcc2 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporter.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporter.java @@ -7,11 +7,15 @@ import io.opentelemetry.exporter.internal.http.HttpExporter; import io.opentelemetry.exporter.internal.http.HttpExporterBuilder; +import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.exporter.internal.otlp.traces.LowAllocationTraceRequestMarshaler; import io.opentelemetry.exporter.internal.otlp.traces.TraceRequestMarshaler; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.export.SpanExporter; +import java.util.ArrayDeque; import java.util.Collection; +import java.util.Deque; import javax.annotation.concurrent.ThreadSafe; /** @@ -22,12 +26,13 @@ @ThreadSafe public final class OtlpHttpSpanExporter implements SpanExporter { - private final HttpExporterBuilder builder; - private final HttpExporter delegate; + private static final boolean LOW_ALLOCATION_MODE = true; + private static final Deque requests = new ArrayDeque<>(); - OtlpHttpSpanExporter( - HttpExporterBuilder builder, - HttpExporter delegate) { + private final HttpExporterBuilder builder; + private final HttpExporter delegate; + + OtlpHttpSpanExporter(HttpExporterBuilder builder, HttpExporter delegate) { this.builder = builder; this.delegate = delegate; } @@ -72,8 +77,24 @@ public OtlpHttpSpanExporterBuilder toBuilder() { */ @Override public CompletableResultCode export(Collection spans) { - TraceRequestMarshaler exportRequest = TraceRequestMarshaler.create(spans); - return delegate.export(exportRequest, spans.size()); + if (LOW_ALLOCATION_MODE) { + LowAllocationTraceRequestMarshaler request = requests.poll(); + if (request == null) { + request = new LowAllocationTraceRequestMarshaler(); + } + LowAllocationTraceRequestMarshaler exportRequest = request; + exportRequest.initialize(spans); + return delegate + .export(exportRequest, spans.size()) + .whenComplete( + () -> { + exportRequest.reset(); + requests.add(exportRequest); + }); + } else { + TraceRequestMarshaler exportRequest = TraceRequestMarshaler.create(spans); + return delegate.export(exportRequest, spans.size()); + } } /** diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterBuilder.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterBuilder.java index e5039c61907..12b38fa9d5c 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterBuilder.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterBuilder.java @@ -14,7 +14,7 @@ import io.opentelemetry.exporter.internal.compression.CompressorProvider; import io.opentelemetry.exporter.internal.compression.CompressorUtil; import io.opentelemetry.exporter.internal.http.HttpExporterBuilder; -import io.opentelemetry.exporter.internal.otlp.traces.TraceRequestMarshaler; +import io.opentelemetry.exporter.internal.marshal.Marshaler; import io.opentelemetry.exporter.otlp.internal.OtlpUserAgent; import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; @@ -34,9 +34,9 @@ public final class OtlpHttpSpanExporterBuilder { private static final String DEFAULT_ENDPOINT = "http://localhost:4318/v1/traces"; - private final HttpExporterBuilder delegate; + private final HttpExporterBuilder delegate; - OtlpHttpSpanExporterBuilder(HttpExporterBuilder delegate) { + OtlpHttpSpanExporterBuilder(HttpExporterBuilder delegate) { this.delegate = delegate; OtlpUserAgent.addUserAgentHeader(delegate::addConstantHeaders); } diff --git a/exporters/otlp/common/build.gradle.kts b/exporters/otlp/common/build.gradle.kts index def08665e58..048c1952bb4 100644 --- a/exporters/otlp/common/build.gradle.kts +++ b/exporters/otlp/common/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { jmhImplementation("com.fasterxml.jackson.core:jackson-core") jmhImplementation("io.opentelemetry.proto:opentelemetry-proto") jmhImplementation("io.grpc:grpc-netty") + jmhAnnotationProcessor("org.openjdk.jmh:jmh-generator-annprocess") } wire { diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java index 87cce61bfc2..725c939a464 100644 --- a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp; +import io.opentelemetry.exporter.internal.otlp.traces.LowAllocationTraceRequestMarshaler; import io.opentelemetry.exporter.internal.otlp.traces.TraceRequestMarshaler; import java.io.IOException; import java.util.concurrent.TimeUnit; @@ -26,9 +27,9 @@ public class RequestMarshalBenchmarks { @Benchmark @Threads(1) - public TestOutputStream createCustomMarshal(RequestMarshalState state) { + public int createCustomMarshal(RequestMarshalState state) { TraceRequestMarshaler requestMarshaler = TraceRequestMarshaler.create(state.spanDataList); - return new TestOutputStream(requestMarshaler.getBinarySerializedSize()); + return requestMarshaler.getBinarySerializedSize(); } @Benchmark @@ -49,4 +50,44 @@ public TestOutputStream marshalJson(RequestMarshalState state) throws IOExceptio requestMarshaler.writeJsonTo(customOutput); return customOutput; } + + @Benchmark + @Threads(1) + public int createCustomMarshalLowAllocation(RequestMarshalState state) { + LowAllocationTraceRequestMarshaler requestMarshaler = state.lowAllocationTraceRequestMarshaler; + requestMarshaler.initialize(state.spanDataList); + try { + return requestMarshaler.getBinarySerializedSize(); + } finally { + requestMarshaler.reset(); + } + } + + @Benchmark + @Threads(1) + public TestOutputStream marshalCustomLowAllocation(RequestMarshalState state) throws IOException { + LowAllocationTraceRequestMarshaler requestMarshaler = state.lowAllocationTraceRequestMarshaler; + requestMarshaler.initialize(state.spanDataList); + try { + TestOutputStream customOutput = new TestOutputStream(); + requestMarshaler.writeBinaryTo(customOutput); + return customOutput; + } finally { + requestMarshaler.reset(); + } + } + + @Benchmark + @Threads(1) + public TestOutputStream marshalJsonLowAllocation(RequestMarshalState state) throws IOException { + LowAllocationTraceRequestMarshaler requestMarshaler = state.lowAllocationTraceRequestMarshaler; + requestMarshaler.initialize(state.spanDataList); + try { + TestOutputStream customOutput = new TestOutputStream(); + requestMarshaler.writeJsonTo(customOutput); + return customOutput; + } finally { + requestMarshaler.reset(); + } + } } diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalState.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalState.java index 0105c704b76..90978d92cd6 100644 --- a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalState.java +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalState.java @@ -11,6 +11,7 @@ import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.exporter.internal.otlp.traces.LowAllocationTraceRequestMarshaler; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.trace.TestSpanData; @@ -68,6 +69,9 @@ public class RequestMarshalState { List spanDataList; + final LowAllocationTraceRequestMarshaler lowAllocationTraceRequestMarshaler = + new LowAllocationTraceRequestMarshaler(); + @Setup public void setup() { spanDataList = new ArrayList<>(numSpans); diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java index 2293c0c0e58..a4fae6631ac 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java @@ -31,7 +31,7 @@ public void writeTo(Serializer output) throws IOException { output.writeBool(AnyValue.BOOL_VALUE, value); } - private static int calculateSize(boolean value) { + public static int calculateSize(boolean value) { return AnyValue.BOOL_VALUE.getTagSize() + CodedOutputStream.computeBoolSizeNoTag(value); } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java index 5837976c92d..6971acc8da2 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java @@ -31,7 +31,7 @@ public void writeTo(Serializer output) throws IOException { output.writeDouble(AnyValue.DOUBLE_VALUE, value); } - private static int calculateSize(double value) { + public static int calculateSize(double value) { return AnyValue.DOUBLE_VALUE.getTagSize() + CodedOutputStream.computeDoubleSizeNoTag(value); } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java index 498c60e76bb..9971273eb8e 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java @@ -31,7 +31,7 @@ public void writeTo(Serializer output) throws IOException { output.writeInt64(AnyValue.INT_VALUE, value); } - private static int calculateSize(long value) { + public static int calculateSize(long value) { return AnyValue.INT_VALUE.getTagSize() + CodedOutputStream.computeInt64SizeNoTag(value); } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java index 56a3fa06461..d0f2ebb312c 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java @@ -9,10 +9,15 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.incubator.logs.KeyAnyValue; import io.opentelemetry.api.internal.InternalAttributeKeyImpl; +import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; +import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.proto.common.v1.internal.AnyValue; +import io.opentelemetry.proto.common.v1.internal.ArrayValue; import io.opentelemetry.proto.common.v1.internal.KeyValue; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -108,10 +113,265 @@ public void writeTo(Serializer output) throws IOException { output.serializeMessage(KeyValue.VALUE, value); } + public static void writeTo( + Serializer output, + MarshalerContext context, + ProtoFieldInfo protoFieldInfo, + Attributes attributes) + throws IOException { + output.writeStartRepeated(protoFieldInfo); + + if (!attributes.isEmpty()) { + AttributesWriter attributesWriter = + context.getInstance(AttributesWriter.class, AttributesWriter::new); + attributesWriter.init(protoFieldInfo, output, context); + attributes.forEach(attributesWriter); + } + + output.writeEndRepeated(); + } + + private static void writeTo( + Serializer output, MarshalerContext context, AttributeKey attributeKey, Object value) + throws IOException { + byte[] keyUtf8 = context.getByteArray(); + output.serializeString(KeyValue.KEY, keyUtf8); + + output.writeStartMessage(KeyValue.VALUE, context.getSize()); + writeAttributeValue(output, context, attributeKey, value); + output.writeEndMessage(); + } + + @SuppressWarnings("unchecked") + private static void writeAttributeValue( + Serializer output, MarshalerContext context, AttributeKey attributeKey, Object value) + throws IOException { + switch (attributeKey.getType()) { + case STRING: + if (context.marshalStringNoAllocation()) { + output.writeString(AnyValue.STRING_VALUE, (String) value, context.getSize()); + } else { + byte[] valueUtf8 = context.getByteArray(); + // Do not call serialize* method because we always have to write the message tag even if + // the value is empty since it's a oneof. + output.writeString(AnyValue.STRING_VALUE, valueUtf8); + } + return; + case LONG: + // Do not call serialize* method because we always have to write the message tag even if the + // value is empty since it's a oneof. + output.writeInt64(AnyValue.INT_VALUE, (long) value); + return; + case BOOLEAN: + // Do not call serialize* method because we always have to write the message tag even if the + // value is empty since it's a oneof. + output.writeBool(AnyValue.BOOL_VALUE, (boolean) value); + return; + case DOUBLE: + // Do not call serialize* method because we always have to write the message tag even if the + // value is empty since it's a oneof. + output.writeDouble(AnyValue.DOUBLE_VALUE, (double) value); + return; + case STRING_ARRAY: + // output.serializeMessage(AnyValue.ARRAY_VALUE, value); + writeToStringArray(context, output, (List) value); + return; + case LONG_ARRAY: + // output.serializeMessage(AnyValue.ARRAY_VALUE, value); + writeToLongArray(context, output, (List) value); + return; + case BOOLEAN_ARRAY: + writeToBooleanArray(context, output, (List) value); + return; + case DOUBLE_ARRAY: + writeToDoubleArray(context, output, (List) value); + return; + } + // Error prone ensures the switch statement is complete, otherwise only can happen with + // unaligned versions which are not supported. + throw new IllegalArgumentException("Unsupported attribute type."); + } + + private static void writeToStringArray( + MarshalerContext context, Serializer output, List values) throws IOException { + output.writeStartMessage(AnyValue.ARRAY_VALUE, context.getSize()); + if (context.marshalStringNoAllocation()) { + for (String value : values) { + output.writeStartMessage(AnyValue.STRING_VALUE, context.getSize()); + output.writeString(AnyValue.STRING_VALUE, value, context.getSize()); + output.writeEndMessage(); + } + } else { + for (int i = 0; i < values.size(); i++) { + output.writeStartMessage(AnyValue.STRING_VALUE, context.getSize()); + byte[] valueUtf8 = context.getByteArray(); + output.writeString(AnyValue.STRING_VALUE, valueUtf8); + output.writeEndMessage(); + } + } + output.writeEndMessage(); + } + + private static void writeToLongArray( + MarshalerContext context, Serializer output, List values) throws IOException { + output.writeStartMessage(AnyValue.ARRAY_VALUE, context.getSize()); + for (Long value : values) { + output.writeStartMessage(AnyValue.INT_VALUE, context.getSize()); + output.writeInt64(AnyValue.INT_VALUE, value); + output.writeEndMessage(); + } + output.writeEndMessage(); + } + + private static void writeToBooleanArray( + MarshalerContext context, Serializer output, List values) throws IOException { + output.writeStartMessage(AnyValue.ARRAY_VALUE, context.getSize()); + for (Boolean value : values) { + output.writeStartMessage(AnyValue.BOOL_VALUE, context.getSize()); + output.writeBool(AnyValue.BOOL_VALUE, value); + output.writeEndMessage(); + } + output.writeEndMessage(); + } + + private static void writeToDoubleArray( + MarshalerContext context, Serializer output, List values) throws IOException { + output.writeStartMessage(AnyValue.ARRAY_VALUE, context.getSize()); + for (Double value : values) { + output.writeStartMessage(AnyValue.DOUBLE_VALUE, context.getSize()); + output.writeDouble(AnyValue.DOUBLE_VALUE, value); + output.writeEndMessage(); + } + output.writeEndMessage(); + } + private static int calculateSize(byte[] keyUtf8, Marshaler value) { int size = 0; size += MarshalerUtil.sizeBytes(KeyValue.KEY, keyUtf8); size += MarshalerUtil.sizeMessage(KeyValue.VALUE, value); return size; } + + public static int calculateSize( + ProtoFieldInfo field, MarshalerContext context, Attributes attributes) { + if (attributes.isEmpty()) { + return 0; + } + + AttributesSizeCalculator attributesSizeCalculator = + context.getInstance(AttributesSizeCalculator.class, AttributesSizeCalculator::new); + attributesSizeCalculator.init(field, context); + attributes.forEach(attributesSizeCalculator); + + return attributesSizeCalculator.size; + } + + private static int calculateSize( + MarshalerContext context, AttributeKey attributeKey, Object value) { + byte[] keyUtf8; + if (attributeKey.getKey().isEmpty()) { + keyUtf8 = EMPTY_BYTES; + } else if (attributeKey instanceof InternalAttributeKeyImpl) { + keyUtf8 = ((InternalAttributeKeyImpl) attributeKey).getKeyUtf8(); + } else { + keyUtf8 = attributeKey.getKey().getBytes(StandardCharsets.UTF_8); + } + context.addData(keyUtf8); + + int sizeIndex = context.addSize(); + int valueSizeIndex = context.addSize(); + + int size = 0; + size += MarshalerUtil.sizeBytes(KeyValue.KEY, keyUtf8); + int valueSize = calculateValueSize(context, attributeKey, value); + size += MarshalerUtil.sizeMessage(KeyValue.VALUE, valueSize); + + context.setSize(sizeIndex, size); + context.setSize(valueSizeIndex, valueSize); + + return size; + } + + @SuppressWarnings("unchecked") + private static int calculateValueSize( + MarshalerContext context, AttributeKey attributeKey, Object value) { + switch (attributeKey.getType()) { + case STRING: + return StringAnyValueMarshaler.calculateSize(context, (String) value); + case LONG: + return IntAnyValueMarshaler.calculateSize((long) value); + case BOOLEAN: + return BoolAnyValueMarshaler.calculateSize((boolean) value); + case DOUBLE: + return DoubleAnyValueMarshaler.calculateSize((double) value); + case STRING_ARRAY: + return MarshalerUtil.sizeRepeatedMessage( + ArrayValue.VALUES, + StringAnyValueMarshaler::calculateSize, + (List) value, + context); + case LONG_ARRAY: + return MarshalerUtil.sizeRepeatedMessage( + ArrayValue.VALUES, IntAnyValueMarshaler::calculateSize, (List) value); + case BOOLEAN_ARRAY: + return MarshalerUtil.sizeRepeatedMessage( + ArrayValue.VALUES, BoolAnyValueMarshaler::calculateSize, (List) value); + case DOUBLE_ARRAY: + return MarshalerUtil.sizeRepeatedMessage( + ArrayValue.VALUES, DoubleAnyValueMarshaler::calculateSize, (List) value); + } + // Error prone ensures the switch statement is complete, otherwise only can happen with + // unaligned versions which are not supported. + throw new IllegalArgumentException("Unsupported attribute type."); + } + + private static class AttributesWriter implements BiConsumer, Object> { + @SuppressWarnings("NullAway") + ProtoFieldInfo field; + + @SuppressWarnings("NullAway") + Serializer output; + + @SuppressWarnings("NullAway") + MarshalerContext context; + + void init(ProtoFieldInfo field, Serializer output, MarshalerContext context) { + this.field = field; + this.output = output; + this.context = context; + } + + @Override + public void accept(AttributeKey attributeKey, Object value) { + try { + output.writeStartRepeatedElement(field, context.getSize()); + // output.writeStartMessage(field, context.getSize()); + writeTo(output, context, attributeKey, value); + // output.writeEndMessage(); + output.writeEndRepeatedElement(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + } + + private static class AttributesSizeCalculator implements BiConsumer, Object> { + int size; + int fieldTagSize; + + @SuppressWarnings("NullAway") + MarshalerContext context; + + void init(ProtoFieldInfo field, MarshalerContext context) { + this.size = 0; + this.fieldTagSize = field.getTagSize(); + this.context = context; + } + + @Override + public void accept(AttributeKey attributeKey, Object value) { + int fieldSize = calculateSize(context, attributeKey, value); + size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; + } + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueMarshaler.java index e62c55d2da1..5a8ada4f1ec 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueMarshaler.java @@ -6,6 +6,7 @@ package io.opentelemetry.exporter.internal.otlp; import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -42,4 +43,18 @@ private static int calculateSize(byte[] valueUtf8) { return AnyValue.STRING_VALUE.getTagSize() + CodedOutputStream.computeByteArraySizeNoTag(valueUtf8); } + + public static int calculateSize(MarshalerContext context, String value) { + if (context.marshalStringNoAllocation()) { + int utf8Size = MarshalerUtil.getUtf8Size(value); + context.addSize(utf8Size); + return AnyValue.STRING_VALUE.getTagSize() + + CodedOutputStream.computeLengthDelimitedFieldSize(utf8Size); + } else { + byte[] valueUtf8 = MarshalerUtil.toBytes(value); + context.addData(valueUtf8); + return AnyValue.STRING_VALUE.getTagSize() + + CodedOutputStream.computeLengthDelimitedFieldSize(valueUtf8.length); + } + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansMarshaler.java index 26af3ea3fd7..14acfd488f9 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansMarshaler.java @@ -5,11 +5,13 @@ package io.opentelemetry.exporter.internal.otlp.traces; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; 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.InstrumentationScopeMarshaler; import io.opentelemetry.proto.trace.v1.internal.ScopeSpans; +import io.opentelemetry.sdk.trace.data.SpanData; import java.io.IOException; import java.util.List; @@ -35,6 +37,18 @@ public void writeTo(Serializer output) throws IOException { output.serializeString(ScopeSpans.SCHEMA_URL, schemaUrlUtf8); } + public static void writeTo( + Serializer output, + MarshalerContext context, + InstrumentationScopeMarshaler instrumentationScopeMarshaler, + List spanData, + byte[] schemaUrlUtf8) + throws IOException { + output.serializeMessage(ScopeSpans.SCOPE, instrumentationScopeMarshaler); + output.serializeRepeatedMessage(ScopeSpans.SPANS, spanData, context, SpanMarshaler::writeTo); + output.serializeString(ScopeSpans.SCHEMA_URL, schemaUrlUtf8); + } + private static int calculateSize( InstrumentationScopeMarshaler instrumentationScope, byte[] schemaUrlUtf8, @@ -43,6 +57,24 @@ private static int calculateSize( size += MarshalerUtil.sizeMessage(ScopeSpans.SCOPE, instrumentationScope); size += MarshalerUtil.sizeBytes(ScopeSpans.SCHEMA_URL, schemaUrlUtf8); size += MarshalerUtil.sizeRepeatedMessage(ScopeSpans.SPANS, spanMarshalers); + + return size; + } + + public static int calculateSize( + InstrumentationScopeMarshaler instrumentationScope, + byte[] schemaUrlUtf8, + MarshalerContext context, + List spanData) { + int sizeIndex = context.addSize(); + int size = 0; + size += MarshalerUtil.sizeMessage(ScopeSpans.SCOPE, instrumentationScope); + size += MarshalerUtil.sizeBytes(ScopeSpans.SCHEMA_URL, schemaUrlUtf8); + size += + MarshalerUtil.sizeRepeatedMessage( + ScopeSpans.SPANS, SpanMarshaler::calculateSpanSize, spanData, context); + context.setSize(sizeIndex, size); + return size; } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java new file mode 100644 index 00000000000..0882649db79 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java @@ -0,0 +1,153 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.traces; + +import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; +import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.proto.collector.trace.v1.internal.ExportTraceServiceRequest; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Function; + +/** + * {@link Marshaler} to convert SDK {@link SpanData} to OTLP ExportTraceServiceRequest. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class LowAllocationTraceRequestMarshaler extends Marshaler { + + private final MarshalerContext context = new MarshalerContext(); + + @SuppressWarnings("NullAway") + private Map>> resourceAndScopeMap; + + private int size; + + public void initialize(Collection spanDataList) { + resourceAndScopeMap = groupByResourceAndScope(context, spanDataList); + size = calculateSize(context, resourceAndScopeMap); + } + + public void reset() { + context.reset(); + } + + @Override + public int getBinarySerializedSize() { + return size; + } + + private final ResourceScopeMapWriter resourceScopeMapWriter = new ResourceScopeMapWriter(); + + @Override + public void writeTo(Serializer output) { + // serializing can be retried, reset the indexes, so we could call writeTo multiple times + context.resetReadIndex(); + resourceScopeMapWriter.init(output, context); + resourceAndScopeMap.forEach(resourceScopeMapWriter); + } + + private static int calculateSize( + MarshalerContext context, + Map>> resourceAndScopeMap) { + if (resourceAndScopeMap.isEmpty()) { + return 0; + } + + ResourceScopeMapSizeCalculator resourceScopeMapSizeCalculator = + context.getInstance( + ResourceScopeMapSizeCalculator.class, ResourceScopeMapSizeCalculator::new); + resourceScopeMapSizeCalculator.init(ExportTraceServiceRequest.RESOURCE_SPANS, context); + resourceAndScopeMap.forEach(resourceScopeMapSizeCalculator); + + return resourceScopeMapSizeCalculator.size; + } + + private static Map>> + groupByResourceAndScope(MarshalerContext context, Collection spanDataList) { + + if (spanDataList.isEmpty()) { + return Collections.emptyMap(); + } + + return MarshalerUtil.groupByResourceAndScope( + spanDataList, + // TODO(anuraaga): Replace with an internal SdkData type of interface that exposes these + // two. + SpanData::getResource, + SpanData::getInstrumentationScopeInfo, + Function.identity(), + context); + } + + private static class ResourceScopeMapWriter + implements BiConsumer>> { + @SuppressWarnings("NullAway") + Serializer output; + + @SuppressWarnings("NullAway") + MarshalerContext context; + + void init(Serializer output, MarshalerContext context) { + this.output = output; + this.context = context; + } + + @Override + public void accept( + Resource resource, + Map> instrumentationScopeInfoListMap) { + try { + output.writeStartRepeated(ExportTraceServiceRequest.RESOURCE_SPANS); + output.writeStartRepeatedElement( + ExportTraceServiceRequest.RESOURCE_SPANS, context.getSize()); + + ResourceSpansMarshaler.writeTo(output, instrumentationScopeInfoListMap, context); + + output.writeEndRepeatedElement(); + output.writeEndRepeated(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + } + + private static class ResourceScopeMapSizeCalculator + implements BiConsumer>> { + int size; + int fieldTagSize; + + @SuppressWarnings("NullAway") + MarshalerContext context; + + void init(ProtoFieldInfo field, MarshalerContext context) { + this.size = 0; + this.fieldTagSize = field.getTagSize(); + this.context = context; + } + + @Override + public void accept( + Resource resource, + Map> instrumentationScopeInfoListMap) { + int fieldSize = + ResourceSpansMarshaler.calculateSize(context, resource, instrumentationScopeInfoListMap); + size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; + } + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java index 0e9d5a91e09..85a1996e804 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java @@ -5,8 +5,11 @@ package io.opentelemetry.exporter.internal.otlp.traces; +import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; +import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.exporter.internal.otlp.InstrumentationScopeMarshaler; import io.opentelemetry.exporter.internal.otlp.ResourceMarshaler; @@ -18,6 +21,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.function.BiConsumer; /** * A Marshaler of ResourceSpans. @@ -78,6 +82,23 @@ public void writeTo(Serializer output) throws IOException { output.serializeString(ResourceSpans.SCHEMA_URL, schemaUrlUtf8); } + public static void writeTo( + Serializer output, + Map> scopeMap, + MarshalerContext context) + throws IOException { + ResourceMarshaler resourceMarshaler = context.getObject(ResourceMarshaler.class); + output.serializeMessage(ResourceSpans.RESOURCE, resourceMarshaler); + + ScopeSpanListWriter scopeSpanListWriter = + context.getInstance(ScopeSpanListWriter.class, ScopeSpanListWriter::new); + scopeSpanListWriter.init(output, context); + scopeMap.forEach(scopeSpanListWriter); + + byte[] schemaUrlUtf8 = context.getByteArray(); + output.serializeString(ResourceSpans.SCHEMA_URL, schemaUrlUtf8); + } + private static int calculateSize( ResourceMarshaler resourceMarshaler, byte[] schemaUrlUtf8, @@ -88,6 +109,34 @@ private static int calculateSize( size += MarshalerUtil.sizeRepeatedMessage( ResourceSpans.SCOPE_SPANS, instrumentationScopeSpansMarshalers); + + return size; + } + + public static int calculateSize( + MarshalerContext context, + Resource resource, + Map> scopeMap) { + + int size = 0; + int sizeIndex = context.addSize(); + + ResourceMarshaler resourceMarshaler = ResourceMarshaler.create(resource); + context.addData(resourceMarshaler); + size += MarshalerUtil.sizeMessage(ResourceSpans.RESOURCE, resourceMarshaler); + + ScopeSpanListSizeCalculator scopeSpanListSizeCalculator = + context.getInstance(ScopeSpanListSizeCalculator.class, ScopeSpanListSizeCalculator::new); + scopeSpanListSizeCalculator.initialize(ResourceSpans.SCOPE_SPANS, context); + scopeMap.forEach(scopeSpanListSizeCalculator); + size += scopeSpanListSizeCalculator.size; + + byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(resource.getSchemaUrl()); + context.addData(schemaUrlUtf8); + size += MarshalerUtil.sizeBytes(ResourceSpans.SCHEMA_URL, schemaUrlUtf8); + + context.setSize(sizeIndex, size); + return size; } @@ -101,4 +150,65 @@ private static int calculateSize( SpanData::getInstrumentationScopeInfo, SpanMarshaler::create); } + + private static class ScopeSpanListWriter + implements BiConsumer> { + @SuppressWarnings("NullAway") + Serializer output; + + @SuppressWarnings("NullAway") + MarshalerContext context; + + void init(Serializer output, MarshalerContext context) { + this.output = output; + this.context = context; + } + + @Override + public void accept(InstrumentationScopeInfo instrumentationScopeInfo, List spanData) { + try { + output.writeStartRepeated(ResourceSpans.SCOPE_SPANS); + output.writeStartRepeatedElement(ResourceSpans.SCOPE_SPANS, context.getSize()); + + InstrumentationScopeMarshaler instrumentationScopeMarshaler = + context.getObject(InstrumentationScopeMarshaler.class); + byte[] schemaUrlUtf8 = context.getByteArray(); + InstrumentationScopeSpansMarshaler.writeTo( + output, context, instrumentationScopeMarshaler, spanData, schemaUrlUtf8); + + output.writeEndRepeatedElement(); + output.writeEndRepeated(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + } + + private static class ScopeSpanListSizeCalculator + implements BiConsumer> { + int size; + int fieldTagSize; + + @SuppressWarnings("NullAway") + MarshalerContext context; + + void initialize(ProtoFieldInfo field, MarshalerContext context) { + this.size = 0; + this.fieldTagSize = field.getTagSize(); + this.context = context; + } + + @Override + public void accept(InstrumentationScopeInfo instrumentationScopeInfo, List spanData) { + InstrumentationScopeMarshaler instrumentationScopeMarshaler = + InstrumentationScopeMarshaler.create(instrumentationScopeInfo); + context.addData(instrumentationScopeMarshaler); + byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(instrumentationScopeInfo.getSchemaUrl()); + context.addData(schemaUrlUtf8); + int fieldSize = + InstrumentationScopeSpansMarshaler.calculateSize( + instrumentationScopeMarshaler, schemaUrlUtf8, context, spanData); + size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; + } + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventMarshaler.java index 2b2cc1d7775..50c3ca05baf 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp.traces; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -64,6 +65,20 @@ public void writeTo(Serializer output) throws IOException { output.serializeUInt32(Span.Event.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); } + public static void writeTo(Serializer output, EventData eventData, MarshalerContext context) + throws IOException { + output.serializeFixed64(Span.Event.TIME_UNIX_NANO, eventData.getEpochNanos()); + if (context.marshalStringNoAllocation()) { + output.writeString(Span.Event.NAME, eventData.getName(), context.getSize()); + } else { + output.serializeString(Span.Event.NAME, context.getByteArray()); + } + KeyValueMarshaler.writeTo(output, context, Span.Event.ATTRIBUTES, eventData.getAttributes()); + int droppedAttributesCount = + eventData.getTotalAttributeCount() - eventData.getAttributes().size(); + output.serializeUInt32(Span.Event.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); + } + private static int calculateSize( long epochNanos, byte[] name, @@ -76,4 +91,27 @@ private static int calculateSize( size += MarshalerUtil.sizeUInt32(Span.Event.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); return size; } + + public static int calculateSize(MarshalerContext context, EventData event) { + int sizeIndex = context.addSize(); + + int size = 0; + size += MarshalerUtil.sizeFixed64(Span.Event.TIME_UNIX_NANO, event.getEpochNanos()); + if (context.marshalStringNoAllocation()) { + int utf8Size = MarshalerUtil.getUtf8Size(event.getName()); + context.addSize(utf8Size); + size += MarshalerUtil.sizeBytes(Span.Event.NAME, utf8Size); + } else { + byte[] nameUtf8 = MarshalerUtil.toBytes(event.getName()); + context.addData(nameUtf8); + size += MarshalerUtil.sizeBytes(Span.Event.NAME, nameUtf8); + } + size += KeyValueMarshaler.calculateSize(Span.Event.ATTRIBUTES, context, event.getAttributes()); + int droppedAttributesCount = event.getTotalAttributeCount() - event.getAttributes().size(); + size += MarshalerUtil.sizeUInt32(Span.Event.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); + + context.setSize(sizeIndex, size); + + return size; + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java index 6adcac370e1..63b61e02e4c 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java @@ -9,6 +9,7 @@ import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -92,6 +93,19 @@ public void writeTo(Serializer output) throws IOException { output.serializeByteAsFixed32(Span.Link.FLAGS, traceFlags.asByte()); } + public static void writeTo(Serializer output, LinkData linkData, MarshalerContext context) + throws IOException { + output.serializeTraceId(Span.Link.TRACE_ID, linkData.getSpanContext().getTraceId(), context); + output.serializeSpanId(Span.Link.SPAN_ID, linkData.getSpanContext().getSpanId(), context); + output.serializeString(Span.Link.TRACE_STATE, context.getByteArray()); + KeyValueMarshaler.writeTo(output, context, Span.Link.ATTRIBUTES, linkData.getAttributes()); + int droppedAttributesCount = + linkData.getTotalAttributeCount() - linkData.getAttributes().size(); + output.serializeUInt32(Span.Link.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); + output.serializeByteAsFixed32( + Span.Link.FLAGS, linkData.getSpanContext().getTraceFlags().asByte()); + } + private static int calculateSize( String traceId, String spanId, @@ -108,4 +122,29 @@ private static int calculateSize( size += MarshalerUtil.sizeByteAsFixed32(Span.Link.FLAGS, flags.asByte()); return size; } + + public static int calculateSize(MarshalerContext context, LinkData link) { + int sizeIndex = context.addSize(); + TraceState traceState = link.getSpanContext().getTraceState(); + byte[] traceStateUtf8 = + traceState.isEmpty() + ? EMPTY_BYTES + : encodeTraceState(traceState).getBytes(StandardCharsets.UTF_8); + context.addData(traceStateUtf8); + + int size = 0; + size += MarshalerUtil.sizeTraceId(Span.Link.TRACE_ID, link.getSpanContext().getTraceId()); + size += MarshalerUtil.sizeSpanId(Span.Link.SPAN_ID, link.getSpanContext().getSpanId()); + size += MarshalerUtil.sizeBytes(Span.Link.TRACE_STATE, traceStateUtf8); + size += KeyValueMarshaler.calculateSize(Span.Link.ATTRIBUTES, context, link.getAttributes()); + int droppedAttributesCount = link.getTotalAttributeCount() - link.getAttributes().size(); + size += MarshalerUtil.sizeUInt32(Span.Link.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); + size += + MarshalerUtil.sizeByteAsFixed32( + Span.Link.FLAGS, link.getSpanContext().getTraceFlags().asByte()); + + context.setSize(sizeIndex, size); + + return size; + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java index e2e83c0f129..b9ebc61d001 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java @@ -10,6 +10,7 @@ import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoEnumInfo; @@ -157,6 +158,52 @@ public void writeTo(Serializer output) throws IOException { output.serializeByteAsFixed32(Span.FLAGS, flags.asByte()); } + public static void writeTo(Serializer output, SpanData spanData, MarshalerContext context) + throws IOException { + output.serializeTraceId(Span.TRACE_ID, spanData.getTraceId(), context); + output.serializeSpanId(Span.SPAN_ID, spanData.getSpanId(), context); + + byte[] traceStateUtf8 = context.getByteArray(); + output.serializeString(Span.TRACE_STATE, traceStateUtf8); + String parentSpanId = + spanData.getParentSpanContext().isValid() + ? spanData.getParentSpanContext().getSpanId() + : null; + output.serializeSpanId(Span.PARENT_SPAN_ID, parentSpanId, context); + + if (context.marshalStringNoAllocation()) { + output.writeString(Span.NAME, spanData.getName(), context.getSize()); + } else { + byte[] nameUtf8 = context.getByteArray(); + output.serializeString(Span.NAME, nameUtf8); + } + + output.serializeEnum(Span.KIND, toProtoSpanKind(spanData.getKind())); + + output.serializeFixed64(Span.START_TIME_UNIX_NANO, spanData.getStartEpochNanos()); + output.serializeFixed64(Span.END_TIME_UNIX_NANO, spanData.getEndEpochNanos()); + + KeyValueMarshaler.writeTo(output, context, Span.ATTRIBUTES, spanData.getAttributes()); + int droppedAttributesCount = + spanData.getTotalAttributeCount() - spanData.getAttributes().size(); + output.serializeUInt32(Span.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); + + output.serializeRepeatedMessage( + Span.EVENTS, spanData.getEvents(), context, SpanEventMarshaler::writeTo); + int droppedEventsCount = spanData.getTotalRecordedEvents() - spanData.getEvents().size(); + output.serializeUInt32(Span.DROPPED_EVENTS_COUNT, droppedEventsCount); + + output.serializeRepeatedMessage( + Span.LINKS, spanData.getLinks(), context, SpanLinkMarshaler::writeTo); + int droppedLinksCount = spanData.getTotalRecordedLinks() - spanData.getLinks().size(); + output.serializeUInt32(Span.DROPPED_LINKS_COUNT, droppedLinksCount); + + output.serializeMessage( + Span.STATUS, spanData.getStatus(), context, SpanStatusMarshaler::writeTo); + + output.serializeByteAsFixed32(Span.FLAGS, spanData.getSpanContext().getTraceFlags().asByte()); + } + private static int calculateSize( String traceId, String spanId, @@ -197,6 +244,71 @@ private static int calculateSize( size += MarshalerUtil.sizeMessage(Span.STATUS, spanStatusMarshaler); size += MarshalerUtil.sizeByteAsFixed32(Span.FLAGS, flags.asByte()); + + return size; + } + + public static int calculateSpanSize(MarshalerContext context, SpanData spanData) { + int sizeIndex = context.addSize(); + int size = 0; + size += MarshalerUtil.sizeTraceId(Span.TRACE_ID, spanData.getTraceId()); + size += MarshalerUtil.sizeSpanId(Span.SPAN_ID, spanData.getSpanId()); + + TraceState traceState = spanData.getSpanContext().getTraceState(); + byte[] traceStateUtf8 = + traceState.isEmpty() + ? EMPTY_BYTES + : encodeTraceState(traceState).getBytes(StandardCharsets.UTF_8); + context.addData(traceStateUtf8); + + size += MarshalerUtil.sizeBytes(Span.TRACE_STATE, traceStateUtf8); + String parentSpanId = + spanData.getParentSpanContext().isValid() + ? spanData.getParentSpanContext().getSpanId() + : null; + size += MarshalerUtil.sizeSpanId(Span.PARENT_SPAN_ID, parentSpanId); + + if (context.marshalStringNoAllocation()) { + int utf8Size = MarshalerUtil.getUtf8Size(spanData.getName()); + context.addSize(utf8Size); + size += MarshalerUtil.sizeBytes(Span.NAME, utf8Size); + } else { + byte[] nameUtf8 = MarshalerUtil.toBytes(spanData.getName()); + context.addData(nameUtf8); + size += MarshalerUtil.sizeBytes(Span.NAME, nameUtf8); + } + + size += MarshalerUtil.sizeEnum(Span.KIND, toProtoSpanKind(spanData.getKind())); + + size += MarshalerUtil.sizeFixed64(Span.START_TIME_UNIX_NANO, spanData.getStartEpochNanos()); + size += MarshalerUtil.sizeFixed64(Span.END_TIME_UNIX_NANO, spanData.getEndEpochNanos()); + + size += KeyValueMarshaler.calculateSize(Span.ATTRIBUTES, context, spanData.getAttributes()); + int droppedAttributesCount = + spanData.getTotalAttributeCount() - spanData.getAttributes().size(); + size += MarshalerUtil.sizeUInt32(Span.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); + + size += + MarshalerUtil.sizeRepeatedMessage( + Span.EVENTS, SpanEventMarshaler::calculateSize, spanData.getEvents(), context); + int droppedEventsCount = spanData.getTotalRecordedEvents() - spanData.getEvents().size(); + size += MarshalerUtil.sizeUInt32(Span.DROPPED_EVENTS_COUNT, droppedEventsCount); + + size += + MarshalerUtil.sizeRepeatedMessage( + Span.LINKS, SpanLinkMarshaler::calculateSize, spanData.getLinks(), context); + int droppedLinksCount = spanData.getTotalRecordedLinks() - spanData.getLinks().size(); + size += MarshalerUtil.sizeUInt32(Span.DROPPED_LINKS_COUNT, droppedLinksCount); + + int spanStatusSize = SpanStatusMarshaler.calculateSize(context, spanData.getStatus()); + size += MarshalerUtil.sizeMessage(Span.STATUS, spanStatusSize); + + size += + MarshalerUtil.sizeByteAsFixed32( + Span.FLAGS, spanData.getSpanContext().getTraceFlags().asByte()); + + context.setSize(sizeIndex, size); + return size; } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusMarshaler.java index 0809e85c978..0bde37a9b62 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusMarshaler.java @@ -6,6 +6,7 @@ package io.opentelemetry.exporter.internal.otlp.traces; import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoEnumInfo; @@ -30,7 +31,7 @@ static SpanStatusMarshaler create(StatusData status) { } private SpanStatusMarshaler(ProtoEnumInfo protoStatusCode, byte[] descriptionUtf8) { - super(computeSize(protoStatusCode, descriptionUtf8)); + super(calculateSize(protoStatusCode, descriptionUtf8)); this.protoStatusCode = protoStatusCode; this.descriptionUtf8 = descriptionUtf8; } @@ -41,10 +42,44 @@ public void writeTo(Serializer output) throws IOException { output.serializeEnum(Status.CODE, protoStatusCode); } - private static int computeSize(ProtoEnumInfo protoStatusCode, byte[] descriptionUtf8) { + public static void writeTo(Serializer output, StatusData status, MarshalerContext context) + throws IOException { + ProtoEnumInfo protoStatusCode = Status.StatusCode.STATUS_CODE_UNSET; + if (status.getStatusCode() == StatusCode.OK) { + protoStatusCode = Status.StatusCode.STATUS_CODE_OK; + } else if (status.getStatusCode() == StatusCode.ERROR) { + protoStatusCode = Status.StatusCode.STATUS_CODE_ERROR; + } + + byte[] descriptionUtf8 = context.getByteArray(); + + output.serializeString(Status.MESSAGE, descriptionUtf8); + output.serializeEnum(Status.CODE, protoStatusCode); + } + + private static int calculateSize(ProtoEnumInfo protoStatusCode, byte[] descriptionUtf8) { int size = 0; size += MarshalerUtil.sizeBytes(Status.MESSAGE, descriptionUtf8); size += MarshalerUtil.sizeEnum(Status.CODE, protoStatusCode); return size; } + + public static int calculateSize(MarshalerContext context, StatusData status) { + ProtoEnumInfo protoStatusCode = Status.StatusCode.STATUS_CODE_UNSET; + if (status.getStatusCode() == StatusCode.OK) { + protoStatusCode = Status.StatusCode.STATUS_CODE_OK; + } else if (status.getStatusCode() == StatusCode.ERROR) { + protoStatusCode = Status.StatusCode.STATUS_CODE_ERROR; + } + byte[] descriptionUtf8 = MarshalerUtil.toBytes(status.getDescription()); + context.addData(descriptionUtf8); + + int size = 0; + size += MarshalerUtil.sizeBytes(Status.MESSAGE, descriptionUtf8); + size += MarshalerUtil.sizeEnum(Status.CODE, protoStatusCode); + + context.addSize(size); + + return size; + } } diff --git a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshalerTest.java b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshalerTest.java new file mode 100644 index 00000000000..a99e29bb293 --- /dev/null +++ b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshalerTest.java @@ -0,0 +1,71 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.traces; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; + +class LowAllocationTraceRequestMarshalerTest { + + @Test + void validateOutput() throws Exception { + RequestMarshalState state = new RequestMarshalState(); + state.setup(); + + byte[] result; + { + TraceRequestMarshaler requestMarshaler = TraceRequestMarshaler.create(state.spanDataList); + ByteArrayOutputStream customOutput = + new ByteArrayOutputStream(requestMarshaler.getBinarySerializedSize()); + requestMarshaler.writeBinaryTo(customOutput); + result = customOutput.toByteArray(); + } + + byte[] lowAllocationResult; + { + LowAllocationTraceRequestMarshaler requestMarshaler = + new LowAllocationTraceRequestMarshaler(); + requestMarshaler.initialize(state.spanDataList); + ByteArrayOutputStream customOutput = + new ByteArrayOutputStream(requestMarshaler.getBinarySerializedSize()); + requestMarshaler.writeBinaryTo(customOutput); + lowAllocationResult = customOutput.toByteArray(); + } + + assertThat(lowAllocationResult).isEqualTo(result); + } + + @Test + void validateJsonOutput() throws Exception { + RequestMarshalState state = new RequestMarshalState(); + state.setup(); + + String result; + { + TraceRequestMarshaler requestMarshaler = TraceRequestMarshaler.create(state.spanDataList); + ByteArrayOutputStream customOutput = + new ByteArrayOutputStream(requestMarshaler.getBinarySerializedSize()); + requestMarshaler.writeJsonTo(customOutput); + result = new String(customOutput.toByteArray(), StandardCharsets.UTF_8); + } + + String lowAllocationResult; + { + LowAllocationTraceRequestMarshaler requestMarshaler = + new LowAllocationTraceRequestMarshaler(); + requestMarshaler.initialize(state.spanDataList); + ByteArrayOutputStream customOutput = + new ByteArrayOutputStream(requestMarshaler.getBinarySerializedSize()); + requestMarshaler.writeJsonTo(customOutput); + lowAllocationResult = new String(customOutput.toByteArray(), StandardCharsets.UTF_8); + } + + assertThat(lowAllocationResult).isEqualTo(result); + } +} diff --git a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/RequestMarshalState.java b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/RequestMarshalState.java new file mode 100644 index 00000000000..4b37e8b985a --- /dev/null +++ b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/RequestMarshalState.java @@ -0,0 +1,105 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.traces; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.TraceFlags; +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.testing.trace.TestSpanData; +import io.opentelemetry.sdk.trace.data.EventData; +import io.opentelemetry.sdk.trace.data.LinkData; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.data.StatusData; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class RequestMarshalState { + + private static final AttributeKey KEY_BOOL = AttributeKey.booleanKey("key_bool"); + private static final AttributeKey KEY_STRING = AttributeKey.stringKey("key_string"); + private static final AttributeKey KEY_INT = AttributeKey.longKey("key_int"); + private static final AttributeKey KEY_DOUBLE = AttributeKey.doubleKey("key_double"); + private static final AttributeKey> KEY_STRING_ARRAY = + AttributeKey.stringArrayKey("key_string_array"); + private static final AttributeKey> KEY_LONG_ARRAY = + AttributeKey.longArrayKey("key_long_array"); + private static final AttributeKey> KEY_DOUBLE_ARRAY = + AttributeKey.doubleArrayKey("key_double_array"); + private static final AttributeKey> KEY_BOOLEAN_ARRAY = + AttributeKey.booleanArrayKey("key_boolean_array"); + private static final AttributeKey LINK_ATTR_KEY = AttributeKey.stringKey("link_attr_key"); + + private static final Resource RESOURCE = + Resource.create( + Attributes.builder() + .put(KEY_BOOL, true) + .put(KEY_STRING, "string") + .put(KEY_INT, 100L) + .put(KEY_DOUBLE, 100.3) + .put(KEY_STRING_ARRAY, Arrays.asList("string", "string")) + .put(KEY_LONG_ARRAY, Arrays.asList(12L, 23L)) + .put(KEY_DOUBLE_ARRAY, Arrays.asList(12.3, 23.1)) + .put(KEY_BOOLEAN_ARRAY, Arrays.asList(true, false)) + .build()); + + private static final InstrumentationScopeInfo INSTRUMENTATION_SCOPE_INFO = + InstrumentationScopeInfo.create("name"); + private static final String TRACE_ID = "7b2e170db4df2d593ddb4ddf2ddf2d59"; + private static final String SPAN_ID = "170d3ddb4d23e81f"; + private static final SpanContext SPAN_CONTEXT = + SpanContext.create(TRACE_ID, SPAN_ID, TraceFlags.getSampled(), TraceState.getDefault()); + + int numSpans = 1; + + List spanDataList; + + public void setup() { + spanDataList = new ArrayList<>(numSpans); + for (int i = 0; i < numSpans; i++) { + spanDataList.add(createSpanData()); + } + } + + private static SpanData createSpanData() { + return TestSpanData.builder() + .setResource(RESOURCE) + .setInstrumentationScopeInfo(INSTRUMENTATION_SCOPE_INFO) + .setHasEnded(true) + .setSpanContext(SPAN_CONTEXT) + .setParentSpanContext(SpanContext.getInvalid()) + .setName("GET /api/endpoint") + .setKind(SpanKind.SERVER) + .setStartEpochNanos(12345) + .setEndEpochNanos(12349) + .setAttributes( + Attributes.builder() + .put(KEY_BOOL, true) + // .put(KEY_STRING, "string") + .put(KEY_INT, 100L) + .put(KEY_DOUBLE, 100.3) + .build()) + .setTotalAttributeCount(2) + .setEvents( + Arrays.asList( + EventData.create(12347, "my_event_1", Attributes.empty()), + EventData.create(12348, "my_event_2", Attributes.of(KEY_INT, 1234L)), + EventData.create(12349, "my_event_3", Attributes.empty()))) + .setTotalRecordedEvents(4) + .setLinks( + Arrays.asList( + LinkData.create(SPAN_CONTEXT), + LinkData.create(SPAN_CONTEXT, Attributes.of(LINK_ATTR_KEY, "value")))) + .setTotalRecordedLinks(3) + .setStatus(StatusData.ok()) + .build(); + } +} From 2bf88e61204ea411c18b149e5cd5b68077916e69 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 28 Mar 2024 23:48:04 +0200 Subject: [PATCH 02/15] modify flaky test --- .../internal/AbstractHttpTelemetryExporterTest.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java index 27d9e5f2f2a..fb479a32850 100644 --- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java +++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java @@ -38,6 +38,7 @@ import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse; import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest; import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse; +import io.opentelemetry.proto.trace.v1.ResourceSpans; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; @@ -281,7 +282,13 @@ void multipleItems() { } assertThat(exporter.export(telemetry).join(10, TimeUnit.SECONDS).isSuccess()).isTrue(); List expectedResourceTelemetry = toProto(telemetry); - assertThat(exportedResourceTelemetry).containsExactlyElementsOf(expectedResourceTelemetry); + + assertThat(exportedResourceTelemetry).hasSize(1); + assertThat(expectedResourceTelemetry).hasSize(1); + ResourceSpans exportedResourceSpans = (ResourceSpans) exportedResourceTelemetry.peek(); + ResourceSpans expectedResourceSpans = (ResourceSpans) expectedResourceTelemetry.get(0); + assertThat(exportedResourceSpans.getScopeSpansList()) + .containsExactlyInAnyOrderElementsOf(expectedResourceSpans.getScopeSpansList()); } @Test From 8a3a92fe40509d01977ffa4dec34eb8d973f417a Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 29 Mar 2024 00:08:42 +0200 Subject: [PATCH 03/15] fix test --- .../internal/AbstractHttpTelemetryExporterTest.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java index fb479a32850..0fe2f206a0a 100644 --- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java +++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java @@ -285,10 +285,14 @@ void multipleItems() { assertThat(exportedResourceTelemetry).hasSize(1); assertThat(expectedResourceTelemetry).hasSize(1); - ResourceSpans exportedResourceSpans = (ResourceSpans) exportedResourceTelemetry.peek(); - ResourceSpans expectedResourceSpans = (ResourceSpans) expectedResourceTelemetry.get(0); - assertThat(exportedResourceSpans.getScopeSpansList()) - .containsExactlyInAnyOrderElementsOf(expectedResourceSpans.getScopeSpansList()); + if (exportedResourceTelemetry.peek() instanceof ResourceSpans) { + ResourceSpans exportedResourceSpans = (ResourceSpans) exportedResourceTelemetry.peek(); + ResourceSpans expectedResourceSpans = (ResourceSpans) expectedResourceTelemetry.get(0); + assertThat(exportedResourceSpans.getScopeSpansList()) + .containsExactlyInAnyOrderElementsOf(expectedResourceSpans.getScopeSpansList()); + } else { + assertThat(exportedResourceTelemetry).containsExactlyElementsOf(expectedResourceTelemetry); + } } @Test From 3fd5be924ab4fb684f014ab98f4374ad486e2170 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Tue, 2 Apr 2024 10:53:57 +0300 Subject: [PATCH 04/15] add metrics marshaling --- .../internal/marshal/JsonSerializer.java | 4 +- .../internal/marshal/MarshalerContext.java | 9 +- .../internal/marshal/MarshalerUtil.java | 130 ++++-- .../internal/marshal/ProtoSerializer.java | 4 +- .../exporter/internal/marshal/Serializer.java | 70 ++- .../http/metrics/OtlpHttpMetricExporter.java | 35 +- .../OtlpHttpMetricExporterBuilder.java | 6 +- .../MetricsRequestMarshalerBenchmark.java | 35 ++ .../otlp/RequestMarshalBenchmarks.java | 9 +- .../internal/otlp/RequestMarshalState.java | 4 - ...bstractResourceScopeMapSizeCalculator.java | 44 ++ .../otlp/AbstractResourceScopeMapWriter.java | 53 +++ .../otlp/AbstractScopeListSizeCalculator.java | 49 +++ .../otlp/AbstractScopeListWriter.java | 56 +++ .../internal/otlp/ArrayAnyValueMarshaler.java | 41 ++ .../internal/otlp/BoolAnyValueMarshaler.java | 14 + .../otlp/DoubleAnyValueMarshaler.java | 14 + .../internal/otlp/IntAnyValueMarshaler.java | 14 + .../internal/otlp/KeyValueMarshaler.java | 127 ++---- .../otlp/StringAnyValueMarshaler.java | 12 +- .../otlp/metrics/ExemplarMarshaler.java | 83 +++- .../ExponentialHistogramBucketsMarshaler.java | 19 + ...xponentialHistogramDataPointMarshaler.java | 81 +++- .../ExponentialHistogramMarshaler.java | 41 +- .../internal/otlp/metrics/GaugeMarshaler.java | 27 ++ .../metrics/HistogramDataPointMarshaler.java | 50 +++ .../otlp/metrics/HistogramMarshaler.java | 33 ++ .../InstrumentationScopeMetricsMarshaler.java | 32 ++ .../LowAllocationMetricsRequestMarshaler.java | 118 +++++ .../otlp/metrics/MetricMarshaler.java | 204 +++++++++ .../metrics/NumberDataPointMarshaler.java | 57 ++- .../metrics/ResourceMetricsMarshaler.java | 74 ++++ .../internal/otlp/metrics/SumMarshaler.java | 36 ++ .../metrics/SummaryDataPointMarshaler.java | 35 ++ .../otlp/metrics/SummaryMarshaler.java | 26 ++ .../metrics/ValueAtQuantileMarshaler.java | 11 + .../InstrumentationScopeSpansMarshaler.java | 14 +- .../LowAllocationTraceRequestMarshaler.java | 65 +-- .../otlp/traces/ResourceSpansMarshaler.java | 74 +--- .../otlp/traces/SpanEventMarshaler.java | 19 +- .../otlp/traces/SpanLinkMarshaler.java | 21 +- .../internal/otlp/traces/SpanMarshaler.java | 82 ++-- .../otlp/traces/SpanStatusMarshaler.java | 4 +- ...AllocationMetricsRequestMarshalerTest.java | 416 ++++++++++++++++++ .../otlp/traces/RequestMarshalState.java | 6 +- 45 files changed, 1989 insertions(+), 369 deletions(-) create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshaler.java create mode 100644 exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshalerTest.java diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java index 654b09238a0..00b02d64521 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java @@ -175,8 +175,8 @@ public void serializeRepeatedMessage( public void serializeRepeatedMessage( ProtoFieldInfo field, List messages, - MarshalerContext context, - MessageConsumer consumer) + MessageConsumer consumer, + MarshalerContext context) throws IOException { generator.writeArrayFieldStart(field.getJsonName()); for (int i = 0; i < messages.size(); i++) { diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java index 5e7a59d488e..28af8a048a2 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java @@ -25,10 +25,10 @@ public final class MarshalerContext { public static final boolean MARSHAL_STRING_NO_ALLOCATION = true; - private int[] sizes = new int[1024]; + private int[] sizes = new int[16]; private int sizeReadIndex; private int sizeWriteIndex; - private Object[] data = new Object[1024]; + private Object[] data = new Object[16]; private int dataReadIndex; private int dataWriteIndex; @@ -49,6 +49,7 @@ public int addSize() { private void growSizeIfNeeded() { if (sizeWriteIndex == sizes.length) { int[] newSizes = new int[sizes.length * 2]; + System.arraycopy(sizes, 0, newSizes, 0, sizes.length); sizes = newSizes; } } @@ -203,11 +204,11 @@ public void reset() { listPool.reset(); } - private final Map, Object> instanceMap = new HashMap<>(); + private final Map instanceMap = new HashMap<>(); /** Returns cached instance produced by the given supplier. */ @SuppressWarnings("unchecked") - public T getInstance(Class key, Supplier supplier) { + public T getInstance(Object key, Supplier supplier) { T result = (T) instanceMap.get(key); if (result == null) { result = supplier.get(); diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java index 708bddeb488..d0d307665c8 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java @@ -19,9 +19,9 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.ToIntBiFunction; -import java.util.function.ToIntFunction; import javax.annotation.Nullable; /** @@ -73,31 +73,60 @@ Map>> groupByResourceAndScope( } /** Groups SDK items by resource and instrumentation scope. */ - public static - Map>> groupByResourceAndScope( - Collection dataList, - Function getResource, - Function getInstrumentationScope, - Function createMarshaler, - MarshalerContext context) { - Map>> result = context.getIdentityMap(); - for (T data : dataList) { + public static Map>> groupByResourceAndScope( + Collection dataList, + Function getResource, + Function getInstrumentationScope, + MarshalerContext context) { + Map>> result = context.getIdentityMap(); + + Grouper grouper = context.getInstance(Grouper.class, Grouper::new); + grouper.initialize(result, getResource, getInstrumentationScope, context); + dataList.forEach(grouper); + + return result; + } + + private static class Grouper implements Consumer { + @SuppressWarnings("NullAway") + private Map>> result; + + @SuppressWarnings("NullAway") + private Function getResource; + + @SuppressWarnings("NullAway") + private Function getInstrumentationScope; + + @SuppressWarnings("NullAway") + private MarshalerContext context; + + void initialize( + Map>> result, + Function getResource, + Function getInstrumentationScope, + MarshalerContext context) { + this.result = result; + this.getResource = getResource; + this.getInstrumentationScope = getInstrumentationScope; + this.context = context; + } + + @Override + public void accept(T data) { Resource resource = getResource.apply(data); - Map> scopeInfoListMap = result.get(resource); + Map> scopeInfoListMap = result.get(resource); if (scopeInfoListMap == null) { scopeInfoListMap = context.getIdentityMap(); result.put(resource, scopeInfoListMap); } InstrumentationScopeInfo instrumentationScopeInfo = getInstrumentationScope.apply(data); - List marshalerList = scopeInfoListMap.get(instrumentationScopeInfo); - if (marshalerList == null) { - marshalerList = context.getList(); - scopeInfoListMap.put(instrumentationScopeInfo, marshalerList); + List elementList = scopeInfoListMap.get(instrumentationScopeInfo); + if (elementList == null) { + elementList = context.getList(); + scopeInfoListMap.put(instrumentationScopeInfo, elementList); } - marshalerList.add(createMarshaler.apply(data)); + elementList.add(data); } - - return result; } /** Preserialize into JSON format. */ @@ -218,8 +247,8 @@ public static int sizeRepeatedMessage( /** Returns the size of a repeated message field. */ public static int sizeRepeatedMessage( ProtoFieldInfo field, - ToIntBiFunction consumer, List messages, + ToIntBiFunction consumer, MarshalerContext context) { if (messages.isEmpty()) { return 0; @@ -229,7 +258,9 @@ public static int sizeRepeatedMessage( int fieldTagSize = field.getTagSize(); for (int i = 0; i < messages.size(); i++) { T message = messages.get(i); - int fieldSize = consumer.applyAsInt(context, message); + int sizeIndex = context.addSize(); + int fieldSize = consumer.applyAsInt(message, context); + context.setSize(sizeIndex, fieldSize); size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; } return size; @@ -237,25 +268,56 @@ public static int sizeRepeatedMessage( /** Returns the size of a repeated message field. */ public static int sizeRepeatedMessage( - ProtoFieldInfo field, ToIntFunction consumer, List messages) { + ProtoFieldInfo field, + Collection messages, + ToIntBiFunction consumer, + MarshalerContext context, + Object key) { if (messages.isEmpty()) { return 0; } - int size = 0; - int fieldTagSize = field.getTagSize(); - for (int i = 0; i < messages.size(); i++) { - T message = messages.get(i); - int fieldSize = consumer.applyAsInt(message); + RepeatedElementSizeCalculator sizeCalculator = + context.getInstance(key, RepeatedElementSizeCalculator::new); + sizeCalculator.initialize(field, consumer, context); + messages.forEach(sizeCalculator); + + return sizeCalculator.size; + } + + private static class RepeatedElementSizeCalculator implements Consumer { + private int size; + private int fieldTagSize; + + @SuppressWarnings("NullAway") + private ToIntBiFunction calculateSize; + + @SuppressWarnings("NullAway") + private MarshalerContext context; + + void initialize( + ProtoFieldInfo field, + ToIntBiFunction calculateSize, + MarshalerContext context) { + this.size = 0; + this.fieldTagSize = field.getTagSize(); + this.calculateSize = calculateSize; + this.context = context; + } + + @Override + public void accept(T element) { + int sizeIndex = context.addSize(); + int fieldSize = calculateSize.applyAsInt(element, context); + context.setSize(sizeIndex, fieldSize); size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; } - return size; } /** Returns the size of a message field. */ public static int sizeMessage(ProtoFieldInfo field, Marshaler message) { int fieldSize = message.getBinarySerializedSize(); - return sizeMessage(field, fieldSize); + return field.getTagSize() + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; } /** Returns the size of a message field. */ @@ -263,6 +325,18 @@ public static int sizeMessage(ProtoFieldInfo field, int fieldSize) { return field.getTagSize() + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; } + public static int sizeMessage( + ProtoFieldInfo field, + T element, + ToIntBiFunction sizeCalculator, + MarshalerContext context) { + int sizeIndex = context.addSize(); + int fieldSize = sizeCalculator.applyAsInt(element, context); + int size = field.getTagSize() + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; + context.setSize(sizeIndex, fieldSize); + return size; + } + /** Returns the size of a bool field. */ public static int sizeBool(ProtoFieldInfo field, boolean value) { if (!value) { diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java index 085aeb64d58..a6c68e4454e 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java @@ -215,8 +215,8 @@ public void serializeRepeatedMessage( public void serializeRepeatedMessage( ProtoFieldInfo field, List messages, - MarshalerContext context, - MessageConsumer consumer) + MessageConsumer consumer, + MarshalerContext context) throws IOException { for (int i = 0; i < messages.size(); i++) { T message = messages.get(i); diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java index 4c1a4425d2e..c80266c4be3 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java @@ -7,7 +7,9 @@ import io.opentelemetry.sdk.internal.DynamicPrimitiveLongList; import java.io.IOException; +import java.util.Collection; import java.util.List; +import java.util.function.Consumer; import javax.annotation.Nullable; /** @@ -244,8 +246,8 @@ public void serializeMessage(ProtoFieldInfo field, Marshaler message) throws IOE public void serializeMessage( ProtoFieldInfo field, T message, - MarshalerContext context, - MessageConsumer consumer) + MessageConsumer consumer, + MarshalerContext context) throws IOException { writeStartMessage(field, context.getSize()); consumer.accept(this, message, context); @@ -269,7 +271,8 @@ public void serializeRepeatedFixed64(ProtoFieldInfo field, List values) th return; } writeStartRepeatedPrimitive(field, WireFormat.FIXED64_SIZE, values.size()); - for (long value : values) { + for (int i = 0; i < values.size(); i++) { + Long value = values.get(i); writeFixed64Value(value); } writeEndRepeatedPrimitive(); @@ -338,7 +341,8 @@ public void serializeRepeatedDouble(ProtoFieldInfo field, List values) return; } writeStartRepeatedPrimitive(field, WireFormat.FIXED64_SIZE, values.size()); - for (double value : values) { + for (int i = 0; i < values.size(); i++) { + Double value = values.get(i); writeDoubleValue(value); } writeEndRepeatedPrimitive(); @@ -357,10 +361,64 @@ public abstract void serializeRepeatedMessage( public abstract void serializeRepeatedMessage( ProtoFieldInfo field, List messages, - MarshalerContext context, - MessageConsumer consumer) + MessageConsumer consumer, + MarshalerContext context) throws IOException; + public void serializeRepeatedMessage( + ProtoFieldInfo field, + Collection messages, + MessageConsumer consumer, + MarshalerContext context, + Object key) + throws IOException { + writeStartRepeated(field); + + if (!messages.isEmpty()) { + RepeatedElementWriter writer = context.getInstance(key, RepeatedElementWriter::new); + writer.initialize(field, this, consumer, context); + messages.forEach(writer); + } + + writeEndRepeated(); + } + + private static class RepeatedElementWriter implements Consumer { + @SuppressWarnings("NullAway") + private ProtoFieldInfo field; + + @SuppressWarnings("NullAway") + private Serializer output; + + @SuppressWarnings("NullAway") + private MessageConsumer write; + + @SuppressWarnings("NullAway") + private MarshalerContext context; + + void initialize( + ProtoFieldInfo field, + Serializer output, + MessageConsumer write, + MarshalerContext context) { + this.field = field; + this.output = output; + this.write = write; + this.context = context; + } + + @Override + public void accept(T element) { + try { + output.writeStartRepeatedElement(field, context.getSize()); + write.accept(output, element, context); + output.writeEndRepeatedElement(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + } + /** Writes start of repeated messages. */ public abstract void writeStartRepeated(ProtoFieldInfo field) throws IOException; diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporter.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporter.java index 922baaaec5b..f12d66c740c 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporter.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporter.java @@ -7,6 +7,8 @@ import io.opentelemetry.exporter.internal.http.HttpExporter; import io.opentelemetry.exporter.internal.http.HttpExporterBuilder; +import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.exporter.internal.otlp.metrics.LowAllocationMetricsRequestMarshaler; import io.opentelemetry.exporter.internal.otlp.metrics.MetricsRequestMarshaler; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.metrics.Aggregation; @@ -16,7 +18,9 @@ import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; import io.opentelemetry.sdk.metrics.export.MetricExporter; +import java.util.ArrayDeque; import java.util.Collection; +import java.util.Deque; import javax.annotation.concurrent.ThreadSafe; /** @@ -27,14 +31,17 @@ @ThreadSafe public final class OtlpHttpMetricExporter implements MetricExporter { - private final HttpExporterBuilder builder; - private final HttpExporter delegate; + private static final boolean LOW_ALLOCATION_MODE = true; + private static final Deque requests = new ArrayDeque<>(); + + private final HttpExporterBuilder builder; + private final HttpExporter delegate; private final AggregationTemporalitySelector aggregationTemporalitySelector; private final DefaultAggregationSelector defaultAggregationSelector; OtlpHttpMetricExporter( - HttpExporterBuilder builder, - HttpExporter delegate, + HttpExporterBuilder builder, + HttpExporter delegate, AggregationTemporalitySelector aggregationTemporalitySelector, DefaultAggregationSelector defaultAggregationSelector) { this.builder = builder; @@ -93,8 +100,24 @@ public Aggregation getDefaultAggregation(InstrumentType instrumentType) { */ @Override public CompletableResultCode export(Collection metrics) { - MetricsRequestMarshaler exportRequest = MetricsRequestMarshaler.create(metrics); - return delegate.export(exportRequest, metrics.size()); + if (LOW_ALLOCATION_MODE) { + LowAllocationMetricsRequestMarshaler request = requests.poll(); + if (request == null) { + request = new LowAllocationMetricsRequestMarshaler(); + } + LowAllocationMetricsRequestMarshaler exportRequest = request; + exportRequest.initialize(metrics); + return delegate + .export(exportRequest, metrics.size()) + .whenComplete( + () -> { + exportRequest.reset(); + requests.add(exportRequest); + }); + } else { + MetricsRequestMarshaler exportRequest = MetricsRequestMarshaler.create(metrics); + return delegate.export(exportRequest, metrics.size()); + } } /** diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterBuilder.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterBuilder.java index 8fa21d1aa50..4e9c5b6b0f0 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterBuilder.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterBuilder.java @@ -13,7 +13,7 @@ import io.opentelemetry.exporter.internal.compression.CompressorProvider; import io.opentelemetry.exporter.internal.compression.CompressorUtil; import io.opentelemetry.exporter.internal.http.HttpExporterBuilder; -import io.opentelemetry.exporter.internal.otlp.metrics.MetricsRequestMarshaler; +import io.opentelemetry.exporter.internal.marshal.Marshaler; import io.opentelemetry.exporter.otlp.internal.OtlpUserAgent; import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.RetryPolicy; @@ -40,14 +40,14 @@ public final class OtlpHttpMetricExporterBuilder { private static final AggregationTemporalitySelector DEFAULT_AGGREGATION_TEMPORALITY_SELECTOR = AggregationTemporalitySelector.alwaysCumulative(); - private final HttpExporterBuilder delegate; + private final HttpExporterBuilder delegate; private AggregationTemporalitySelector aggregationTemporalitySelector = DEFAULT_AGGREGATION_TEMPORALITY_SELECTOR; private DefaultAggregationSelector defaultAggregationSelector = DefaultAggregationSelector.getDefault(); - OtlpHttpMetricExporterBuilder(HttpExporterBuilder delegate) { + OtlpHttpMetricExporterBuilder(HttpExporterBuilder delegate) { this.delegate = delegate; delegate.setMeterProvider(MeterProvider::noop); OtlpUserAgent.addUserAgentHeader(delegate::addConstantHeaders); diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/MetricsRequestMarshalerBenchmark.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/MetricsRequestMarshalerBenchmark.java index e284357e401..5835956981d 100644 --- a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/MetricsRequestMarshalerBenchmark.java +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/MetricsRequestMarshalerBenchmark.java @@ -13,6 +13,7 @@ import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.LongUpDownCounter; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.exporter.internal.otlp.metrics.LowAllocationMetricsRequestMarshaler; import io.opentelemetry.exporter.internal.otlp.metrics.MetricsRequestMarshaler; import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.data.MetricData; @@ -38,6 +39,8 @@ public class MetricsRequestMarshalerBenchmark { private static final Collection METRICS; + private static final LowAllocationMetricsRequestMarshaler MARSHALER = + new LowAllocationMetricsRequestMarshaler(); static { InMemoryMetricReader metricReader = InMemoryMetricReader.create(); @@ -122,4 +125,36 @@ public TestOutputStream marshaler() throws IOException { marshaler.writeBinaryTo(bos); return bos; } + + @Benchmark + public TestOutputStream marshalerJson() throws IOException { + MetricsRequestMarshaler marshaler = MetricsRequestMarshaler.create(METRICS); + TestOutputStream bos = new TestOutputStream(); + marshaler.writeJsonTo(bos); + return bos; + } + + @Benchmark + public TestOutputStream marshalerLowAllocation() throws IOException { + MARSHALER.initialize(METRICS); + try { + TestOutputStream bos = new TestOutputStream(); + MARSHALER.writeBinaryTo(bos); + return bos; + } finally { + MARSHALER.reset(); + } + } + + @Benchmark + public TestOutputStream marshalerJsonLowAllocation() throws IOException { + MARSHALER.initialize(METRICS); + try { + TestOutputStream bos = new TestOutputStream(); + MARSHALER.writeJsonTo(bos); + return bos; + } finally { + MARSHALER.reset(); + } + } } diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java index 725c939a464..82ac64ec22b 100644 --- a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java @@ -25,6 +25,9 @@ @Fork(1) public class RequestMarshalBenchmarks { + private static final LowAllocationTraceRequestMarshaler MARSHALER = + new LowAllocationTraceRequestMarshaler(); + @Benchmark @Threads(1) public int createCustomMarshal(RequestMarshalState state) { @@ -54,7 +57,7 @@ public TestOutputStream marshalJson(RequestMarshalState state) throws IOExceptio @Benchmark @Threads(1) public int createCustomMarshalLowAllocation(RequestMarshalState state) { - LowAllocationTraceRequestMarshaler requestMarshaler = state.lowAllocationTraceRequestMarshaler; + LowAllocationTraceRequestMarshaler requestMarshaler = MARSHALER; requestMarshaler.initialize(state.spanDataList); try { return requestMarshaler.getBinarySerializedSize(); @@ -66,7 +69,7 @@ public int createCustomMarshalLowAllocation(RequestMarshalState state) { @Benchmark @Threads(1) public TestOutputStream marshalCustomLowAllocation(RequestMarshalState state) throws IOException { - LowAllocationTraceRequestMarshaler requestMarshaler = state.lowAllocationTraceRequestMarshaler; + LowAllocationTraceRequestMarshaler requestMarshaler = MARSHALER; requestMarshaler.initialize(state.spanDataList); try { TestOutputStream customOutput = new TestOutputStream(); @@ -80,7 +83,7 @@ public TestOutputStream marshalCustomLowAllocation(RequestMarshalState state) th @Benchmark @Threads(1) public TestOutputStream marshalJsonLowAllocation(RequestMarshalState state) throws IOException { - LowAllocationTraceRequestMarshaler requestMarshaler = state.lowAllocationTraceRequestMarshaler; + LowAllocationTraceRequestMarshaler requestMarshaler = MARSHALER; requestMarshaler.initialize(state.spanDataList); try { TestOutputStream customOutput = new TestOutputStream(); diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalState.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalState.java index 90978d92cd6..0105c704b76 100644 --- a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalState.java +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalState.java @@ -11,7 +11,6 @@ import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; -import io.opentelemetry.exporter.internal.otlp.traces.LowAllocationTraceRequestMarshaler; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.trace.TestSpanData; @@ -69,9 +68,6 @@ public class RequestMarshalState { List spanDataList; - final LowAllocationTraceRequestMarshaler lowAllocationTraceRequestMarshaler = - new LowAllocationTraceRequestMarshaler(); - @Setup public void setup() { spanDataList = new ArrayList<>(numSpans); diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java new file mode 100644 index 00000000000..e38e24a3411 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java @@ -0,0 +1,44 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp; + +import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.resources.Resource; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; + +public abstract class AbstractResourceScopeMapSizeCalculator + implements BiConsumer>> { + private int size; + private int fieldTagSize; + + @SuppressWarnings("NullAway") + protected MarshalerContext context; + + public void initialize(ProtoFieldInfo field, MarshalerContext context) { + this.size = 0; + this.fieldTagSize = field.getTagSize(); + this.context = context; + } + + public abstract int calculateSize( + Resource resource, Map> instrumentationScopeInfoListMap); + + @Override + public void accept( + Resource resource, Map> instrumentationScopeInfoListMap) { + int fieldSize = calculateSize(resource, instrumentationScopeInfoListMap); + size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; + } + + public int getSize() { + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java new file mode 100644 index 00000000000..48a700cb238 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java @@ -0,0 +1,53 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.resources.Resource; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; + +public abstract class AbstractResourceScopeMapWriter + implements BiConsumer>> { + @SuppressWarnings("NullAway") + protected Serializer output; + + @SuppressWarnings("NullAway") + private ProtoFieldInfo field; + + @SuppressWarnings("NullAway") + protected MarshalerContext context; + + public void initialize(Serializer output, ProtoFieldInfo field, MarshalerContext context) { + this.output = output; + this.field = field; + this.context = context; + } + + protected abstract void handle( + Map> instrumentationScopeInfoListMap) throws IOException; + + @Override + public void accept( + Resource resource, Map> instrumentationScopeInfoListMap) { + try { + output.writeStartRepeated(field); + output.writeStartRepeatedElement(field, context.getSize()); + + handle(instrumentationScopeInfoListMap); + + output.writeEndRepeatedElement(); + output.writeEndRepeated(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java new file mode 100644 index 00000000000..5f03b8d0c7e --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java @@ -0,0 +1,49 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp; + +import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import java.util.List; +import java.util.function.BiConsumer; + +public abstract class AbstractScopeListSizeCalculator + implements BiConsumer> { + private int size; + private int fieldTagSize; + + @SuppressWarnings("NullAway") + protected MarshalerContext context; + + public void initialize(ProtoFieldInfo field, MarshalerContext context) { + this.size = 0; + this.fieldTagSize = field.getTagSize(); + this.context = context; + } + + public abstract int calculateSize( + InstrumentationScopeMarshaler instrumentationScopeMarshaler, + byte[] schemaUrlUtf8, + List list); + + @Override + public void accept(InstrumentationScopeInfo instrumentationScopeInfo, List list) { + InstrumentationScopeMarshaler instrumentationScopeMarshaler = + InstrumentationScopeMarshaler.create(instrumentationScopeInfo); + context.addData(instrumentationScopeMarshaler); + byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(instrumentationScopeInfo.getSchemaUrl()); + context.addData(schemaUrlUtf8); + int fieldSize = calculateSize(instrumentationScopeMarshaler, schemaUrlUtf8, list); + size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; + } + + public int getSize() { + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java new file mode 100644 index 00000000000..1ce0a07f51a --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java @@ -0,0 +1,56 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import java.io.IOException; +import java.util.List; +import java.util.function.BiConsumer; + +public abstract class AbstractScopeListWriter + implements BiConsumer> { + @SuppressWarnings("NullAway") + protected Serializer output; + + @SuppressWarnings("NullAway") + protected ProtoFieldInfo field; + + @SuppressWarnings("NullAway") + protected MarshalerContext context; + + public void initialize(Serializer output, ProtoFieldInfo field, MarshalerContext context) { + this.output = output; + this.field = field; + this.context = context; + } + + protected abstract void handle( + InstrumentationScopeMarshaler instrumentationScopeMarshaler, + List list, + byte[] schemaUrlUtf8) + throws IOException; + + @Override + public void accept(InstrumentationScopeInfo instrumentationScopeInfo, List list) { + try { + output.writeStartRepeated(field); + output.writeStartRepeatedElement(field, context.getSize()); + + InstrumentationScopeMarshaler instrumentationScopeMarshaler = + context.getObject(InstrumentationScopeMarshaler.class); + byte[] schemaUrlUtf8 = context.getByteArray(); + handle(instrumentationScopeMarshaler, list, schemaUrlUtf8); + + output.writeEndRepeatedElement(); + output.writeEndRepeated(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueMarshaler.java index aa1c25e9c14..b83e7f83601 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueMarshaler.java @@ -5,15 +5,19 @@ package io.opentelemetry.exporter.internal.otlp; +import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; 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.marshal.Serializer.MessageConsumer; import io.opentelemetry.proto.common.v1.internal.AnyValue; import io.opentelemetry.proto.common.v1.internal.ArrayValue; import java.io.IOException; import java.util.List; import java.util.function.Function; +import java.util.function.ToIntBiFunction; final class ArrayAnyValueMarshaler extends MarshalerWithSize { private final Marshaler value; @@ -59,10 +63,33 @@ public void writeTo(Serializer output) throws IOException { output.serializeMessage(AnyValue.ARRAY_VALUE, value); } + public static void writeTo( + Serializer output, + List list, + MessageConsumer consumer, + MarshalerContext context) + throws IOException { + output.writeStartMessage(AnyValue.ARRAY_VALUE, context.getSize()); + ArrayValueMarshaler.writeTo(output, list, consumer, context); + output.writeEndMessage(); + } + private static int calculateSize(Marshaler value) { return MarshalerUtil.sizeMessage(AnyValue.ARRAY_VALUE, value); } + public static int calculateSize( + List list, ToIntBiFunction consumer, MarshalerContext context) { + int sizeIndex = context.addSize(); + int fieldSize = ArrayValueMarshaler.calculateSize(list, consumer, context); + int size = + AnyValue.ARRAY_VALUE.getTagSize() + + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + + fieldSize; + context.setSize(sizeIndex, fieldSize); + return size; + } + private static class ArrayValueMarshaler extends MarshalerWithSize { private final Marshaler[] values; @@ -77,8 +104,22 @@ public void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(ArrayValue.VALUES, values); } + public static void writeTo( + Serializer output, + List messages, + MessageConsumer consumer, + MarshalerContext context) + throws IOException { + output.serializeRepeatedMessage(ArrayValue.VALUES, messages, consumer, context); + } + private static int calculateSize(Marshaler[] values) { return MarshalerUtil.sizeRepeatedMessage(ArrayValue.VALUES, values); } + + public static int calculateSize( + List messages, ToIntBiFunction consumer, MarshalerContext context) { + return MarshalerUtil.sizeRepeatedMessage(ArrayValue.VALUES, messages, consumer, context); + } } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java index a4fae6631ac..4af1bce6fe9 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java @@ -6,6 +6,7 @@ package io.opentelemetry.exporter.internal.otlp; import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.proto.common.v1.internal.AnyValue; @@ -31,7 +32,20 @@ public void writeTo(Serializer output) throws IOException { output.writeBool(AnyValue.BOOL_VALUE, value); } + public static void writeTo(Serializer output, boolean value) throws IOException { + output.writeBool(AnyValue.BOOL_VALUE, value); + } + + public static void writeTo(Serializer output, boolean value, MarshalerContext context) + throws IOException { + writeTo(output, value); + } + public static int calculateSize(boolean value) { return AnyValue.BOOL_VALUE.getTagSize() + CodedOutputStream.computeBoolSizeNoTag(value); } + + public static int calculateSize(boolean value, MarshalerContext context) { + return calculateSize(value); + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java index 6971acc8da2..b5d9c0b30b2 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java @@ -6,6 +6,7 @@ package io.opentelemetry.exporter.internal.otlp; import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.proto.common.v1.internal.AnyValue; @@ -31,7 +32,20 @@ public void writeTo(Serializer output) throws IOException { output.writeDouble(AnyValue.DOUBLE_VALUE, value); } + public static void writeTo(Serializer output, double value) throws IOException { + output.writeDouble(AnyValue.DOUBLE_VALUE, value); + } + + public static void writeTo(Serializer output, double value, MarshalerContext context) + throws IOException { + writeTo(output, value); + } + public static int calculateSize(double value) { return AnyValue.DOUBLE_VALUE.getTagSize() + CodedOutputStream.computeDoubleSizeNoTag(value); } + + public static int calculateSize(double value, MarshalerContext context) { + return calculateSize(value); + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java index 9971273eb8e..0038038c552 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java @@ -6,6 +6,7 @@ package io.opentelemetry.exporter.internal.otlp; import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.proto.common.v1.internal.AnyValue; @@ -31,7 +32,20 @@ public void writeTo(Serializer output) throws IOException { output.writeInt64(AnyValue.INT_VALUE, value); } + public static void writeTo(Serializer output, long value) throws IOException { + output.writeInt64(AnyValue.INT_VALUE, value); + } + + public static void writeTo(Serializer output, long value, MarshalerContext context) + throws IOException { + writeTo(output, value); + } + public static int calculateSize(long value) { return AnyValue.INT_VALUE.getTagSize() + CodedOutputStream.computeInt64SizeNoTag(value); } + + public static int calculateSize(long value, MarshalerContext context) { + return calculateSize(value); + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java index d0f2ebb312c..3968efa0e2c 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java @@ -16,8 +16,6 @@ import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; import io.opentelemetry.exporter.internal.marshal.Serializer; -import io.opentelemetry.proto.common.v1.internal.AnyValue; -import io.opentelemetry.proto.common.v1.internal.ArrayValue; import io.opentelemetry.proto.common.v1.internal.KeyValue; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -124,7 +122,7 @@ public static void writeTo( if (!attributes.isEmpty()) { AttributesWriter attributesWriter = context.getInstance(AttributesWriter.class, AttributesWriter::new); - attributesWriter.init(protoFieldInfo, output, context); + attributesWriter.initialize(protoFieldInfo, output, context); attributes.forEach(attributesWriter); } @@ -148,43 +146,32 @@ private static void writeAttributeValue( throws IOException { switch (attributeKey.getType()) { case STRING: - if (context.marshalStringNoAllocation()) { - output.writeString(AnyValue.STRING_VALUE, (String) value, context.getSize()); - } else { - byte[] valueUtf8 = context.getByteArray(); - // Do not call serialize* method because we always have to write the message tag even if - // the value is empty since it's a oneof. - output.writeString(AnyValue.STRING_VALUE, valueUtf8); - } + StringAnyValueMarshaler.writeTo(output, (String) value, context); return; case LONG: - // Do not call serialize* method because we always have to write the message tag even if the - // value is empty since it's a oneof. - output.writeInt64(AnyValue.INT_VALUE, (long) value); + IntAnyValueMarshaler.writeTo(output, (long) value); return; case BOOLEAN: - // Do not call serialize* method because we always have to write the message tag even if the - // value is empty since it's a oneof. - output.writeBool(AnyValue.BOOL_VALUE, (boolean) value); + BoolAnyValueMarshaler.writeTo(output, (boolean) value); return; case DOUBLE: - // Do not call serialize* method because we always have to write the message tag even if the - // value is empty since it's a oneof. - output.writeDouble(AnyValue.DOUBLE_VALUE, (double) value); + DoubleAnyValueMarshaler.writeTo(output, (double) value); return; case STRING_ARRAY: - // output.serializeMessage(AnyValue.ARRAY_VALUE, value); - writeToStringArray(context, output, (List) value); + ArrayAnyValueMarshaler.writeTo( + output, (List) value, StringAnyValueMarshaler::writeTo, context); return; case LONG_ARRAY: - // output.serializeMessage(AnyValue.ARRAY_VALUE, value); - writeToLongArray(context, output, (List) value); + ArrayAnyValueMarshaler.writeTo( + output, (List) value, IntAnyValueMarshaler::writeTo, context); return; case BOOLEAN_ARRAY: - writeToBooleanArray(context, output, (List) value); + ArrayAnyValueMarshaler.writeTo( + output, (List) value, BoolAnyValueMarshaler::writeTo, context); return; case DOUBLE_ARRAY: - writeToDoubleArray(context, output, (List) value); + ArrayAnyValueMarshaler.writeTo( + output, (List) value, DoubleAnyValueMarshaler::writeTo, context); return; } // Error prone ensures the switch statement is complete, otherwise only can happen with @@ -192,59 +179,6 @@ private static void writeAttributeValue( throw new IllegalArgumentException("Unsupported attribute type."); } - private static void writeToStringArray( - MarshalerContext context, Serializer output, List values) throws IOException { - output.writeStartMessage(AnyValue.ARRAY_VALUE, context.getSize()); - if (context.marshalStringNoAllocation()) { - for (String value : values) { - output.writeStartMessage(AnyValue.STRING_VALUE, context.getSize()); - output.writeString(AnyValue.STRING_VALUE, value, context.getSize()); - output.writeEndMessage(); - } - } else { - for (int i = 0; i < values.size(); i++) { - output.writeStartMessage(AnyValue.STRING_VALUE, context.getSize()); - byte[] valueUtf8 = context.getByteArray(); - output.writeString(AnyValue.STRING_VALUE, valueUtf8); - output.writeEndMessage(); - } - } - output.writeEndMessage(); - } - - private static void writeToLongArray( - MarshalerContext context, Serializer output, List values) throws IOException { - output.writeStartMessage(AnyValue.ARRAY_VALUE, context.getSize()); - for (Long value : values) { - output.writeStartMessage(AnyValue.INT_VALUE, context.getSize()); - output.writeInt64(AnyValue.INT_VALUE, value); - output.writeEndMessage(); - } - output.writeEndMessage(); - } - - private static void writeToBooleanArray( - MarshalerContext context, Serializer output, List values) throws IOException { - output.writeStartMessage(AnyValue.ARRAY_VALUE, context.getSize()); - for (Boolean value : values) { - output.writeStartMessage(AnyValue.BOOL_VALUE, context.getSize()); - output.writeBool(AnyValue.BOOL_VALUE, value); - output.writeEndMessage(); - } - output.writeEndMessage(); - } - - private static void writeToDoubleArray( - MarshalerContext context, Serializer output, List values) throws IOException { - output.writeStartMessage(AnyValue.ARRAY_VALUE, context.getSize()); - for (Double value : values) { - output.writeStartMessage(AnyValue.DOUBLE_VALUE, context.getSize()); - output.writeDouble(AnyValue.DOUBLE_VALUE, value); - output.writeEndMessage(); - } - output.writeEndMessage(); - } - private static int calculateSize(byte[] keyUtf8, Marshaler value) { int size = 0; size += MarshalerUtil.sizeBytes(KeyValue.KEY, keyUtf8); @@ -253,7 +187,7 @@ private static int calculateSize(byte[] keyUtf8, Marshaler value) { } public static int calculateSize( - ProtoFieldInfo field, MarshalerContext context, Attributes attributes) { + ProtoFieldInfo field, Attributes attributes, MarshalerContext context) { if (attributes.isEmpty()) { return 0; } @@ -267,7 +201,7 @@ public static int calculateSize( } private static int calculateSize( - MarshalerContext context, AttributeKey attributeKey, Object value) { + AttributeKey attributeKey, Object value, MarshalerContext context) { byte[] keyUtf8; if (attributeKey.getKey().isEmpty()) { keyUtf8 = EMPTY_BYTES; @@ -283,7 +217,7 @@ private static int calculateSize( int size = 0; size += MarshalerUtil.sizeBytes(KeyValue.KEY, keyUtf8); - int valueSize = calculateValueSize(context, attributeKey, value); + int valueSize = calculateValueSize(attributeKey, value, context); size += MarshalerUtil.sizeMessage(KeyValue.VALUE, valueSize); context.setSize(sizeIndex, size); @@ -294,10 +228,10 @@ private static int calculateSize( @SuppressWarnings("unchecked") private static int calculateValueSize( - MarshalerContext context, AttributeKey attributeKey, Object value) { + AttributeKey attributeKey, Object value, MarshalerContext context) { switch (attributeKey.getType()) { case STRING: - return StringAnyValueMarshaler.calculateSize(context, (String) value); + return StringAnyValueMarshaler.calculateSize((String) value, context); case LONG: return IntAnyValueMarshaler.calculateSize((long) value); case BOOLEAN: @@ -305,20 +239,17 @@ private static int calculateValueSize( case DOUBLE: return DoubleAnyValueMarshaler.calculateSize((double) value); case STRING_ARRAY: - return MarshalerUtil.sizeRepeatedMessage( - ArrayValue.VALUES, - StringAnyValueMarshaler::calculateSize, - (List) value, - context); + return ArrayAnyValueMarshaler.calculateSize( + (List) value, StringAnyValueMarshaler::calculateSize, context); case LONG_ARRAY: - return MarshalerUtil.sizeRepeatedMessage( - ArrayValue.VALUES, IntAnyValueMarshaler::calculateSize, (List) value); + return ArrayAnyValueMarshaler.calculateSize( + (List) value, IntAnyValueMarshaler::calculateSize, context); case BOOLEAN_ARRAY: - return MarshalerUtil.sizeRepeatedMessage( - ArrayValue.VALUES, BoolAnyValueMarshaler::calculateSize, (List) value); + return ArrayAnyValueMarshaler.calculateSize( + (List) value, BoolAnyValueMarshaler::calculateSize, context); case DOUBLE_ARRAY: - return MarshalerUtil.sizeRepeatedMessage( - ArrayValue.VALUES, DoubleAnyValueMarshaler::calculateSize, (List) value); + return ArrayAnyValueMarshaler.calculateSize( + (List) value, DoubleAnyValueMarshaler::calculateSize, context); } // Error prone ensures the switch statement is complete, otherwise only can happen with // unaligned versions which are not supported. @@ -335,7 +266,7 @@ private static class AttributesWriter implements BiConsumer, Obj @SuppressWarnings("NullAway") MarshalerContext context; - void init(ProtoFieldInfo field, Serializer output, MarshalerContext context) { + void initialize(ProtoFieldInfo field, Serializer output, MarshalerContext context) { this.field = field; this.output = output; this.context = context; @@ -345,9 +276,7 @@ void init(ProtoFieldInfo field, Serializer output, MarshalerContext context) { public void accept(AttributeKey attributeKey, Object value) { try { output.writeStartRepeatedElement(field, context.getSize()); - // output.writeStartMessage(field, context.getSize()); writeTo(output, context, attributeKey, value); - // output.writeEndMessage(); output.writeEndRepeatedElement(); } catch (IOException e) { throw new IllegalStateException(e); @@ -370,7 +299,7 @@ void init(ProtoFieldInfo field, MarshalerContext context) { @Override public void accept(AttributeKey attributeKey, Object value) { - int fieldSize = calculateSize(context, attributeKey, value); + int fieldSize = calculateSize(attributeKey, value, context); size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueMarshaler.java index 5a8ada4f1ec..fcb167eb06b 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueMarshaler.java @@ -39,12 +39,22 @@ public void writeTo(Serializer output) throws IOException { output.writeString(AnyValue.STRING_VALUE, valueUtf8); } + public static void writeTo(Serializer output, String value, MarshalerContext context) + throws IOException { + if (context.marshalStringNoAllocation()) { + output.writeString(AnyValue.STRING_VALUE, value, context.getSize()); + } else { + byte[] valueUtf8 = context.getByteArray(); + output.writeString(AnyValue.STRING_VALUE, valueUtf8); + } + } + private static int calculateSize(byte[] valueUtf8) { return AnyValue.STRING_VALUE.getTagSize() + CodedOutputStream.computeByteArraySizeNoTag(valueUtf8); } - public static int calculateSize(MarshalerContext context, String value) { + public static int calculateSize(String value, MarshalerContext context) { if (context.marshalStringNoAllocation()) { int utf8Size = MarshalerUtil.getUtf8Size(value); context.addSize(utf8Size); diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExemplarMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExemplarMarshaler.java index 8d16c9e40d7..b2aa9c24270 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExemplarMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExemplarMarshaler.java @@ -6,6 +6,7 @@ package io.opentelemetry.exporter.internal.otlp.metrics; import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; @@ -37,18 +38,12 @@ static ExemplarMarshaler[] createRepeated(List exemplars return marshalers; } - private static ExemplarMarshaler create(ExemplarData exemplar) { + // Visible for testing + static ExemplarMarshaler create(ExemplarData exemplar) { KeyValueMarshaler[] attributeMarshalers = KeyValueMarshaler.createForAttributes(exemplar.getFilteredAttributes()); - ProtoFieldInfo valueField; - if (exemplar instanceof LongExemplarData) { - valueField = io.opentelemetry.proto.metrics.v1.internal.Exemplar.AS_INT; - } else { - assert exemplar instanceof DoubleExemplarData; - valueField = io.opentelemetry.proto.metrics.v1.internal.Exemplar.AS_DOUBLE; - } - + ProtoFieldInfo valueField = getValueField(exemplar); return new ExemplarMarshaler( exemplar.getEpochNanos(), exemplar, @@ -91,6 +86,35 @@ public void writeTo(Serializer output) throws IOException { filteredAttributeMarshalers); } + public static void writeTo(Serializer output, ExemplarData exemplar, MarshalerContext context) + throws IOException { + output.serializeFixed64( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.TIME_UNIX_NANO, + exemplar.getEpochNanos()); + ProtoFieldInfo valueField = getValueField(exemplar); + if (valueField == io.opentelemetry.proto.metrics.v1.internal.Exemplar.AS_INT) { + output.serializeFixed64Optional(valueField, ((LongExemplarData) exemplar).getValue()); + } else { + output.serializeDoubleOptional(valueField, ((DoubleExemplarData) exemplar).getValue()); + } + SpanContext spanContext = exemplar.getSpanContext(); + if (spanContext.isValid()) { + output.serializeSpanId( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.SPAN_ID, + spanContext.getSpanId(), + context); + output.serializeTraceId( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.TRACE_ID, + spanContext.getTraceId(), + context); + } + KeyValueMarshaler.writeTo( + output, + context, + io.opentelemetry.proto.metrics.v1.internal.Exemplar.FILTERED_ATTRIBUTES, + exemplar.getFilteredAttributes()); + } + private static int calculateSize( long timeUnixNano, ProtoFieldInfo valueField, @@ -121,4 +145,45 @@ private static int calculateSize( filteredAttributeMarshalers); return size; } + + public static int calculateSize(ExemplarData exemplar, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeFixed64( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.TIME_UNIX_NANO, + exemplar.getEpochNanos()); + ProtoFieldInfo valueField = getValueField(exemplar); + if (valueField == io.opentelemetry.proto.metrics.v1.internal.Exemplar.AS_INT) { + size += + MarshalerUtil.sizeFixed64Optional(valueField, ((LongExemplarData) exemplar).getValue()); + } else { + size += + MarshalerUtil.sizeDoubleOptional(valueField, ((DoubleExemplarData) exemplar).getValue()); + } + SpanContext spanContext = exemplar.getSpanContext(); + if (spanContext.isValid()) { + size += + MarshalerUtil.sizeSpanId( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.SPAN_ID, spanContext.getSpanId()); + size += + MarshalerUtil.sizeTraceId( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.TRACE_ID, + spanContext.getTraceId()); + } + size += + KeyValueMarshaler.calculateSize( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.FILTERED_ATTRIBUTES, + exemplar.getFilteredAttributes(), + context); + return size; + } + + private static ProtoFieldInfo getValueField(ExemplarData exemplar) { + if (exemplar instanceof LongExemplarData) { + return io.opentelemetry.proto.metrics.v1.internal.Exemplar.AS_INT; + } else { + assert exemplar instanceof DoubleExemplarData; + return io.opentelemetry.proto.metrics.v1.internal.Exemplar.AS_DOUBLE; + } + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramBucketsMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramBucketsMarshaler.java index 1f5affce3c0..09cfd46821b 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramBucketsMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramBucketsMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp.metrics; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -45,6 +46,20 @@ protected void writeTo(Serializer output) throws IOException { } } + public static void writeTo( + Serializer output, ExponentialHistogramBuckets buckets, MarshalerContext context) + throws IOException { + output.serializeSInt32(ExponentialHistogramDataPoint.Buckets.OFFSET, buckets.getOffset()); + List counts = buckets.getBucketCounts(); + if (counts instanceof DynamicPrimitiveLongList) { + output.serializeRepeatedUInt64( + ExponentialHistogramDataPoint.Buckets.BUCKET_COUNTS, (DynamicPrimitiveLongList) counts); + } else { + output.serializeRepeatedUInt64( + ExponentialHistogramDataPoint.Buckets.BUCKET_COUNTS, PrimitiveLongList.toArray(counts)); + } + } + private static int calculateSize(int offset, List counts) { int size = 0; size += MarshalerUtil.sizeSInt32(ExponentialHistogramDataPoint.Buckets.OFFSET, offset); @@ -61,4 +76,8 @@ private static int calculateSize(int offset, List counts) { } return size; } + + public static int calculateSize(ExponentialHistogramBuckets buckets, MarshalerContext context) { + return calculateSize(buckets.getOffset(), buckets.getBucketCounts()); + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramDataPointMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramDataPointMarshaler.java index 071833954ad..2449569346d 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramDataPointMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramDataPointMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp.metrics; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -139,6 +140,41 @@ protected void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(ExponentialHistogramDataPoint.ATTRIBUTES, attributes); } + public static void writeTo( + Serializer output, ExponentialHistogramPointData point, MarshalerContext context) + throws IOException { + output.serializeFixed64( + ExponentialHistogramDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + output.serializeFixed64(ExponentialHistogramDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + output.serializeFixed64(ExponentialHistogramDataPoint.COUNT, point.getCount()); + output.serializeDouble(ExponentialHistogramDataPoint.SUM, point.getSum()); + if (point.hasMin()) { + output.serializeDoubleOptional(ExponentialHistogramDataPoint.MIN, point.getMin()); + } + if (point.hasMax()) { + output.serializeDoubleOptional(ExponentialHistogramDataPoint.MAX, point.getMax()); + } + output.serializeSInt32(ExponentialHistogramDataPoint.SCALE, point.getScale()); + output.serializeFixed64(ExponentialHistogramDataPoint.ZERO_COUNT, point.getZeroCount()); + output.serializeMessage( + ExponentialHistogramDataPoint.POSITIVE, + point.getPositiveBuckets(), + ExponentialHistogramBucketsMarshaler::writeTo, + context); + output.serializeMessage( + ExponentialHistogramDataPoint.NEGATIVE, + point.getNegativeBuckets(), + ExponentialHistogramBucketsMarshaler::writeTo, + context); + output.serializeRepeatedMessage( + ExponentialHistogramDataPoint.EXEMPLARS, + point.getExemplars(), + ExemplarMarshaler::writeTo, + context); + KeyValueMarshaler.writeTo( + output, context, ExponentialHistogramDataPoint.ATTRIBUTES, point.getAttributes()); + } + private static int calculateSize( long startTimeUnixNano, long timeUnixNano, @@ -159,7 +195,6 @@ private static int calculateSize( MarshalerUtil.sizeFixed64( ExponentialHistogramDataPoint.START_TIME_UNIX_NANO, startTimeUnixNano); size += MarshalerUtil.sizeFixed64(ExponentialHistogramDataPoint.TIME_UNIX_NANO, timeUnixNano); - size += MarshalerUtil.sizeSInt32(ExponentialHistogramDataPoint.SCALE, scale); size += MarshalerUtil.sizeFixed64(ExponentialHistogramDataPoint.COUNT, count); size += MarshalerUtil.sizeDouble(ExponentialHistogramDataPoint.SUM, sum); if (hasMin) { @@ -168,6 +203,7 @@ private static int calculateSize( if (hasMax) { size += MarshalerUtil.sizeDoubleOptional(ExponentialHistogramDataPoint.MAX, max); } + size += MarshalerUtil.sizeSInt32(ExponentialHistogramDataPoint.SCALE, scale); size += MarshalerUtil.sizeFixed64(ExponentialHistogramDataPoint.ZERO_COUNT, zeroCount); size += MarshalerUtil.sizeMessage(ExponentialHistogramDataPoint.POSITIVE, positiveBucketMarshaler); @@ -181,4 +217,47 @@ private static int calculateSize( ExponentialHistogramDataPoint.ATTRIBUTES, attributesMarshalers); return size; } + + public static int calculateSize(ExponentialHistogramPointData point, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeFixed64( + ExponentialHistogramDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + size += + MarshalerUtil.sizeFixed64( + ExponentialHistogramDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + size += MarshalerUtil.sizeFixed64(ExponentialHistogramDataPoint.COUNT, point.getCount()); + size += MarshalerUtil.sizeDouble(ExponentialHistogramDataPoint.SUM, point.getSum()); + if (point.hasMin()) { + size += MarshalerUtil.sizeDoubleOptional(ExponentialHistogramDataPoint.MIN, point.getMin()); + } + if (point.hasMax()) { + size += MarshalerUtil.sizeDoubleOptional(ExponentialHistogramDataPoint.MAX, point.getMax()); + } + size += MarshalerUtil.sizeSInt32(ExponentialHistogramDataPoint.SCALE, point.getScale()); + size += + MarshalerUtil.sizeFixed64(ExponentialHistogramDataPoint.ZERO_COUNT, point.getZeroCount()); + size += + MarshalerUtil.sizeMessage( + ExponentialHistogramDataPoint.POSITIVE, + point.getPositiveBuckets(), + ExponentialHistogramBucketsMarshaler::calculateSize, + context); + size += + MarshalerUtil.sizeMessage( + ExponentialHistogramDataPoint.NEGATIVE, + point.getNegativeBuckets(), + ExponentialHistogramBucketsMarshaler::calculateSize, + context); + size += + MarshalerUtil.sizeRepeatedMessage( + ExponentialHistogramDataPoint.EXEMPLARS, + point.getExemplars(), + ExemplarMarshaler::calculateSize, + context); + size += + KeyValueMarshaler.calculateSize( + ExponentialHistogramDataPoint.ATTRIBUTES, point.getAttributes(), context); + return size; + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramMarshaler.java index 9ad9b10296a..fe29916ba5e 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp.metrics; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoEnumInfo; @@ -18,15 +19,17 @@ * any time. */ public class ExponentialHistogramMarshaler extends MarshalerWithSize { + private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); + private static final Object DATA_POINT_WRITER_KEY = new Object(); + private final ExponentialHistogramDataPointMarshaler[] dataPoints; private final ProtoEnumInfo aggregationTemporality; - static ExponentialHistogramMarshaler create(ExponentialHistogramData histogramData) { + static ExponentialHistogramMarshaler create(ExponentialHistogramData histogram) { ExponentialHistogramDataPointMarshaler[] dataPoints = - ExponentialHistogramDataPointMarshaler.createRepeated(histogramData.getPoints()); + ExponentialHistogramDataPointMarshaler.createRepeated(histogram.getPoints()); return new ExponentialHistogramMarshaler( - dataPoints, - MetricsMarshalerUtil.mapToTemporality(histogramData.getAggregationTemporality())); + dataPoints, MetricsMarshalerUtil.mapToTemporality(histogram.getAggregationTemporality())); } private ExponentialHistogramMarshaler( @@ -43,6 +46,20 @@ protected void writeTo(Serializer output) throws IOException { output.serializeEnum(ExponentialHistogram.AGGREGATION_TEMPORALITY, aggregationTemporality); } + public static void writeTo( + Serializer output, ExponentialHistogramData histogram, MarshalerContext context) + throws IOException { + output.serializeRepeatedMessage( + ExponentialHistogram.DATA_POINTS, + histogram.getPoints(), + ExponentialHistogramDataPointMarshaler::writeTo, + context, + DATA_POINT_WRITER_KEY); + output.serializeEnum( + ExponentialHistogram.AGGREGATION_TEMPORALITY, + MetricsMarshalerUtil.mapToTemporality(histogram.getAggregationTemporality())); + } + private static int calculateSize( ExponentialHistogramDataPointMarshaler[] dataPointMarshalers, ProtoEnumInfo aggregationTemporality) { @@ -54,4 +71,20 @@ private static int calculateSize( ExponentialHistogram.AGGREGATION_TEMPORALITY, aggregationTemporality); return size; } + + public static int calculateSize(ExponentialHistogramData histogram, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeRepeatedMessage( + ExponentialHistogram.DATA_POINTS, + histogram.getPoints(), + ExponentialHistogramDataPointMarshaler::calculateSize, + context, + DATA_POINT_SIZE_CALCULATOR_KEY); + size += + MarshalerUtil.sizeEnum( + ExponentialHistogram.AGGREGATION_TEMPORALITY, + MetricsMarshalerUtil.mapToTemporality(histogram.getAggregationTemporality())); + return size; + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeMarshaler.java index f1512f0715e..b36cb35c2a5 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp.metrics; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -14,6 +15,9 @@ import java.io.IOException; final class GaugeMarshaler extends MarshalerWithSize { + private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); + private static final Object DATA_POINT_WRITER_KEY = new Object(); + private final NumberDataPointMarshaler[] dataPoints; static GaugeMarshaler create(GaugeData gauge) { @@ -33,9 +37,32 @@ public void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(Gauge.DATA_POINTS, dataPoints); } + public static void writeTo( + Serializer output, GaugeData gauge, MarshalerContext context) + throws IOException { + output.serializeRepeatedMessage( + Gauge.DATA_POINTS, + gauge.getPoints(), + NumberDataPointMarshaler::writeTo, + context, + DATA_POINT_WRITER_KEY); + } + private static int calculateSize(NumberDataPointMarshaler[] dataPoints) { int size = 0; size += MarshalerUtil.sizeRepeatedMessage(Gauge.DATA_POINTS, dataPoints); return size; } + + public static int calculateSize(GaugeData gauge, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeRepeatedMessage( + Gauge.DATA_POINTS, + gauge.getPoints(), + NumberDataPointMarshaler::calculateSize, + context, + DATA_POINT_SIZE_CALCULATOR_KEY); + return size; + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramDataPointMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramDataPointMarshaler.java index 8022635e868..41ebff49d15 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramDataPointMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramDataPointMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp.metrics; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -119,6 +120,26 @@ public void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(HistogramDataPoint.ATTRIBUTES, attributes); } + public static void writeTo(Serializer output, HistogramPointData point, MarshalerContext context) + throws IOException { + output.serializeFixed64(HistogramDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + output.serializeFixed64(HistogramDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + output.serializeFixed64(HistogramDataPoint.COUNT, point.getCount()); + output.serializeDoubleOptional(HistogramDataPoint.SUM, point.getSum()); + if (point.hasMin()) { + output.serializeDoubleOptional(HistogramDataPoint.MIN, point.getMin()); + } + if (point.hasMax()) { + output.serializeDoubleOptional(HistogramDataPoint.MAX, point.getMax()); + } + output.serializeRepeatedFixed64(HistogramDataPoint.BUCKET_COUNTS, point.getCounts()); + output.serializeRepeatedDouble(HistogramDataPoint.EXPLICIT_BOUNDS, point.getBoundaries()); + output.serializeRepeatedMessage( + HistogramDataPoint.EXEMPLARS, point.getExemplars(), ExemplarMarshaler::writeTo, context); + KeyValueMarshaler.writeTo( + output, context, HistogramDataPoint.ATTRIBUTES, point.getAttributes()); + } + private static int calculateSize( long startTimeUnixNano, long timeUnixNano, @@ -149,4 +170,33 @@ private static int calculateSize( size += MarshalerUtil.sizeRepeatedMessage(HistogramDataPoint.ATTRIBUTES, attributes); return size; } + + public static int calculateSize(HistogramPointData point, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeFixed64( + HistogramDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + size += MarshalerUtil.sizeFixed64(HistogramDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + size += MarshalerUtil.sizeFixed64(HistogramDataPoint.COUNT, point.getCount()); + size += MarshalerUtil.sizeDoubleOptional(HistogramDataPoint.SUM, point.getSum()); + if (point.hasMin()) { + size += MarshalerUtil.sizeDoubleOptional(HistogramDataPoint.MIN, point.getMin()); + } + if (point.hasMax()) { + size += MarshalerUtil.sizeDoubleOptional(HistogramDataPoint.MAX, point.getMax()); + } + size += MarshalerUtil.sizeRepeatedFixed64(HistogramDataPoint.BUCKET_COUNTS, point.getCounts()); + size += + MarshalerUtil.sizeRepeatedDouble(HistogramDataPoint.EXPLICIT_BOUNDS, point.getBoundaries()); + size += + MarshalerUtil.sizeRepeatedMessage( + HistogramDataPoint.EXEMPLARS, + point.getExemplars(), + ExemplarMarshaler::calculateSize, + context); + size += + KeyValueMarshaler.calculateSize( + HistogramDataPoint.ATTRIBUTES, point.getAttributes(), context); + return size; + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramMarshaler.java index 6082c84dbf8..14fe05b1101 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp.metrics; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoEnumInfo; @@ -14,6 +15,9 @@ import java.io.IOException; final class HistogramMarshaler extends MarshalerWithSize { + private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); + private static final Object DATA_POINT_WRITER_KEY = new Object(); + private final HistogramDataPointMarshaler[] dataPoints; private final ProtoEnumInfo aggregationTemporality; @@ -38,6 +42,19 @@ public void writeTo(Serializer output) throws IOException { output.serializeEnum(Histogram.AGGREGATION_TEMPORALITY, aggregationTemporality); } + public static void writeTo(Serializer output, HistogramData histogram, MarshalerContext context) + throws IOException { + output.serializeRepeatedMessage( + Histogram.DATA_POINTS, + histogram.getPoints(), + HistogramDataPointMarshaler::writeTo, + context, + DATA_POINT_WRITER_KEY); + output.serializeEnum( + Histogram.AGGREGATION_TEMPORALITY, + MetricsMarshalerUtil.mapToTemporality(histogram.getAggregationTemporality())); + } + private static int calculateSize( HistogramDataPointMarshaler[] dataPoints, ProtoEnumInfo aggregationTemporality) { int size = 0; @@ -45,4 +62,20 @@ private static int calculateSize( size += MarshalerUtil.sizeEnum(Histogram.AGGREGATION_TEMPORALITY, aggregationTemporality); return size; } + + public static int calculateSize(HistogramData histogram, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeRepeatedMessage( + Histogram.DATA_POINTS, + histogram.getPoints(), + HistogramDataPointMarshaler::calculateSize, + context, + DATA_POINT_SIZE_CALCULATOR_KEY); + size += + MarshalerUtil.sizeEnum( + Histogram.AGGREGATION_TEMPORALITY, + MetricsMarshalerUtil.mapToTemporality(histogram.getAggregationTemporality())); + return size; + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsMarshaler.java index c4d3ee7ebde..5f90e884efc 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsMarshaler.java @@ -6,11 +6,13 @@ package io.opentelemetry.exporter.internal.otlp.metrics; import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; 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.InstrumentationScopeMarshaler; import io.opentelemetry.proto.metrics.v1.internal.ScopeMetrics; +import io.opentelemetry.sdk.metrics.data.MetricData; import java.io.IOException; import java.util.List; @@ -36,6 +38,19 @@ public void writeTo(Serializer output) throws IOException { output.serializeString(ScopeMetrics.SCHEMA_URL, schemaUrlUtf8); } + public static void writeTo( + Serializer output, + MarshalerContext context, + InstrumentationScopeMarshaler instrumentationScopeMarshaler, + List metricData, + byte[] schemaUrlUtf8) + throws IOException { + output.serializeMessage(ScopeMetrics.SCOPE, instrumentationScopeMarshaler); + output.serializeRepeatedMessage( + ScopeMetrics.METRICS, metricData, MetricMarshaler::writeTo, context); + output.serializeString(ScopeMetrics.SCHEMA_URL, schemaUrlUtf8); + } + private static int calculateSize( InstrumentationScopeMarshaler instrumentationScope, byte[] schemaUrlUtf8, @@ -46,4 +61,21 @@ private static int calculateSize( size += MarshalerUtil.sizeRepeatedMessage(ScopeMetrics.METRICS, metricMarshalers); return size; } + + public static int calculateSize( + InstrumentationScopeMarshaler instrumentationScope, + byte[] schemaUrlUtf8, + MarshalerContext context, + List metricData) { + int sizeIndex = context.addSize(); + int size = 0; + size += MarshalerUtil.sizeMessage(ScopeMetrics.SCOPE, instrumentationScope); + size += MarshalerUtil.sizeBytes(ScopeMetrics.SCHEMA_URL, schemaUrlUtf8); + size += + MarshalerUtil.sizeRepeatedMessage( + ScopeMetrics.METRICS, metricData, MetricMarshaler::calculateSize, context); + context.setSize(sizeIndex, size); + + return size; + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshaler.java new file mode 100644 index 00000000000..b52e138fc86 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshaler.java @@ -0,0 +1,118 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.otlp.AbstractResourceScopeMapSizeCalculator; +import io.opentelemetry.exporter.internal.otlp.AbstractResourceScopeMapWriter; +import io.opentelemetry.proto.collector.metrics.v1.internal.ExportMetricsServiceRequest; +import io.opentelemetry.proto.collector.trace.v1.internal.ExportTraceServiceRequest; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.resources.Resource; +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * {@link Marshaler} to convert SDK {@link MetricData} to OTLP ExportMetricsServiceRequest. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class LowAllocationMetricsRequestMarshaler extends Marshaler { + + private final MarshalerContext context = new MarshalerContext(); + + @SuppressWarnings("NullAway") + private Map>> resourceAndScopeMap; + + private int size; + + public void initialize(Collection metricDataList) { + resourceAndScopeMap = groupByResourceAndScope(context, metricDataList); + size = calculateSize(context, resourceAndScopeMap); + } + + public void reset() { + context.reset(); + } + + @Override + public int getBinarySerializedSize() { + return size; + } + + private final ResourceScopeMapWriter resourceScopeMapWriter = new ResourceScopeMapWriter(); + + @Override + public void writeTo(Serializer output) { + // serializing can be retried, reset the indexes, so we could call writeTo multiple times + context.resetReadIndex(); + resourceScopeMapWriter.initialize( + output, ExportMetricsServiceRequest.RESOURCE_METRICS, context); + resourceAndScopeMap.forEach(resourceScopeMapWriter); + } + + private static int calculateSize( + MarshalerContext context, + Map>> resourceAndScopeMap) { + if (resourceAndScopeMap.isEmpty()) { + return 0; + } + + ResourceScopeMapSizeCalculator resourceScopeMapSizeCalculator = + context.getInstance( + ResourceScopeMapSizeCalculator.class, ResourceScopeMapSizeCalculator::new); + resourceScopeMapSizeCalculator.initialize(ExportTraceServiceRequest.RESOURCE_SPANS, context); + resourceAndScopeMap.forEach(resourceScopeMapSizeCalculator); + + return resourceScopeMapSizeCalculator.getSize(); + } + + private static Map>> + groupByResourceAndScope(MarshalerContext context, Collection metricDataList) { + + if (metricDataList.isEmpty()) { + return Collections.emptyMap(); + } + + return MarshalerUtil.groupByResourceAndScope( + metricDataList, + // TODO(anuraaga): Replace with an internal SdkData type of interface that exposes these + // two. + MetricData::getResource, + MetricData::getInstrumentationScopeInfo, + context); + } + + private static class ResourceScopeMapWriter extends AbstractResourceScopeMapWriter { + + @Override + protected void handle( + Map> instrumentationScopeInfoListMap) + throws IOException { + ResourceMetricsMarshaler.writeTo(output, instrumentationScopeInfoListMap, context); + } + } + + private static class ResourceScopeMapSizeCalculator + extends AbstractResourceScopeMapSizeCalculator { + + @Override + public int calculateSize( + Resource resource, + Map> instrumentationScopeInfoListMap) { + return ResourceMetricsMarshaler.calculateSize( + context, resource, instrumentationScopeInfoListMap); + } + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricMarshaler.java index 6b91a407c5f..0a4b2d33743 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricMarshaler.java @@ -5,14 +5,26 @@ package io.opentelemetry.exporter.internal.otlp.metrics; +import static io.opentelemetry.sdk.metrics.data.MetricDataType.DOUBLE_GAUGE; +import static io.opentelemetry.sdk.metrics.data.MetricDataType.DOUBLE_SUM; +import static io.opentelemetry.sdk.metrics.data.MetricDataType.EXPONENTIAL_HISTOGRAM; +import static io.opentelemetry.sdk.metrics.data.MetricDataType.HISTOGRAM; +import static io.opentelemetry.sdk.metrics.data.MetricDataType.LONG_GAUGE; +import static io.opentelemetry.sdk.metrics.data.MetricDataType.LONG_SUM; +import static io.opentelemetry.sdk.metrics.data.MetricDataType.SUMMARY; + import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.proto.metrics.v1.internal.Metric; import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.data.MetricDataType; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; final class MetricMarshaler extends MarshalerWithSize { private final byte[] nameUtf8; @@ -90,6 +102,30 @@ public void writeTo(Serializer output) throws IOException { output.serializeMessage(dataField, dataMarshaler); } + public static void writeTo(Serializer output, MetricData metricData, MarshalerContext context) + throws IOException { + DataHandler dataHandler = DATA_HANDLERS.get(metricData.getType()); + if (dataHandler == null) { + // Someone not using BOM to align versions as we require. Just skip the metric. + return; + } + + if (context.marshalStringNoAllocation()) { + output.serializeString(Metric.NAME, metricData.getName(), context.getSize()); + output.serializeString(Metric.DESCRIPTION, metricData.getDescription(), context.getSize()); + output.serializeString(Metric.UNIT, metricData.getUnit(), context.getSize()); + } else { + byte[] nameUtf8 = context.getByteArray(); + output.serializeString(Metric.NAME, nameUtf8); + byte[] descriptionUtf8 = context.getByteArray(); + output.serializeString(Metric.DESCRIPTION, descriptionUtf8); + byte[] unitUtf8 = context.getByteArray(); + output.serializeString(Metric.UNIT, unitUtf8); + } + + dataHandler.writeTo(output, metricData, context); + } + private static int calculateSize( byte[] nameUtf8, byte[] descriptionUtf8, @@ -103,4 +139,172 @@ private static int calculateSize( size += MarshalerUtil.sizeMessage(dataField, dataMarshaler); return size; } + + public static int calculateSize(MetricData metricData, MarshalerContext context) { + DataHandler dataHandler = DATA_HANDLERS.get(metricData.getType()); + if (dataHandler == null) { + // Someone not using BOM to align versions as we require. Just skip the metric. + return 0; + } + + int size = 0; + if (context.marshalStringNoAllocation()) { + int nameUtf8Size = MarshalerUtil.getUtf8Size(metricData.getName()); + context.addSize(nameUtf8Size); + size += MarshalerUtil.sizeBytes(Metric.NAME, nameUtf8Size); + + int descriptionUtf8Size = MarshalerUtil.getUtf8Size(metricData.getDescription()); + context.addSize(descriptionUtf8Size); + size += MarshalerUtil.sizeBytes(Metric.DESCRIPTION, descriptionUtf8Size); + + int unitUtf8Size = MarshalerUtil.getUtf8Size(metricData.getUnit()); + context.addSize(unitUtf8Size); + size += MarshalerUtil.sizeBytes(Metric.NAME, unitUtf8Size); + } else { + byte[] nameUtf8 = MarshalerUtil.toBytes(metricData.getName()); + context.addData(nameUtf8); + size += MarshalerUtil.sizeBytes(Metric.NAME, nameUtf8); + + byte[] descriptionUtf8 = MarshalerUtil.toBytes(metricData.getDescription()); + context.addData(descriptionUtf8); + size += MarshalerUtil.sizeBytes(Metric.DESCRIPTION, descriptionUtf8); + + byte[] unitUtf8 = MarshalerUtil.toBytes(metricData.getUnit()); + context.addData(unitUtf8); + size += MarshalerUtil.sizeBytes(Metric.UNIT, unitUtf8); + } + + size += + MarshalerUtil.sizeMessage( + dataHandler.dataField, metricData, dataHandler::calculateSize, context); + + return size; + } + + private static final Map DATA_HANDLERS = new HashMap<>(); + + static { + DATA_HANDLERS.put( + LONG_GAUGE, + new DataHandler(Metric.GAUGE) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return GaugeMarshaler.calculateSize(metricData.getLongGaugeData(), context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.GAUGE, metric.getLongGaugeData(), GaugeMarshaler::writeTo, context); + } + }); + DATA_HANDLERS.put( + DOUBLE_GAUGE, + new DataHandler(Metric.GAUGE) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return GaugeMarshaler.calculateSize(metricData.getDoubleGaugeData(), context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.GAUGE, metric.getDoubleGaugeData(), GaugeMarshaler::writeTo, context); + } + }); + DATA_HANDLERS.put( + LONG_SUM, + new DataHandler(Metric.SUM) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return SumMarshaler.calculateSize(metricData.getLongSumData(), context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.SUM, metric.getLongSumData(), SumMarshaler::writeTo, context); + } + }); + DATA_HANDLERS.put( + DOUBLE_SUM, + new DataHandler(Metric.SUM) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return SumMarshaler.calculateSize(metricData.getDoubleSumData(), context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.SUM, metric.getDoubleSumData(), SumMarshaler::writeTo, context); + } + }); + DATA_HANDLERS.put( + SUMMARY, + new DataHandler(Metric.SUMMARY) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return SummaryMarshaler.calculateSize(metricData.getSummaryData(), context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.SUMMARY, metric.getSummaryData(), SummaryMarshaler::writeTo, context); + } + }); + DATA_HANDLERS.put( + HISTOGRAM, + new DataHandler(Metric.HISTOGRAM) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return HistogramMarshaler.calculateSize(metricData.getHistogramData(), context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.HISTOGRAM, metric.getHistogramData(), HistogramMarshaler::writeTo, context); + } + }); + DATA_HANDLERS.put( + EXPONENTIAL_HISTOGRAM, + new DataHandler(Metric.EXPONENTIAL_HISTOGRAM) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return ExponentialHistogramMarshaler.calculateSize( + metricData.getExponentialHistogramData(), context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.EXPONENTIAL_HISTOGRAM, + metric.getExponentialHistogramData(), + ExponentialHistogramMarshaler::writeTo, + context); + } + }); + } + + private abstract static class DataHandler { + final ProtoFieldInfo dataField; + + DataHandler(ProtoFieldInfo dataField) { + this.dataField = dataField; + } + + abstract int calculateSize(MetricData metricData, MarshalerContext context); + + abstract void writeTo(Serializer output, MetricData metricData, MarshalerContext context) + throws IOException; + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/NumberDataPointMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/NumberDataPointMarshaler.java index 51a432096cd..bc8e3db02d8 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/NumberDataPointMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/NumberDataPointMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp.metrics; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; @@ -42,19 +43,11 @@ static NumberDataPointMarshaler create(PointData point) { KeyValueMarshaler[] attributeMarshalers = KeyValueMarshaler.createForAttributes(point.getAttributes()); - ProtoFieldInfo valueField; - if (point instanceof LongPointData) { - valueField = NumberDataPoint.AS_INT; - } else { - assert point instanceof DoublePointData; - valueField = NumberDataPoint.AS_DOUBLE; - } - return new NumberDataPointMarshaler( point.getStartEpochNanos(), point.getEpochNanos(), point, - valueField, + getValueField(point), exemplarMarshalers, attributeMarshalers); } @@ -88,6 +81,21 @@ public void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(NumberDataPoint.ATTRIBUTES, attributes); } + public static void writeTo(Serializer output, PointData point, MarshalerContext context) + throws IOException { + output.serializeFixed64(NumberDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + output.serializeFixed64(NumberDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + ProtoFieldInfo valueField = getValueField(point); + if (valueField == NumberDataPoint.AS_INT) { + output.serializeFixed64Optional(valueField, ((LongPointData) point).getValue()); + } else { + output.serializeDoubleOptional(valueField, ((DoublePointData) point).getValue()); + } + output.serializeRepeatedMessage( + NumberDataPoint.EXEMPLARS, point.getExemplars(), ExemplarMarshaler::writeTo, context); + KeyValueMarshaler.writeTo(output, context, NumberDataPoint.ATTRIBUTES, point.getAttributes()); + } + private static int calculateSize( long startTimeUnixNano, long timeUnixNano, @@ -107,4 +115,35 @@ private static int calculateSize( size += MarshalerUtil.sizeRepeatedMessage(NumberDataPoint.ATTRIBUTES, attributes); return size; } + + public static int calculateSize(PointData point, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeFixed64(NumberDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + size += MarshalerUtil.sizeFixed64(NumberDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + ProtoFieldInfo valueField = getValueField(point); + if (valueField == NumberDataPoint.AS_INT) { + size += MarshalerUtil.sizeFixed64Optional(valueField, ((LongPointData) point).getValue()); + } else { + size += MarshalerUtil.sizeDoubleOptional(valueField, ((DoublePointData) point).getValue()); + } + size += + MarshalerUtil.sizeRepeatedMessage( + NumberDataPoint.EXEMPLARS, + point.getExemplars(), + ExemplarMarshaler::calculateSize, + context); + size += + KeyValueMarshaler.calculateSize(NumberDataPoint.ATTRIBUTES, point.getAttributes(), context); + return size; + } + + private static ProtoFieldInfo getValueField(PointData pointData) { + if (pointData instanceof LongPointData) { + return NumberDataPoint.AS_INT; + } else { + assert pointData instanceof DoublePointData; + return NumberDataPoint.AS_DOUBLE; + } + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsMarshaler.java index 24db5957b93..fa0ac67eb8f 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsMarshaler.java @@ -6,9 +6,12 @@ package io.opentelemetry.exporter.internal.otlp.metrics; import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; 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.AbstractScopeListSizeCalculator; +import io.opentelemetry.exporter.internal.otlp.AbstractScopeListWriter; import io.opentelemetry.exporter.internal.otlp.InstrumentationScopeMarshaler; import io.opentelemetry.exporter.internal.otlp.ResourceMarshaler; import io.opentelemetry.proto.metrics.v1.internal.ResourceMetrics; @@ -81,6 +84,23 @@ public void writeTo(Serializer output) throws IOException { output.serializeString(ResourceMetrics.SCHEMA_URL, schemaUrl); } + public static void writeTo( + Serializer output, + Map> scopeMap, + MarshalerContext context) + throws IOException { + ResourceMarshaler resourceMarshaler = context.getObject(ResourceMarshaler.class); + output.serializeMessage(ResourceMetrics.RESOURCE, resourceMarshaler); + + ScopeMetricListWriter scopeMetricListWriter = + context.getInstance(ScopeMetricListWriter.class, ScopeMetricListWriter::new); + scopeMetricListWriter.initialize(output, ResourceMetrics.SCOPE_METRICS, context); + scopeMap.forEach(scopeMetricListWriter); + + byte[] schemaUrlUtf8 = context.getByteArray(); + output.serializeString(ResourceMetrics.SCHEMA_URL, schemaUrlUtf8); + } + private static int calculateSize( ResourceMarshaler resourceMarshaler, byte[] schemaUrl, @@ -94,6 +114,34 @@ private static int calculateSize( return size; } + public static int calculateSize( + MarshalerContext context, + Resource resource, + Map> scopeMap) { + + int size = 0; + int sizeIndex = context.addSize(); + + ResourceMarshaler resourceMarshaler = ResourceMarshaler.create(resource); + context.addData(resourceMarshaler); + size += MarshalerUtil.sizeMessage(ResourceMetrics.RESOURCE, resourceMarshaler); + + ScopeMetricListSizeCalculator scopeMetricListSizeCalculator = + context.getInstance( + ScopeMetricListSizeCalculator.class, ScopeMetricListSizeCalculator::new); + scopeMetricListSizeCalculator.initialize(ResourceMetrics.SCOPE_METRICS, context); + scopeMap.forEach(scopeMetricListSizeCalculator); + size += scopeMetricListSizeCalculator.getSize(); + + byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(resource.getSchemaUrl()); + context.addData(schemaUrlUtf8); + size += MarshalerUtil.sizeBytes(ResourceMetrics.SCHEMA_URL, schemaUrlUtf8); + + context.setSize(sizeIndex, size); + + return size; + } + private static Map>> groupByResourceAndScope(Collection metricDataList) { return MarshalerUtil.groupByResourceAndScope( @@ -104,4 +152,30 @@ private static int calculateSize( MetricData::getInstrumentationScopeInfo, MetricMarshaler::create); } + + private static class ScopeMetricListWriter extends AbstractScopeListWriter { + + @Override + protected void handle( + InstrumentationScopeMarshaler instrumentationScopeMarshaler, + List list, + byte[] schemaUrlUtf8) + throws IOException { + InstrumentationScopeMetricsMarshaler.writeTo( + output, context, instrumentationScopeMarshaler, list, schemaUrlUtf8); + } + } + + private static class ScopeMetricListSizeCalculator + extends AbstractScopeListSizeCalculator { + + @Override + public int calculateSize( + InstrumentationScopeMarshaler instrumentationScopeMarshaler, + byte[] schemaUrlUtf8, + List list) { + return InstrumentationScopeMetricsMarshaler.calculateSize( + instrumentationScopeMarshaler, schemaUrlUtf8, context, list); + } + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumMarshaler.java index f349b6df883..ef4248ce039 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp.metrics; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoEnumInfo; @@ -15,6 +16,9 @@ import java.io.IOException; final class SumMarshaler extends MarshalerWithSize { + private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); + private static final Object DATA_POINT_WRITER_KEY = new Object(); + private final NumberDataPointMarshaler[] dataPoints; private final ProtoEnumInfo aggregationTemporality; private final boolean isMonotonic; @@ -46,6 +50,21 @@ public void writeTo(Serializer output) throws IOException { output.serializeBool(Sum.IS_MONOTONIC, isMonotonic); } + public static void writeTo( + Serializer output, SumData sum, MarshalerContext context) + throws IOException { + output.serializeRepeatedMessage( + Sum.DATA_POINTS, + sum.getPoints(), + NumberDataPointMarshaler::writeTo, + context, + DATA_POINT_WRITER_KEY); + output.serializeEnum( + Sum.AGGREGATION_TEMPORALITY, + MetricsMarshalerUtil.mapToTemporality(sum.getAggregationTemporality())); + output.serializeBool(Sum.IS_MONOTONIC, sum.isMonotonic()); + } + private static int calculateSize( NumberDataPointMarshaler[] dataPoints, ProtoEnumInfo aggregationTemporality, @@ -56,4 +75,21 @@ private static int calculateSize( size += MarshalerUtil.sizeBool(Sum.IS_MONOTONIC, isMonotonic); return size; } + + public static int calculateSize(SumData sum, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeRepeatedMessage( + Sum.DATA_POINTS, + sum.getPoints(), + NumberDataPointMarshaler::calculateSize, + context, + DATA_POINT_SIZE_CALCULATOR_KEY); + size += + MarshalerUtil.sizeEnum( + Sum.AGGREGATION_TEMPORALITY, + MetricsMarshalerUtil.mapToTemporality(sum.getAggregationTemporality())); + size += MarshalerUtil.sizeBool(Sum.IS_MONOTONIC, sum.isMonotonic()); + return size; + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryDataPointMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryDataPointMarshaler.java index c0b6a1dcded..b12f1bb5f22 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryDataPointMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryDataPointMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp.metrics; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -72,6 +73,20 @@ public void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(SummaryDataPoint.ATTRIBUTES, attributes); } + public static void writeTo(Serializer output, SummaryPointData point, MarshalerContext context) + throws IOException { + output.serializeFixed64(SummaryDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + output.serializeFixed64(SummaryDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + output.serializeFixed64(SummaryDataPoint.COUNT, point.getCount()); + output.serializeDoubleOptional(SummaryDataPoint.SUM, point.getSum()); + output.serializeRepeatedMessage( + SummaryDataPoint.QUANTILE_VALUES, + point.getValues(), + ValueAtQuantileMarshaler::writeTo, + context); + KeyValueMarshaler.writeTo(output, context, SummaryDataPoint.ATTRIBUTES, point.getAttributes()); + } + private static int calculateSize( long startTimeUnixNano, long timeUnixNano, @@ -88,4 +103,24 @@ private static int calculateSize( size += MarshalerUtil.sizeRepeatedMessage(SummaryDataPoint.ATTRIBUTES, attributes); return size; } + + public static int calculateSize(SummaryPointData point, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeFixed64( + SummaryDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + size += MarshalerUtil.sizeFixed64(SummaryDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + size += MarshalerUtil.sizeFixed64(SummaryDataPoint.COUNT, point.getCount()); + size += MarshalerUtil.sizeDoubleOptional(SummaryDataPoint.SUM, point.getSum()); + size += + MarshalerUtil.sizeRepeatedMessage( + SummaryDataPoint.QUANTILE_VALUES, + point.getValues(), + ValueAtQuantileMarshaler::calculateSize, + context); + size += + KeyValueMarshaler.calculateSize( + SummaryDataPoint.ATTRIBUTES, point.getAttributes(), context); + return size; + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryMarshaler.java index 09bc0029661..9c432aa2985 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp.metrics; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -13,6 +14,9 @@ import java.io.IOException; final class SummaryMarshaler extends MarshalerWithSize { + private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); + private static final Object DATA_POINT_WRITER_KEY = new Object(); + private final SummaryDataPointMarshaler[] dataPoints; static SummaryMarshaler create(SummaryData summary) { @@ -31,9 +35,31 @@ public void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(Summary.DATA_POINTS, dataPoints); } + public static void writeTo(Serializer output, SummaryData summary, MarshalerContext context) + throws IOException { + output.serializeRepeatedMessage( + Summary.DATA_POINTS, + summary.getPoints(), + SummaryDataPointMarshaler::writeTo, + context, + DATA_POINT_WRITER_KEY); + } + private static int calculateSize(SummaryDataPointMarshaler[] dataPoints) { int size = 0; size += MarshalerUtil.sizeRepeatedMessage(Summary.DATA_POINTS, dataPoints); return size; } + + public static int calculateSize(SummaryData summary, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeRepeatedMessage( + Summary.DATA_POINTS, + summary.getPoints(), + SummaryDataPointMarshaler::calculateSize, + context, + DATA_POINT_SIZE_CALCULATOR_KEY); + return size; + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ValueAtQuantileMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ValueAtQuantileMarshaler.java index 6f9ec38ef61..350e3ed08bf 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ValueAtQuantileMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ValueAtQuantileMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp.metrics; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -42,10 +43,20 @@ public void writeTo(Serializer output) throws IOException { output.serializeDouble(SummaryDataPoint.ValueAtQuantile.VALUE, value); } + public static void writeTo(Serializer output, ValueAtQuantile value, MarshalerContext context) + throws IOException { + output.serializeDouble(SummaryDataPoint.ValueAtQuantile.QUANTILE, value.getQuantile()); + output.serializeDouble(SummaryDataPoint.ValueAtQuantile.VALUE, value.getValue()); + } + private static int calculateSize(double quantile, double value) { int size = 0; size += MarshalerUtil.sizeDouble(SummaryDataPoint.ValueAtQuantile.QUANTILE, quantile); size += MarshalerUtil.sizeDouble(SummaryDataPoint.ValueAtQuantile.VALUE, value); return size; } + + public static int calculateSize(ValueAtQuantile value, MarshalerContext context) { + return calculateSize(value.getQuantile(), value.getValue()); + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansMarshaler.java index 14acfd488f9..812533d66b2 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansMarshaler.java @@ -39,13 +39,13 @@ public void writeTo(Serializer output) throws IOException { public static void writeTo( Serializer output, - MarshalerContext context, InstrumentationScopeMarshaler instrumentationScopeMarshaler, - List spanData, - byte[] schemaUrlUtf8) + List spans, + byte[] schemaUrlUtf8, + MarshalerContext context) throws IOException { output.serializeMessage(ScopeSpans.SCOPE, instrumentationScopeMarshaler); - output.serializeRepeatedMessage(ScopeSpans.SPANS, spanData, context, SpanMarshaler::writeTo); + output.serializeRepeatedMessage(ScopeSpans.SPANS, spans, SpanMarshaler::writeTo, context); output.serializeString(ScopeSpans.SCHEMA_URL, schemaUrlUtf8); } @@ -64,15 +64,15 @@ private static int calculateSize( public static int calculateSize( InstrumentationScopeMarshaler instrumentationScope, byte[] schemaUrlUtf8, - MarshalerContext context, - List spanData) { + List spans, + MarshalerContext context) { int sizeIndex = context.addSize(); int size = 0; size += MarshalerUtil.sizeMessage(ScopeSpans.SCOPE, instrumentationScope); size += MarshalerUtil.sizeBytes(ScopeSpans.SCHEMA_URL, schemaUrlUtf8); size += MarshalerUtil.sizeRepeatedMessage( - ScopeSpans.SPANS, SpanMarshaler::calculateSpanSize, spanData, context); + ScopeSpans.SPANS, spans, SpanMarshaler::calculateSize, context); context.setSize(sizeIndex, size); return size; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java index 0882649db79..74bd3160ea2 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java @@ -5,12 +5,12 @@ package io.opentelemetry.exporter.internal.otlp.traces; -import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; import io.opentelemetry.exporter.internal.marshal.Marshaler; import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; -import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.otlp.AbstractResourceScopeMapSizeCalculator; +import io.opentelemetry.exporter.internal.otlp.AbstractResourceScopeMapWriter; import io.opentelemetry.proto.collector.trace.v1.internal.ExportTraceServiceRequest; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.resources.Resource; @@ -20,8 +20,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.function.BiConsumer; -import java.util.function.Function; /** * {@link Marshaler} to convert SDK {@link SpanData} to OTLP ExportTraceServiceRequest. @@ -58,7 +56,7 @@ public int getBinarySerializedSize() { public void writeTo(Serializer output) { // serializing can be retried, reset the indexes, so we could call writeTo multiple times context.resetReadIndex(); - resourceScopeMapWriter.init(output, context); + resourceScopeMapWriter.initialize(output, ExportTraceServiceRequest.RESOURCE_SPANS, context); resourceAndScopeMap.forEach(resourceScopeMapWriter); } @@ -72,10 +70,10 @@ private static int calculateSize( ResourceScopeMapSizeCalculator resourceScopeMapSizeCalculator = context.getInstance( ResourceScopeMapSizeCalculator.class, ResourceScopeMapSizeCalculator::new); - resourceScopeMapSizeCalculator.init(ExportTraceServiceRequest.RESOURCE_SPANS, context); + resourceScopeMapSizeCalculator.initialize(ExportTraceServiceRequest.RESOURCE_SPANS, context); resourceAndScopeMap.forEach(resourceScopeMapSizeCalculator); - return resourceScopeMapSizeCalculator.size; + return resourceScopeMapSizeCalculator.getSize(); } private static Map>> @@ -91,63 +89,28 @@ private static int calculateSize( // two. SpanData::getResource, SpanData::getInstrumentationScopeInfo, - Function.identity(), context); } - private static class ResourceScopeMapWriter - implements BiConsumer>> { - @SuppressWarnings("NullAway") - Serializer output; - - @SuppressWarnings("NullAway") - MarshalerContext context; - - void init(Serializer output, MarshalerContext context) { - this.output = output; - this.context = context; - } + private static class ResourceScopeMapWriter extends AbstractResourceScopeMapWriter { @Override - public void accept( - Resource resource, - Map> instrumentationScopeInfoListMap) { - try { - output.writeStartRepeated(ExportTraceServiceRequest.RESOURCE_SPANS); - output.writeStartRepeatedElement( - ExportTraceServiceRequest.RESOURCE_SPANS, context.getSize()); - - ResourceSpansMarshaler.writeTo(output, instrumentationScopeInfoListMap, context); - - output.writeEndRepeatedElement(); - output.writeEndRepeated(); - } catch (IOException e) { - throw new IllegalStateException(e); - } + protected void handle( + Map> instrumentationScopeInfoListMap) + throws IOException { + ResourceSpansMarshaler.writeTo(output, instrumentationScopeInfoListMap, context); } } private static class ResourceScopeMapSizeCalculator - implements BiConsumer>> { - int size; - int fieldTagSize; - - @SuppressWarnings("NullAway") - MarshalerContext context; - - void init(ProtoFieldInfo field, MarshalerContext context) { - this.size = 0; - this.fieldTagSize = field.getTagSize(); - this.context = context; - } + extends AbstractResourceScopeMapSizeCalculator { @Override - public void accept( + public int calculateSize( Resource resource, Map> instrumentationScopeInfoListMap) { - int fieldSize = - ResourceSpansMarshaler.calculateSize(context, resource, instrumentationScopeInfoListMap); - size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; + return ResourceSpansMarshaler.calculateSize( + context, resource, instrumentationScopeInfoListMap); } } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java index 85a1996e804..9944c3c03f2 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java @@ -5,12 +5,12 @@ package io.opentelemetry.exporter.internal.otlp.traces; -import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; -import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.otlp.AbstractScopeListSizeCalculator; +import io.opentelemetry.exporter.internal.otlp.AbstractScopeListWriter; import io.opentelemetry.exporter.internal.otlp.InstrumentationScopeMarshaler; import io.opentelemetry.exporter.internal.otlp.ResourceMarshaler; import io.opentelemetry.proto.trace.v1.internal.ResourceSpans; @@ -21,7 +21,6 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.function.BiConsumer; /** * A Marshaler of ResourceSpans. @@ -92,7 +91,7 @@ public static void writeTo( ScopeSpanListWriter scopeSpanListWriter = context.getInstance(ScopeSpanListWriter.class, ScopeSpanListWriter::new); - scopeSpanListWriter.init(output, context); + scopeSpanListWriter.initialize(output, ResourceSpans.SCOPE_SPANS, context); scopeMap.forEach(scopeSpanListWriter); byte[] schemaUrlUtf8 = context.getByteArray(); @@ -129,7 +128,7 @@ public static int calculateSize( context.getInstance(ScopeSpanListSizeCalculator.class, ScopeSpanListSizeCalculator::new); scopeSpanListSizeCalculator.initialize(ResourceSpans.SCOPE_SPANS, context); scopeMap.forEach(scopeSpanListSizeCalculator); - size += scopeSpanListSizeCalculator.size; + size += scopeSpanListSizeCalculator.getSize(); byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(resource.getSchemaUrl()); context.addData(schemaUrlUtf8); @@ -151,64 +150,29 @@ public static int calculateSize( SpanMarshaler::create); } - private static class ScopeSpanListWriter - implements BiConsumer> { - @SuppressWarnings("NullAway") - Serializer output; - - @SuppressWarnings("NullAway") - MarshalerContext context; - - void init(Serializer output, MarshalerContext context) { - this.output = output; - this.context = context; - } + private static class ScopeSpanListWriter extends AbstractScopeListWriter { @Override - public void accept(InstrumentationScopeInfo instrumentationScopeInfo, List spanData) { - try { - output.writeStartRepeated(ResourceSpans.SCOPE_SPANS); - output.writeStartRepeatedElement(ResourceSpans.SCOPE_SPANS, context.getSize()); - - InstrumentationScopeMarshaler instrumentationScopeMarshaler = - context.getObject(InstrumentationScopeMarshaler.class); - byte[] schemaUrlUtf8 = context.getByteArray(); - InstrumentationScopeSpansMarshaler.writeTo( - output, context, instrumentationScopeMarshaler, spanData, schemaUrlUtf8); - - output.writeEndRepeatedElement(); - output.writeEndRepeated(); - } catch (IOException e) { - throw new IllegalStateException(e); - } + protected void handle( + InstrumentationScopeMarshaler instrumentationScopeMarshaler, + List list, + byte[] schemaUrlUtf8) + throws IOException { + InstrumentationScopeSpansMarshaler.writeTo( + output, instrumentationScopeMarshaler, list, schemaUrlUtf8, context); } } private static class ScopeSpanListSizeCalculator - implements BiConsumer> { - int size; - int fieldTagSize; - - @SuppressWarnings("NullAway") - MarshalerContext context; - - void initialize(ProtoFieldInfo field, MarshalerContext context) { - this.size = 0; - this.fieldTagSize = field.getTagSize(); - this.context = context; - } + extends AbstractScopeListSizeCalculator { @Override - public void accept(InstrumentationScopeInfo instrumentationScopeInfo, List spanData) { - InstrumentationScopeMarshaler instrumentationScopeMarshaler = - InstrumentationScopeMarshaler.create(instrumentationScopeInfo); - context.addData(instrumentationScopeMarshaler); - byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(instrumentationScopeInfo.getSchemaUrl()); - context.addData(schemaUrlUtf8); - int fieldSize = - InstrumentationScopeSpansMarshaler.calculateSize( - instrumentationScopeMarshaler, schemaUrlUtf8, context, spanData); - size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; + public int calculateSize( + InstrumentationScopeMarshaler instrumentationScopeMarshaler, + byte[] schemaUrlUtf8, + List list) { + return InstrumentationScopeSpansMarshaler.calculateSize( + instrumentationScopeMarshaler, schemaUrlUtf8, list, context); } } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventMarshaler.java index 50c3ca05baf..7ddf6c54e44 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventMarshaler.java @@ -65,17 +65,16 @@ public void writeTo(Serializer output) throws IOException { output.serializeUInt32(Span.Event.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); } - public static void writeTo(Serializer output, EventData eventData, MarshalerContext context) + public static void writeTo(Serializer output, EventData event, MarshalerContext context) throws IOException { - output.serializeFixed64(Span.Event.TIME_UNIX_NANO, eventData.getEpochNanos()); + output.serializeFixed64(Span.Event.TIME_UNIX_NANO, event.getEpochNanos()); if (context.marshalStringNoAllocation()) { - output.writeString(Span.Event.NAME, eventData.getName(), context.getSize()); + output.writeString(Span.Event.NAME, event.getName(), context.getSize()); } else { output.serializeString(Span.Event.NAME, context.getByteArray()); } - KeyValueMarshaler.writeTo(output, context, Span.Event.ATTRIBUTES, eventData.getAttributes()); - int droppedAttributesCount = - eventData.getTotalAttributeCount() - eventData.getAttributes().size(); + KeyValueMarshaler.writeTo(output, context, Span.Event.ATTRIBUTES, event.getAttributes()); + int droppedAttributesCount = event.getTotalAttributeCount() - event.getAttributes().size(); output.serializeUInt32(Span.Event.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); } @@ -92,9 +91,7 @@ private static int calculateSize( return size; } - public static int calculateSize(MarshalerContext context, EventData event) { - int sizeIndex = context.addSize(); - + public static int calculateSize(EventData event, MarshalerContext context) { int size = 0; size += MarshalerUtil.sizeFixed64(Span.Event.TIME_UNIX_NANO, event.getEpochNanos()); if (context.marshalStringNoAllocation()) { @@ -106,12 +103,10 @@ public static int calculateSize(MarshalerContext context, EventData event) { context.addData(nameUtf8); size += MarshalerUtil.sizeBytes(Span.Event.NAME, nameUtf8); } - size += KeyValueMarshaler.calculateSize(Span.Event.ATTRIBUTES, context, event.getAttributes()); + size += KeyValueMarshaler.calculateSize(Span.Event.ATTRIBUTES, event.getAttributes(), context); int droppedAttributesCount = event.getTotalAttributeCount() - event.getAttributes().size(); size += MarshalerUtil.sizeUInt32(Span.Event.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); - context.setSize(sizeIndex, size); - return size; } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java index 63b61e02e4c..14f17082e72 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java @@ -93,17 +93,15 @@ public void writeTo(Serializer output) throws IOException { output.serializeByteAsFixed32(Span.Link.FLAGS, traceFlags.asByte()); } - public static void writeTo(Serializer output, LinkData linkData, MarshalerContext context) + public static void writeTo(Serializer output, LinkData link, MarshalerContext context) throws IOException { - output.serializeTraceId(Span.Link.TRACE_ID, linkData.getSpanContext().getTraceId(), context); - output.serializeSpanId(Span.Link.SPAN_ID, linkData.getSpanContext().getSpanId(), context); + output.serializeTraceId(Span.Link.TRACE_ID, link.getSpanContext().getTraceId(), context); + output.serializeSpanId(Span.Link.SPAN_ID, link.getSpanContext().getSpanId(), context); output.serializeString(Span.Link.TRACE_STATE, context.getByteArray()); - KeyValueMarshaler.writeTo(output, context, Span.Link.ATTRIBUTES, linkData.getAttributes()); - int droppedAttributesCount = - linkData.getTotalAttributeCount() - linkData.getAttributes().size(); + KeyValueMarshaler.writeTo(output, context, Span.Link.ATTRIBUTES, link.getAttributes()); + int droppedAttributesCount = link.getTotalAttributeCount() - link.getAttributes().size(); output.serializeUInt32(Span.Link.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); - output.serializeByteAsFixed32( - Span.Link.FLAGS, linkData.getSpanContext().getTraceFlags().asByte()); + output.serializeByteAsFixed32(Span.Link.FLAGS, link.getSpanContext().getTraceFlags().asByte()); } private static int calculateSize( @@ -123,8 +121,7 @@ private static int calculateSize( return size; } - public static int calculateSize(MarshalerContext context, LinkData link) { - int sizeIndex = context.addSize(); + public static int calculateSize(LinkData link, MarshalerContext context) { TraceState traceState = link.getSpanContext().getTraceState(); byte[] traceStateUtf8 = traceState.isEmpty() @@ -136,15 +133,13 @@ public static int calculateSize(MarshalerContext context, LinkData link) { size += MarshalerUtil.sizeTraceId(Span.Link.TRACE_ID, link.getSpanContext().getTraceId()); size += MarshalerUtil.sizeSpanId(Span.Link.SPAN_ID, link.getSpanContext().getSpanId()); size += MarshalerUtil.sizeBytes(Span.Link.TRACE_STATE, traceStateUtf8); - size += KeyValueMarshaler.calculateSize(Span.Link.ATTRIBUTES, context, link.getAttributes()); + size += KeyValueMarshaler.calculateSize(Span.Link.ATTRIBUTES, link.getAttributes(), context); int droppedAttributesCount = link.getTotalAttributeCount() - link.getAttributes().size(); size += MarshalerUtil.sizeUInt32(Span.Link.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); size += MarshalerUtil.sizeByteAsFixed32( Span.Link.FLAGS, link.getSpanContext().getTraceFlags().asByte()); - context.setSize(sizeIndex, size); - return size; } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java index b9ebc61d001..41ff239d32f 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java @@ -158,50 +158,46 @@ public void writeTo(Serializer output) throws IOException { output.serializeByteAsFixed32(Span.FLAGS, flags.asByte()); } - public static void writeTo(Serializer output, SpanData spanData, MarshalerContext context) + public static void writeTo(Serializer output, SpanData span, MarshalerContext context) throws IOException { - output.serializeTraceId(Span.TRACE_ID, spanData.getTraceId(), context); - output.serializeSpanId(Span.SPAN_ID, spanData.getSpanId(), context); + output.serializeTraceId(Span.TRACE_ID, span.getTraceId(), context); + output.serializeSpanId(Span.SPAN_ID, span.getSpanId(), context); byte[] traceStateUtf8 = context.getByteArray(); output.serializeString(Span.TRACE_STATE, traceStateUtf8); String parentSpanId = - spanData.getParentSpanContext().isValid() - ? spanData.getParentSpanContext().getSpanId() - : null; + span.getParentSpanContext().isValid() ? span.getParentSpanContext().getSpanId() : null; output.serializeSpanId(Span.PARENT_SPAN_ID, parentSpanId, context); if (context.marshalStringNoAllocation()) { - output.writeString(Span.NAME, spanData.getName(), context.getSize()); + output.writeString(Span.NAME, span.getName(), context.getSize()); } else { byte[] nameUtf8 = context.getByteArray(); output.serializeString(Span.NAME, nameUtf8); } - output.serializeEnum(Span.KIND, toProtoSpanKind(spanData.getKind())); + output.serializeEnum(Span.KIND, toProtoSpanKind(span.getKind())); - output.serializeFixed64(Span.START_TIME_UNIX_NANO, spanData.getStartEpochNanos()); - output.serializeFixed64(Span.END_TIME_UNIX_NANO, spanData.getEndEpochNanos()); + output.serializeFixed64(Span.START_TIME_UNIX_NANO, span.getStartEpochNanos()); + output.serializeFixed64(Span.END_TIME_UNIX_NANO, span.getEndEpochNanos()); - KeyValueMarshaler.writeTo(output, context, Span.ATTRIBUTES, spanData.getAttributes()); - int droppedAttributesCount = - spanData.getTotalAttributeCount() - spanData.getAttributes().size(); + KeyValueMarshaler.writeTo(output, context, Span.ATTRIBUTES, span.getAttributes()); + int droppedAttributesCount = span.getTotalAttributeCount() - span.getAttributes().size(); output.serializeUInt32(Span.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); output.serializeRepeatedMessage( - Span.EVENTS, spanData.getEvents(), context, SpanEventMarshaler::writeTo); - int droppedEventsCount = spanData.getTotalRecordedEvents() - spanData.getEvents().size(); + Span.EVENTS, span.getEvents(), SpanEventMarshaler::writeTo, context); + int droppedEventsCount = span.getTotalRecordedEvents() - span.getEvents().size(); output.serializeUInt32(Span.DROPPED_EVENTS_COUNT, droppedEventsCount); output.serializeRepeatedMessage( - Span.LINKS, spanData.getLinks(), context, SpanLinkMarshaler::writeTo); - int droppedLinksCount = spanData.getTotalRecordedLinks() - spanData.getLinks().size(); + Span.LINKS, span.getLinks(), SpanLinkMarshaler::writeTo, context); + int droppedLinksCount = span.getTotalRecordedLinks() - span.getLinks().size(); output.serializeUInt32(Span.DROPPED_LINKS_COUNT, droppedLinksCount); - output.serializeMessage( - Span.STATUS, spanData.getStatus(), context, SpanStatusMarshaler::writeTo); + output.serializeMessage(Span.STATUS, span.getStatus(), SpanStatusMarshaler::writeTo, context); - output.serializeByteAsFixed32(Span.FLAGS, spanData.getSpanContext().getTraceFlags().asByte()); + output.serializeByteAsFixed32(Span.FLAGS, span.getSpanContext().getTraceFlags().asByte()); } private static int calculateSize( @@ -248,13 +244,12 @@ private static int calculateSize( return size; } - public static int calculateSpanSize(MarshalerContext context, SpanData spanData) { - int sizeIndex = context.addSize(); + public static int calculateSize(SpanData span, MarshalerContext context) { int size = 0; - size += MarshalerUtil.sizeTraceId(Span.TRACE_ID, spanData.getTraceId()); - size += MarshalerUtil.sizeSpanId(Span.SPAN_ID, spanData.getSpanId()); + size += MarshalerUtil.sizeTraceId(Span.TRACE_ID, span.getTraceId()); + size += MarshalerUtil.sizeSpanId(Span.SPAN_ID, span.getSpanId()); - TraceState traceState = spanData.getSpanContext().getTraceState(); + TraceState traceState = span.getSpanContext().getTraceState(); byte[] traceStateUtf8 = traceState.isEmpty() ? EMPTY_BYTES @@ -263,51 +258,46 @@ public static int calculateSpanSize(MarshalerContext context, SpanData spanData) size += MarshalerUtil.sizeBytes(Span.TRACE_STATE, traceStateUtf8); String parentSpanId = - spanData.getParentSpanContext().isValid() - ? spanData.getParentSpanContext().getSpanId() - : null; + span.getParentSpanContext().isValid() ? span.getParentSpanContext().getSpanId() : null; size += MarshalerUtil.sizeSpanId(Span.PARENT_SPAN_ID, parentSpanId); if (context.marshalStringNoAllocation()) { - int utf8Size = MarshalerUtil.getUtf8Size(spanData.getName()); + int utf8Size = MarshalerUtil.getUtf8Size(span.getName()); context.addSize(utf8Size); size += MarshalerUtil.sizeBytes(Span.NAME, utf8Size); } else { - byte[] nameUtf8 = MarshalerUtil.toBytes(spanData.getName()); + byte[] nameUtf8 = MarshalerUtil.toBytes(span.getName()); context.addData(nameUtf8); size += MarshalerUtil.sizeBytes(Span.NAME, nameUtf8); } - size += MarshalerUtil.sizeEnum(Span.KIND, toProtoSpanKind(spanData.getKind())); + size += MarshalerUtil.sizeEnum(Span.KIND, toProtoSpanKind(span.getKind())); - size += MarshalerUtil.sizeFixed64(Span.START_TIME_UNIX_NANO, spanData.getStartEpochNanos()); - size += MarshalerUtil.sizeFixed64(Span.END_TIME_UNIX_NANO, spanData.getEndEpochNanos()); + size += MarshalerUtil.sizeFixed64(Span.START_TIME_UNIX_NANO, span.getStartEpochNanos()); + size += MarshalerUtil.sizeFixed64(Span.END_TIME_UNIX_NANO, span.getEndEpochNanos()); - size += KeyValueMarshaler.calculateSize(Span.ATTRIBUTES, context, spanData.getAttributes()); - int droppedAttributesCount = - spanData.getTotalAttributeCount() - spanData.getAttributes().size(); + size += KeyValueMarshaler.calculateSize(Span.ATTRIBUTES, span.getAttributes(), context); + int droppedAttributesCount = span.getTotalAttributeCount() - span.getAttributes().size(); size += MarshalerUtil.sizeUInt32(Span.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); size += MarshalerUtil.sizeRepeatedMessage( - Span.EVENTS, SpanEventMarshaler::calculateSize, spanData.getEvents(), context); - int droppedEventsCount = spanData.getTotalRecordedEvents() - spanData.getEvents().size(); + Span.EVENTS, span.getEvents(), SpanEventMarshaler::calculateSize, context); + int droppedEventsCount = span.getTotalRecordedEvents() - span.getEvents().size(); size += MarshalerUtil.sizeUInt32(Span.DROPPED_EVENTS_COUNT, droppedEventsCount); size += MarshalerUtil.sizeRepeatedMessage( - Span.LINKS, SpanLinkMarshaler::calculateSize, spanData.getLinks(), context); - int droppedLinksCount = spanData.getTotalRecordedLinks() - spanData.getLinks().size(); + Span.LINKS, span.getLinks(), SpanLinkMarshaler::calculateSize, context); + int droppedLinksCount = span.getTotalRecordedLinks() - span.getLinks().size(); size += MarshalerUtil.sizeUInt32(Span.DROPPED_LINKS_COUNT, droppedLinksCount); - int spanStatusSize = SpanStatusMarshaler.calculateSize(context, spanData.getStatus()); - size += MarshalerUtil.sizeMessage(Span.STATUS, spanStatusSize); - size += - MarshalerUtil.sizeByteAsFixed32( - Span.FLAGS, spanData.getSpanContext().getTraceFlags().asByte()); + MarshalerUtil.sizeMessage( + Span.STATUS, span.getStatus(), SpanStatusMarshaler::calculateSize, context); - context.setSize(sizeIndex, size); + size += + MarshalerUtil.sizeByteAsFixed32(Span.FLAGS, span.getSpanContext().getTraceFlags().asByte()); return size; } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusMarshaler.java index 0bde37a9b62..024e7b6456a 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusMarshaler.java @@ -64,7 +64,7 @@ private static int calculateSize(ProtoEnumInfo protoStatusCode, byte[] descripti return size; } - public static int calculateSize(MarshalerContext context, StatusData status) { + public static int calculateSize(StatusData status, MarshalerContext context) { ProtoEnumInfo protoStatusCode = Status.StatusCode.STATUS_CODE_UNSET; if (status.getStatusCode() == StatusCode.OK) { protoStatusCode = Status.StatusCode.STATUS_CODE_OK; @@ -78,8 +78,6 @@ public static int calculateSize(MarshalerContext context, StatusData status) { size += MarshalerUtil.sizeBytes(Status.MESSAGE, descriptionUtf8); size += MarshalerUtil.sizeEnum(Status.CODE, protoStatusCode); - context.addSize(size); - return size; } } diff --git a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshalerTest.java b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshalerTest.java new file mode 100644 index 00000000000..9f1684a9d4e --- /dev/null +++ b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshalerTest.java @@ -0,0 +1,416 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Named.named; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleCounter; +import io.opentelemetry.api.metrics.DoubleHistogram; +import io.opentelemetry.api.metrics.DoubleUpDownCounter; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.metrics.LongHistogram; +import io.opentelemetry.api.metrics.LongUpDownCounter; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.TraceFlags; +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.sdk.metrics.Aggregation; +import io.opentelemetry.sdk.metrics.InstrumentSelector; +import io.opentelemetry.sdk.metrics.SdkMeterProvider; +import io.opentelemetry.sdk.metrics.View; +import io.opentelemetry.sdk.metrics.data.ExemplarData; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.data.SummaryData; +import io.opentelemetry.sdk.metrics.data.SummaryPointData; +import io.opentelemetry.sdk.metrics.data.ValueAtQuantile; +import io.opentelemetry.sdk.metrics.internal.data.ImmutableDoubleExemplarData; +import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongExemplarData; +import io.opentelemetry.sdk.metrics.internal.data.ImmutableSummaryData; +import io.opentelemetry.sdk.metrics.internal.data.ImmutableSummaryPointData; +import io.opentelemetry.sdk.metrics.internal.data.ImmutableValueAtQuantile; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; + +class LowAllocationMetricsRequestMarshalerTest { + + @SuppressWarnings("SystemOut") + @ParameterizedTest + @ArgumentsSource(MetricsProvider.class) + void validateOutput(Collection metrics) throws Exception { + byte[] result; + { + MetricsRequestMarshaler requestMarshaler = MetricsRequestMarshaler.create(metrics); + ByteArrayOutputStream customOutput = + new ByteArrayOutputStream(requestMarshaler.getBinarySerializedSize()); + requestMarshaler.writeBinaryTo(customOutput); + result = customOutput.toByteArray(); + } + + byte[] lowAllocationResult; + { + LowAllocationMetricsRequestMarshaler requestMarshaler = + new LowAllocationMetricsRequestMarshaler(); + requestMarshaler.initialize(metrics); + ByteArrayOutputStream customOutput = + new ByteArrayOutputStream(requestMarshaler.getBinarySerializedSize()); + requestMarshaler.writeBinaryTo(customOutput); + lowAllocationResult = customOutput.toByteArray(); + } + + // XXX + for (int i = 0; i < lowAllocationResult.length; i++) { + if (lowAllocationResult[i] != result[i]) { + System.err.println(i + " " + lowAllocationResult[i] + " " + result[i]); + } + } + + assertThat(lowAllocationResult).isEqualTo(result); + } + + @ParameterizedTest + @ArgumentsSource(MetricsProvider.class) + void validateJsonOutput(Collection metrics) throws Exception { + String result; + { + MetricsRequestMarshaler requestMarshaler = MetricsRequestMarshaler.create(metrics); + ByteArrayOutputStream customOutput = + new ByteArrayOutputStream(requestMarshaler.getBinarySerializedSize()); + requestMarshaler.writeJsonTo(customOutput); + result = new String(customOutput.toByteArray(), StandardCharsets.UTF_8); + } + + String lowAllocationResult; + { + LowAllocationMetricsRequestMarshaler requestMarshaler = + new LowAllocationMetricsRequestMarshaler(); + requestMarshaler.initialize(metrics); + ByteArrayOutputStream customOutput = + new ByteArrayOutputStream(requestMarshaler.getBinarySerializedSize()); + requestMarshaler.writeJsonTo(customOutput); + lowAllocationResult = new String(customOutput.toByteArray(), StandardCharsets.UTF_8); + } + + assertThat(lowAllocationResult).isEqualTo(result); + } + + @ParameterizedTest + @ArgumentsSource(ExemplarProvider.class) + void validateExemplar(ExemplarData exemplar) throws Exception { + byte[] result; + { + Marshaler marshaler = ExemplarMarshaler.create(exemplar); + ByteArrayOutputStream customOutput = + new ByteArrayOutputStream(marshaler.getBinarySerializedSize()); + marshaler.writeBinaryTo(customOutput); + result = customOutput.toByteArray(); + } + + byte[] lowAllocationResult; + { + MarshalerContext context = new MarshalerContext(); + class TestMarshaler extends MarshalerWithSize { + + protected TestMarshaler() { + super(ExemplarMarshaler.calculateSize(exemplar, context)); + } + + @Override + protected void writeTo(Serializer output) throws IOException { + ExemplarMarshaler.writeTo(output, exemplar, context); + } + } + Marshaler marshaler = new TestMarshaler(); + ByteArrayOutputStream customOutput = + new ByteArrayOutputStream(marshaler.getBinarySerializedSize()); + marshaler.writeBinaryTo(customOutput); + lowAllocationResult = customOutput.toByteArray(); + } + + assertThat(lowAllocationResult).isEqualTo(result); + } + + @Test + void validateSummary() throws Exception { + List percentileValues = + Arrays.asList(ImmutableValueAtQuantile.create(3.0, 4.0)); + List points = + Arrays.asList( + ImmutableSummaryPointData.create( + 12345, 12346, Attributes.empty(), 1, 2.0, percentileValues)); + SummaryData summary = ImmutableSummaryData.create(points); + + byte[] result; + { + Marshaler marshaler = SummaryMarshaler.create(summary); + ByteArrayOutputStream customOutput = + new ByteArrayOutputStream(marshaler.getBinarySerializedSize()); + marshaler.writeBinaryTo(customOutput); + result = customOutput.toByteArray(); + } + + byte[] lowAllocationResult; + { + MarshalerContext context = new MarshalerContext(); + class TestMarshaler extends MarshalerWithSize { + + protected TestMarshaler() { + super(SummaryMarshaler.calculateSize(summary, context)); + } + + @Override + protected void writeTo(Serializer output) throws IOException { + SummaryMarshaler.writeTo(output, summary, context); + } + } + Marshaler marshaler = new TestMarshaler(); + ByteArrayOutputStream customOutput = + new ByteArrayOutputStream(marshaler.getBinarySerializedSize()); + marshaler.writeBinaryTo(customOutput); + lowAllocationResult = customOutput.toByteArray(); + } + + assertThat(lowAllocationResult).isEqualTo(result); + } + + private static Collection metrics(Consumer metricProducer) { + InMemoryMetricReader metricReader = InMemoryMetricReader.create(); + SdkMeterProvider meterProvider = + SdkMeterProvider.builder() + .registerMetricReader(metricReader) + .registerView( + InstrumentSelector.builder().setName("exponentialhistogram").build(), + View.builder() + .setAggregation(Aggregation.base2ExponentialBucketHistogram()) + .build()) + .setResource( + Resource.create( + Attributes.builder() + .put(AttributeKey.booleanKey("key_bool"), true) + .put(AttributeKey.stringKey("key_string"), "string") + .put(AttributeKey.longKey("key_int"), 100L) + .put(AttributeKey.doubleKey("key_double"), 100.3) + .put( + AttributeKey.stringArrayKey("key_string_array"), + Arrays.asList("string", "string")) + .put(AttributeKey.longArrayKey("key_long_array"), Arrays.asList(12L, 23L)) + .put( + AttributeKey.doubleArrayKey("key_double_array"), + Arrays.asList(12.3, 23.1)) + .put( + AttributeKey.booleanArrayKey("key_boolean_array"), + Arrays.asList(true, false)) + .build())) + .build(); + metricProducer.accept(meterProvider); + + return metricReader.collectAllMetrics(); + } + + private static class MetricsProvider implements ArgumentsProvider { + @Override + public Stream provideArguments(ExtensionContext context) { + return Stream.of( + arguments( + named( + "long gauge", + metrics( + meterProvider -> + meterProvider + .get("long gauge") + .gaugeBuilder("gauge") + .setDescription("gauge description") + .setUnit("unit") + .ofLongs() + .buildWithCallback( + measurement -> + measurement.record( + 5, + Attributes.of( + AttributeKey.stringKey("key"), "value")))))), + arguments( + named( + "long counter", + metrics( + meterProvider -> { + LongCounter longCounter = + meterProvider + .get("long counter") + .counterBuilder("counter") + .setDescription("counter description") + .setUnit("unit") + .build(); + longCounter.add(1); + longCounter.add(2, Attributes.of(AttributeKey.longKey("lives"), 9L)); + longCounter.add(3); + }))), + arguments( + named( + "long updowncounter", + metrics( + meterProvider -> { + LongUpDownCounter longUpDownCounter = + meterProvider + .get("long updowncounter") + .upDownCounterBuilder("updowncounter") + .setDescription("updowncounter description") + .setUnit("unit") + .build(); + longUpDownCounter.add(1); + longUpDownCounter.add( + -1, Attributes.of(AttributeKey.booleanKey("on"), true)); + longUpDownCounter.add(1); + }))), + arguments( + named( + "double gauge", + metrics( + meterProvider -> + meterProvider + .get("double gauge") + .gaugeBuilder("doublegauge") + .setDescription("doublegauge") + .setUnit("unit") + .buildWithCallback(measurement -> measurement.record(5.0))))), + arguments( + named( + "double counter", + metrics( + meterProvider -> { + DoubleCounter doubleCounter = + meterProvider + .get("double counter") + .counterBuilder("doublecounter") + .ofDoubles() + .build(); + doubleCounter.add(1.0); + doubleCounter.add(2.0); + }))), + arguments( + named( + "double updowncounter", + metrics( + meterProvider -> { + DoubleUpDownCounter doubleUpDownCounter = + meterProvider + .get("double updowncounter") + .upDownCounterBuilder("doubleupdown") + .ofDoubles() + .build(); + doubleUpDownCounter.add(1.0); + doubleUpDownCounter.add(-1.0); + }))), + arguments( + named( + "double histogram", + metrics( + meterProvider -> { + DoubleHistogram histogram = + meterProvider + .get("double histogram") + .histogramBuilder("histogram") + .build(); + histogram.record(1.0); + histogram.record(2.0); + histogram.record(3.0); + histogram.record(4.0); + histogram.record(5.0); + }))), + arguments( + named( + "long histogram", + metrics( + meterProvider -> { + LongHistogram histogram = + meterProvider + .get("long histogram") + .histogramBuilder("histogram") + .ofLongs() + .build(); + histogram.record(1); + histogram.record(2); + histogram.record(3); + histogram.record(4); + histogram.record(5); + }))), + arguments( + named( + "double exponential histogram", + metrics( + meterProvider -> { + DoubleHistogram histogram = + meterProvider + .get("double exponential histogram") + .histogramBuilder("exponentialhistogram") + .build(); + histogram.record(1.0); + histogram.record(2.0); + histogram.record(3.0); + histogram.record(4.0); + histogram.record(5.0); + }))), + arguments( + named( + "long exponential histogram", + metrics( + meterProvider -> { + DoubleHistogram histogram = + meterProvider + .get("long exponential histogram") + .histogramBuilder("exponentialhistogram") + .build(); + histogram.record(1); + histogram.record(2); + histogram.record(3); + histogram.record(4); + histogram.record(5); + })))); + } + } + + private static class ExemplarProvider implements ArgumentsProvider { + @Override + public Stream provideArguments(ExtensionContext context) { + SpanContext spanContext = + SpanContext.create( + "7b2e170db4df2d593ddb4ddf2ddf2d59", + "170d3ddb4d23e81f", + TraceFlags.getSampled(), + TraceState.getDefault()); + + return Stream.of( + arguments( + named( + "double exemplar", + ImmutableDoubleExemplarData.create(Attributes.empty(), 12345, spanContext, 5.0))), + arguments( + named( + "long exemplar", + ImmutableLongExemplarData.create(Attributes.empty(), 12345, spanContext, 5)))); + } + } +} diff --git a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/RequestMarshalState.java b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/RequestMarshalState.java index 4b37e8b985a..d06e1d4c1c6 100644 --- a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/RequestMarshalState.java +++ b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/RequestMarshalState.java @@ -83,9 +83,13 @@ private static SpanData createSpanData() { .setAttributes( Attributes.builder() .put(KEY_BOOL, true) - // .put(KEY_STRING, "string") + .put(KEY_STRING, "string") .put(KEY_INT, 100L) .put(KEY_DOUBLE, 100.3) + .put(KEY_STRING_ARRAY, Arrays.asList("string", "string")) + .put(KEY_LONG_ARRAY, Arrays.asList(12L, 23L)) + .put(KEY_DOUBLE_ARRAY, Arrays.asList(12.3, 23.1)) + .put(KEY_BOOLEAN_ARRAY, Arrays.asList(true, false)) .build()) .setTotalAttributeCount(2) .setEvents( From 35d78c2b0d594b77a5a5068d5c8a7500bf2352a9 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Tue, 2 Apr 2024 15:50:32 +0300 Subject: [PATCH 05/15] serializing attribute keys --- .../exporter/internal/marshal/Serializer.java | 3 -- ...bstractResourceScopeMapSizeCalculator.java | 1 - .../otlp/AbstractResourceScopeMapWriter.java | 2 - .../otlp/AbstractScopeListSizeCalculator.java | 1 - .../otlp/AbstractScopeListWriter.java | 2 - .../internal/otlp/KeyValueMarshaler.java | 43 +++++++++++-------- ...AllocationMetricsRequestMarshalerTest.java | 8 ---- 7 files changed, 25 insertions(+), 35 deletions(-) diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java index c80266c4be3..33394ce9117 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java @@ -386,13 +386,10 @@ public void serializeRepeatedMessage( private static class RepeatedElementWriter implements Consumer { @SuppressWarnings("NullAway") private ProtoFieldInfo field; - @SuppressWarnings("NullAway") private Serializer output; - @SuppressWarnings("NullAway") private MessageConsumer write; - @SuppressWarnings("NullAway") private MarshalerContext context; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java index e38e24a3411..437a2d2e77c 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java @@ -18,7 +18,6 @@ public abstract class AbstractResourceScopeMapSizeCalculator implements BiConsumer>> { private int size; private int fieldTagSize; - @SuppressWarnings("NullAway") protected MarshalerContext context; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java index 48a700cb238..8558112ba1f 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java @@ -19,10 +19,8 @@ public abstract class AbstractResourceScopeMapWriter implements BiConsumer>> { @SuppressWarnings("NullAway") protected Serializer output; - @SuppressWarnings("NullAway") private ProtoFieldInfo field; - @SuppressWarnings("NullAway") protected MarshalerContext context; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java index 5f03b8d0c7e..6245067fcc9 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java @@ -17,7 +17,6 @@ public abstract class AbstractScopeListSizeCalculator implements BiConsumer> { private int size; private int fieldTagSize; - @SuppressWarnings("NullAway") protected MarshalerContext context; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java index 1ce0a07f51a..71ce0c8426e 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java @@ -17,10 +17,8 @@ public abstract class AbstractScopeListWriter implements BiConsumer> { @SuppressWarnings("NullAway") protected Serializer output; - @SuppressWarnings("NullAway") protected ProtoFieldInfo field; - @SuppressWarnings("NullAway") protected MarshalerContext context; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java index 3968efa0e2c..6ac10e32d8e 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java @@ -132,8 +132,16 @@ public static void writeTo( private static void writeTo( Serializer output, MarshalerContext context, AttributeKey attributeKey, Object value) throws IOException { - byte[] keyUtf8 = context.getByteArray(); - output.serializeString(KeyValue.KEY, keyUtf8); + if (attributeKey.getKey().isEmpty()) { + output.serializeString(KeyValue.KEY, EMPTY_BYTES); + } else if (attributeKey instanceof InternalAttributeKeyImpl) { + byte[] keyUtf8 = ((InternalAttributeKeyImpl) attributeKey).getKeyUtf8(); + output.serializeString(KeyValue.KEY, keyUtf8); + } else if (context.marshalStringNoAllocation()) { + output.writeString(KeyValue.KEY, attributeKey.getKey(), context.getSize()); + } else { + output.serializeString(KeyValue.KEY, context.getByteArray()); + } output.writeStartMessage(KeyValue.VALUE, context.getSize()); writeAttributeValue(output, context, attributeKey, value); @@ -202,21 +210,23 @@ public static int calculateSize( private static int calculateSize( AttributeKey attributeKey, Object value, MarshalerContext context) { - byte[] keyUtf8; - if (attributeKey.getKey().isEmpty()) { - keyUtf8 = EMPTY_BYTES; - } else if (attributeKey instanceof InternalAttributeKeyImpl) { - keyUtf8 = ((InternalAttributeKeyImpl) attributeKey).getKeyUtf8(); - } else { - keyUtf8 = attributeKey.getKey().getBytes(StandardCharsets.UTF_8); - } - context.addData(keyUtf8); - int sizeIndex = context.addSize(); - int valueSizeIndex = context.addSize(); - int size = 0; - size += MarshalerUtil.sizeBytes(KeyValue.KEY, keyUtf8); + if (!attributeKey.getKey().isEmpty()) { + if (attributeKey instanceof InternalAttributeKeyImpl) { + byte[] keyUtf8 = ((InternalAttributeKeyImpl) attributeKey).getKeyUtf8(); + size += MarshalerUtil.sizeBytes(KeyValue.KEY, keyUtf8); + } else if (context.marshalStringNoAllocation()) { + int utf8Size = MarshalerUtil.getUtf8Size(attributeKey.getKey()); + context.addSize(utf8Size); + size += MarshalerUtil.sizeBytes(KeyValue.KEY, utf8Size); + } else { + byte[] keyUtf8 = attributeKey.getKey().getBytes(StandardCharsets.UTF_8); + context.addData(keyUtf8); + size += MarshalerUtil.sizeBytes(KeyValue.KEY, keyUtf8); + } + } + int valueSizeIndex = context.addSize(); int valueSize = calculateValueSize(attributeKey, value, context); size += MarshalerUtil.sizeMessage(KeyValue.VALUE, valueSize); @@ -259,10 +269,8 @@ private static int calculateValueSize( private static class AttributesWriter implements BiConsumer, Object> { @SuppressWarnings("NullAway") ProtoFieldInfo field; - @SuppressWarnings("NullAway") Serializer output; - @SuppressWarnings("NullAway") MarshalerContext context; @@ -287,7 +295,6 @@ public void accept(AttributeKey attributeKey, Object value) { private static class AttributesSizeCalculator implements BiConsumer, Object> { int size; int fieldTagSize; - @SuppressWarnings("NullAway") MarshalerContext context; diff --git a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshalerTest.java b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshalerTest.java index 9f1684a9d4e..01f218170b9 100644 --- a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshalerTest.java +++ b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshalerTest.java @@ -58,7 +58,6 @@ class LowAllocationMetricsRequestMarshalerTest { - @SuppressWarnings("SystemOut") @ParameterizedTest @ArgumentsSource(MetricsProvider.class) void validateOutput(Collection metrics) throws Exception { @@ -82,13 +81,6 @@ void validateOutput(Collection metrics) throws Exception { lowAllocationResult = customOutput.toByteArray(); } - // XXX - for (int i = 0; i < lowAllocationResult.length; i++) { - if (lowAllocationResult[i] != result[i]) { - System.err.println(i + " " + lowAllocationResult[i] + " " + result[i]); - } - } - assertThat(lowAllocationResult).isEqualTo(result); } From 66078faeb8612bbc8e996611ee4fade4a86e888e Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Tue, 2 Apr 2024 15:54:03 +0300 Subject: [PATCH 06/15] spotless --- .../io/opentelemetry/exporter/internal/marshal/Serializer.java | 3 +++ .../internal/otlp/AbstractResourceScopeMapSizeCalculator.java | 1 + .../exporter/internal/otlp/AbstractResourceScopeMapWriter.java | 2 ++ .../internal/otlp/AbstractScopeListSizeCalculator.java | 1 + .../exporter/internal/otlp/AbstractScopeListWriter.java | 2 ++ .../exporter/internal/otlp/KeyValueMarshaler.java | 3 +++ 6 files changed, 12 insertions(+) diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java index 33394ce9117..c80266c4be3 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java @@ -386,10 +386,13 @@ public void serializeRepeatedMessage( private static class RepeatedElementWriter implements Consumer { @SuppressWarnings("NullAway") private ProtoFieldInfo field; + @SuppressWarnings("NullAway") private Serializer output; + @SuppressWarnings("NullAway") private MessageConsumer write; + @SuppressWarnings("NullAway") private MarshalerContext context; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java index 437a2d2e77c..e38e24a3411 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java @@ -18,6 +18,7 @@ public abstract class AbstractResourceScopeMapSizeCalculator implements BiConsumer>> { private int size; private int fieldTagSize; + @SuppressWarnings("NullAway") protected MarshalerContext context; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java index 8558112ba1f..48a700cb238 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java @@ -19,8 +19,10 @@ public abstract class AbstractResourceScopeMapWriter implements BiConsumer>> { @SuppressWarnings("NullAway") protected Serializer output; + @SuppressWarnings("NullAway") private ProtoFieldInfo field; + @SuppressWarnings("NullAway") protected MarshalerContext context; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java index 6245067fcc9..5f03b8d0c7e 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java @@ -17,6 +17,7 @@ public abstract class AbstractScopeListSizeCalculator implements BiConsumer> { private int size; private int fieldTagSize; + @SuppressWarnings("NullAway") protected MarshalerContext context; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java index 71ce0c8426e..1ce0a07f51a 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java @@ -17,8 +17,10 @@ public abstract class AbstractScopeListWriter implements BiConsumer> { @SuppressWarnings("NullAway") protected Serializer output; + @SuppressWarnings("NullAway") protected ProtoFieldInfo field; + @SuppressWarnings("NullAway") protected MarshalerContext context; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java index 6ac10e32d8e..608b5478e6d 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java @@ -269,8 +269,10 @@ private static int calculateValueSize( private static class AttributesWriter implements BiConsumer, Object> { @SuppressWarnings("NullAway") ProtoFieldInfo field; + @SuppressWarnings("NullAway") Serializer output; + @SuppressWarnings("NullAway") MarshalerContext context; @@ -295,6 +297,7 @@ public void accept(AttributeKey attributeKey, Object value) { private static class AttributesSizeCalculator implements BiConsumer, Object> { int size; int fieldTagSize; + @SuppressWarnings("NullAway") MarshalerContext context; From 2472bdbc7bda30627aa9bb65ffe33b7ed0a2c8ea Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 5 Apr 2024 15:58:58 +0300 Subject: [PATCH 07/15] move statless marshaling code to separate classes --- .../internal/marshal/JsonSerializer.java | 6 +- .../internal/marshal/MarshalerUtil.java | 136 ++++++++++- .../internal/marshal/ProtoSerializer.java | 6 +- .../exporter/internal/marshal/Serializer.java | 141 +++++++++-- .../internal/marshal/StatelessMarshaler.java | 15 ++ .../internal/marshal/StatelessMarshaler2.java | 15 ++ ...bstractResourceScopeMapSizeCalculator.java | 44 ---- .../otlp/AbstractResourceScopeMapWriter.java | 53 ----- .../otlp/AbstractScopeListSizeCalculator.java | 49 ---- .../otlp/AbstractScopeListWriter.java | 56 ----- .../internal/otlp/ArrayAnyValueMarshaler.java | 41 ---- .../otlp/ArrayAnyValueStatelessMarshaler.java | 86 +++++++ .../internal/otlp/BoolAnyValueMarshaler.java | 10 - .../otlp/BoolAnyValueStatelessMarshaler.java | 28 +++ .../otlp/DoubleAnyValueMarshaler.java | 10 - .../DoubleAnyValueStatelessMarshaler.java | 28 +++ .../internal/otlp/IntAnyValueMarshaler.java | 10 - .../otlp/IntAnyValueStatelessMarshaler.java | 31 +++ .../internal/otlp/KeyValueMarshaler.java | 199 ---------------- .../otlp/KeyValueStatelessMarshaler.java | 173 ++++++++++++++ .../otlp/StringAnyValueMarshaler.java | 25 -- .../StringAnyValueStatelessMarshaler.java | 34 +++ .../otlp/metrics/ExemplarMarshaler.java | 64 +---- .../metrics/ExemplarStatelessMarshaler.java | 91 ++++++++ .../ExponentialHistogramBucketsMarshaler.java | 27 +-- ...ialHistogramBucketsStatelessMarshaler.java | 46 ++++ ...xponentialHistogramDataPointMarshaler.java | 85 +------ ...lHistogramDataPointStatelessMarshaler.java | 109 +++++++++ .../ExponentialHistogramMarshaler.java | 40 +--- ...xponentialHistogramStatelessMarshaler.java | 54 +++++ .../internal/otlp/metrics/GaugeMarshaler.java | 27 --- .../otlp/metrics/GaugeStatelessMarshaler.java | 47 ++++ .../metrics/HistogramDataPointMarshaler.java | 50 ---- .../HistogramDataPointStatelessMarshaler.java | 80 +++++++ .../otlp/metrics/HistogramMarshaler.java | 33 --- .../metrics/HistogramStatelessMarshaler.java | 51 ++++ .../InstrumentationScopeMetricsMarshaler.java | 32 --- ...ntationScopeMetricsStatelessMarshaler.java | 63 +++++ .../LowAllocationMetricsRequestMarshaler.java | 57 ++--- .../otlp/metrics/MetricMarshaler.java | 204 ---------------- .../metrics/MetricStatelessMarshaler.java | 220 ++++++++++++++++++ .../metrics/NumberDataPointMarshaler.java | 40 +--- .../NumberDataPointStatelessMarshaler.java | 74 ++++++ .../metrics/ResourceMetricsMarshaler.java | 74 ------ .../ResourceMetricsStatelessMarshaler.java | 80 +++++++ .../internal/otlp/metrics/SumMarshaler.java | 36 --- .../otlp/metrics/SumStatelessMarshaler.java | 54 +++++ .../metrics/SummaryDataPointMarshaler.java | 35 --- .../SummaryDataPointStatelessMarshaler.java | 63 +++++ .../otlp/metrics/SummaryMarshaler.java | 26 --- .../metrics/SummaryStatelessMarshaler.java | 44 ++++ .../metrics/ValueAtQuantileMarshaler.java | 13 +- .../ValueAtQuantileStatelessMarshaler.java | 29 +++ .../InstrumentationScopeSpansMarshaler.java | 5 +- ...mentationScopeSpansStatelessMarshaler.java | 64 +++++ .../LowAllocationTraceRequestMarshaler.java | 56 ++--- .../otlp/traces/ResourceSpansMarshaler.java | 35 +-- .../ResourceSpansStatelessMarshaler.java | 80 +++++++ .../otlp/traces/SpanEventMarshaler.java | 33 --- .../traces/SpanEventStatelessMarshaler.java | 47 ++++ .../otlp/traces/SpanLinkMarshaler.java | 34 --- .../traces/SpanLinkStatelessMarshaler.java | 65 ++++++ .../internal/otlp/traces/SpanMarshaler.java | 101 -------- .../otlp/traces/SpanStatelessMarshaler.java | 116 +++++++++ .../otlp/traces/SpanStatusMarshaler.java | 33 --- .../traces/SpanStatusStatelessMarshaler.java | 54 +++++ ...AllocationMetricsRequestMarshalerTest.java | 8 +- 67 files changed, 2240 insertions(+), 1635 deletions(-) create mode 100644 exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/StatelessMarshaler.java create mode 100644 exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/StatelessMarshaler2.java delete mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java delete mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java delete mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java delete mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExemplarStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramBucketsStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramDataPointStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramDataPointStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/NumberDataPointStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryDataPointStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ValueAtQuantileStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatelessMarshaler.java create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusStatelessMarshaler.java diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java index 00b02d64521..9dcc784f89b 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java @@ -174,15 +174,15 @@ public void serializeRepeatedMessage( @Override public void serializeRepeatedMessage( ProtoFieldInfo field, - List messages, - MessageConsumer consumer, + List messages, + StatelessMarshaler marshaler, MarshalerContext context) throws IOException { generator.writeArrayFieldStart(field.getJsonName()); for (int i = 0; i < messages.size(); i++) { T message = messages.get(i); generator.writeStartObject(); - consumer.accept(this, message, context); + marshaler.writeTo(this, message, context); generator.writeEndObject(); } generator.writeEndArray(); diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java index d0d307665c8..741a01e1a1b 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java @@ -5,6 +5,8 @@ package io.opentelemetry.exporter.internal.marshal; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanId; import io.opentelemetry.api.trace.TraceId; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; @@ -19,6 +21,7 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.ToIntBiFunction; @@ -35,6 +38,7 @@ public final class MarshalerUtil { CodedOutputStream.computeLengthDelimitedFieldSize(TraceId.getLength() / 2); private static final int SPAN_ID_VALUE_SIZE = CodedOutputStream.computeLengthDelimitedFieldSize(SpanId.getLength() / 2); + private static final Object ATTRIBUTES_SIZE_CALCULATOR_KEY = new Object(); private static final boolean JSON_AVAILABLE; @@ -266,11 +270,32 @@ public static int sizeRepeatedMessage( return size; } + public static int sizeRepeatedMessage( + ProtoFieldInfo field, + List messages, + StatelessMarshaler marshaler, + MarshalerContext context) { + if (messages.isEmpty()) { + return 0; + } + + int size = 0; + int fieldTagSize = field.getTagSize(); + for (int i = 0; i < messages.size(); i++) { + T message = messages.get(i); + int sizeIndex = context.addSize(); + int fieldSize = marshaler.getBinarySerializedSize(message, context); + context.setSize(sizeIndex, fieldSize); + size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; + } + return size; + } + /** Returns the size of a repeated message field. */ public static int sizeRepeatedMessage( ProtoFieldInfo field, - Collection messages, - ToIntBiFunction consumer, + Collection messages, + StatelessMarshaler marshaler, MarshalerContext context, Object key) { if (messages.isEmpty()) { @@ -279,36 +304,96 @@ public static int sizeRepeatedMessage( RepeatedElementSizeCalculator sizeCalculator = context.getInstance(key, RepeatedElementSizeCalculator::new); - sizeCalculator.initialize(field, consumer, context); + sizeCalculator.initialize(field, marshaler, context); messages.forEach(sizeCalculator); return sizeCalculator.size; } + public static int sizeRepeatedMessage( + ProtoFieldInfo field, + Map messages, + StatelessMarshaler2 marshaler, + MarshalerContext context, + Object key) { + if (messages.isEmpty()) { + return 0; + } + + RepeatedElementPairSizeCalculator sizeCalculator = + context.getInstance(key, RepeatedElementPairSizeCalculator::new); + sizeCalculator.initialize(field, marshaler, context); + messages.forEach(sizeCalculator); + + return sizeCalculator.size; + } + + public static int sizeRepeatedMessage( + ProtoFieldInfo field, + Attributes attributes, + StatelessMarshaler2, Object> marshaler, + MarshalerContext context) { + if (attributes.isEmpty()) { + return 0; + } + + RepeatedElementPairSizeCalculator, Object> sizeCalculator = + context.getInstance(ATTRIBUTES_SIZE_CALCULATOR_KEY, RepeatedElementPairSizeCalculator::new); + sizeCalculator.initialize(field, marshaler, context); + attributes.forEach(sizeCalculator); + + return sizeCalculator.size; + } + private static class RepeatedElementSizeCalculator implements Consumer { private int size; private int fieldTagSize; @SuppressWarnings("NullAway") - private ToIntBiFunction calculateSize; + private StatelessMarshaler marshaler; @SuppressWarnings("NullAway") private MarshalerContext context; void initialize( - ProtoFieldInfo field, - ToIntBiFunction calculateSize, - MarshalerContext context) { + ProtoFieldInfo field, StatelessMarshaler marshaler, MarshalerContext context) { this.size = 0; this.fieldTagSize = field.getTagSize(); - this.calculateSize = calculateSize; + this.marshaler = marshaler; this.context = context; } @Override public void accept(T element) { int sizeIndex = context.addSize(); - int fieldSize = calculateSize.applyAsInt(element, context); + int fieldSize = marshaler.getBinarySerializedSize(element, context); + context.setSize(sizeIndex, fieldSize); + size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; + } + } + + private static class RepeatedElementPairSizeCalculator implements BiConsumer { + private int size; + private int fieldTagSize; + + @SuppressWarnings("NullAway") + private StatelessMarshaler2 marshaler; + + @SuppressWarnings("NullAway") + private MarshalerContext context; + + void initialize( + ProtoFieldInfo field, StatelessMarshaler2 marshaler, MarshalerContext context) { + this.size = 0; + this.fieldTagSize = field.getTagSize(); + this.marshaler = marshaler; + this.context = context; + } + + @Override + public void accept(K key, V value) { + int sizeIndex = context.addSize(); + int fieldSize = marshaler.getBinarySerializedSize(key, value, context); context.setSize(sizeIndex, fieldSize); size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; } @@ -326,12 +411,22 @@ public static int sizeMessage(ProtoFieldInfo field, int fieldSize) { } public static int sizeMessage( + ProtoFieldInfo field, T element, StatelessMarshaler marshaler, MarshalerContext context) { + int sizeIndex = context.addSize(); + int fieldSize = marshaler.getBinarySerializedSize(element, context); + int size = field.getTagSize() + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; + context.setSize(sizeIndex, fieldSize); + return size; + } + + public static int sizeMessage( ProtoFieldInfo field, - T element, - ToIntBiFunction sizeCalculator, + K key, + V value, + StatelessMarshaler2 marshaler, MarshalerContext context) { int sizeIndex = context.addSize(); - int fieldSize = sizeCalculator.applyAsInt(element, context); + int fieldSize = marshaler.getBinarySerializedSize(key, value, context); int size = field.getTagSize() + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; context.setSize(sizeIndex, fieldSize); return size; @@ -458,6 +553,23 @@ public static int sizeSpanId(ProtoFieldInfo field, @Nullable String spanId) { return field.getTagSize() + SPAN_ID_VALUE_SIZE; } + /** Returns the size of a string field. */ + @SuppressWarnings("SystemOut") + public static int sizeString(ProtoFieldInfo field, String value, MarshalerContext context) { + if (value.isEmpty()) { + return sizeBytes(field, 0); + } + if (context.marshalStringNoAllocation()) { + int utf8Size = MarshalerUtil.getUtf8Size(value); + context.addSize(utf8Size); + return sizeBytes(field, utf8Size); + } else { + byte[] valueUtf8 = MarshalerUtil.toBytes(value); + context.addData(valueUtf8); + return sizeBytes(field, valueUtf8.length); + } + } + /** Converts the string to utf8 bytes for encoding. */ public static byte[] toBytes(@Nullable String value) { if (value == null || value.isEmpty()) { diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java index a6c68e4454e..bd871619f73 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java @@ -214,14 +214,14 @@ public void serializeRepeatedMessage( @Override public void serializeRepeatedMessage( ProtoFieldInfo field, - List messages, - MessageConsumer consumer, + List messages, + StatelessMarshaler marshaler, MarshalerContext context) throws IOException { for (int i = 0; i < messages.size(); i++) { T message = messages.get(i); writeStartMessage(field, context.getSize()); - consumer.accept(this, message, context); + marshaler.writeTo(this, message, context); writeEndMessage(); } } diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java index c80266c4be3..3eb283b044a 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java @@ -5,10 +5,14 @@ package io.opentelemetry.exporter.internal.marshal; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.sdk.internal.DynamicPrimitiveLongList; import java.io.IOException; import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; import java.util.function.Consumer; import javax.annotation.Nullable; @@ -25,6 +29,7 @@ * at any time. */ public abstract class Serializer implements AutoCloseable { + private static final Object ATTRIBUTES_WRITER_KEY = new Object(); Serializer() {} @@ -215,6 +220,19 @@ public void serializeString(ProtoFieldInfo field, String string, int utf8Length) writeString(field, string, utf8Length); } + public void serializeString(ProtoFieldInfo field, String string, MarshalerContext context) + throws IOException { + if (string.isEmpty()) { + return; + } + if (context.marshalStringNoAllocation()) { + writeString(field, string, context.getSize()); + } else { + byte[] valueUtf8 = context.getByteArray(); + writeString(field, valueUtf8); + } + } + /** Writes a protobuf {@code string} field, even if it matches the default value. */ public abstract void writeString(ProtoFieldInfo field, byte[] utf8Bytes) throws IOException; @@ -231,10 +249,10 @@ public void serializeBytes(ProtoFieldInfo field, byte[] value) throws IOExceptio public abstract void writeBytes(ProtoFieldInfo field, byte[] value) throws IOException; - public abstract void writeStartMessage(ProtoFieldInfo field, int protoMessageSize) + protected abstract void writeStartMessage(ProtoFieldInfo field, int protoMessageSize) throws IOException; - public abstract void writeEndMessage() throws IOException; + protected abstract void writeEndMessage() throws IOException; /** Serializes a protobuf embedded {@code message}. */ public void serializeMessage(ProtoFieldInfo field, Marshaler message) throws IOException { @@ -244,13 +262,22 @@ public void serializeMessage(ProtoFieldInfo field, Marshaler message) throws IOE } public void serializeMessage( + ProtoFieldInfo field, T message, StatelessMarshaler marshaler, MarshalerContext context) + throws IOException { + writeStartMessage(field, context.getSize()); + marshaler.writeTo(this, message, context); + writeEndMessage(); + } + + public void serializeMessage( ProtoFieldInfo field, - T message, - MessageConsumer consumer, + K key, + V value, + StatelessMarshaler2 marshaler, MarshalerContext context) throws IOException { writeStartMessage(field, context.getSize()); - consumer.accept(this, message, context); + marshaler.writeTo(this, key, value, context); writeEndMessage(); } @@ -360,15 +387,15 @@ public abstract void serializeRepeatedMessage( /** Serializes {@code repeated message} field. */ public abstract void serializeRepeatedMessage( ProtoFieldInfo field, - List messages, - MessageConsumer consumer, + List messages, + StatelessMarshaler marshaler, MarshalerContext context) throws IOException; public void serializeRepeatedMessage( ProtoFieldInfo field, - Collection messages, - MessageConsumer consumer, + Collection messages, + StatelessMarshaler marshaler, MarshalerContext context, Object key) throws IOException { @@ -376,13 +403,50 @@ public void serializeRepeatedMessage( if (!messages.isEmpty()) { RepeatedElementWriter writer = context.getInstance(key, RepeatedElementWriter::new); - writer.initialize(field, this, consumer, context); + writer.initialize(field, this, marshaler, context); + messages.forEach(writer); + } + + writeEndRepeated(); + } + + public void serializeRepeatedMessage( + ProtoFieldInfo field, + Map messages, + StatelessMarshaler2 marshaler, + MarshalerContext context, + Object key) + throws IOException { + writeStartRepeated(field); + + if (!messages.isEmpty()) { + RepeatedElementPairWriter writer = + context.getInstance(key, RepeatedElementPairWriter::new); + writer.initialize(field, this, marshaler, context); messages.forEach(writer); } writeEndRepeated(); } + public void serializeRepeatedMessage( + ProtoFieldInfo field, + Attributes attributes, + StatelessMarshaler2, Object> marshaler, + MarshalerContext context) + throws IOException { + writeStartRepeated(field); + + if (!attributes.isEmpty()) { + RepeatedElementPairWriter, Object> writer = + context.getInstance(ATTRIBUTES_WRITER_KEY, RepeatedElementPairWriter::new); + writer.initialize(field, this, marshaler, context); + attributes.forEach(writer); + } + + writeEndRepeated(); + } + private static class RepeatedElementWriter implements Consumer { @SuppressWarnings("NullAway") private ProtoFieldInfo field; @@ -391,7 +455,7 @@ private static class RepeatedElementWriter implements Consumer { private Serializer output; @SuppressWarnings("NullAway") - private MessageConsumer write; + private StatelessMarshaler marshaler; @SuppressWarnings("NullAway") private MarshalerContext context; @@ -399,11 +463,11 @@ private static class RepeatedElementWriter implements Consumer { void initialize( ProtoFieldInfo field, Serializer output, - MessageConsumer write, + StatelessMarshaler marshaler, MarshalerContext context) { this.field = field; this.output = output; - this.write = write; + this.marshaler = marshaler; this.context = context; } @@ -411,7 +475,43 @@ void initialize( public void accept(T element) { try { output.writeStartRepeatedElement(field, context.getSize()); - write.accept(output, element, context); + marshaler.writeTo(output, element, context); + output.writeEndRepeatedElement(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + } + + private static class RepeatedElementPairWriter implements BiConsumer { + @SuppressWarnings("NullAway") + private ProtoFieldInfo field; + + @SuppressWarnings("NullAway") + private Serializer output; + + @SuppressWarnings("NullAway") + private StatelessMarshaler2 marshaler; + + @SuppressWarnings("NullAway") + private MarshalerContext context; + + void initialize( + ProtoFieldInfo field, + Serializer output, + StatelessMarshaler2 marshaler, + MarshalerContext context) { + this.field = field; + this.output = output; + this.marshaler = marshaler; + this.context = context; + } + + @Override + public void accept(K key, V value) { + try { + output.writeStartRepeatedElement(field, context.getSize()); + marshaler.writeTo(output, key, value, context); output.writeEndRepeatedElement(); } catch (IOException e) { throw new IllegalStateException(e); @@ -420,17 +520,17 @@ public void accept(T element) { } /** Writes start of repeated messages. */ - public abstract void writeStartRepeated(ProtoFieldInfo field) throws IOException; + protected abstract void writeStartRepeated(ProtoFieldInfo field) throws IOException; /** Writes end of repeated messages. */ - public abstract void writeEndRepeated() throws IOException; + protected abstract void writeEndRepeated() throws IOException; /** Writes start of a repeated message element. */ - public abstract void writeStartRepeatedElement(ProtoFieldInfo field, int protoMessageSize) + protected abstract void writeStartRepeatedElement(ProtoFieldInfo field, int protoMessageSize) throws IOException; /** Writes end of a repeated message element. */ - public abstract void writeEndRepeatedElement() throws IOException; + protected abstract void writeEndRepeatedElement() throws IOException; /** Writes the value for a message field that has been pre-serialized. */ public abstract void writeSerializedMessage(byte[] protoSerialized, String jsonSerialized) @@ -438,9 +538,4 @@ public abstract void writeSerializedMessage(byte[] protoSerialized, String jsonS @Override public abstract void close() throws IOException; - - @FunctionalInterface - public interface MessageConsumer { - void accept(O output, D data, C context) throws IOException; - } } diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/StatelessMarshaler.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/StatelessMarshaler.java new file mode 100644 index 00000000000..efdd9c2075f --- /dev/null +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/StatelessMarshaler.java @@ -0,0 +1,15 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.marshal; + +import java.io.IOException; + +public interface StatelessMarshaler { + + int getBinarySerializedSize(T value, MarshalerContext context); + + void writeTo(Serializer output, T value, MarshalerContext context) throws IOException; +} diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/StatelessMarshaler2.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/StatelessMarshaler2.java new file mode 100644 index 00000000000..7742e25e070 --- /dev/null +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/StatelessMarshaler2.java @@ -0,0 +1,15 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.marshal; + +import java.io.IOException; + +public interface StatelessMarshaler2 { + + int getBinarySerializedSize(K key, V value, MarshalerContext context); + + void writeTo(Serializer output, K key, V value, MarshalerContext context) throws IOException; +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java deleted file mode 100644 index e38e24a3411..00000000000 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapSizeCalculator.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.exporter.internal.otlp; - -import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; -import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; -import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.resources.Resource; -import java.util.List; -import java.util.Map; -import java.util.function.BiConsumer; - -public abstract class AbstractResourceScopeMapSizeCalculator - implements BiConsumer>> { - private int size; - private int fieldTagSize; - - @SuppressWarnings("NullAway") - protected MarshalerContext context; - - public void initialize(ProtoFieldInfo field, MarshalerContext context) { - this.size = 0; - this.fieldTagSize = field.getTagSize(); - this.context = context; - } - - public abstract int calculateSize( - Resource resource, Map> instrumentationScopeInfoListMap); - - @Override - public void accept( - Resource resource, Map> instrumentationScopeInfoListMap) { - int fieldSize = calculateSize(resource, instrumentationScopeInfoListMap); - size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; - } - - public int getSize() { - return size; - } -} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java deleted file mode 100644 index 48a700cb238..00000000000 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractResourceScopeMapWriter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.exporter.internal.otlp; - -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; -import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; -import io.opentelemetry.exporter.internal.marshal.Serializer; -import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.resources.Resource; -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.function.BiConsumer; - -public abstract class AbstractResourceScopeMapWriter - implements BiConsumer>> { - @SuppressWarnings("NullAway") - protected Serializer output; - - @SuppressWarnings("NullAway") - private ProtoFieldInfo field; - - @SuppressWarnings("NullAway") - protected MarshalerContext context; - - public void initialize(Serializer output, ProtoFieldInfo field, MarshalerContext context) { - this.output = output; - this.field = field; - this.context = context; - } - - protected abstract void handle( - Map> instrumentationScopeInfoListMap) throws IOException; - - @Override - public void accept( - Resource resource, Map> instrumentationScopeInfoListMap) { - try { - output.writeStartRepeated(field); - output.writeStartRepeatedElement(field, context.getSize()); - - handle(instrumentationScopeInfoListMap); - - output.writeEndRepeatedElement(); - output.writeEndRepeated(); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } -} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java deleted file mode 100644 index 5f03b8d0c7e..00000000000 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListSizeCalculator.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.exporter.internal.otlp; - -import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; -import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; -import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; -import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import java.util.List; -import java.util.function.BiConsumer; - -public abstract class AbstractScopeListSizeCalculator - implements BiConsumer> { - private int size; - private int fieldTagSize; - - @SuppressWarnings("NullAway") - protected MarshalerContext context; - - public void initialize(ProtoFieldInfo field, MarshalerContext context) { - this.size = 0; - this.fieldTagSize = field.getTagSize(); - this.context = context; - } - - public abstract int calculateSize( - InstrumentationScopeMarshaler instrumentationScopeMarshaler, - byte[] schemaUrlUtf8, - List list); - - @Override - public void accept(InstrumentationScopeInfo instrumentationScopeInfo, List list) { - InstrumentationScopeMarshaler instrumentationScopeMarshaler = - InstrumentationScopeMarshaler.create(instrumentationScopeInfo); - context.addData(instrumentationScopeMarshaler); - byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(instrumentationScopeInfo.getSchemaUrl()); - context.addData(schemaUrlUtf8); - int fieldSize = calculateSize(instrumentationScopeMarshaler, schemaUrlUtf8, list); - size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; - } - - public int getSize() { - return size; - } -} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java deleted file mode 100644 index 1ce0a07f51a..00000000000 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AbstractScopeListWriter.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.exporter.internal.otlp; - -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; -import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; -import io.opentelemetry.exporter.internal.marshal.Serializer; -import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import java.io.IOException; -import java.util.List; -import java.util.function.BiConsumer; - -public abstract class AbstractScopeListWriter - implements BiConsumer> { - @SuppressWarnings("NullAway") - protected Serializer output; - - @SuppressWarnings("NullAway") - protected ProtoFieldInfo field; - - @SuppressWarnings("NullAway") - protected MarshalerContext context; - - public void initialize(Serializer output, ProtoFieldInfo field, MarshalerContext context) { - this.output = output; - this.field = field; - this.context = context; - } - - protected abstract void handle( - InstrumentationScopeMarshaler instrumentationScopeMarshaler, - List list, - byte[] schemaUrlUtf8) - throws IOException; - - @Override - public void accept(InstrumentationScopeInfo instrumentationScopeInfo, List list) { - try { - output.writeStartRepeated(field); - output.writeStartRepeatedElement(field, context.getSize()); - - InstrumentationScopeMarshaler instrumentationScopeMarshaler = - context.getObject(InstrumentationScopeMarshaler.class); - byte[] schemaUrlUtf8 = context.getByteArray(); - handle(instrumentationScopeMarshaler, list, schemaUrlUtf8); - - output.writeEndRepeatedElement(); - output.writeEndRepeated(); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } -} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueMarshaler.java index b83e7f83601..aa1c25e9c14 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueMarshaler.java @@ -5,19 +5,15 @@ package io.opentelemetry.exporter.internal.otlp; -import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; import io.opentelemetry.exporter.internal.marshal.Marshaler; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; 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.marshal.Serializer.MessageConsumer; import io.opentelemetry.proto.common.v1.internal.AnyValue; import io.opentelemetry.proto.common.v1.internal.ArrayValue; import java.io.IOException; import java.util.List; import java.util.function.Function; -import java.util.function.ToIntBiFunction; final class ArrayAnyValueMarshaler extends MarshalerWithSize { private final Marshaler value; @@ -63,33 +59,10 @@ public void writeTo(Serializer output) throws IOException { output.serializeMessage(AnyValue.ARRAY_VALUE, value); } - public static void writeTo( - Serializer output, - List list, - MessageConsumer consumer, - MarshalerContext context) - throws IOException { - output.writeStartMessage(AnyValue.ARRAY_VALUE, context.getSize()); - ArrayValueMarshaler.writeTo(output, list, consumer, context); - output.writeEndMessage(); - } - private static int calculateSize(Marshaler value) { return MarshalerUtil.sizeMessage(AnyValue.ARRAY_VALUE, value); } - public static int calculateSize( - List list, ToIntBiFunction consumer, MarshalerContext context) { - int sizeIndex = context.addSize(); - int fieldSize = ArrayValueMarshaler.calculateSize(list, consumer, context); - int size = - AnyValue.ARRAY_VALUE.getTagSize() - + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) - + fieldSize; - context.setSize(sizeIndex, fieldSize); - return size; - } - private static class ArrayValueMarshaler extends MarshalerWithSize { private final Marshaler[] values; @@ -104,22 +77,8 @@ public void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(ArrayValue.VALUES, values); } - public static void writeTo( - Serializer output, - List messages, - MessageConsumer consumer, - MarshalerContext context) - throws IOException { - output.serializeRepeatedMessage(ArrayValue.VALUES, messages, consumer, context); - } - private static int calculateSize(Marshaler[] values) { return MarshalerUtil.sizeRepeatedMessage(ArrayValue.VALUES, values); } - - public static int calculateSize( - List messages, ToIntBiFunction consumer, MarshalerContext context) { - return MarshalerUtil.sizeRepeatedMessage(ArrayValue.VALUES, messages, consumer, context); - } } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueStatelessMarshaler.java new file mode 100644 index 00000000000..dcc6f9ff05c --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueStatelessMarshaler.java @@ -0,0 +1,86 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp; + +import io.opentelemetry.api.common.AttributeType; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler2; +import io.opentelemetry.proto.common.v1.internal.ArrayValue; +import java.io.IOException; +import java.util.List; + +final class ArrayAnyValueStatelessMarshaler + implements StatelessMarshaler2> { + static final ArrayAnyValueStatelessMarshaler INSTANCE = + new ArrayAnyValueStatelessMarshaler<>(); + + @SuppressWarnings("unchecked") + @Override + public void writeTo(Serializer output, AttributeType type, List list, MarshalerContext context) + throws IOException { + switch (type) { + case STRING_ARRAY: + output.serializeRepeatedMessage( + ArrayValue.VALUES, + (List) list, + StringAnyValueStatelessMarshaler.INSTANCE, + context); + return; + case LONG_ARRAY: + output.serializeRepeatedMessage( + ArrayValue.VALUES, (List) list, IntAnyValueStatelessMarshaler.INSTANCE, context); + return; + case BOOLEAN_ARRAY: + output.serializeRepeatedMessage( + ArrayValue.VALUES, + (List) list, + BoolAnyValueStatelessMarshaler.INSTANCE, + context); + return; + case DOUBLE_ARRAY: + output.serializeRepeatedMessage( + ArrayValue.VALUES, + (List) list, + DoubleAnyValueStatelessMarshaler.INSTANCE, + context); + return; + default: + throw new IllegalArgumentException("Unsupported attribute type."); + } + } + + @SuppressWarnings("unchecked") + @Override + public int getBinarySerializedSize(AttributeType type, List list, MarshalerContext context) { + switch (type) { + case STRING_ARRAY: + return MarshalerUtil.sizeRepeatedMessage( + ArrayValue.VALUES, + (List) list, + StringAnyValueStatelessMarshaler.INSTANCE, + context); + case LONG_ARRAY: + return MarshalerUtil.sizeRepeatedMessage( + ArrayValue.VALUES, (List) list, IntAnyValueStatelessMarshaler.INSTANCE, context); + case BOOLEAN_ARRAY: + return MarshalerUtil.sizeRepeatedMessage( + ArrayValue.VALUES, + (List) list, + BoolAnyValueStatelessMarshaler.INSTANCE, + context); + case DOUBLE_ARRAY: + return MarshalerUtil.sizeRepeatedMessage( + ArrayValue.VALUES, + (List) list, + DoubleAnyValueStatelessMarshaler.INSTANCE, + context); + default: + throw new IllegalArgumentException("Unsupported attribute type."); + } + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java index 4af1bce6fe9..aed4ab59cbc 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java @@ -6,7 +6,6 @@ package io.opentelemetry.exporter.internal.otlp; import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.proto.common.v1.internal.AnyValue; @@ -36,16 +35,7 @@ public static void writeTo(Serializer output, boolean value) throws IOException output.writeBool(AnyValue.BOOL_VALUE, value); } - public static void writeTo(Serializer output, boolean value, MarshalerContext context) - throws IOException { - writeTo(output, value); - } - public static int calculateSize(boolean value) { return AnyValue.BOOL_VALUE.getTagSize() + CodedOutputStream.computeBoolSizeNoTag(value); } - - public static int calculateSize(boolean value, MarshalerContext context) { - return calculateSize(value); - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueStatelessMarshaler.java new file mode 100644 index 00000000000..0ad4fdd5af6 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueStatelessMarshaler.java @@ -0,0 +1,28 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp; + +import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.proto.common.v1.internal.AnyValue; +import java.io.IOException; + +final class BoolAnyValueStatelessMarshaler implements StatelessMarshaler { + static final BoolAnyValueStatelessMarshaler INSTANCE = new BoolAnyValueStatelessMarshaler(); + + @Override + public void writeTo(Serializer output, Boolean value, MarshalerContext context) + throws IOException { + output.writeBool(AnyValue.BOOL_VALUE, value); + } + + @Override + public int getBinarySerializedSize(Boolean value, MarshalerContext context) { + return AnyValue.BOOL_VALUE.getTagSize() + CodedOutputStream.computeBoolSizeNoTag(value); + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java index b5d9c0b30b2..8621fead694 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java @@ -6,7 +6,6 @@ package io.opentelemetry.exporter.internal.otlp; import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.proto.common.v1.internal.AnyValue; @@ -36,16 +35,7 @@ public static void writeTo(Serializer output, double value) throws IOException { output.writeDouble(AnyValue.DOUBLE_VALUE, value); } - public static void writeTo(Serializer output, double value, MarshalerContext context) - throws IOException { - writeTo(output, value); - } - public static int calculateSize(double value) { return AnyValue.DOUBLE_VALUE.getTagSize() + CodedOutputStream.computeDoubleSizeNoTag(value); } - - public static int calculateSize(double value, MarshalerContext context) { - return calculateSize(value); - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueStatelessMarshaler.java new file mode 100644 index 00000000000..e4a312961f9 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueStatelessMarshaler.java @@ -0,0 +1,28 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp; + +import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.proto.common.v1.internal.AnyValue; +import java.io.IOException; + +final class DoubleAnyValueStatelessMarshaler implements StatelessMarshaler { + static final DoubleAnyValueStatelessMarshaler INSTANCE = new DoubleAnyValueStatelessMarshaler(); + + @Override + public void writeTo(Serializer output, Double value, MarshalerContext context) + throws IOException { + output.writeDouble(AnyValue.DOUBLE_VALUE, value); + } + + @Override + public int getBinarySerializedSize(Double value, MarshalerContext context) { + return AnyValue.DOUBLE_VALUE.getTagSize() + CodedOutputStream.computeDoubleSizeNoTag(value); + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java index 0038038c552..38c9b038019 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java @@ -6,7 +6,6 @@ package io.opentelemetry.exporter.internal.otlp; import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.proto.common.v1.internal.AnyValue; @@ -36,16 +35,7 @@ public static void writeTo(Serializer output, long value) throws IOException { output.writeInt64(AnyValue.INT_VALUE, value); } - public static void writeTo(Serializer output, long value, MarshalerContext context) - throws IOException { - writeTo(output, value); - } - public static int calculateSize(long value) { return AnyValue.INT_VALUE.getTagSize() + CodedOutputStream.computeInt64SizeNoTag(value); } - - public static int calculateSize(long value, MarshalerContext context) { - return calculateSize(value); - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueStatelessMarshaler.java new file mode 100644 index 00000000000..871f17d6ddf --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueStatelessMarshaler.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp; + +import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.proto.common.v1.internal.AnyValue; +import java.io.IOException; + +final class IntAnyValueStatelessMarshaler implements StatelessMarshaler { + static final IntAnyValueStatelessMarshaler INSTANCE = new IntAnyValueStatelessMarshaler(); + + @Override + public void writeTo(Serializer output, Long value, MarshalerContext context) throws IOException { + output.writeInt64(AnyValue.INT_VALUE, value); + } + + public static int calculateSize(long value) { + return AnyValue.INT_VALUE.getTagSize() + CodedOutputStream.computeInt64SizeNoTag(value); + } + + @Override + public int getBinarySerializedSize(Long value, MarshalerContext context) { + return AnyValue.INT_VALUE.getTagSize() + CodedOutputStream.computeInt64SizeNoTag(value); + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java index 608b5478e6d..56a3fa06461 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java @@ -9,12 +9,9 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.incubator.logs.KeyAnyValue; import io.opentelemetry.api.internal.InternalAttributeKeyImpl; -import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; import io.opentelemetry.exporter.internal.marshal.Marshaler; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; -import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.proto.common.v1.internal.KeyValue; import java.io.IOException; @@ -111,206 +108,10 @@ public void writeTo(Serializer output) throws IOException { output.serializeMessage(KeyValue.VALUE, value); } - public static void writeTo( - Serializer output, - MarshalerContext context, - ProtoFieldInfo protoFieldInfo, - Attributes attributes) - throws IOException { - output.writeStartRepeated(protoFieldInfo); - - if (!attributes.isEmpty()) { - AttributesWriter attributesWriter = - context.getInstance(AttributesWriter.class, AttributesWriter::new); - attributesWriter.initialize(protoFieldInfo, output, context); - attributes.forEach(attributesWriter); - } - - output.writeEndRepeated(); - } - - private static void writeTo( - Serializer output, MarshalerContext context, AttributeKey attributeKey, Object value) - throws IOException { - if (attributeKey.getKey().isEmpty()) { - output.serializeString(KeyValue.KEY, EMPTY_BYTES); - } else if (attributeKey instanceof InternalAttributeKeyImpl) { - byte[] keyUtf8 = ((InternalAttributeKeyImpl) attributeKey).getKeyUtf8(); - output.serializeString(KeyValue.KEY, keyUtf8); - } else if (context.marshalStringNoAllocation()) { - output.writeString(KeyValue.KEY, attributeKey.getKey(), context.getSize()); - } else { - output.serializeString(KeyValue.KEY, context.getByteArray()); - } - - output.writeStartMessage(KeyValue.VALUE, context.getSize()); - writeAttributeValue(output, context, attributeKey, value); - output.writeEndMessage(); - } - - @SuppressWarnings("unchecked") - private static void writeAttributeValue( - Serializer output, MarshalerContext context, AttributeKey attributeKey, Object value) - throws IOException { - switch (attributeKey.getType()) { - case STRING: - StringAnyValueMarshaler.writeTo(output, (String) value, context); - return; - case LONG: - IntAnyValueMarshaler.writeTo(output, (long) value); - return; - case BOOLEAN: - BoolAnyValueMarshaler.writeTo(output, (boolean) value); - return; - case DOUBLE: - DoubleAnyValueMarshaler.writeTo(output, (double) value); - return; - case STRING_ARRAY: - ArrayAnyValueMarshaler.writeTo( - output, (List) value, StringAnyValueMarshaler::writeTo, context); - return; - case LONG_ARRAY: - ArrayAnyValueMarshaler.writeTo( - output, (List) value, IntAnyValueMarshaler::writeTo, context); - return; - case BOOLEAN_ARRAY: - ArrayAnyValueMarshaler.writeTo( - output, (List) value, BoolAnyValueMarshaler::writeTo, context); - return; - case DOUBLE_ARRAY: - ArrayAnyValueMarshaler.writeTo( - output, (List) value, DoubleAnyValueMarshaler::writeTo, context); - return; - } - // Error prone ensures the switch statement is complete, otherwise only can happen with - // unaligned versions which are not supported. - throw new IllegalArgumentException("Unsupported attribute type."); - } - private static int calculateSize(byte[] keyUtf8, Marshaler value) { int size = 0; size += MarshalerUtil.sizeBytes(KeyValue.KEY, keyUtf8); size += MarshalerUtil.sizeMessage(KeyValue.VALUE, value); return size; } - - public static int calculateSize( - ProtoFieldInfo field, Attributes attributes, MarshalerContext context) { - if (attributes.isEmpty()) { - return 0; - } - - AttributesSizeCalculator attributesSizeCalculator = - context.getInstance(AttributesSizeCalculator.class, AttributesSizeCalculator::new); - attributesSizeCalculator.init(field, context); - attributes.forEach(attributesSizeCalculator); - - return attributesSizeCalculator.size; - } - - private static int calculateSize( - AttributeKey attributeKey, Object value, MarshalerContext context) { - int sizeIndex = context.addSize(); - int size = 0; - if (!attributeKey.getKey().isEmpty()) { - if (attributeKey instanceof InternalAttributeKeyImpl) { - byte[] keyUtf8 = ((InternalAttributeKeyImpl) attributeKey).getKeyUtf8(); - size += MarshalerUtil.sizeBytes(KeyValue.KEY, keyUtf8); - } else if (context.marshalStringNoAllocation()) { - int utf8Size = MarshalerUtil.getUtf8Size(attributeKey.getKey()); - context.addSize(utf8Size); - size += MarshalerUtil.sizeBytes(KeyValue.KEY, utf8Size); - } else { - byte[] keyUtf8 = attributeKey.getKey().getBytes(StandardCharsets.UTF_8); - context.addData(keyUtf8); - size += MarshalerUtil.sizeBytes(KeyValue.KEY, keyUtf8); - } - } - int valueSizeIndex = context.addSize(); - int valueSize = calculateValueSize(attributeKey, value, context); - size += MarshalerUtil.sizeMessage(KeyValue.VALUE, valueSize); - - context.setSize(sizeIndex, size); - context.setSize(valueSizeIndex, valueSize); - - return size; - } - - @SuppressWarnings("unchecked") - private static int calculateValueSize( - AttributeKey attributeKey, Object value, MarshalerContext context) { - switch (attributeKey.getType()) { - case STRING: - return StringAnyValueMarshaler.calculateSize((String) value, context); - case LONG: - return IntAnyValueMarshaler.calculateSize((long) value); - case BOOLEAN: - return BoolAnyValueMarshaler.calculateSize((boolean) value); - case DOUBLE: - return DoubleAnyValueMarshaler.calculateSize((double) value); - case STRING_ARRAY: - return ArrayAnyValueMarshaler.calculateSize( - (List) value, StringAnyValueMarshaler::calculateSize, context); - case LONG_ARRAY: - return ArrayAnyValueMarshaler.calculateSize( - (List) value, IntAnyValueMarshaler::calculateSize, context); - case BOOLEAN_ARRAY: - return ArrayAnyValueMarshaler.calculateSize( - (List) value, BoolAnyValueMarshaler::calculateSize, context); - case DOUBLE_ARRAY: - return ArrayAnyValueMarshaler.calculateSize( - (List) value, DoubleAnyValueMarshaler::calculateSize, context); - } - // Error prone ensures the switch statement is complete, otherwise only can happen with - // unaligned versions which are not supported. - throw new IllegalArgumentException("Unsupported attribute type."); - } - - private static class AttributesWriter implements BiConsumer, Object> { - @SuppressWarnings("NullAway") - ProtoFieldInfo field; - - @SuppressWarnings("NullAway") - Serializer output; - - @SuppressWarnings("NullAway") - MarshalerContext context; - - void initialize(ProtoFieldInfo field, Serializer output, MarshalerContext context) { - this.field = field; - this.output = output; - this.context = context; - } - - @Override - public void accept(AttributeKey attributeKey, Object value) { - try { - output.writeStartRepeatedElement(field, context.getSize()); - writeTo(output, context, attributeKey, value); - output.writeEndRepeatedElement(); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - } - - private static class AttributesSizeCalculator implements BiConsumer, Object> { - int size; - int fieldTagSize; - - @SuppressWarnings("NullAway") - MarshalerContext context; - - void init(ProtoFieldInfo field, MarshalerContext context) { - this.size = 0; - this.fieldTagSize = field.getTagSize(); - this.context = context; - } - - @Override - public void accept(AttributeKey attributeKey, Object value) { - int fieldSize = calculateSize(attributeKey, value, context); - size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; - } - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueStatelessMarshaler.java new file mode 100644 index 00000000000..b2545369666 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueStatelessMarshaler.java @@ -0,0 +1,173 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.AttributeType; +import io.opentelemetry.api.internal.InternalAttributeKeyImpl; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler2; +import io.opentelemetry.proto.common.v1.internal.AnyValue; +import io.opentelemetry.proto.common.v1.internal.KeyValue; +import java.io.IOException; +import java.util.List; + +/** + * A Marshaler of key value pairs. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class KeyValueStatelessMarshaler + implements StatelessMarshaler2, Object> { + public static final KeyValueStatelessMarshaler INSTANCE = new KeyValueStatelessMarshaler(); + private static final byte[] EMPTY_BYTES = new byte[0]; + + @Override + public void writeTo( + Serializer output, AttributeKey attributeKey, Object value, MarshalerContext context) + throws IOException { + if (attributeKey.getKey().isEmpty()) { + output.serializeString(KeyValue.KEY, EMPTY_BYTES); + } else if (attributeKey instanceof InternalAttributeKeyImpl) { + byte[] keyUtf8 = ((InternalAttributeKeyImpl) attributeKey).getKeyUtf8(); + output.serializeString(KeyValue.KEY, keyUtf8); + } else { + output.serializeString(KeyValue.KEY, attributeKey.getKey(), context); + } + output.serializeMessage( + KeyValue.VALUE, attributeKey, value, ValueStatelessMarshaler.INSTANCE, context); + } + + @Override + public int getBinarySerializedSize( + AttributeKey attributeKey, Object value, MarshalerContext context) { + int size = 0; + if (!attributeKey.getKey().isEmpty()) { + if (attributeKey instanceof InternalAttributeKeyImpl) { + byte[] keyUtf8 = ((InternalAttributeKeyImpl) attributeKey).getKeyUtf8(); + size += MarshalerUtil.sizeBytes(KeyValue.KEY, keyUtf8); + } else { + return MarshalerUtil.sizeString(KeyValue.KEY, attributeKey.getKey(), context); + } + } + size += + MarshalerUtil.sizeMessage( + KeyValue.VALUE, attributeKey, value, ValueStatelessMarshaler.INSTANCE, context); + + return size; + } + + private static class ValueStatelessMarshaler + implements StatelessMarshaler2, Object> { + static final ValueStatelessMarshaler INSTANCE = new ValueStatelessMarshaler(); + + @SuppressWarnings("unchecked") + @Override + public int getBinarySerializedSize( + AttributeKey attributeKey, Object value, MarshalerContext context) { + AttributeType attributeType = attributeKey.getType(); + switch (attributeType) { + case STRING: + return StringAnyValueStatelessMarshaler.INSTANCE.getBinarySerializedSize( + (String) value, context); + case LONG: + return IntAnyValueStatelessMarshaler.INSTANCE.getBinarySerializedSize( + (Long) value, context); + case BOOLEAN: + return BoolAnyValueStatelessMarshaler.INSTANCE.getBinarySerializedSize( + (Boolean) value, context); + case DOUBLE: + return DoubleAnyValueStatelessMarshaler.INSTANCE.getBinarySerializedSize( + (Double) value, context); + case STRING_ARRAY: + case LONG_ARRAY: + case BOOLEAN_ARRAY: + case DOUBLE_ARRAY: + return MarshalerUtil.sizeMessage( + AnyValue.ARRAY_VALUE, + attributeType, + (List) value, + ArrayAnyValueStatelessMarshaler.INSTANCE, + context); + /* + case STRING_ARRAY: + return ArrayAnyValueMarshaler.calculateSize( + (List) value, StringAnyValueMarshaler::calculateSize, context); + case LONG_ARRAY: + return ArrayAnyValueMarshaler.calculateSize( + (List) value, IntAnyValueMarshaler::calculateSize, context); + case BOOLEAN_ARRAY: + return ArrayAnyValueMarshaler.calculateSize( + (List) value, BoolAnyValueMarshaler::calculateSize, context); + case DOUBLE_ARRAY: + return ArrayAnyValueMarshaler.calculateSize( + (List) value, DoubleAnyValueMarshaler::calculateSize, context); + + */ + } + // Error prone ensures the switch statement is complete, otherwise only can happen with + // unaligned versions which are not supported. + throw new IllegalArgumentException("Unsupported attribute type."); + } + + @SuppressWarnings("unchecked") + @Override + public void writeTo( + Serializer output, AttributeKey attributeKey, Object value, MarshalerContext context) + throws IOException { + AttributeType attributeType = attributeKey.getType(); + switch (attributeType) { + case STRING: + StringAnyValueStatelessMarshaler.INSTANCE.writeTo(output, (String) value, context); + return; + case LONG: + IntAnyValueStatelessMarshaler.INSTANCE.writeTo(output, (Long) value, context); + return; + case BOOLEAN: + BoolAnyValueStatelessMarshaler.INSTANCE.writeTo(output, (Boolean) value, context); + return; + case DOUBLE: + DoubleAnyValueStatelessMarshaler.INSTANCE.writeTo(output, (Double) value, context); + return; + case STRING_ARRAY: + case LONG_ARRAY: + case BOOLEAN_ARRAY: + case DOUBLE_ARRAY: + output.serializeMessage( + AnyValue.ARRAY_VALUE, + attributeType, + (List) value, + ArrayAnyValueStatelessMarshaler.INSTANCE, + context); + return; + /* + case STRING_ARRAY: + ArrayAnyValueMarshaler.writeTo( + output, (List) value, StringAnyValueMarshaler::writeTo, context); + return; + case LONG_ARRAY: + ArrayAnyValueMarshaler.writeTo( + output, (List) value, IntAnyValueMarshaler::writeTo, context); + return; + case BOOLEAN_ARRAY: + ArrayAnyValueMarshaler.writeTo( + output, (List) value, BoolAnyValueMarshaler::writeTo, context); + return; + case DOUBLE_ARRAY: + ArrayAnyValueMarshaler.writeTo( + output, (List) value, DoubleAnyValueMarshaler::writeTo, context); + return; + */ + } + // Error prone ensures the switch statement is complete, otherwise only can happen with + // unaligned versions which are not supported. + throw new IllegalArgumentException("Unsupported attribute type."); + } + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueMarshaler.java index fcb167eb06b..e62c55d2da1 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueMarshaler.java @@ -6,7 +6,6 @@ package io.opentelemetry.exporter.internal.otlp; import io.opentelemetry.exporter.internal.marshal.CodedOutputStream; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -39,32 +38,8 @@ public void writeTo(Serializer output) throws IOException { output.writeString(AnyValue.STRING_VALUE, valueUtf8); } - public static void writeTo(Serializer output, String value, MarshalerContext context) - throws IOException { - if (context.marshalStringNoAllocation()) { - output.writeString(AnyValue.STRING_VALUE, value, context.getSize()); - } else { - byte[] valueUtf8 = context.getByteArray(); - output.writeString(AnyValue.STRING_VALUE, valueUtf8); - } - } - private static int calculateSize(byte[] valueUtf8) { return AnyValue.STRING_VALUE.getTagSize() + CodedOutputStream.computeByteArraySizeNoTag(valueUtf8); } - - public static int calculateSize(String value, MarshalerContext context) { - if (context.marshalStringNoAllocation()) { - int utf8Size = MarshalerUtil.getUtf8Size(value); - context.addSize(utf8Size); - return AnyValue.STRING_VALUE.getTagSize() - + CodedOutputStream.computeLengthDelimitedFieldSize(utf8Size); - } else { - byte[] valueUtf8 = MarshalerUtil.toBytes(value); - context.addData(valueUtf8); - return AnyValue.STRING_VALUE.getTagSize() - + CodedOutputStream.computeLengthDelimitedFieldSize(valueUtf8.length); - } - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueStatelessMarshaler.java new file mode 100644 index 00000000000..26e80097308 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/StringAnyValueStatelessMarshaler.java @@ -0,0 +1,34 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.proto.common.v1.internal.AnyValue; +import java.io.IOException; + +/** + * A Marshaler of string-valued {@link AnyValue}. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +final class StringAnyValueStatelessMarshaler implements StatelessMarshaler { + static final StringAnyValueStatelessMarshaler INSTANCE = new StringAnyValueStatelessMarshaler(); + + @Override + public void writeTo(Serializer output, String value, MarshalerContext context) + throws IOException { + output.serializeString(AnyValue.STRING_VALUE, value, context); + } + + @Override + public int getBinarySerializedSize(String value, MarshalerContext context) { + return MarshalerUtil.sizeString(AnyValue.STRING_VALUE, value, context); + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExemplarMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExemplarMarshaler.java index b2aa9c24270..d9f879c4366 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExemplarMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExemplarMarshaler.java @@ -6,7 +6,6 @@ package io.opentelemetry.exporter.internal.otlp.metrics; import io.opentelemetry.api.trace.SpanContext; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; @@ -86,35 +85,6 @@ public void writeTo(Serializer output) throws IOException { filteredAttributeMarshalers); } - public static void writeTo(Serializer output, ExemplarData exemplar, MarshalerContext context) - throws IOException { - output.serializeFixed64( - io.opentelemetry.proto.metrics.v1.internal.Exemplar.TIME_UNIX_NANO, - exemplar.getEpochNanos()); - ProtoFieldInfo valueField = getValueField(exemplar); - if (valueField == io.opentelemetry.proto.metrics.v1.internal.Exemplar.AS_INT) { - output.serializeFixed64Optional(valueField, ((LongExemplarData) exemplar).getValue()); - } else { - output.serializeDoubleOptional(valueField, ((DoubleExemplarData) exemplar).getValue()); - } - SpanContext spanContext = exemplar.getSpanContext(); - if (spanContext.isValid()) { - output.serializeSpanId( - io.opentelemetry.proto.metrics.v1.internal.Exemplar.SPAN_ID, - spanContext.getSpanId(), - context); - output.serializeTraceId( - io.opentelemetry.proto.metrics.v1.internal.Exemplar.TRACE_ID, - spanContext.getTraceId(), - context); - } - KeyValueMarshaler.writeTo( - output, - context, - io.opentelemetry.proto.metrics.v1.internal.Exemplar.FILTERED_ATTRIBUTES, - exemplar.getFilteredAttributes()); - } - private static int calculateSize( long timeUnixNano, ProtoFieldInfo valueField, @@ -146,39 +116,7 @@ private static int calculateSize( return size; } - public static int calculateSize(ExemplarData exemplar, MarshalerContext context) { - int size = 0; - size += - MarshalerUtil.sizeFixed64( - io.opentelemetry.proto.metrics.v1.internal.Exemplar.TIME_UNIX_NANO, - exemplar.getEpochNanos()); - ProtoFieldInfo valueField = getValueField(exemplar); - if (valueField == io.opentelemetry.proto.metrics.v1.internal.Exemplar.AS_INT) { - size += - MarshalerUtil.sizeFixed64Optional(valueField, ((LongExemplarData) exemplar).getValue()); - } else { - size += - MarshalerUtil.sizeDoubleOptional(valueField, ((DoubleExemplarData) exemplar).getValue()); - } - SpanContext spanContext = exemplar.getSpanContext(); - if (spanContext.isValid()) { - size += - MarshalerUtil.sizeSpanId( - io.opentelemetry.proto.metrics.v1.internal.Exemplar.SPAN_ID, spanContext.getSpanId()); - size += - MarshalerUtil.sizeTraceId( - io.opentelemetry.proto.metrics.v1.internal.Exemplar.TRACE_ID, - spanContext.getTraceId()); - } - size += - KeyValueMarshaler.calculateSize( - io.opentelemetry.proto.metrics.v1.internal.Exemplar.FILTERED_ATTRIBUTES, - exemplar.getFilteredAttributes(), - context); - return size; - } - - private static ProtoFieldInfo getValueField(ExemplarData exemplar) { + static ProtoFieldInfo getValueField(ExemplarData exemplar) { if (exemplar instanceof LongExemplarData) { return io.opentelemetry.proto.metrics.v1.internal.Exemplar.AS_INT; } else { diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExemplarStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExemplarStatelessMarshaler.java new file mode 100644 index 00000000000..9032899ea4f --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExemplarStatelessMarshaler.java @@ -0,0 +1,91 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import static io.opentelemetry.exporter.internal.otlp.metrics.ExemplarMarshaler.getValueField; + +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.exporter.internal.otlp.KeyValueStatelessMarshaler; +import io.opentelemetry.sdk.metrics.data.DoubleExemplarData; +import io.opentelemetry.sdk.metrics.data.ExemplarData; +import io.opentelemetry.sdk.metrics.data.LongExemplarData; +import java.io.IOException; + +final class ExemplarStatelessMarshaler implements StatelessMarshaler { + static final ExemplarStatelessMarshaler INSTANCE = new ExemplarStatelessMarshaler(); + + private ExemplarStatelessMarshaler() {} + + @Override + public void writeTo(Serializer output, ExemplarData exemplar, MarshalerContext context) + throws IOException { + output.serializeFixed64( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.TIME_UNIX_NANO, + exemplar.getEpochNanos()); + ProtoFieldInfo valueField = getValueField(exemplar); + if (valueField == io.opentelemetry.proto.metrics.v1.internal.Exemplar.AS_INT) { + output.serializeFixed64Optional(valueField, ((LongExemplarData) exemplar).getValue()); + } else { + output.serializeDoubleOptional(valueField, ((DoubleExemplarData) exemplar).getValue()); + } + SpanContext spanContext = exemplar.getSpanContext(); + if (spanContext.isValid()) { + output.serializeSpanId( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.SPAN_ID, + spanContext.getSpanId(), + context); + output.serializeTraceId( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.TRACE_ID, + spanContext.getTraceId(), + context); + } + output.serializeRepeatedMessage( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.FILTERED_ATTRIBUTES, + exemplar.getFilteredAttributes(), + KeyValueStatelessMarshaler.INSTANCE, + context); + } + + @Override + public int getBinarySerializedSize(ExemplarData exemplar, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeFixed64( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.TIME_UNIX_NANO, + exemplar.getEpochNanos()); + ProtoFieldInfo valueField = getValueField(exemplar); + if (valueField == io.opentelemetry.proto.metrics.v1.internal.Exemplar.AS_INT) { + size += + MarshalerUtil.sizeFixed64Optional(valueField, ((LongExemplarData) exemplar).getValue()); + } else { + size += + MarshalerUtil.sizeDoubleOptional(valueField, ((DoubleExemplarData) exemplar).getValue()); + } + SpanContext spanContext = exemplar.getSpanContext(); + if (spanContext.isValid()) { + size += + MarshalerUtil.sizeSpanId( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.SPAN_ID, spanContext.getSpanId()); + size += + MarshalerUtil.sizeTraceId( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.TRACE_ID, + spanContext.getTraceId()); + } + size += + MarshalerUtil.sizeRepeatedMessage( + io.opentelemetry.proto.metrics.v1.internal.Exemplar.FILTERED_ATTRIBUTES, + exemplar.getFilteredAttributes(), + KeyValueStatelessMarshaler.INSTANCE, + context); + + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramBucketsMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramBucketsMarshaler.java index 09cfd46821b..1f9fbc9b73b 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramBucketsMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramBucketsMarshaler.java @@ -5,7 +5,6 @@ package io.opentelemetry.exporter.internal.otlp.metrics; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -16,11 +15,7 @@ import java.io.IOException; import java.util.List; -/** - * This class is internal and is hence not for public use. Its APIs are unstable and can change at - * any time. - */ -public class ExponentialHistogramBucketsMarshaler extends MarshalerWithSize { +final class ExponentialHistogramBucketsMarshaler extends MarshalerWithSize { private final int offset; private final List counts; @@ -46,21 +41,7 @@ protected void writeTo(Serializer output) throws IOException { } } - public static void writeTo( - Serializer output, ExponentialHistogramBuckets buckets, MarshalerContext context) - throws IOException { - output.serializeSInt32(ExponentialHistogramDataPoint.Buckets.OFFSET, buckets.getOffset()); - List counts = buckets.getBucketCounts(); - if (counts instanceof DynamicPrimitiveLongList) { - output.serializeRepeatedUInt64( - ExponentialHistogramDataPoint.Buckets.BUCKET_COUNTS, (DynamicPrimitiveLongList) counts); - } else { - output.serializeRepeatedUInt64( - ExponentialHistogramDataPoint.Buckets.BUCKET_COUNTS, PrimitiveLongList.toArray(counts)); - } - } - - private static int calculateSize(int offset, List counts) { + static int calculateSize(int offset, List counts) { int size = 0; size += MarshalerUtil.sizeSInt32(ExponentialHistogramDataPoint.Buckets.OFFSET, offset); if (counts instanceof DynamicPrimitiveLongList) { @@ -76,8 +57,4 @@ private static int calculateSize(int offset, List counts) { } return size; } - - public static int calculateSize(ExponentialHistogramBuckets buckets, MarshalerContext context) { - return calculateSize(buckets.getOffset(), buckets.getBucketCounts()); - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramBucketsStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramBucketsStatelessMarshaler.java new file mode 100644 index 00000000000..9fd852a6c45 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramBucketsStatelessMarshaler.java @@ -0,0 +1,46 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.ExponentialHistogramDataPoint; +import io.opentelemetry.sdk.internal.DynamicPrimitiveLongList; +import io.opentelemetry.sdk.internal.PrimitiveLongList; +import io.opentelemetry.sdk.metrics.data.ExponentialHistogramBuckets; +import java.io.IOException; +import java.util.List; + +final class ExponentialHistogramBucketsStatelessMarshaler + implements StatelessMarshaler { + static final ExponentialHistogramBucketsStatelessMarshaler INSTANCE = + new ExponentialHistogramBucketsStatelessMarshaler(); + + private ExponentialHistogramBucketsStatelessMarshaler() {} + + @Override + public void writeTo( + Serializer output, ExponentialHistogramBuckets buckets, MarshalerContext context) + throws IOException { + output.serializeSInt32(ExponentialHistogramDataPoint.Buckets.OFFSET, buckets.getOffset()); + List counts = buckets.getBucketCounts(); + if (counts instanceof DynamicPrimitiveLongList) { + output.serializeRepeatedUInt64( + ExponentialHistogramDataPoint.Buckets.BUCKET_COUNTS, (DynamicPrimitiveLongList) counts); + } else { + output.serializeRepeatedUInt64( + ExponentialHistogramDataPoint.Buckets.BUCKET_COUNTS, PrimitiveLongList.toArray(counts)); + } + } + + @Override + public int getBinarySerializedSize( + ExponentialHistogramBuckets buckets, MarshalerContext context) { + return ExponentialHistogramBucketsMarshaler.calculateSize( + buckets.getOffset(), buckets.getBucketCounts()); + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramDataPointMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramDataPointMarshaler.java index 2449569346d..0ca4de1cc10 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramDataPointMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramDataPointMarshaler.java @@ -5,7 +5,6 @@ package io.opentelemetry.exporter.internal.otlp.metrics; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -15,11 +14,7 @@ import java.io.IOException; import java.util.Collection; -/** - * This class is internal and is hence not for public use. Its APIs are unstable and can change at - * any time. - */ -public class ExponentialHistogramDataPointMarshaler extends MarshalerWithSize { +final class ExponentialHistogramDataPointMarshaler extends MarshalerWithSize { private final long startTimeUnixNano; private final long timeUnixNano; @@ -140,41 +135,6 @@ protected void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(ExponentialHistogramDataPoint.ATTRIBUTES, attributes); } - public static void writeTo( - Serializer output, ExponentialHistogramPointData point, MarshalerContext context) - throws IOException { - output.serializeFixed64( - ExponentialHistogramDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); - output.serializeFixed64(ExponentialHistogramDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); - output.serializeFixed64(ExponentialHistogramDataPoint.COUNT, point.getCount()); - output.serializeDouble(ExponentialHistogramDataPoint.SUM, point.getSum()); - if (point.hasMin()) { - output.serializeDoubleOptional(ExponentialHistogramDataPoint.MIN, point.getMin()); - } - if (point.hasMax()) { - output.serializeDoubleOptional(ExponentialHistogramDataPoint.MAX, point.getMax()); - } - output.serializeSInt32(ExponentialHistogramDataPoint.SCALE, point.getScale()); - output.serializeFixed64(ExponentialHistogramDataPoint.ZERO_COUNT, point.getZeroCount()); - output.serializeMessage( - ExponentialHistogramDataPoint.POSITIVE, - point.getPositiveBuckets(), - ExponentialHistogramBucketsMarshaler::writeTo, - context); - output.serializeMessage( - ExponentialHistogramDataPoint.NEGATIVE, - point.getNegativeBuckets(), - ExponentialHistogramBucketsMarshaler::writeTo, - context); - output.serializeRepeatedMessage( - ExponentialHistogramDataPoint.EXEMPLARS, - point.getExemplars(), - ExemplarMarshaler::writeTo, - context); - KeyValueMarshaler.writeTo( - output, context, ExponentialHistogramDataPoint.ATTRIBUTES, point.getAttributes()); - } - private static int calculateSize( long startTimeUnixNano, long timeUnixNano, @@ -217,47 +177,4 @@ private static int calculateSize( ExponentialHistogramDataPoint.ATTRIBUTES, attributesMarshalers); return size; } - - public static int calculateSize(ExponentialHistogramPointData point, MarshalerContext context) { - int size = 0; - size += - MarshalerUtil.sizeFixed64( - ExponentialHistogramDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); - size += - MarshalerUtil.sizeFixed64( - ExponentialHistogramDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); - size += MarshalerUtil.sizeFixed64(ExponentialHistogramDataPoint.COUNT, point.getCount()); - size += MarshalerUtil.sizeDouble(ExponentialHistogramDataPoint.SUM, point.getSum()); - if (point.hasMin()) { - size += MarshalerUtil.sizeDoubleOptional(ExponentialHistogramDataPoint.MIN, point.getMin()); - } - if (point.hasMax()) { - size += MarshalerUtil.sizeDoubleOptional(ExponentialHistogramDataPoint.MAX, point.getMax()); - } - size += MarshalerUtil.sizeSInt32(ExponentialHistogramDataPoint.SCALE, point.getScale()); - size += - MarshalerUtil.sizeFixed64(ExponentialHistogramDataPoint.ZERO_COUNT, point.getZeroCount()); - size += - MarshalerUtil.sizeMessage( - ExponentialHistogramDataPoint.POSITIVE, - point.getPositiveBuckets(), - ExponentialHistogramBucketsMarshaler::calculateSize, - context); - size += - MarshalerUtil.sizeMessage( - ExponentialHistogramDataPoint.NEGATIVE, - point.getNegativeBuckets(), - ExponentialHistogramBucketsMarshaler::calculateSize, - context); - size += - MarshalerUtil.sizeRepeatedMessage( - ExponentialHistogramDataPoint.EXEMPLARS, - point.getExemplars(), - ExemplarMarshaler::calculateSize, - context); - size += - KeyValueMarshaler.calculateSize( - ExponentialHistogramDataPoint.ATTRIBUTES, point.getAttributes(), context); - return size; - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramDataPointStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramDataPointStatelessMarshaler.java new file mode 100644 index 00000000000..ac5364ce487 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramDataPointStatelessMarshaler.java @@ -0,0 +1,109 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.exporter.internal.otlp.KeyValueStatelessMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.ExponentialHistogramDataPoint; +import io.opentelemetry.sdk.metrics.data.ExponentialHistogramPointData; +import java.io.IOException; + +final class ExponentialHistogramDataPointStatelessMarshaler + implements StatelessMarshaler { + static final ExponentialHistogramDataPointStatelessMarshaler INSTANCE = + new ExponentialHistogramDataPointStatelessMarshaler(); + + @Override + public void writeTo( + Serializer output, ExponentialHistogramPointData point, MarshalerContext context) + throws IOException { + output.serializeFixed64( + ExponentialHistogramDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + output.serializeFixed64(ExponentialHistogramDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + output.serializeFixed64(ExponentialHistogramDataPoint.COUNT, point.getCount()); + output.serializeDouble(ExponentialHistogramDataPoint.SUM, point.getSum()); + if (point.hasMin()) { + output.serializeDoubleOptional(ExponentialHistogramDataPoint.MIN, point.getMin()); + } + if (point.hasMax()) { + output.serializeDoubleOptional(ExponentialHistogramDataPoint.MAX, point.getMax()); + } + output.serializeSInt32(ExponentialHistogramDataPoint.SCALE, point.getScale()); + output.serializeFixed64(ExponentialHistogramDataPoint.ZERO_COUNT, point.getZeroCount()); + output.serializeMessage( + ExponentialHistogramDataPoint.POSITIVE, + point.getPositiveBuckets(), + ExponentialHistogramBucketsStatelessMarshaler.INSTANCE, + context); + output.serializeMessage( + ExponentialHistogramDataPoint.NEGATIVE, + point.getNegativeBuckets(), + ExponentialHistogramBucketsStatelessMarshaler.INSTANCE, + context); + output.serializeRepeatedMessage( + ExponentialHistogramDataPoint.EXEMPLARS, + point.getExemplars(), + ExemplarStatelessMarshaler.INSTANCE, + context); + output.serializeRepeatedMessage( + ExponentialHistogramDataPoint.ATTRIBUTES, + point.getAttributes(), + KeyValueStatelessMarshaler.INSTANCE, + context); + } + + @Override + public int getBinarySerializedSize( + ExponentialHistogramPointData point, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeFixed64( + ExponentialHistogramDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + size += + MarshalerUtil.sizeFixed64( + ExponentialHistogramDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + size += MarshalerUtil.sizeFixed64(ExponentialHistogramDataPoint.COUNT, point.getCount()); + size += MarshalerUtil.sizeDouble(ExponentialHistogramDataPoint.SUM, point.getSum()); + if (point.hasMin()) { + size += MarshalerUtil.sizeDoubleOptional(ExponentialHistogramDataPoint.MIN, point.getMin()); + } + if (point.hasMax()) { + size += MarshalerUtil.sizeDoubleOptional(ExponentialHistogramDataPoint.MAX, point.getMax()); + } + size += MarshalerUtil.sizeSInt32(ExponentialHistogramDataPoint.SCALE, point.getScale()); + size += + MarshalerUtil.sizeFixed64(ExponentialHistogramDataPoint.ZERO_COUNT, point.getZeroCount()); + size += + MarshalerUtil.sizeMessage( + ExponentialHistogramDataPoint.POSITIVE, + point.getPositiveBuckets(), + ExponentialHistogramBucketsStatelessMarshaler.INSTANCE, + context); + size += + MarshalerUtil.sizeMessage( + ExponentialHistogramDataPoint.NEGATIVE, + point.getNegativeBuckets(), + ExponentialHistogramBucketsStatelessMarshaler.INSTANCE, + context); + size += + MarshalerUtil.sizeRepeatedMessage( + ExponentialHistogramDataPoint.EXEMPLARS, + point.getExemplars(), + ExemplarStatelessMarshaler.INSTANCE, + context); + size += + MarshalerUtil.sizeRepeatedMessage( + ExponentialHistogramDataPoint.ATTRIBUTES, + point.getAttributes(), + KeyValueStatelessMarshaler.INSTANCE, + context); + + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramMarshaler.java index fe29916ba5e..30cb7ece8f2 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramMarshaler.java @@ -5,7 +5,6 @@ package io.opentelemetry.exporter.internal.otlp.metrics; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoEnumInfo; @@ -14,14 +13,7 @@ import io.opentelemetry.sdk.metrics.data.ExponentialHistogramData; import java.io.IOException; -/** - * This class is internal and is hence not for public use. Its APIs are unstable and can change at - * any time. - */ -public class ExponentialHistogramMarshaler extends MarshalerWithSize { - private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); - private static final Object DATA_POINT_WRITER_KEY = new Object(); - +final class ExponentialHistogramMarshaler extends MarshalerWithSize { private final ExponentialHistogramDataPointMarshaler[] dataPoints; private final ProtoEnumInfo aggregationTemporality; @@ -46,20 +38,6 @@ protected void writeTo(Serializer output) throws IOException { output.serializeEnum(ExponentialHistogram.AGGREGATION_TEMPORALITY, aggregationTemporality); } - public static void writeTo( - Serializer output, ExponentialHistogramData histogram, MarshalerContext context) - throws IOException { - output.serializeRepeatedMessage( - ExponentialHistogram.DATA_POINTS, - histogram.getPoints(), - ExponentialHistogramDataPointMarshaler::writeTo, - context, - DATA_POINT_WRITER_KEY); - output.serializeEnum( - ExponentialHistogram.AGGREGATION_TEMPORALITY, - MetricsMarshalerUtil.mapToTemporality(histogram.getAggregationTemporality())); - } - private static int calculateSize( ExponentialHistogramDataPointMarshaler[] dataPointMarshalers, ProtoEnumInfo aggregationTemporality) { @@ -71,20 +49,4 @@ private static int calculateSize( ExponentialHistogram.AGGREGATION_TEMPORALITY, aggregationTemporality); return size; } - - public static int calculateSize(ExponentialHistogramData histogram, MarshalerContext context) { - int size = 0; - size += - MarshalerUtil.sizeRepeatedMessage( - ExponentialHistogram.DATA_POINTS, - histogram.getPoints(), - ExponentialHistogramDataPointMarshaler::calculateSize, - context, - DATA_POINT_SIZE_CALCULATOR_KEY); - size += - MarshalerUtil.sizeEnum( - ExponentialHistogram.AGGREGATION_TEMPORALITY, - MetricsMarshalerUtil.mapToTemporality(histogram.getAggregationTemporality())); - return size; - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramStatelessMarshaler.java new file mode 100644 index 00000000000..3340c55b67c --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramStatelessMarshaler.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.ExponentialHistogram; +import io.opentelemetry.sdk.metrics.data.ExponentialHistogramData; +import java.io.IOException; + +final class ExponentialHistogramStatelessMarshaler + implements StatelessMarshaler { + static final ExponentialHistogramStatelessMarshaler INSTANCE = + new ExponentialHistogramStatelessMarshaler(); + private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); + private static final Object DATA_POINT_WRITER_KEY = new Object(); + + @Override + public void writeTo( + Serializer output, ExponentialHistogramData histogram, MarshalerContext context) + throws IOException { + output.serializeRepeatedMessage( + ExponentialHistogram.DATA_POINTS, + histogram.getPoints(), + ExponentialHistogramDataPointStatelessMarshaler.INSTANCE, + context, + DATA_POINT_WRITER_KEY); + output.serializeEnum( + ExponentialHistogram.AGGREGATION_TEMPORALITY, + MetricsMarshalerUtil.mapToTemporality(histogram.getAggregationTemporality())); + } + + @Override + public int getBinarySerializedSize(ExponentialHistogramData histogram, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeRepeatedMessage( + ExponentialHistogram.DATA_POINTS, + histogram.getPoints(), + ExponentialHistogramDataPointStatelessMarshaler.INSTANCE, + context, + DATA_POINT_SIZE_CALCULATOR_KEY); + size += + MarshalerUtil.sizeEnum( + ExponentialHistogram.AGGREGATION_TEMPORALITY, + MetricsMarshalerUtil.mapToTemporality(histogram.getAggregationTemporality())); + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeMarshaler.java index b36cb35c2a5..f1512f0715e 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeMarshaler.java @@ -5,7 +5,6 @@ package io.opentelemetry.exporter.internal.otlp.metrics; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -15,9 +14,6 @@ import java.io.IOException; final class GaugeMarshaler extends MarshalerWithSize { - private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); - private static final Object DATA_POINT_WRITER_KEY = new Object(); - private final NumberDataPointMarshaler[] dataPoints; static GaugeMarshaler create(GaugeData gauge) { @@ -37,32 +33,9 @@ public void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(Gauge.DATA_POINTS, dataPoints); } - public static void writeTo( - Serializer output, GaugeData gauge, MarshalerContext context) - throws IOException { - output.serializeRepeatedMessage( - Gauge.DATA_POINTS, - gauge.getPoints(), - NumberDataPointMarshaler::writeTo, - context, - DATA_POINT_WRITER_KEY); - } - private static int calculateSize(NumberDataPointMarshaler[] dataPoints) { int size = 0; size += MarshalerUtil.sizeRepeatedMessage(Gauge.DATA_POINTS, dataPoints); return size; } - - public static int calculateSize(GaugeData gauge, MarshalerContext context) { - int size = 0; - size += - MarshalerUtil.sizeRepeatedMessage( - Gauge.DATA_POINTS, - gauge.getPoints(), - NumberDataPointMarshaler::calculateSize, - context, - DATA_POINT_SIZE_CALCULATOR_KEY); - return size; - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeStatelessMarshaler.java new file mode 100644 index 00000000000..e17d370f04e --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeStatelessMarshaler.java @@ -0,0 +1,47 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.Gauge; +import io.opentelemetry.sdk.metrics.data.GaugeData; +import io.opentelemetry.sdk.metrics.data.PointData; +import java.io.IOException; + +final class GaugeStatelessMarshaler implements StatelessMarshaler> { + static final GaugeStatelessMarshaler INSTANCE = new GaugeStatelessMarshaler(); + private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); + private static final Object DATA_POINT_WRITER_KEY = new Object(); + + @Override + public void writeTo( + Serializer output, GaugeData gauge, MarshalerContext context) + throws IOException { + output.serializeRepeatedMessage( + Gauge.DATA_POINTS, + gauge.getPoints(), + NumberDataPointStatelessMarshaler.INSTANCE, + context, + DATA_POINT_WRITER_KEY); + } + + @Override + public int getBinarySerializedSize( + GaugeData gauge, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeRepeatedMessage( + Gauge.DATA_POINTS, + gauge.getPoints(), + NumberDataPointStatelessMarshaler.INSTANCE, + context, + DATA_POINT_SIZE_CALCULATOR_KEY); + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramDataPointMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramDataPointMarshaler.java index 41ebff49d15..8022635e868 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramDataPointMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramDataPointMarshaler.java @@ -5,7 +5,6 @@ package io.opentelemetry.exporter.internal.otlp.metrics; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -120,26 +119,6 @@ public void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(HistogramDataPoint.ATTRIBUTES, attributes); } - public static void writeTo(Serializer output, HistogramPointData point, MarshalerContext context) - throws IOException { - output.serializeFixed64(HistogramDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); - output.serializeFixed64(HistogramDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); - output.serializeFixed64(HistogramDataPoint.COUNT, point.getCount()); - output.serializeDoubleOptional(HistogramDataPoint.SUM, point.getSum()); - if (point.hasMin()) { - output.serializeDoubleOptional(HistogramDataPoint.MIN, point.getMin()); - } - if (point.hasMax()) { - output.serializeDoubleOptional(HistogramDataPoint.MAX, point.getMax()); - } - output.serializeRepeatedFixed64(HistogramDataPoint.BUCKET_COUNTS, point.getCounts()); - output.serializeRepeatedDouble(HistogramDataPoint.EXPLICIT_BOUNDS, point.getBoundaries()); - output.serializeRepeatedMessage( - HistogramDataPoint.EXEMPLARS, point.getExemplars(), ExemplarMarshaler::writeTo, context); - KeyValueMarshaler.writeTo( - output, context, HistogramDataPoint.ATTRIBUTES, point.getAttributes()); - } - private static int calculateSize( long startTimeUnixNano, long timeUnixNano, @@ -170,33 +149,4 @@ private static int calculateSize( size += MarshalerUtil.sizeRepeatedMessage(HistogramDataPoint.ATTRIBUTES, attributes); return size; } - - public static int calculateSize(HistogramPointData point, MarshalerContext context) { - int size = 0; - size += - MarshalerUtil.sizeFixed64( - HistogramDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); - size += MarshalerUtil.sizeFixed64(HistogramDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); - size += MarshalerUtil.sizeFixed64(HistogramDataPoint.COUNT, point.getCount()); - size += MarshalerUtil.sizeDoubleOptional(HistogramDataPoint.SUM, point.getSum()); - if (point.hasMin()) { - size += MarshalerUtil.sizeDoubleOptional(HistogramDataPoint.MIN, point.getMin()); - } - if (point.hasMax()) { - size += MarshalerUtil.sizeDoubleOptional(HistogramDataPoint.MAX, point.getMax()); - } - size += MarshalerUtil.sizeRepeatedFixed64(HistogramDataPoint.BUCKET_COUNTS, point.getCounts()); - size += - MarshalerUtil.sizeRepeatedDouble(HistogramDataPoint.EXPLICIT_BOUNDS, point.getBoundaries()); - size += - MarshalerUtil.sizeRepeatedMessage( - HistogramDataPoint.EXEMPLARS, - point.getExemplars(), - ExemplarMarshaler::calculateSize, - context); - size += - KeyValueMarshaler.calculateSize( - HistogramDataPoint.ATTRIBUTES, point.getAttributes(), context); - return size; - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramDataPointStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramDataPointStatelessMarshaler.java new file mode 100644 index 00000000000..7d9bcceda82 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramDataPointStatelessMarshaler.java @@ -0,0 +1,80 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.exporter.internal.otlp.KeyValueStatelessMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.HistogramDataPoint; +import io.opentelemetry.sdk.metrics.data.HistogramPointData; +import java.io.IOException; + +final class HistogramDataPointStatelessMarshaler implements StatelessMarshaler { + static final HistogramDataPointStatelessMarshaler INSTANCE = + new HistogramDataPointStatelessMarshaler(); + + @Override + public void writeTo(Serializer output, HistogramPointData point, MarshalerContext context) + throws IOException { + output.serializeFixed64(HistogramDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + output.serializeFixed64(HistogramDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + output.serializeFixed64(HistogramDataPoint.COUNT, point.getCount()); + output.serializeDoubleOptional(HistogramDataPoint.SUM, point.getSum()); + if (point.hasMin()) { + output.serializeDoubleOptional(HistogramDataPoint.MIN, point.getMin()); + } + if (point.hasMax()) { + output.serializeDoubleOptional(HistogramDataPoint.MAX, point.getMax()); + } + output.serializeRepeatedFixed64(HistogramDataPoint.BUCKET_COUNTS, point.getCounts()); + output.serializeRepeatedDouble(HistogramDataPoint.EXPLICIT_BOUNDS, point.getBoundaries()); + output.serializeRepeatedMessage( + HistogramDataPoint.EXEMPLARS, + point.getExemplars(), + ExemplarStatelessMarshaler.INSTANCE, + context); + output.serializeRepeatedMessage( + HistogramDataPoint.ATTRIBUTES, + point.getAttributes(), + KeyValueStatelessMarshaler.INSTANCE, + context); + } + + @Override + public int getBinarySerializedSize(HistogramPointData point, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeFixed64( + HistogramDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + size += MarshalerUtil.sizeFixed64(HistogramDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + size += MarshalerUtil.sizeFixed64(HistogramDataPoint.COUNT, point.getCount()); + size += MarshalerUtil.sizeDoubleOptional(HistogramDataPoint.SUM, point.getSum()); + if (point.hasMin()) { + size += MarshalerUtil.sizeDoubleOptional(HistogramDataPoint.MIN, point.getMin()); + } + if (point.hasMax()) { + size += MarshalerUtil.sizeDoubleOptional(HistogramDataPoint.MAX, point.getMax()); + } + size += MarshalerUtil.sizeRepeatedFixed64(HistogramDataPoint.BUCKET_COUNTS, point.getCounts()); + size += + MarshalerUtil.sizeRepeatedDouble(HistogramDataPoint.EXPLICIT_BOUNDS, point.getBoundaries()); + size += + MarshalerUtil.sizeRepeatedMessage( + HistogramDataPoint.EXEMPLARS, + point.getExemplars(), + ExemplarStatelessMarshaler.INSTANCE, + context); + size += + MarshalerUtil.sizeRepeatedMessage( + HistogramDataPoint.ATTRIBUTES, + point.getAttributes(), + KeyValueStatelessMarshaler.INSTANCE, + context); + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramMarshaler.java index 14fe05b1101..6082c84dbf8 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramMarshaler.java @@ -5,7 +5,6 @@ package io.opentelemetry.exporter.internal.otlp.metrics; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoEnumInfo; @@ -15,9 +14,6 @@ import java.io.IOException; final class HistogramMarshaler extends MarshalerWithSize { - private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); - private static final Object DATA_POINT_WRITER_KEY = new Object(); - private final HistogramDataPointMarshaler[] dataPoints; private final ProtoEnumInfo aggregationTemporality; @@ -42,19 +38,6 @@ public void writeTo(Serializer output) throws IOException { output.serializeEnum(Histogram.AGGREGATION_TEMPORALITY, aggregationTemporality); } - public static void writeTo(Serializer output, HistogramData histogram, MarshalerContext context) - throws IOException { - output.serializeRepeatedMessage( - Histogram.DATA_POINTS, - histogram.getPoints(), - HistogramDataPointMarshaler::writeTo, - context, - DATA_POINT_WRITER_KEY); - output.serializeEnum( - Histogram.AGGREGATION_TEMPORALITY, - MetricsMarshalerUtil.mapToTemporality(histogram.getAggregationTemporality())); - } - private static int calculateSize( HistogramDataPointMarshaler[] dataPoints, ProtoEnumInfo aggregationTemporality) { int size = 0; @@ -62,20 +45,4 @@ private static int calculateSize( size += MarshalerUtil.sizeEnum(Histogram.AGGREGATION_TEMPORALITY, aggregationTemporality); return size; } - - public static int calculateSize(HistogramData histogram, MarshalerContext context) { - int size = 0; - size += - MarshalerUtil.sizeRepeatedMessage( - Histogram.DATA_POINTS, - histogram.getPoints(), - HistogramDataPointMarshaler::calculateSize, - context, - DATA_POINT_SIZE_CALCULATOR_KEY); - size += - MarshalerUtil.sizeEnum( - Histogram.AGGREGATION_TEMPORALITY, - MetricsMarshalerUtil.mapToTemporality(histogram.getAggregationTemporality())); - return size; - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramStatelessMarshaler.java new file mode 100644 index 00000000000..a45404e0ab0 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramStatelessMarshaler.java @@ -0,0 +1,51 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.Histogram; +import io.opentelemetry.sdk.metrics.data.HistogramData; +import java.io.IOException; + +final class HistogramStatelessMarshaler implements StatelessMarshaler { + static final HistogramStatelessMarshaler INSTANCE = new HistogramStatelessMarshaler(); + private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); + private static final Object DATA_POINT_WRITER_KEY = new Object(); + + @Override + public void writeTo(Serializer output, HistogramData histogram, MarshalerContext context) + throws IOException { + output.serializeRepeatedMessage( + Histogram.DATA_POINTS, + histogram.getPoints(), + HistogramDataPointStatelessMarshaler.INSTANCE, + context, + DATA_POINT_WRITER_KEY); + output.serializeEnum( + Histogram.AGGREGATION_TEMPORALITY, + MetricsMarshalerUtil.mapToTemporality(histogram.getAggregationTemporality())); + } + + @Override + public int getBinarySerializedSize(HistogramData histogram, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeRepeatedMessage( + Histogram.DATA_POINTS, + histogram.getPoints(), + HistogramDataPointStatelessMarshaler.INSTANCE, + context, + DATA_POINT_SIZE_CALCULATOR_KEY); + size += + MarshalerUtil.sizeEnum( + Histogram.AGGREGATION_TEMPORALITY, + MetricsMarshalerUtil.mapToTemporality(histogram.getAggregationTemporality())); + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsMarshaler.java index 5f90e884efc..c4d3ee7ebde 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsMarshaler.java @@ -6,13 +6,11 @@ package io.opentelemetry.exporter.internal.otlp.metrics; import io.opentelemetry.exporter.internal.marshal.Marshaler; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; 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.InstrumentationScopeMarshaler; import io.opentelemetry.proto.metrics.v1.internal.ScopeMetrics; -import io.opentelemetry.sdk.metrics.data.MetricData; import java.io.IOException; import java.util.List; @@ -38,19 +36,6 @@ public void writeTo(Serializer output) throws IOException { output.serializeString(ScopeMetrics.SCHEMA_URL, schemaUrlUtf8); } - public static void writeTo( - Serializer output, - MarshalerContext context, - InstrumentationScopeMarshaler instrumentationScopeMarshaler, - List metricData, - byte[] schemaUrlUtf8) - throws IOException { - output.serializeMessage(ScopeMetrics.SCOPE, instrumentationScopeMarshaler); - output.serializeRepeatedMessage( - ScopeMetrics.METRICS, metricData, MetricMarshaler::writeTo, context); - output.serializeString(ScopeMetrics.SCHEMA_URL, schemaUrlUtf8); - } - private static int calculateSize( InstrumentationScopeMarshaler instrumentationScope, byte[] schemaUrlUtf8, @@ -61,21 +46,4 @@ private static int calculateSize( size += MarshalerUtil.sizeRepeatedMessage(ScopeMetrics.METRICS, metricMarshalers); return size; } - - public static int calculateSize( - InstrumentationScopeMarshaler instrumentationScope, - byte[] schemaUrlUtf8, - MarshalerContext context, - List metricData) { - int sizeIndex = context.addSize(); - int size = 0; - size += MarshalerUtil.sizeMessage(ScopeMetrics.SCOPE, instrumentationScope); - size += MarshalerUtil.sizeBytes(ScopeMetrics.SCHEMA_URL, schemaUrlUtf8); - size += - MarshalerUtil.sizeRepeatedMessage( - ScopeMetrics.METRICS, metricData, MetricMarshaler::calculateSize, context); - context.setSize(sizeIndex, size); - - return size; - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsStatelessMarshaler.java new file mode 100644 index 00000000000..014352f86b6 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsStatelessMarshaler.java @@ -0,0 +1,63 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler2; +import io.opentelemetry.exporter.internal.otlp.InstrumentationScopeMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.ScopeMetrics; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.metrics.data.MetricData; +import java.io.IOException; +import java.util.List; + +final class InstrumentationScopeMetricsStatelessMarshaler + implements StatelessMarshaler2> { + static final InstrumentationScopeMetricsStatelessMarshaler INSTANCE = + new InstrumentationScopeMetricsStatelessMarshaler(); + + @Override + public void writeTo( + Serializer output, + InstrumentationScopeInfo instrumentationScope, + List metrics, + MarshalerContext context) + throws IOException { + InstrumentationScopeMarshaler instrumentationScopeMarshaler = + context.getObject(InstrumentationScopeMarshaler.class); + byte[] schemaUrlUtf8 = context.getByteArray(); + output.serializeMessage(ScopeMetrics.SCOPE, instrumentationScopeMarshaler); + output.serializeRepeatedMessage( + ScopeMetrics.METRICS, metrics, MetricStatelessMarshaler.INSTANCE, context); + output.serializeString(ScopeMetrics.SCHEMA_URL, schemaUrlUtf8); + } + + @Override + public int getBinarySerializedSize( + InstrumentationScopeInfo instrumentationScope, + List metrics, + MarshalerContext context) { + InstrumentationScopeMarshaler instrumentationScopeMarshaler = + InstrumentationScopeMarshaler.create(instrumentationScope); + context.addData(instrumentationScopeMarshaler); + // XXX + byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(instrumentationScope.getSchemaUrl()); + context.addData(schemaUrlUtf8); + + // int sizeIndex = context.addSize(); + int size = 0; + size += MarshalerUtil.sizeMessage(ScopeMetrics.SCOPE, instrumentationScopeMarshaler); + size += MarshalerUtil.sizeBytes(ScopeMetrics.SCHEMA_URL, schemaUrlUtf8); + size += + MarshalerUtil.sizeRepeatedMessage( + ScopeMetrics.METRICS, metrics, MetricStatelessMarshaler.INSTANCE, context); + // context.setSize(sizeIndex, size); + + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshaler.java index b52e138fc86..03d3abb4e02 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshaler.java @@ -9,10 +9,7 @@ import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.Serializer; -import io.opentelemetry.exporter.internal.otlp.AbstractResourceScopeMapSizeCalculator; -import io.opentelemetry.exporter.internal.otlp.AbstractResourceScopeMapWriter; import io.opentelemetry.proto.collector.metrics.v1.internal.ExportMetricsServiceRequest; -import io.opentelemetry.proto.collector.trace.v1.internal.ExportTraceServiceRequest; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.resources.Resource; @@ -29,6 +26,8 @@ * at any time. */ public final class LowAllocationMetricsRequestMarshaler extends Marshaler { + private static final Object RESOURCE_METRIC_SIZE_CALCULATOR_KEY = new Object(); + private static final Object RESOURCE_METRIC_WRITER_KEY = new Object(); private final MarshalerContext context = new MarshalerContext(); @@ -51,31 +50,27 @@ public int getBinarySerializedSize() { return size; } - private final ResourceScopeMapWriter resourceScopeMapWriter = new ResourceScopeMapWriter(); - @Override - public void writeTo(Serializer output) { + public void writeTo(Serializer output) throws IOException { // serializing can be retried, reset the indexes, so we could call writeTo multiple times context.resetReadIndex(); - resourceScopeMapWriter.initialize( - output, ExportMetricsServiceRequest.RESOURCE_METRICS, context); - resourceAndScopeMap.forEach(resourceScopeMapWriter); + output.serializeRepeatedMessage( + ExportMetricsServiceRequest.RESOURCE_METRICS, + resourceAndScopeMap, + ResourceMetricsStatelessMarshaler.INSTANCE, + context, + RESOURCE_METRIC_WRITER_KEY); } private static int calculateSize( MarshalerContext context, Map>> resourceAndScopeMap) { - if (resourceAndScopeMap.isEmpty()) { - return 0; - } - - ResourceScopeMapSizeCalculator resourceScopeMapSizeCalculator = - context.getInstance( - ResourceScopeMapSizeCalculator.class, ResourceScopeMapSizeCalculator::new); - resourceScopeMapSizeCalculator.initialize(ExportTraceServiceRequest.RESOURCE_SPANS, context); - resourceAndScopeMap.forEach(resourceScopeMapSizeCalculator); - - return resourceScopeMapSizeCalculator.getSize(); + return MarshalerUtil.sizeRepeatedMessage( + ExportMetricsServiceRequest.RESOURCE_METRICS, + resourceAndScopeMap, + ResourceMetricsStatelessMarshaler.INSTANCE, + context, + RESOURCE_METRIC_SIZE_CALCULATOR_KEY); } private static Map>> @@ -93,26 +88,4 @@ private static int calculateSize( MetricData::getInstrumentationScopeInfo, context); } - - private static class ResourceScopeMapWriter extends AbstractResourceScopeMapWriter { - - @Override - protected void handle( - Map> instrumentationScopeInfoListMap) - throws IOException { - ResourceMetricsMarshaler.writeTo(output, instrumentationScopeInfoListMap, context); - } - } - - private static class ResourceScopeMapSizeCalculator - extends AbstractResourceScopeMapSizeCalculator { - - @Override - public int calculateSize( - Resource resource, - Map> instrumentationScopeInfoListMap) { - return ResourceMetricsMarshaler.calculateSize( - context, resource, instrumentationScopeInfoListMap); - } - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricMarshaler.java index 0a4b2d33743..6b91a407c5f 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricMarshaler.java @@ -5,26 +5,14 @@ package io.opentelemetry.exporter.internal.otlp.metrics; -import static io.opentelemetry.sdk.metrics.data.MetricDataType.DOUBLE_GAUGE; -import static io.opentelemetry.sdk.metrics.data.MetricDataType.DOUBLE_SUM; -import static io.opentelemetry.sdk.metrics.data.MetricDataType.EXPONENTIAL_HISTOGRAM; -import static io.opentelemetry.sdk.metrics.data.MetricDataType.HISTOGRAM; -import static io.opentelemetry.sdk.metrics.data.MetricDataType.LONG_GAUGE; -import static io.opentelemetry.sdk.metrics.data.MetricDataType.LONG_SUM; -import static io.opentelemetry.sdk.metrics.data.MetricDataType.SUMMARY; - import io.opentelemetry.exporter.internal.marshal.Marshaler; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.proto.metrics.v1.internal.Metric; import io.opentelemetry.sdk.metrics.data.MetricData; -import io.opentelemetry.sdk.metrics.data.MetricDataType; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; final class MetricMarshaler extends MarshalerWithSize { private final byte[] nameUtf8; @@ -102,30 +90,6 @@ public void writeTo(Serializer output) throws IOException { output.serializeMessage(dataField, dataMarshaler); } - public static void writeTo(Serializer output, MetricData metricData, MarshalerContext context) - throws IOException { - DataHandler dataHandler = DATA_HANDLERS.get(metricData.getType()); - if (dataHandler == null) { - // Someone not using BOM to align versions as we require. Just skip the metric. - return; - } - - if (context.marshalStringNoAllocation()) { - output.serializeString(Metric.NAME, metricData.getName(), context.getSize()); - output.serializeString(Metric.DESCRIPTION, metricData.getDescription(), context.getSize()); - output.serializeString(Metric.UNIT, metricData.getUnit(), context.getSize()); - } else { - byte[] nameUtf8 = context.getByteArray(); - output.serializeString(Metric.NAME, nameUtf8); - byte[] descriptionUtf8 = context.getByteArray(); - output.serializeString(Metric.DESCRIPTION, descriptionUtf8); - byte[] unitUtf8 = context.getByteArray(); - output.serializeString(Metric.UNIT, unitUtf8); - } - - dataHandler.writeTo(output, metricData, context); - } - private static int calculateSize( byte[] nameUtf8, byte[] descriptionUtf8, @@ -139,172 +103,4 @@ private static int calculateSize( size += MarshalerUtil.sizeMessage(dataField, dataMarshaler); return size; } - - public static int calculateSize(MetricData metricData, MarshalerContext context) { - DataHandler dataHandler = DATA_HANDLERS.get(metricData.getType()); - if (dataHandler == null) { - // Someone not using BOM to align versions as we require. Just skip the metric. - return 0; - } - - int size = 0; - if (context.marshalStringNoAllocation()) { - int nameUtf8Size = MarshalerUtil.getUtf8Size(metricData.getName()); - context.addSize(nameUtf8Size); - size += MarshalerUtil.sizeBytes(Metric.NAME, nameUtf8Size); - - int descriptionUtf8Size = MarshalerUtil.getUtf8Size(metricData.getDescription()); - context.addSize(descriptionUtf8Size); - size += MarshalerUtil.sizeBytes(Metric.DESCRIPTION, descriptionUtf8Size); - - int unitUtf8Size = MarshalerUtil.getUtf8Size(metricData.getUnit()); - context.addSize(unitUtf8Size); - size += MarshalerUtil.sizeBytes(Metric.NAME, unitUtf8Size); - } else { - byte[] nameUtf8 = MarshalerUtil.toBytes(metricData.getName()); - context.addData(nameUtf8); - size += MarshalerUtil.sizeBytes(Metric.NAME, nameUtf8); - - byte[] descriptionUtf8 = MarshalerUtil.toBytes(metricData.getDescription()); - context.addData(descriptionUtf8); - size += MarshalerUtil.sizeBytes(Metric.DESCRIPTION, descriptionUtf8); - - byte[] unitUtf8 = MarshalerUtil.toBytes(metricData.getUnit()); - context.addData(unitUtf8); - size += MarshalerUtil.sizeBytes(Metric.UNIT, unitUtf8); - } - - size += - MarshalerUtil.sizeMessage( - dataHandler.dataField, metricData, dataHandler::calculateSize, context); - - return size; - } - - private static final Map DATA_HANDLERS = new HashMap<>(); - - static { - DATA_HANDLERS.put( - LONG_GAUGE, - new DataHandler(Metric.GAUGE) { - @Override - public int calculateSize(MetricData metricData, MarshalerContext context) { - return GaugeMarshaler.calculateSize(metricData.getLongGaugeData(), context); - } - - @Override - public void writeTo(Serializer output, MetricData metric, MarshalerContext context) - throws IOException { - output.serializeMessage( - Metric.GAUGE, metric.getLongGaugeData(), GaugeMarshaler::writeTo, context); - } - }); - DATA_HANDLERS.put( - DOUBLE_GAUGE, - new DataHandler(Metric.GAUGE) { - @Override - public int calculateSize(MetricData metricData, MarshalerContext context) { - return GaugeMarshaler.calculateSize(metricData.getDoubleGaugeData(), context); - } - - @Override - public void writeTo(Serializer output, MetricData metric, MarshalerContext context) - throws IOException { - output.serializeMessage( - Metric.GAUGE, metric.getDoubleGaugeData(), GaugeMarshaler::writeTo, context); - } - }); - DATA_HANDLERS.put( - LONG_SUM, - new DataHandler(Metric.SUM) { - @Override - public int calculateSize(MetricData metricData, MarshalerContext context) { - return SumMarshaler.calculateSize(metricData.getLongSumData(), context); - } - - @Override - public void writeTo(Serializer output, MetricData metric, MarshalerContext context) - throws IOException { - output.serializeMessage( - Metric.SUM, metric.getLongSumData(), SumMarshaler::writeTo, context); - } - }); - DATA_HANDLERS.put( - DOUBLE_SUM, - new DataHandler(Metric.SUM) { - @Override - public int calculateSize(MetricData metricData, MarshalerContext context) { - return SumMarshaler.calculateSize(metricData.getDoubleSumData(), context); - } - - @Override - public void writeTo(Serializer output, MetricData metric, MarshalerContext context) - throws IOException { - output.serializeMessage( - Metric.SUM, metric.getDoubleSumData(), SumMarshaler::writeTo, context); - } - }); - DATA_HANDLERS.put( - SUMMARY, - new DataHandler(Metric.SUMMARY) { - @Override - public int calculateSize(MetricData metricData, MarshalerContext context) { - return SummaryMarshaler.calculateSize(metricData.getSummaryData(), context); - } - - @Override - public void writeTo(Serializer output, MetricData metric, MarshalerContext context) - throws IOException { - output.serializeMessage( - Metric.SUMMARY, metric.getSummaryData(), SummaryMarshaler::writeTo, context); - } - }); - DATA_HANDLERS.put( - HISTOGRAM, - new DataHandler(Metric.HISTOGRAM) { - @Override - public int calculateSize(MetricData metricData, MarshalerContext context) { - return HistogramMarshaler.calculateSize(metricData.getHistogramData(), context); - } - - @Override - public void writeTo(Serializer output, MetricData metric, MarshalerContext context) - throws IOException { - output.serializeMessage( - Metric.HISTOGRAM, metric.getHistogramData(), HistogramMarshaler::writeTo, context); - } - }); - DATA_HANDLERS.put( - EXPONENTIAL_HISTOGRAM, - new DataHandler(Metric.EXPONENTIAL_HISTOGRAM) { - @Override - public int calculateSize(MetricData metricData, MarshalerContext context) { - return ExponentialHistogramMarshaler.calculateSize( - metricData.getExponentialHistogramData(), context); - } - - @Override - public void writeTo(Serializer output, MetricData metric, MarshalerContext context) - throws IOException { - output.serializeMessage( - Metric.EXPONENTIAL_HISTOGRAM, - metric.getExponentialHistogramData(), - ExponentialHistogramMarshaler::writeTo, - context); - } - }); - } - - private abstract static class DataHandler { - final ProtoFieldInfo dataField; - - DataHandler(ProtoFieldInfo dataField) { - this.dataField = dataField; - } - - abstract int calculateSize(MetricData metricData, MarshalerContext context); - - abstract void writeTo(Serializer output, MetricData metricData, MarshalerContext context) - throws IOException; - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricStatelessMarshaler.java new file mode 100644 index 00000000000..538abdb70e8 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricStatelessMarshaler.java @@ -0,0 +1,220 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import static io.opentelemetry.sdk.metrics.data.MetricDataType.DOUBLE_GAUGE; +import static io.opentelemetry.sdk.metrics.data.MetricDataType.DOUBLE_SUM; +import static io.opentelemetry.sdk.metrics.data.MetricDataType.EXPONENTIAL_HISTOGRAM; +import static io.opentelemetry.sdk.metrics.data.MetricDataType.HISTOGRAM; +import static io.opentelemetry.sdk.metrics.data.MetricDataType.LONG_GAUGE; +import static io.opentelemetry.sdk.metrics.data.MetricDataType.LONG_SUM; +import static io.opentelemetry.sdk.metrics.data.MetricDataType.SUMMARY; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.Metric; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.data.MetricDataType; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +final class MetricStatelessMarshaler implements StatelessMarshaler { + static final MetricStatelessMarshaler INSTANCE = new MetricStatelessMarshaler(); + private static final Map DATA_HANDLERS = new HashMap<>(); + + static { + DATA_HANDLERS.put( + LONG_GAUGE, + new DataHandler(Metric.GAUGE) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return MarshalerUtil.sizeMessage( + dataField, + metricData.getLongGaugeData(), + GaugeStatelessMarshaler.INSTANCE, + context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.GAUGE, metric.getLongGaugeData(), GaugeStatelessMarshaler.INSTANCE, context); + } + }); + DATA_HANDLERS.put( + DOUBLE_GAUGE, + new DataHandler(Metric.GAUGE) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return MarshalerUtil.sizeMessage( + dataField, + metricData.getDoubleGaugeData(), + GaugeStatelessMarshaler.INSTANCE, + context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.GAUGE, + metric.getDoubleGaugeData(), + GaugeStatelessMarshaler.INSTANCE, + context); + } + }); + DATA_HANDLERS.put( + LONG_SUM, + new DataHandler(Metric.SUM) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return MarshalerUtil.sizeMessage( + dataField, metricData.getLongSumData(), SumStatelessMarshaler.INSTANCE, context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.SUM, metric.getLongSumData(), SumStatelessMarshaler.INSTANCE, context); + } + }); + DATA_HANDLERS.put( + DOUBLE_SUM, + new DataHandler(Metric.SUM) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return MarshalerUtil.sizeMessage( + dataField, metricData.getDoubleSumData(), SumStatelessMarshaler.INSTANCE, context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.SUM, metric.getDoubleSumData(), SumStatelessMarshaler.INSTANCE, context); + } + }); + DATA_HANDLERS.put( + SUMMARY, + new DataHandler(Metric.SUMMARY) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return MarshalerUtil.sizeMessage( + dataField, + metricData.getSummaryData(), + SummaryStatelessMarshaler.INSTANCE, + context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.SUMMARY, + metric.getSummaryData(), + SummaryStatelessMarshaler.INSTANCE, + context); + } + }); + DATA_HANDLERS.put( + HISTOGRAM, + new DataHandler(Metric.HISTOGRAM) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return MarshalerUtil.sizeMessage( + dataField, + metricData.getHistogramData(), + HistogramStatelessMarshaler.INSTANCE, + context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.HISTOGRAM, + metric.getHistogramData(), + HistogramStatelessMarshaler.INSTANCE, + context); + } + }); + DATA_HANDLERS.put( + EXPONENTIAL_HISTOGRAM, + new DataHandler(Metric.EXPONENTIAL_HISTOGRAM) { + @Override + public int calculateSize(MetricData metricData, MarshalerContext context) { + return MarshalerUtil.sizeMessage( + dataField, + metricData.getExponentialHistogramData(), + ExponentialHistogramStatelessMarshaler.INSTANCE, + context); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + output.serializeMessage( + Metric.EXPONENTIAL_HISTOGRAM, + metric.getExponentialHistogramData(), + ExponentialHistogramStatelessMarshaler.INSTANCE, + context); + } + }); + } + + @Override + public void writeTo(Serializer output, MetricData metric, MarshalerContext context) + throws IOException { + DataHandler dataHandler = DATA_HANDLERS.get(metric.getType()); + if (dataHandler == null) { + // Someone not using BOM to align versions as we require. Just skip the metric. + return; + } + + output.serializeString(Metric.NAME, metric.getName(), context); + output.serializeString(Metric.DESCRIPTION, metric.getDescription(), context); + output.serializeString(Metric.UNIT, metric.getUnit(), context); + + dataHandler.writeTo(output, metric, context); + } + + @Override + public int getBinarySerializedSize(MetricData metric, MarshalerContext context) { + DataHandler dataHandler = DATA_HANDLERS.get(metric.getType()); + if (dataHandler == null) { + // Someone not using BOM to align versions as we require. Just skip the metric. + return 0; + } + + int size = 0; + size += MarshalerUtil.sizeString(Metric.NAME, metric.getName(), context); + size += MarshalerUtil.sizeString(Metric.DESCRIPTION, metric.getDescription(), context); + size += MarshalerUtil.sizeString(Metric.UNIT, metric.getUnit(), context); + + size += dataHandler.calculateSize(metric, context); + + return size; + } + + private abstract static class DataHandler { + final ProtoFieldInfo dataField; + + DataHandler(ProtoFieldInfo dataField) { + this.dataField = dataField; + } + + abstract int calculateSize(MetricData metricData, MarshalerContext context); + + abstract void writeTo(Serializer output, MetricData metricData, MarshalerContext context) + throws IOException; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/NumberDataPointMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/NumberDataPointMarshaler.java index bc8e3db02d8..fa4a4c94495 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/NumberDataPointMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/NumberDataPointMarshaler.java @@ -5,7 +5,6 @@ package io.opentelemetry.exporter.internal.otlp.metrics; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; @@ -81,21 +80,6 @@ public void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(NumberDataPoint.ATTRIBUTES, attributes); } - public static void writeTo(Serializer output, PointData point, MarshalerContext context) - throws IOException { - output.serializeFixed64(NumberDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); - output.serializeFixed64(NumberDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); - ProtoFieldInfo valueField = getValueField(point); - if (valueField == NumberDataPoint.AS_INT) { - output.serializeFixed64Optional(valueField, ((LongPointData) point).getValue()); - } else { - output.serializeDoubleOptional(valueField, ((DoublePointData) point).getValue()); - } - output.serializeRepeatedMessage( - NumberDataPoint.EXEMPLARS, point.getExemplars(), ExemplarMarshaler::writeTo, context); - KeyValueMarshaler.writeTo(output, context, NumberDataPoint.ATTRIBUTES, point.getAttributes()); - } - private static int calculateSize( long startTimeUnixNano, long timeUnixNano, @@ -116,29 +100,7 @@ private static int calculateSize( return size; } - public static int calculateSize(PointData point, MarshalerContext context) { - int size = 0; - size += - MarshalerUtil.sizeFixed64(NumberDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); - size += MarshalerUtil.sizeFixed64(NumberDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); - ProtoFieldInfo valueField = getValueField(point); - if (valueField == NumberDataPoint.AS_INT) { - size += MarshalerUtil.sizeFixed64Optional(valueField, ((LongPointData) point).getValue()); - } else { - size += MarshalerUtil.sizeDoubleOptional(valueField, ((DoublePointData) point).getValue()); - } - size += - MarshalerUtil.sizeRepeatedMessage( - NumberDataPoint.EXEMPLARS, - point.getExemplars(), - ExemplarMarshaler::calculateSize, - context); - size += - KeyValueMarshaler.calculateSize(NumberDataPoint.ATTRIBUTES, point.getAttributes(), context); - return size; - } - - private static ProtoFieldInfo getValueField(PointData pointData) { + static ProtoFieldInfo getValueField(PointData pointData) { if (pointData instanceof LongPointData) { return NumberDataPoint.AS_INT; } else { diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/NumberDataPointStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/NumberDataPointStatelessMarshaler.java new file mode 100644 index 00000000000..8b0ff857283 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/NumberDataPointStatelessMarshaler.java @@ -0,0 +1,74 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import static io.opentelemetry.exporter.internal.otlp.metrics.NumberDataPointMarshaler.getValueField; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.ProtoFieldInfo; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.exporter.internal.otlp.KeyValueStatelessMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.NumberDataPoint; +import io.opentelemetry.sdk.metrics.data.DoublePointData; +import io.opentelemetry.sdk.metrics.data.LongPointData; +import io.opentelemetry.sdk.metrics.data.PointData; +import java.io.IOException; + +final class NumberDataPointStatelessMarshaler implements StatelessMarshaler { + static final NumberDataPointStatelessMarshaler INSTANCE = new NumberDataPointStatelessMarshaler(); + + @Override + public void writeTo(Serializer output, PointData point, MarshalerContext context) + throws IOException { + output.serializeFixed64(NumberDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + output.serializeFixed64(NumberDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + ProtoFieldInfo valueField = getValueField(point); + if (valueField == NumberDataPoint.AS_INT) { + output.serializeFixed64Optional(valueField, ((LongPointData) point).getValue()); + } else { + output.serializeDoubleOptional(valueField, ((DoublePointData) point).getValue()); + } + output.serializeRepeatedMessage( + NumberDataPoint.EXEMPLARS, + point.getExemplars(), + ExemplarStatelessMarshaler.INSTANCE, + context); + output.serializeRepeatedMessage( + NumberDataPoint.ATTRIBUTES, + point.getAttributes(), + KeyValueStatelessMarshaler.INSTANCE, + context); + } + + @Override + public int getBinarySerializedSize(PointData point, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeFixed64(NumberDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + size += MarshalerUtil.sizeFixed64(NumberDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + ProtoFieldInfo valueField = getValueField(point); + if (valueField == NumberDataPoint.AS_INT) { + size += MarshalerUtil.sizeFixed64Optional(valueField, ((LongPointData) point).getValue()); + } else { + size += MarshalerUtil.sizeDoubleOptional(valueField, ((DoublePointData) point).getValue()); + } + size += + MarshalerUtil.sizeRepeatedMessage( + NumberDataPoint.EXEMPLARS, + point.getExemplars(), + ExemplarStatelessMarshaler.INSTANCE, + context); + size += + MarshalerUtil.sizeRepeatedMessage( + NumberDataPoint.ATTRIBUTES, + point.getAttributes(), + KeyValueStatelessMarshaler.INSTANCE, + context); + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsMarshaler.java index fa0ac67eb8f..24db5957b93 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsMarshaler.java @@ -6,12 +6,9 @@ package io.opentelemetry.exporter.internal.otlp.metrics; import io.opentelemetry.exporter.internal.marshal.Marshaler; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; 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.AbstractScopeListSizeCalculator; -import io.opentelemetry.exporter.internal.otlp.AbstractScopeListWriter; import io.opentelemetry.exporter.internal.otlp.InstrumentationScopeMarshaler; import io.opentelemetry.exporter.internal.otlp.ResourceMarshaler; import io.opentelemetry.proto.metrics.v1.internal.ResourceMetrics; @@ -84,23 +81,6 @@ public void writeTo(Serializer output) throws IOException { output.serializeString(ResourceMetrics.SCHEMA_URL, schemaUrl); } - public static void writeTo( - Serializer output, - Map> scopeMap, - MarshalerContext context) - throws IOException { - ResourceMarshaler resourceMarshaler = context.getObject(ResourceMarshaler.class); - output.serializeMessage(ResourceMetrics.RESOURCE, resourceMarshaler); - - ScopeMetricListWriter scopeMetricListWriter = - context.getInstance(ScopeMetricListWriter.class, ScopeMetricListWriter::new); - scopeMetricListWriter.initialize(output, ResourceMetrics.SCOPE_METRICS, context); - scopeMap.forEach(scopeMetricListWriter); - - byte[] schemaUrlUtf8 = context.getByteArray(); - output.serializeString(ResourceMetrics.SCHEMA_URL, schemaUrlUtf8); - } - private static int calculateSize( ResourceMarshaler resourceMarshaler, byte[] schemaUrl, @@ -114,34 +94,6 @@ private static int calculateSize( return size; } - public static int calculateSize( - MarshalerContext context, - Resource resource, - Map> scopeMap) { - - int size = 0; - int sizeIndex = context.addSize(); - - ResourceMarshaler resourceMarshaler = ResourceMarshaler.create(resource); - context.addData(resourceMarshaler); - size += MarshalerUtil.sizeMessage(ResourceMetrics.RESOURCE, resourceMarshaler); - - ScopeMetricListSizeCalculator scopeMetricListSizeCalculator = - context.getInstance( - ScopeMetricListSizeCalculator.class, ScopeMetricListSizeCalculator::new); - scopeMetricListSizeCalculator.initialize(ResourceMetrics.SCOPE_METRICS, context); - scopeMap.forEach(scopeMetricListSizeCalculator); - size += scopeMetricListSizeCalculator.getSize(); - - byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(resource.getSchemaUrl()); - context.addData(schemaUrlUtf8); - size += MarshalerUtil.sizeBytes(ResourceMetrics.SCHEMA_URL, schemaUrlUtf8); - - context.setSize(sizeIndex, size); - - return size; - } - private static Map>> groupByResourceAndScope(Collection metricDataList) { return MarshalerUtil.groupByResourceAndScope( @@ -152,30 +104,4 @@ public static int calculateSize( MetricData::getInstrumentationScopeInfo, MetricMarshaler::create); } - - private static class ScopeMetricListWriter extends AbstractScopeListWriter { - - @Override - protected void handle( - InstrumentationScopeMarshaler instrumentationScopeMarshaler, - List list, - byte[] schemaUrlUtf8) - throws IOException { - InstrumentationScopeMetricsMarshaler.writeTo( - output, context, instrumentationScopeMarshaler, list, schemaUrlUtf8); - } - } - - private static class ScopeMetricListSizeCalculator - extends AbstractScopeListSizeCalculator { - - @Override - public int calculateSize( - InstrumentationScopeMarshaler instrumentationScopeMarshaler, - byte[] schemaUrlUtf8, - List list) { - return InstrumentationScopeMetricsMarshaler.calculateSize( - instrumentationScopeMarshaler, schemaUrlUtf8, context, list); - } - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsStatelessMarshaler.java new file mode 100644 index 00000000000..4cafc1e879c --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsStatelessMarshaler.java @@ -0,0 +1,80 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler2; +import io.opentelemetry.exporter.internal.otlp.ResourceMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.ResourceMetrics; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.resources.Resource; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * A Marshaler of ResourceMetrics. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class ResourceMetricsStatelessMarshaler + implements StatelessMarshaler2>> { + static final ResourceMetricsStatelessMarshaler INSTANCE = new ResourceMetricsStatelessMarshaler(); + private static final Object SCOPE_SPAN_WRITER_KEY = new Object(); + private static final Object SCOPE_SPAN_SIZE_CALCULATOR_KEY = new Object(); + + @Override + public void writeTo( + Serializer output, + Resource resource, + Map> scopeMap, + MarshalerContext context) + throws IOException { + ResourceMarshaler resourceMarshaler = context.getObject(ResourceMarshaler.class); + output.serializeMessage(ResourceMetrics.RESOURCE, resourceMarshaler); + + output.serializeRepeatedMessage( + ResourceMetrics.SCOPE_METRICS, + scopeMap, + InstrumentationScopeMetricsStatelessMarshaler.INSTANCE, + context, + SCOPE_SPAN_WRITER_KEY); + + byte[] schemaUrlUtf8 = context.getByteArray(); + output.serializeString(ResourceMetrics.SCHEMA_URL, schemaUrlUtf8); + } + + @Override + public int getBinarySerializedSize( + Resource resource, + Map> scopeMap, + MarshalerContext context) { + + int size = 0; + + ResourceMarshaler resourceMarshaler = ResourceMarshaler.create(resource); + context.addData(resourceMarshaler); + size += MarshalerUtil.sizeMessage(ResourceMetrics.RESOURCE, resourceMarshaler); + + size += + MarshalerUtil.sizeRepeatedMessage( + ResourceMetrics.SCOPE_METRICS, + scopeMap, + InstrumentationScopeMetricsStatelessMarshaler.INSTANCE, + context, + SCOPE_SPAN_SIZE_CALCULATOR_KEY); + + byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(resource.getSchemaUrl()); + context.addData(schemaUrlUtf8); + size += MarshalerUtil.sizeBytes(ResourceMetrics.SCHEMA_URL, schemaUrlUtf8); + + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumMarshaler.java index ef4248ce039..f349b6df883 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumMarshaler.java @@ -5,7 +5,6 @@ package io.opentelemetry.exporter.internal.otlp.metrics; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoEnumInfo; @@ -16,9 +15,6 @@ import java.io.IOException; final class SumMarshaler extends MarshalerWithSize { - private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); - private static final Object DATA_POINT_WRITER_KEY = new Object(); - private final NumberDataPointMarshaler[] dataPoints; private final ProtoEnumInfo aggregationTemporality; private final boolean isMonotonic; @@ -50,21 +46,6 @@ public void writeTo(Serializer output) throws IOException { output.serializeBool(Sum.IS_MONOTONIC, isMonotonic); } - public static void writeTo( - Serializer output, SumData sum, MarshalerContext context) - throws IOException { - output.serializeRepeatedMessage( - Sum.DATA_POINTS, - sum.getPoints(), - NumberDataPointMarshaler::writeTo, - context, - DATA_POINT_WRITER_KEY); - output.serializeEnum( - Sum.AGGREGATION_TEMPORALITY, - MetricsMarshalerUtil.mapToTemporality(sum.getAggregationTemporality())); - output.serializeBool(Sum.IS_MONOTONIC, sum.isMonotonic()); - } - private static int calculateSize( NumberDataPointMarshaler[] dataPoints, ProtoEnumInfo aggregationTemporality, @@ -75,21 +56,4 @@ private static int calculateSize( size += MarshalerUtil.sizeBool(Sum.IS_MONOTONIC, isMonotonic); return size; } - - public static int calculateSize(SumData sum, MarshalerContext context) { - int size = 0; - size += - MarshalerUtil.sizeRepeatedMessage( - Sum.DATA_POINTS, - sum.getPoints(), - NumberDataPointMarshaler::calculateSize, - context, - DATA_POINT_SIZE_CALCULATOR_KEY); - size += - MarshalerUtil.sizeEnum( - Sum.AGGREGATION_TEMPORALITY, - MetricsMarshalerUtil.mapToTemporality(sum.getAggregationTemporality())); - size += MarshalerUtil.sizeBool(Sum.IS_MONOTONIC, sum.isMonotonic()); - return size; - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumStatelessMarshaler.java new file mode 100644 index 00000000000..c007eddacae --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumStatelessMarshaler.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.Sum; +import io.opentelemetry.sdk.metrics.data.PointData; +import io.opentelemetry.sdk.metrics.data.SumData; +import java.io.IOException; + +final class SumStatelessMarshaler implements StatelessMarshaler> { + static final SumStatelessMarshaler INSTANCE = new SumStatelessMarshaler(); + private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); + private static final Object DATA_POINT_WRITER_KEY = new Object(); + + @Override + public void writeTo(Serializer output, SumData sum, MarshalerContext context) + throws IOException { + output.serializeRepeatedMessage( + Sum.DATA_POINTS, + sum.getPoints(), + NumberDataPointStatelessMarshaler.INSTANCE, + context, + DATA_POINT_WRITER_KEY); + output.serializeEnum( + Sum.AGGREGATION_TEMPORALITY, + MetricsMarshalerUtil.mapToTemporality(sum.getAggregationTemporality())); + output.serializeBool(Sum.IS_MONOTONIC, sum.isMonotonic()); + } + + @Override + public int getBinarySerializedSize(SumData sum, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeRepeatedMessage( + Sum.DATA_POINTS, + sum.getPoints(), + NumberDataPointStatelessMarshaler.INSTANCE, + context, + DATA_POINT_SIZE_CALCULATOR_KEY); + size += + MarshalerUtil.sizeEnum( + Sum.AGGREGATION_TEMPORALITY, + MetricsMarshalerUtil.mapToTemporality(sum.getAggregationTemporality())); + size += MarshalerUtil.sizeBool(Sum.IS_MONOTONIC, sum.isMonotonic()); + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryDataPointMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryDataPointMarshaler.java index b12f1bb5f22..c0b6a1dcded 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryDataPointMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryDataPointMarshaler.java @@ -5,7 +5,6 @@ package io.opentelemetry.exporter.internal.otlp.metrics; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -73,20 +72,6 @@ public void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(SummaryDataPoint.ATTRIBUTES, attributes); } - public static void writeTo(Serializer output, SummaryPointData point, MarshalerContext context) - throws IOException { - output.serializeFixed64(SummaryDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); - output.serializeFixed64(SummaryDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); - output.serializeFixed64(SummaryDataPoint.COUNT, point.getCount()); - output.serializeDoubleOptional(SummaryDataPoint.SUM, point.getSum()); - output.serializeRepeatedMessage( - SummaryDataPoint.QUANTILE_VALUES, - point.getValues(), - ValueAtQuantileMarshaler::writeTo, - context); - KeyValueMarshaler.writeTo(output, context, SummaryDataPoint.ATTRIBUTES, point.getAttributes()); - } - private static int calculateSize( long startTimeUnixNano, long timeUnixNano, @@ -103,24 +88,4 @@ private static int calculateSize( size += MarshalerUtil.sizeRepeatedMessage(SummaryDataPoint.ATTRIBUTES, attributes); return size; } - - public static int calculateSize(SummaryPointData point, MarshalerContext context) { - int size = 0; - size += - MarshalerUtil.sizeFixed64( - SummaryDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); - size += MarshalerUtil.sizeFixed64(SummaryDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); - size += MarshalerUtil.sizeFixed64(SummaryDataPoint.COUNT, point.getCount()); - size += MarshalerUtil.sizeDoubleOptional(SummaryDataPoint.SUM, point.getSum()); - size += - MarshalerUtil.sizeRepeatedMessage( - SummaryDataPoint.QUANTILE_VALUES, - point.getValues(), - ValueAtQuantileMarshaler::calculateSize, - context); - size += - KeyValueMarshaler.calculateSize( - SummaryDataPoint.ATTRIBUTES, point.getAttributes(), context); - return size; - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryDataPointStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryDataPointStatelessMarshaler.java new file mode 100644 index 00000000000..f7903f4eb61 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryDataPointStatelessMarshaler.java @@ -0,0 +1,63 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.exporter.internal.otlp.KeyValueStatelessMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.SummaryDataPoint; +import io.opentelemetry.sdk.metrics.data.SummaryPointData; +import java.io.IOException; + +final class SummaryDataPointStatelessMarshaler implements StatelessMarshaler { + static final SummaryDataPointStatelessMarshaler INSTANCE = + new SummaryDataPointStatelessMarshaler(); + + @Override + public void writeTo(Serializer output, SummaryPointData point, MarshalerContext context) + throws IOException { + output.serializeFixed64(SummaryDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + output.serializeFixed64(SummaryDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + output.serializeFixed64(SummaryDataPoint.COUNT, point.getCount()); + output.serializeDoubleOptional(SummaryDataPoint.SUM, point.getSum()); + output.serializeRepeatedMessage( + SummaryDataPoint.QUANTILE_VALUES, + point.getValues(), + ValueAtQuantileStatelessMarshaler.INSTANCE, + context); + output.serializeRepeatedMessage( + SummaryDataPoint.ATTRIBUTES, + point.getAttributes(), + KeyValueStatelessMarshaler.INSTANCE, + context); + } + + @Override + public int getBinarySerializedSize(SummaryPointData point, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeFixed64( + SummaryDataPoint.START_TIME_UNIX_NANO, point.getStartEpochNanos()); + size += MarshalerUtil.sizeFixed64(SummaryDataPoint.TIME_UNIX_NANO, point.getEpochNanos()); + size += MarshalerUtil.sizeFixed64(SummaryDataPoint.COUNT, point.getCount()); + size += MarshalerUtil.sizeDoubleOptional(SummaryDataPoint.SUM, point.getSum()); + size += + MarshalerUtil.sizeRepeatedMessage( + SummaryDataPoint.QUANTILE_VALUES, + point.getValues(), + ValueAtQuantileStatelessMarshaler.INSTANCE, + context); + size += + MarshalerUtil.sizeRepeatedMessage( + SummaryDataPoint.ATTRIBUTES, + point.getAttributes(), + KeyValueStatelessMarshaler.INSTANCE, + context); + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryMarshaler.java index 9c432aa2985..09bc0029661 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryMarshaler.java @@ -5,7 +5,6 @@ package io.opentelemetry.exporter.internal.otlp.metrics; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -14,9 +13,6 @@ import java.io.IOException; final class SummaryMarshaler extends MarshalerWithSize { - private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); - private static final Object DATA_POINT_WRITER_KEY = new Object(); - private final SummaryDataPointMarshaler[] dataPoints; static SummaryMarshaler create(SummaryData summary) { @@ -35,31 +31,9 @@ public void writeTo(Serializer output) throws IOException { output.serializeRepeatedMessage(Summary.DATA_POINTS, dataPoints); } - public static void writeTo(Serializer output, SummaryData summary, MarshalerContext context) - throws IOException { - output.serializeRepeatedMessage( - Summary.DATA_POINTS, - summary.getPoints(), - SummaryDataPointMarshaler::writeTo, - context, - DATA_POINT_WRITER_KEY); - } - private static int calculateSize(SummaryDataPointMarshaler[] dataPoints) { int size = 0; size += MarshalerUtil.sizeRepeatedMessage(Summary.DATA_POINTS, dataPoints); return size; } - - public static int calculateSize(SummaryData summary, MarshalerContext context) { - int size = 0; - size += - MarshalerUtil.sizeRepeatedMessage( - Summary.DATA_POINTS, - summary.getPoints(), - SummaryDataPointMarshaler::calculateSize, - context, - DATA_POINT_SIZE_CALCULATOR_KEY); - return size; - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryStatelessMarshaler.java new file mode 100644 index 00000000000..9f1fea984a5 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryStatelessMarshaler.java @@ -0,0 +1,44 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.Summary; +import io.opentelemetry.sdk.metrics.data.SummaryData; +import java.io.IOException; + +final class SummaryStatelessMarshaler implements StatelessMarshaler { + static final SummaryStatelessMarshaler INSTANCE = new SummaryStatelessMarshaler(); + private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); + private static final Object DATA_POINT_WRITER_KEY = new Object(); + + @Override + public void writeTo(Serializer output, SummaryData summary, MarshalerContext context) + throws IOException { + output.serializeRepeatedMessage( + Summary.DATA_POINTS, + summary.getPoints(), + SummaryDataPointStatelessMarshaler.INSTANCE, + context, + DATA_POINT_WRITER_KEY); + } + + @Override + public int getBinarySerializedSize(SummaryData summary, MarshalerContext context) { + int size = 0; + size += + MarshalerUtil.sizeRepeatedMessage( + Summary.DATA_POINTS, + summary.getPoints(), + SummaryDataPointStatelessMarshaler.INSTANCE, + context, + DATA_POINT_SIZE_CALCULATOR_KEY); + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ValueAtQuantileMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ValueAtQuantileMarshaler.java index 350e3ed08bf..1c2e6ba09db 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ValueAtQuantileMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ValueAtQuantileMarshaler.java @@ -5,7 +5,6 @@ package io.opentelemetry.exporter.internal.otlp.metrics; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -43,20 +42,10 @@ public void writeTo(Serializer output) throws IOException { output.serializeDouble(SummaryDataPoint.ValueAtQuantile.VALUE, value); } - public static void writeTo(Serializer output, ValueAtQuantile value, MarshalerContext context) - throws IOException { - output.serializeDouble(SummaryDataPoint.ValueAtQuantile.QUANTILE, value.getQuantile()); - output.serializeDouble(SummaryDataPoint.ValueAtQuantile.VALUE, value.getValue()); - } - - private static int calculateSize(double quantile, double value) { + static int calculateSize(double quantile, double value) { int size = 0; size += MarshalerUtil.sizeDouble(SummaryDataPoint.ValueAtQuantile.QUANTILE, quantile); size += MarshalerUtil.sizeDouble(SummaryDataPoint.ValueAtQuantile.VALUE, value); return size; } - - public static int calculateSize(ValueAtQuantile value, MarshalerContext context) { - return calculateSize(value.getQuantile(), value.getValue()); - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ValueAtQuantileStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ValueAtQuantileStatelessMarshaler.java new file mode 100644 index 00000000000..d8332315480 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ValueAtQuantileStatelessMarshaler.java @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.proto.metrics.v1.internal.SummaryDataPoint; +import io.opentelemetry.sdk.metrics.data.ValueAtQuantile; +import java.io.IOException; + +final class ValueAtQuantileStatelessMarshaler implements StatelessMarshaler { + static final ValueAtQuantileStatelessMarshaler INSTANCE = new ValueAtQuantileStatelessMarshaler(); + + @Override + public void writeTo(Serializer output, ValueAtQuantile value, MarshalerContext context) + throws IOException { + output.serializeDouble(SummaryDataPoint.ValueAtQuantile.QUANTILE, value.getQuantile()); + output.serializeDouble(SummaryDataPoint.ValueAtQuantile.VALUE, value.getValue()); + } + + @Override + public int getBinarySerializedSize(ValueAtQuantile value, MarshalerContext context) { + return ValueAtQuantileMarshaler.calculateSize(value.getQuantile(), value.getValue()); + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansMarshaler.java index 812533d66b2..3aeea01c604 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansMarshaler.java @@ -45,7 +45,8 @@ public static void writeTo( MarshalerContext context) throws IOException { output.serializeMessage(ScopeSpans.SCOPE, instrumentationScopeMarshaler); - output.serializeRepeatedMessage(ScopeSpans.SPANS, spans, SpanMarshaler::writeTo, context); + output.serializeRepeatedMessage( + ScopeSpans.SPANS, spans, SpanStatelessMarshaler.INSTANCE, context); output.serializeString(ScopeSpans.SCHEMA_URL, schemaUrlUtf8); } @@ -72,7 +73,7 @@ public static int calculateSize( size += MarshalerUtil.sizeBytes(ScopeSpans.SCHEMA_URL, schemaUrlUtf8); size += MarshalerUtil.sizeRepeatedMessage( - ScopeSpans.SPANS, spans, SpanMarshaler::calculateSize, context); + ScopeSpans.SPANS, spans, SpanStatelessMarshaler.INSTANCE, context); context.setSize(sizeIndex, size); return size; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansStatelessMarshaler.java new file mode 100644 index 00000000000..6a03168b102 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansStatelessMarshaler.java @@ -0,0 +1,64 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.traces; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler2; +import io.opentelemetry.exporter.internal.otlp.InstrumentationScopeMarshaler; +import io.opentelemetry.proto.trace.v1.internal.ScopeSpans; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.io.IOException; +import java.util.List; + +final class InstrumentationScopeSpansStatelessMarshaler + implements StatelessMarshaler2> { + static final InstrumentationScopeSpansStatelessMarshaler INSTANCE = + new InstrumentationScopeSpansStatelessMarshaler(); + + @Override + public void writeTo( + Serializer output, + InstrumentationScopeInfo instrumentationScope, + List spans, + MarshalerContext context) + throws IOException { + InstrumentationScopeMarshaler instrumentationScopeMarshaler = + context.getObject(InstrumentationScopeMarshaler.class); + byte[] schemaUrlUtf8 = context.getByteArray(); + + output.serializeMessage(ScopeSpans.SCOPE, instrumentationScopeMarshaler); + output.serializeRepeatedMessage( + ScopeSpans.SPANS, spans, SpanStatelessMarshaler.INSTANCE, context); + output.serializeString(ScopeSpans.SCHEMA_URL, schemaUrlUtf8); + } + + @Override + public int getBinarySerializedSize( + InstrumentationScopeInfo instrumentationScope, + List spans, + MarshalerContext context) { + InstrumentationScopeMarshaler instrumentationScopeMarshaler = + InstrumentationScopeMarshaler.create(instrumentationScope); + context.addData(instrumentationScopeMarshaler); + // XXX + byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(instrumentationScope.getSchemaUrl()); + context.addData(schemaUrlUtf8); + + // int sizeIndex = context.addSize(); + int size = 0; + size += MarshalerUtil.sizeMessage(ScopeSpans.SCOPE, instrumentationScopeMarshaler); + size += MarshalerUtil.sizeBytes(ScopeSpans.SCHEMA_URL, schemaUrlUtf8); + size += + MarshalerUtil.sizeRepeatedMessage( + ScopeSpans.SPANS, spans, SpanStatelessMarshaler.INSTANCE, context); + // context.setSize(sizeIndex, size); + + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java index 74bd3160ea2..6211d7f00f0 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java @@ -9,8 +9,6 @@ import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.Serializer; -import io.opentelemetry.exporter.internal.otlp.AbstractResourceScopeMapSizeCalculator; -import io.opentelemetry.exporter.internal.otlp.AbstractResourceScopeMapWriter; import io.opentelemetry.proto.collector.trace.v1.internal.ExportTraceServiceRequest; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.resources.Resource; @@ -27,7 +25,10 @@ *

This class is internal and is hence not for public use. Its APIs are unstable and can change * at any time. */ +@SuppressWarnings({"UnusedNestedClass", "UnusedVariable", "CheckedExceptionNotThrown"}) public final class LowAllocationTraceRequestMarshaler extends Marshaler { + private static final Object RESOURCE_SPAN_SIZE_CALCULATOR_KEY = new Object(); + private static final Object RESOURCE_SPAN_WRITER_KEY = new Object(); private final MarshalerContext context = new MarshalerContext(); @@ -50,30 +51,27 @@ public int getBinarySerializedSize() { return size; } - private final ResourceScopeMapWriter resourceScopeMapWriter = new ResourceScopeMapWriter(); - @Override - public void writeTo(Serializer output) { + public void writeTo(Serializer output) throws IOException { // serializing can be retried, reset the indexes, so we could call writeTo multiple times context.resetReadIndex(); - resourceScopeMapWriter.initialize(output, ExportTraceServiceRequest.RESOURCE_SPANS, context); - resourceAndScopeMap.forEach(resourceScopeMapWriter); + output.serializeRepeatedMessage( + ExportTraceServiceRequest.RESOURCE_SPANS, + resourceAndScopeMap, + ResourceSpansStatelessMarshaler.INSTANCE, + context, + RESOURCE_SPAN_WRITER_KEY); } private static int calculateSize( MarshalerContext context, Map>> resourceAndScopeMap) { - if (resourceAndScopeMap.isEmpty()) { - return 0; - } - - ResourceScopeMapSizeCalculator resourceScopeMapSizeCalculator = - context.getInstance( - ResourceScopeMapSizeCalculator.class, ResourceScopeMapSizeCalculator::new); - resourceScopeMapSizeCalculator.initialize(ExportTraceServiceRequest.RESOURCE_SPANS, context); - resourceAndScopeMap.forEach(resourceScopeMapSizeCalculator); - - return resourceScopeMapSizeCalculator.getSize(); + return MarshalerUtil.sizeRepeatedMessage( + ExportTraceServiceRequest.RESOURCE_SPANS, + resourceAndScopeMap, + ResourceSpansStatelessMarshaler.INSTANCE, + context, + RESOURCE_SPAN_SIZE_CALCULATOR_KEY); } private static Map>> @@ -91,26 +89,4 @@ private static int calculateSize( SpanData::getInstrumentationScopeInfo, context); } - - private static class ResourceScopeMapWriter extends AbstractResourceScopeMapWriter { - - @Override - protected void handle( - Map> instrumentationScopeInfoListMap) - throws IOException { - ResourceSpansMarshaler.writeTo(output, instrumentationScopeInfoListMap, context); - } - } - - private static class ResourceScopeMapSizeCalculator - extends AbstractResourceScopeMapSizeCalculator { - - @Override - public int calculateSize( - Resource resource, - Map> instrumentationScopeInfoListMap) { - return ResourceSpansMarshaler.calculateSize( - context, resource, instrumentationScopeInfoListMap); - } - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java index 9944c3c03f2..313b90c4fbc 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java @@ -5,12 +5,9 @@ package io.opentelemetry.exporter.internal.otlp.traces; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; 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.AbstractScopeListSizeCalculator; -import io.opentelemetry.exporter.internal.otlp.AbstractScopeListWriter; import io.opentelemetry.exporter.internal.otlp.InstrumentationScopeMarshaler; import io.opentelemetry.exporter.internal.otlp.ResourceMarshaler; import io.opentelemetry.proto.trace.v1.internal.ResourceSpans; @@ -81,6 +78,7 @@ public void writeTo(Serializer output) throws IOException { output.serializeString(ResourceSpans.SCHEMA_URL, schemaUrlUtf8); } + /* public static void writeTo( Serializer output, Map> scopeMap, @@ -98,6 +96,8 @@ public static void writeTo( output.serializeString(ResourceSpans.SCHEMA_URL, schemaUrlUtf8); } + */ + private static int calculateSize( ResourceMarshaler resourceMarshaler, byte[] schemaUrlUtf8, @@ -112,6 +112,7 @@ private static int calculateSize( return size; } + /* public static int calculateSize( MarshalerContext context, Resource resource, @@ -139,6 +140,8 @@ public static int calculateSize( return size; } + */ + private static Map>> groupByResourceAndScope(Collection spanDataList) { return MarshalerUtil.groupByResourceAndScope( @@ -149,30 +152,4 @@ public static int calculateSize( SpanData::getInstrumentationScopeInfo, SpanMarshaler::create); } - - private static class ScopeSpanListWriter extends AbstractScopeListWriter { - - @Override - protected void handle( - InstrumentationScopeMarshaler instrumentationScopeMarshaler, - List list, - byte[] schemaUrlUtf8) - throws IOException { - InstrumentationScopeSpansMarshaler.writeTo( - output, instrumentationScopeMarshaler, list, schemaUrlUtf8, context); - } - } - - private static class ScopeSpanListSizeCalculator - extends AbstractScopeListSizeCalculator { - - @Override - public int calculateSize( - InstrumentationScopeMarshaler instrumentationScopeMarshaler, - byte[] schemaUrlUtf8, - List list) { - return InstrumentationScopeSpansMarshaler.calculateSize( - instrumentationScopeMarshaler, schemaUrlUtf8, list, context); - } - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansStatelessMarshaler.java new file mode 100644 index 00000000000..2315185f19b --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansStatelessMarshaler.java @@ -0,0 +1,80 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.traces; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler2; +import io.opentelemetry.exporter.internal.otlp.ResourceMarshaler; +import io.opentelemetry.proto.trace.v1.internal.ResourceSpans; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * A Marshaler of ResourceSpans. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class ResourceSpansStatelessMarshaler + implements StatelessMarshaler2>> { + static final ResourceSpansStatelessMarshaler INSTANCE = new ResourceSpansStatelessMarshaler(); + private static final Object SCOPE_SPAN_WRITER_KEY = new Object(); + private static final Object SCOPE_SPAN_SIZE_CALCULATOR_KEY = new Object(); + + @Override + public void writeTo( + Serializer output, + Resource resource, + Map> scopeMap, + MarshalerContext context) + throws IOException { + ResourceMarshaler resourceMarshaler = context.getObject(ResourceMarshaler.class); + output.serializeMessage(ResourceSpans.RESOURCE, resourceMarshaler); + + output.serializeRepeatedMessage( + ResourceSpans.SCOPE_SPANS, + scopeMap, + InstrumentationScopeSpansStatelessMarshaler.INSTANCE, + context, + SCOPE_SPAN_WRITER_KEY); + + byte[] schemaUrlUtf8 = context.getByteArray(); + output.serializeString(ResourceSpans.SCHEMA_URL, schemaUrlUtf8); + } + + @Override + public int getBinarySerializedSize( + Resource resource, + Map> scopeMap, + MarshalerContext context) { + + int size = 0; + + ResourceMarshaler resourceMarshaler = ResourceMarshaler.create(resource); + context.addData(resourceMarshaler); + size += MarshalerUtil.sizeMessage(ResourceSpans.RESOURCE, resourceMarshaler); + + size += + MarshalerUtil.sizeRepeatedMessage( + ResourceSpans.SCOPE_SPANS, + scopeMap, + InstrumentationScopeSpansStatelessMarshaler.INSTANCE, + context, + SCOPE_SPAN_SIZE_CALCULATOR_KEY); + + byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(resource.getSchemaUrl()); + context.addData(schemaUrlUtf8); + size += MarshalerUtil.sizeBytes(ResourceSpans.SCHEMA_URL, schemaUrlUtf8); + + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventMarshaler.java index 7ddf6c54e44..2b2cc1d7775 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventMarshaler.java @@ -5,7 +5,6 @@ package io.opentelemetry.exporter.internal.otlp.traces; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -65,19 +64,6 @@ public void writeTo(Serializer output) throws IOException { output.serializeUInt32(Span.Event.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); } - public static void writeTo(Serializer output, EventData event, MarshalerContext context) - throws IOException { - output.serializeFixed64(Span.Event.TIME_UNIX_NANO, event.getEpochNanos()); - if (context.marshalStringNoAllocation()) { - output.writeString(Span.Event.NAME, event.getName(), context.getSize()); - } else { - output.serializeString(Span.Event.NAME, context.getByteArray()); - } - KeyValueMarshaler.writeTo(output, context, Span.Event.ATTRIBUTES, event.getAttributes()); - int droppedAttributesCount = event.getTotalAttributeCount() - event.getAttributes().size(); - output.serializeUInt32(Span.Event.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); - } - private static int calculateSize( long epochNanos, byte[] name, @@ -90,23 +76,4 @@ private static int calculateSize( size += MarshalerUtil.sizeUInt32(Span.Event.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); return size; } - - public static int calculateSize(EventData event, MarshalerContext context) { - int size = 0; - size += MarshalerUtil.sizeFixed64(Span.Event.TIME_UNIX_NANO, event.getEpochNanos()); - if (context.marshalStringNoAllocation()) { - int utf8Size = MarshalerUtil.getUtf8Size(event.getName()); - context.addSize(utf8Size); - size += MarshalerUtil.sizeBytes(Span.Event.NAME, utf8Size); - } else { - byte[] nameUtf8 = MarshalerUtil.toBytes(event.getName()); - context.addData(nameUtf8); - size += MarshalerUtil.sizeBytes(Span.Event.NAME, nameUtf8); - } - size += KeyValueMarshaler.calculateSize(Span.Event.ATTRIBUTES, event.getAttributes(), context); - int droppedAttributesCount = event.getTotalAttributeCount() - event.getAttributes().size(); - size += MarshalerUtil.sizeUInt32(Span.Event.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); - - return size; - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventStatelessMarshaler.java new file mode 100644 index 00000000000..aa945210577 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanEventStatelessMarshaler.java @@ -0,0 +1,47 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.traces; + +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.exporter.internal.otlp.KeyValueStatelessMarshaler; +import io.opentelemetry.proto.trace.v1.internal.Span; +import io.opentelemetry.sdk.trace.data.EventData; +import java.io.IOException; + +final class SpanEventStatelessMarshaler implements StatelessMarshaler { + static final SpanEventStatelessMarshaler INSTANCE = new SpanEventStatelessMarshaler(); + + @Override + public void writeTo(Serializer output, EventData event, MarshalerContext context) + throws IOException { + output.serializeFixed64(Span.Event.TIME_UNIX_NANO, event.getEpochNanos()); + output.serializeString(Span.Event.NAME, event.getName(), context); + output.serializeRepeatedMessage( + Span.Event.ATTRIBUTES, event.getAttributes(), KeyValueStatelessMarshaler.INSTANCE, context); + int droppedAttributesCount = event.getTotalAttributeCount() - event.getAttributes().size(); + output.serializeUInt32(Span.Event.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); + } + + @Override + public int getBinarySerializedSize(EventData event, MarshalerContext context) { + int size = 0; + size += MarshalerUtil.sizeFixed64(Span.Event.TIME_UNIX_NANO, event.getEpochNanos()); + size += MarshalerUtil.sizeString(Span.Event.NAME, event.getName(), context); + size += + MarshalerUtil.sizeRepeatedMessage( + Span.Event.ATTRIBUTES, + event.getAttributes(), + KeyValueStatelessMarshaler.INSTANCE, + context); + int droppedAttributesCount = event.getTotalAttributeCount() - event.getAttributes().size(); + size += MarshalerUtil.sizeUInt32(Span.Event.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); + + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java index 14f17082e72..6adcac370e1 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java @@ -9,7 +9,6 @@ import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; @@ -93,17 +92,6 @@ public void writeTo(Serializer output) throws IOException { output.serializeByteAsFixed32(Span.Link.FLAGS, traceFlags.asByte()); } - public static void writeTo(Serializer output, LinkData link, MarshalerContext context) - throws IOException { - output.serializeTraceId(Span.Link.TRACE_ID, link.getSpanContext().getTraceId(), context); - output.serializeSpanId(Span.Link.SPAN_ID, link.getSpanContext().getSpanId(), context); - output.serializeString(Span.Link.TRACE_STATE, context.getByteArray()); - KeyValueMarshaler.writeTo(output, context, Span.Link.ATTRIBUTES, link.getAttributes()); - int droppedAttributesCount = link.getTotalAttributeCount() - link.getAttributes().size(); - output.serializeUInt32(Span.Link.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); - output.serializeByteAsFixed32(Span.Link.FLAGS, link.getSpanContext().getTraceFlags().asByte()); - } - private static int calculateSize( String traceId, String spanId, @@ -120,26 +108,4 @@ private static int calculateSize( size += MarshalerUtil.sizeByteAsFixed32(Span.Link.FLAGS, flags.asByte()); return size; } - - public static int calculateSize(LinkData link, MarshalerContext context) { - TraceState traceState = link.getSpanContext().getTraceState(); - byte[] traceStateUtf8 = - traceState.isEmpty() - ? EMPTY_BYTES - : encodeTraceState(traceState).getBytes(StandardCharsets.UTF_8); - context.addData(traceStateUtf8); - - int size = 0; - size += MarshalerUtil.sizeTraceId(Span.Link.TRACE_ID, link.getSpanContext().getTraceId()); - size += MarshalerUtil.sizeSpanId(Span.Link.SPAN_ID, link.getSpanContext().getSpanId()); - size += MarshalerUtil.sizeBytes(Span.Link.TRACE_STATE, traceStateUtf8); - size += KeyValueMarshaler.calculateSize(Span.Link.ATTRIBUTES, link.getAttributes(), context); - int droppedAttributesCount = link.getTotalAttributeCount() - link.getAttributes().size(); - size += MarshalerUtil.sizeUInt32(Span.Link.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); - size += - MarshalerUtil.sizeByteAsFixed32( - Span.Link.FLAGS, link.getSpanContext().getTraceFlags().asByte()); - - return size; - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkStatelessMarshaler.java new file mode 100644 index 00000000000..dbc51745e42 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkStatelessMarshaler.java @@ -0,0 +1,65 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.traces; + +import static io.opentelemetry.api.trace.propagation.internal.W3CTraceContextEncoding.encodeTraceState; + +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.exporter.internal.otlp.KeyValueStatelessMarshaler; +import io.opentelemetry.proto.trace.v1.internal.Span; +import io.opentelemetry.sdk.trace.data.LinkData; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +final class SpanLinkStatelessMarshaler implements StatelessMarshaler { + static final SpanLinkStatelessMarshaler INSTANCE = new SpanLinkStatelessMarshaler(); + private static final byte[] EMPTY_BYTES = new byte[0]; + + @Override + public void writeTo(Serializer output, LinkData link, MarshalerContext context) + throws IOException { + output.serializeTraceId(Span.Link.TRACE_ID, link.getSpanContext().getTraceId(), context); + output.serializeSpanId(Span.Link.SPAN_ID, link.getSpanContext().getSpanId(), context); + output.serializeString(Span.Link.TRACE_STATE, context.getByteArray()); + output.serializeRepeatedMessage( + Span.Link.ATTRIBUTES, link.getAttributes(), KeyValueStatelessMarshaler.INSTANCE, context); + int droppedAttributesCount = link.getTotalAttributeCount() - link.getAttributes().size(); + output.serializeUInt32(Span.Link.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); + output.serializeByteAsFixed32(Span.Link.FLAGS, link.getSpanContext().getTraceFlags().asByte()); + } + + @Override + public int getBinarySerializedSize(LinkData link, MarshalerContext context) { + TraceState traceState = link.getSpanContext().getTraceState(); + byte[] traceStateUtf8 = + traceState.isEmpty() + ? EMPTY_BYTES + : encodeTraceState(traceState).getBytes(StandardCharsets.UTF_8); + context.addData(traceStateUtf8); + + int size = 0; + size += MarshalerUtil.sizeTraceId(Span.Link.TRACE_ID, link.getSpanContext().getTraceId()); + size += MarshalerUtil.sizeSpanId(Span.Link.SPAN_ID, link.getSpanContext().getSpanId()); + size += MarshalerUtil.sizeBytes(Span.Link.TRACE_STATE, traceStateUtf8); + size += + MarshalerUtil.sizeRepeatedMessage( + Span.Link.ATTRIBUTES, + link.getAttributes(), + KeyValueStatelessMarshaler.INSTANCE, + context); + int droppedAttributesCount = link.getTotalAttributeCount() - link.getAttributes().size(); + size += MarshalerUtil.sizeUInt32(Span.Link.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); + size += + MarshalerUtil.sizeByteAsFixed32( + Span.Link.FLAGS, link.getSpanContext().getTraceFlags().asByte()); + + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java index 41ff239d32f..a86c8bae01c 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java @@ -10,7 +10,6 @@ import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoEnumInfo; @@ -158,48 +157,6 @@ public void writeTo(Serializer output) throws IOException { output.serializeByteAsFixed32(Span.FLAGS, flags.asByte()); } - public static void writeTo(Serializer output, SpanData span, MarshalerContext context) - throws IOException { - output.serializeTraceId(Span.TRACE_ID, span.getTraceId(), context); - output.serializeSpanId(Span.SPAN_ID, span.getSpanId(), context); - - byte[] traceStateUtf8 = context.getByteArray(); - output.serializeString(Span.TRACE_STATE, traceStateUtf8); - String parentSpanId = - span.getParentSpanContext().isValid() ? span.getParentSpanContext().getSpanId() : null; - output.serializeSpanId(Span.PARENT_SPAN_ID, parentSpanId, context); - - if (context.marshalStringNoAllocation()) { - output.writeString(Span.NAME, span.getName(), context.getSize()); - } else { - byte[] nameUtf8 = context.getByteArray(); - output.serializeString(Span.NAME, nameUtf8); - } - - output.serializeEnum(Span.KIND, toProtoSpanKind(span.getKind())); - - output.serializeFixed64(Span.START_TIME_UNIX_NANO, span.getStartEpochNanos()); - output.serializeFixed64(Span.END_TIME_UNIX_NANO, span.getEndEpochNanos()); - - KeyValueMarshaler.writeTo(output, context, Span.ATTRIBUTES, span.getAttributes()); - int droppedAttributesCount = span.getTotalAttributeCount() - span.getAttributes().size(); - output.serializeUInt32(Span.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); - - output.serializeRepeatedMessage( - Span.EVENTS, span.getEvents(), SpanEventMarshaler::writeTo, context); - int droppedEventsCount = span.getTotalRecordedEvents() - span.getEvents().size(); - output.serializeUInt32(Span.DROPPED_EVENTS_COUNT, droppedEventsCount); - - output.serializeRepeatedMessage( - Span.LINKS, span.getLinks(), SpanLinkMarshaler::writeTo, context); - int droppedLinksCount = span.getTotalRecordedLinks() - span.getLinks().size(); - output.serializeUInt32(Span.DROPPED_LINKS_COUNT, droppedLinksCount); - - output.serializeMessage(Span.STATUS, span.getStatus(), SpanStatusMarshaler::writeTo, context); - - output.serializeByteAsFixed32(Span.FLAGS, span.getSpanContext().getTraceFlags().asByte()); - } - private static int calculateSize( String traceId, String spanId, @@ -244,64 +201,6 @@ private static int calculateSize( return size; } - public static int calculateSize(SpanData span, MarshalerContext context) { - int size = 0; - size += MarshalerUtil.sizeTraceId(Span.TRACE_ID, span.getTraceId()); - size += MarshalerUtil.sizeSpanId(Span.SPAN_ID, span.getSpanId()); - - TraceState traceState = span.getSpanContext().getTraceState(); - byte[] traceStateUtf8 = - traceState.isEmpty() - ? EMPTY_BYTES - : encodeTraceState(traceState).getBytes(StandardCharsets.UTF_8); - context.addData(traceStateUtf8); - - size += MarshalerUtil.sizeBytes(Span.TRACE_STATE, traceStateUtf8); - String parentSpanId = - span.getParentSpanContext().isValid() ? span.getParentSpanContext().getSpanId() : null; - size += MarshalerUtil.sizeSpanId(Span.PARENT_SPAN_ID, parentSpanId); - - if (context.marshalStringNoAllocation()) { - int utf8Size = MarshalerUtil.getUtf8Size(span.getName()); - context.addSize(utf8Size); - size += MarshalerUtil.sizeBytes(Span.NAME, utf8Size); - } else { - byte[] nameUtf8 = MarshalerUtil.toBytes(span.getName()); - context.addData(nameUtf8); - size += MarshalerUtil.sizeBytes(Span.NAME, nameUtf8); - } - - size += MarshalerUtil.sizeEnum(Span.KIND, toProtoSpanKind(span.getKind())); - - size += MarshalerUtil.sizeFixed64(Span.START_TIME_UNIX_NANO, span.getStartEpochNanos()); - size += MarshalerUtil.sizeFixed64(Span.END_TIME_UNIX_NANO, span.getEndEpochNanos()); - - size += KeyValueMarshaler.calculateSize(Span.ATTRIBUTES, span.getAttributes(), context); - int droppedAttributesCount = span.getTotalAttributeCount() - span.getAttributes().size(); - size += MarshalerUtil.sizeUInt32(Span.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); - - size += - MarshalerUtil.sizeRepeatedMessage( - Span.EVENTS, span.getEvents(), SpanEventMarshaler::calculateSize, context); - int droppedEventsCount = span.getTotalRecordedEvents() - span.getEvents().size(); - size += MarshalerUtil.sizeUInt32(Span.DROPPED_EVENTS_COUNT, droppedEventsCount); - - size += - MarshalerUtil.sizeRepeatedMessage( - Span.LINKS, span.getLinks(), SpanLinkMarshaler::calculateSize, context); - int droppedLinksCount = span.getTotalRecordedLinks() - span.getLinks().size(); - size += MarshalerUtil.sizeUInt32(Span.DROPPED_LINKS_COUNT, droppedLinksCount); - - size += - MarshalerUtil.sizeMessage( - Span.STATUS, span.getStatus(), SpanStatusMarshaler::calculateSize, context); - - size += - MarshalerUtil.sizeByteAsFixed32(Span.FLAGS, span.getSpanContext().getTraceFlags().asByte()); - - return size; - } - // Visible for testing static ProtoEnumInfo toProtoSpanKind(SpanKind kind) { switch (kind) { diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatelessMarshaler.java new file mode 100644 index 00000000000..9313378811d --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatelessMarshaler.java @@ -0,0 +1,116 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.traces; + +import static io.opentelemetry.api.trace.propagation.internal.W3CTraceContextEncoding.encodeTraceState; +import static io.opentelemetry.exporter.internal.otlp.traces.SpanMarshaler.toProtoSpanKind; + +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.exporter.internal.otlp.KeyValueStatelessMarshaler; +import io.opentelemetry.proto.trace.v1.internal.Span; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +final class SpanStatelessMarshaler implements StatelessMarshaler { + static final SpanStatelessMarshaler INSTANCE = new SpanStatelessMarshaler(); + private static final byte[] EMPTY_BYTES = new byte[0]; + + @Override + public void writeTo(Serializer output, SpanData span, MarshalerContext context) + throws IOException { + output.serializeTraceId(Span.TRACE_ID, span.getTraceId(), context); + output.serializeSpanId(Span.SPAN_ID, span.getSpanId(), context); + + byte[] traceStateUtf8 = context.getByteArray(); + output.serializeString(Span.TRACE_STATE, traceStateUtf8); + String parentSpanId = + span.getParentSpanContext().isValid() ? span.getParentSpanContext().getSpanId() : null; + output.serializeSpanId(Span.PARENT_SPAN_ID, parentSpanId, context); + + output.serializeString(Span.NAME, span.getName(), context); + output.serializeEnum(Span.KIND, toProtoSpanKind(span.getKind())); + + output.serializeFixed64(Span.START_TIME_UNIX_NANO, span.getStartEpochNanos()); + output.serializeFixed64(Span.END_TIME_UNIX_NANO, span.getEndEpochNanos()); + + output.serializeRepeatedMessage( + Span.ATTRIBUTES, span.getAttributes(), KeyValueStatelessMarshaler.INSTANCE, context); + int droppedAttributesCount = span.getTotalAttributeCount() - span.getAttributes().size(); + output.serializeUInt32(Span.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); + + output.serializeRepeatedMessage( + Span.EVENTS, span.getEvents(), SpanEventStatelessMarshaler.INSTANCE, context); + int droppedEventsCount = span.getTotalRecordedEvents() - span.getEvents().size(); + output.serializeUInt32(Span.DROPPED_EVENTS_COUNT, droppedEventsCount); + + output.serializeRepeatedMessage( + Span.LINKS, span.getLinks(), SpanLinkStatelessMarshaler.INSTANCE, context); + int droppedLinksCount = span.getTotalRecordedLinks() - span.getLinks().size(); + output.serializeUInt32(Span.DROPPED_LINKS_COUNT, droppedLinksCount); + + output.serializeMessage( + Span.STATUS, span.getStatus(), SpanStatusStatelessMarshaler.INSTANCE, context); + + output.serializeByteAsFixed32(Span.FLAGS, span.getSpanContext().getTraceFlags().asByte()); + } + + @Override + public int getBinarySerializedSize(SpanData span, MarshalerContext context) { + int size = 0; + size += MarshalerUtil.sizeTraceId(Span.TRACE_ID, span.getTraceId()); + size += MarshalerUtil.sizeSpanId(Span.SPAN_ID, span.getSpanId()); + + TraceState traceState = span.getSpanContext().getTraceState(); + byte[] traceStateUtf8 = + traceState.isEmpty() + ? EMPTY_BYTES + : encodeTraceState(traceState).getBytes(StandardCharsets.UTF_8); + context.addData(traceStateUtf8); + + size += MarshalerUtil.sizeBytes(Span.TRACE_STATE, traceStateUtf8); + String parentSpanId = + span.getParentSpanContext().isValid() ? span.getParentSpanContext().getSpanId() : null; + size += MarshalerUtil.sizeSpanId(Span.PARENT_SPAN_ID, parentSpanId); + + size += MarshalerUtil.sizeString(Span.NAME, span.getName(), context); + size += MarshalerUtil.sizeEnum(Span.KIND, toProtoSpanKind(span.getKind())); + + size += MarshalerUtil.sizeFixed64(Span.START_TIME_UNIX_NANO, span.getStartEpochNanos()); + size += MarshalerUtil.sizeFixed64(Span.END_TIME_UNIX_NANO, span.getEndEpochNanos()); + + size += + MarshalerUtil.sizeRepeatedMessage( + Span.ATTRIBUTES, span.getAttributes(), KeyValueStatelessMarshaler.INSTANCE, context); + int droppedAttributesCount = span.getTotalAttributeCount() - span.getAttributes().size(); + size += MarshalerUtil.sizeUInt32(Span.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); + + size += + MarshalerUtil.sizeRepeatedMessage( + Span.EVENTS, span.getEvents(), SpanEventStatelessMarshaler.INSTANCE, context); + int droppedEventsCount = span.getTotalRecordedEvents() - span.getEvents().size(); + size += MarshalerUtil.sizeUInt32(Span.DROPPED_EVENTS_COUNT, droppedEventsCount); + + size += + MarshalerUtil.sizeRepeatedMessage( + Span.LINKS, span.getLinks(), SpanLinkStatelessMarshaler.INSTANCE, context); + int droppedLinksCount = span.getTotalRecordedLinks() - span.getLinks().size(); + size += MarshalerUtil.sizeUInt32(Span.DROPPED_LINKS_COUNT, droppedLinksCount); + + size += + MarshalerUtil.sizeMessage( + Span.STATUS, span.getStatus(), SpanStatusStatelessMarshaler.INSTANCE, context); + + size += + MarshalerUtil.sizeByteAsFixed32(Span.FLAGS, span.getSpanContext().getTraceFlags().asByte()); + + return size; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusMarshaler.java index 024e7b6456a..78fe066f6c8 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusMarshaler.java @@ -6,7 +6,6 @@ package io.opentelemetry.exporter.internal.otlp.traces; import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.ProtoEnumInfo; @@ -42,42 +41,10 @@ public void writeTo(Serializer output) throws IOException { output.serializeEnum(Status.CODE, protoStatusCode); } - public static void writeTo(Serializer output, StatusData status, MarshalerContext context) - throws IOException { - ProtoEnumInfo protoStatusCode = Status.StatusCode.STATUS_CODE_UNSET; - if (status.getStatusCode() == StatusCode.OK) { - protoStatusCode = Status.StatusCode.STATUS_CODE_OK; - } else if (status.getStatusCode() == StatusCode.ERROR) { - protoStatusCode = Status.StatusCode.STATUS_CODE_ERROR; - } - - byte[] descriptionUtf8 = context.getByteArray(); - - output.serializeString(Status.MESSAGE, descriptionUtf8); - output.serializeEnum(Status.CODE, protoStatusCode); - } - private static int calculateSize(ProtoEnumInfo protoStatusCode, byte[] descriptionUtf8) { int size = 0; size += MarshalerUtil.sizeBytes(Status.MESSAGE, descriptionUtf8); size += MarshalerUtil.sizeEnum(Status.CODE, protoStatusCode); return size; } - - public static int calculateSize(StatusData status, MarshalerContext context) { - ProtoEnumInfo protoStatusCode = Status.StatusCode.STATUS_CODE_UNSET; - if (status.getStatusCode() == StatusCode.OK) { - protoStatusCode = Status.StatusCode.STATUS_CODE_OK; - } else if (status.getStatusCode() == StatusCode.ERROR) { - protoStatusCode = Status.StatusCode.STATUS_CODE_ERROR; - } - byte[] descriptionUtf8 = MarshalerUtil.toBytes(status.getDescription()); - context.addData(descriptionUtf8); - - int size = 0; - size += MarshalerUtil.sizeBytes(Status.MESSAGE, descriptionUtf8); - size += MarshalerUtil.sizeEnum(Status.CODE, protoStatusCode); - - return size; - } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusStatelessMarshaler.java new file mode 100644 index 00000000000..5bea9931596 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusStatelessMarshaler.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.traces; + +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; +import io.opentelemetry.exporter.internal.marshal.ProtoEnumInfo; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; +import io.opentelemetry.proto.trace.v1.internal.Status; +import io.opentelemetry.sdk.trace.data.StatusData; +import java.io.IOException; + +final class SpanStatusStatelessMarshaler implements StatelessMarshaler { + static final SpanStatusStatelessMarshaler INSTANCE = new SpanStatusStatelessMarshaler(); + + @Override + public void writeTo(Serializer output, StatusData status, MarshalerContext context) + throws IOException { + ProtoEnumInfo protoStatusCode = Status.StatusCode.STATUS_CODE_UNSET; + if (status.getStatusCode() == StatusCode.OK) { + protoStatusCode = Status.StatusCode.STATUS_CODE_OK; + } else if (status.getStatusCode() == StatusCode.ERROR) { + protoStatusCode = Status.StatusCode.STATUS_CODE_ERROR; + } + + byte[] descriptionUtf8 = context.getByteArray(); + + output.serializeString(Status.MESSAGE, descriptionUtf8); + output.serializeEnum(Status.CODE, protoStatusCode); + } + + @Override + public int getBinarySerializedSize(StatusData status, MarshalerContext context) { + ProtoEnumInfo protoStatusCode = Status.StatusCode.STATUS_CODE_UNSET; + if (status.getStatusCode() == StatusCode.OK) { + protoStatusCode = Status.StatusCode.STATUS_CODE_OK; + } else if (status.getStatusCode() == StatusCode.ERROR) { + protoStatusCode = Status.StatusCode.STATUS_CODE_ERROR; + } + byte[] descriptionUtf8 = MarshalerUtil.toBytes(status.getDescription()); + context.addData(descriptionUtf8); + + int size = 0; + size += MarshalerUtil.sizeBytes(Status.MESSAGE, descriptionUtf8); + size += MarshalerUtil.sizeEnum(Status.CODE, protoStatusCode); + + return size; + } +} diff --git a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshalerTest.java b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshalerTest.java index 01f218170b9..3efc938993f 100644 --- a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshalerTest.java +++ b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshalerTest.java @@ -128,12 +128,12 @@ void validateExemplar(ExemplarData exemplar) throws Exception { class TestMarshaler extends MarshalerWithSize { protected TestMarshaler() { - super(ExemplarMarshaler.calculateSize(exemplar, context)); + super(ExemplarStatelessMarshaler.INSTANCE.getBinarySerializedSize(exemplar, context)); } @Override protected void writeTo(Serializer output) throws IOException { - ExemplarMarshaler.writeTo(output, exemplar, context); + ExemplarStatelessMarshaler.INSTANCE.writeTo(output, exemplar, context); } } Marshaler marshaler = new TestMarshaler(); @@ -171,12 +171,12 @@ void validateSummary() throws Exception { class TestMarshaler extends MarshalerWithSize { protected TestMarshaler() { - super(SummaryMarshaler.calculateSize(summary, context)); + super(SummaryStatelessMarshaler.INSTANCE.getBinarySerializedSize(summary, context)); } @Override protected void writeTo(Serializer output) throws IOException { - SummaryMarshaler.writeTo(output, summary, context); + SummaryStatelessMarshaler.INSTANCE.writeTo(output, summary, context); } } Marshaler marshaler = new TestMarshaler(); From a891aef0615ccea25ac15233202deccc761ee38a Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 5 Apr 2024 19:37:07 +0300 Subject: [PATCH 08/15] polisth --- .../internal/marshal/JsonSerializer.java | 12 +++---- .../internal/marshal/MarshalerContext.java | 19 +--------- .../internal/marshal/MarshalerUtil.java | 35 ++++--------------- .../internal/marshal/ProtoSerializer.java | 12 +++---- .../exporter/internal/marshal/Serializer.java | 8 ++--- .../internal/otlp/BoolAnyValueMarshaler.java | 6 +--- .../otlp/DoubleAnyValueMarshaler.java | 6 +--- .../internal/otlp/IntAnyValueMarshaler.java | 6 +--- .../otlp/IntAnyValueStatelessMarshaler.java | 4 --- .../otlp/KeyValueStatelessMarshaler.java | 33 ----------------- ...ntationScopeMetricsStatelessMarshaler.java | 16 ++++----- .../ResourceMetricsStatelessMarshaler.java | 9 ++--- ...mentationScopeSpansStatelessMarshaler.java | 14 +++----- .../ResourceSpansStatelessMarshaler.java | 9 ++--- .../traces/SpanLinkStatelessMarshaler.java | 2 +- .../otlp/traces/SpanStatelessMarshaler.java | 2 +- .../traces/SpanStatusStatelessMarshaler.java | 2 +- 17 files changed, 47 insertions(+), 148 deletions(-) diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java index 9dcc784f89b..2070e4ecb38 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java @@ -120,12 +120,12 @@ public void writeBytes(ProtoFieldInfo field, byte[] value) throws IOException { } @Override - public void writeStartMessage(ProtoFieldInfo field, int protoMessageSize) throws IOException { + protected void writeStartMessage(ProtoFieldInfo field, int protoMessageSize) throws IOException { generator.writeObjectFieldStart(field.getJsonName()); } @Override - public void writeEndMessage() throws IOException { + protected void writeEndMessage() throws IOException { generator.writeEndObject(); } @@ -189,23 +189,23 @@ public void serializeRepeatedMessage( } @Override - public void writeStartRepeated(ProtoFieldInfo field) throws IOException { + protected void writeStartRepeated(ProtoFieldInfo field) throws IOException { generator.writeArrayFieldStart(field.getJsonName()); } @Override - public void writeEndRepeated() throws IOException { + protected void writeEndRepeated() throws IOException { generator.writeEndArray(); } @Override - public void writeStartRepeatedElement(ProtoFieldInfo field, int protoMessageSize) + protected void writeStartRepeatedElement(ProtoFieldInfo field, int protoMessageSize) throws IOException { generator.writeStartObject(); } @Override - public void writeEndRepeatedElement() throws IOException { + protected void writeEndRepeatedElement() throws IOException { generator.writeEndObject(); } diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java index 28af8a048a2..5d62712e376 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java @@ -62,11 +62,6 @@ public int getSize() { return sizes[sizeReadIndex++]; } - public int addData() { - growDataIfNeeded(); - return dataWriteIndex++; - } - public void addData(@Nullable Object o) { growDataIfNeeded(); data[dataWriteIndex++] = o; @@ -80,22 +75,10 @@ private void growDataIfNeeded() { } } - public byte[] getByteArray() { - return (byte[]) data[dataReadIndex++]; - } - - public String getString() { - return (String) data[dataReadIndex++]; - } - - public T getObject(Class type) { + public T getData(Class type) { return type.cast(data[dataReadIndex++]); } - public void setData(int index, Object value) { - data[index] = value; - } - private final IdPool traceIdPool = new IdPool(TraceId.getLength() / 2); /** Returns a buffer that can be used to hold a trace id. */ diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java index 741a01e1a1b..42312f235ff 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java @@ -24,7 +24,6 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; -import java.util.function.ToIntBiFunction; import javax.annotation.Nullable; /** @@ -249,27 +248,6 @@ public static int sizeRepeatedMessage( } /** Returns the size of a repeated message field. */ - public static int sizeRepeatedMessage( - ProtoFieldInfo field, - List messages, - ToIntBiFunction consumer, - MarshalerContext context) { - if (messages.isEmpty()) { - return 0; - } - - int size = 0; - int fieldTagSize = field.getTagSize(); - for (int i = 0; i < messages.size(); i++) { - T message = messages.get(i); - int sizeIndex = context.addSize(); - int fieldSize = consumer.applyAsInt(message, context); - context.setSize(sizeIndex, fieldSize); - size += fieldTagSize + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; - } - return size; - } - public static int sizeRepeatedMessage( ProtoFieldInfo field, List messages, @@ -310,6 +288,7 @@ public static int sizeRepeatedMessage( return sizeCalculator.size; } + /** Returns the size of a repeated message field. */ public static int sizeRepeatedMessage( ProtoFieldInfo field, Map messages, @@ -328,6 +307,7 @@ public static int sizeRepeatedMessage( return sizeCalculator.size; } + /** Returns the size of a repeated message field. */ public static int sizeRepeatedMessage( ProtoFieldInfo field, Attributes attributes, @@ -406,10 +386,6 @@ public static int sizeMessage(ProtoFieldInfo field, Marshaler message) { } /** Returns the size of a message field. */ - public static int sizeMessage(ProtoFieldInfo field, int fieldSize) { - return field.getTagSize() + CodedOutputStream.computeUInt32SizeNoTag(fieldSize) + fieldSize; - } - public static int sizeMessage( ProtoFieldInfo field, T element, StatelessMarshaler marshaler, MarshalerContext context) { int sizeIndex = context.addSize(); @@ -419,6 +395,7 @@ public static int sizeMessage( return size; } + /** Returns the size of a message field. */ public static int sizeMessage( ProtoFieldInfo field, K key, @@ -554,9 +531,9 @@ public static int sizeSpanId(ProtoFieldInfo field, @Nullable String spanId) { } /** Returns the size of a string field. */ - @SuppressWarnings("SystemOut") - public static int sizeString(ProtoFieldInfo field, String value, MarshalerContext context) { - if (value.isEmpty()) { + public static int sizeString( + ProtoFieldInfo field, @Nullable String value, MarshalerContext context) { + if (value == null || value.isEmpty()) { return sizeBytes(field, 0); } if (context.marshalStringNoAllocation()) { diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java index bd871619f73..da84e98b05b 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java @@ -161,13 +161,13 @@ public void writeBytes(ProtoFieldInfo field, byte[] value) throws IOException { } @Override - public void writeStartMessage(ProtoFieldInfo field, int protoMessageSize) throws IOException { + protected void writeStartMessage(ProtoFieldInfo field, int protoMessageSize) throws IOException { output.writeUInt32NoTag(field.getTag()); output.writeUInt32NoTag(protoMessageSize); } @Override - public void writeEndMessage() { + protected void writeEndMessage() { // Do nothing } @@ -227,23 +227,23 @@ public void serializeRepeatedMessage( } @Override - public void writeStartRepeated(ProtoFieldInfo field) { + protected void writeStartRepeated(ProtoFieldInfo field) { // Do nothing } @Override - public void writeEndRepeated() { + protected void writeEndRepeated() { // Do nothing } @Override - public void writeStartRepeatedElement(ProtoFieldInfo field, int protoMessageSize) + protected void writeStartRepeatedElement(ProtoFieldInfo field, int protoMessageSize) throws IOException { writeStartMessage(field, protoMessageSize); } @Override - public void writeEndRepeatedElement() { + protected void writeEndRepeatedElement() { writeEndMessage(); } diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java index 3eb283b044a..7dc879ac0b5 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java @@ -220,15 +220,15 @@ public void serializeString(ProtoFieldInfo field, String string, int utf8Length) writeString(field, string, utf8Length); } - public void serializeString(ProtoFieldInfo field, String string, MarshalerContext context) - throws IOException { - if (string.isEmpty()) { + public void serializeString( + ProtoFieldInfo field, @Nullable String string, MarshalerContext context) throws IOException { + if (string == null || string.isEmpty()) { return; } if (context.marshalStringNoAllocation()) { writeString(field, string, context.getSize()); } else { - byte[] valueUtf8 = context.getByteArray(); + byte[] valueUtf8 = context.getData(byte[].class); writeString(field, valueUtf8); } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java index aed4ab59cbc..2293c0c0e58 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/BoolAnyValueMarshaler.java @@ -31,11 +31,7 @@ public void writeTo(Serializer output) throws IOException { output.writeBool(AnyValue.BOOL_VALUE, value); } - public static void writeTo(Serializer output, boolean value) throws IOException { - output.writeBool(AnyValue.BOOL_VALUE, value); - } - - public static int calculateSize(boolean value) { + private static int calculateSize(boolean value) { return AnyValue.BOOL_VALUE.getTagSize() + CodedOutputStream.computeBoolSizeNoTag(value); } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java index 8621fead694..5837976c92d 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/DoubleAnyValueMarshaler.java @@ -31,11 +31,7 @@ public void writeTo(Serializer output) throws IOException { output.writeDouble(AnyValue.DOUBLE_VALUE, value); } - public static void writeTo(Serializer output, double value) throws IOException { - output.writeDouble(AnyValue.DOUBLE_VALUE, value); - } - - public static int calculateSize(double value) { + private static int calculateSize(double value) { return AnyValue.DOUBLE_VALUE.getTagSize() + CodedOutputStream.computeDoubleSizeNoTag(value); } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java index 38c9b038019..498c60e76bb 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueMarshaler.java @@ -31,11 +31,7 @@ public void writeTo(Serializer output) throws IOException { output.writeInt64(AnyValue.INT_VALUE, value); } - public static void writeTo(Serializer output, long value) throws IOException { - output.writeInt64(AnyValue.INT_VALUE, value); - } - - public static int calculateSize(long value) { + private static int calculateSize(long value) { return AnyValue.INT_VALUE.getTagSize() + CodedOutputStream.computeInt64SizeNoTag(value); } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueStatelessMarshaler.java index 871f17d6ddf..799ac631f64 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IntAnyValueStatelessMarshaler.java @@ -20,10 +20,6 @@ public void writeTo(Serializer output, Long value, MarshalerContext context) thr output.writeInt64(AnyValue.INT_VALUE, value); } - public static int calculateSize(long value) { - return AnyValue.INT_VALUE.getTagSize() + CodedOutputStream.computeInt64SizeNoTag(value); - } - @Override public int getBinarySerializedSize(Long value, MarshalerContext context) { return AnyValue.INT_VALUE.getTagSize() + CodedOutputStream.computeInt64SizeNoTag(value); diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueStatelessMarshaler.java index b2545369666..0b12eaecd50 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueStatelessMarshaler.java @@ -95,21 +95,6 @@ public int getBinarySerializedSize( (List) value, ArrayAnyValueStatelessMarshaler.INSTANCE, context); - /* - case STRING_ARRAY: - return ArrayAnyValueMarshaler.calculateSize( - (List) value, StringAnyValueMarshaler::calculateSize, context); - case LONG_ARRAY: - return ArrayAnyValueMarshaler.calculateSize( - (List) value, IntAnyValueMarshaler::calculateSize, context); - case BOOLEAN_ARRAY: - return ArrayAnyValueMarshaler.calculateSize( - (List) value, BoolAnyValueMarshaler::calculateSize, context); - case DOUBLE_ARRAY: - return ArrayAnyValueMarshaler.calculateSize( - (List) value, DoubleAnyValueMarshaler::calculateSize, context); - - */ } // Error prone ensures the switch statement is complete, otherwise only can happen with // unaligned versions which are not supported. @@ -146,24 +131,6 @@ public void writeTo( ArrayAnyValueStatelessMarshaler.INSTANCE, context); return; - /* - case STRING_ARRAY: - ArrayAnyValueMarshaler.writeTo( - output, (List) value, StringAnyValueMarshaler::writeTo, context); - return; - case LONG_ARRAY: - ArrayAnyValueMarshaler.writeTo( - output, (List) value, IntAnyValueMarshaler::writeTo, context); - return; - case BOOLEAN_ARRAY: - ArrayAnyValueMarshaler.writeTo( - output, (List) value, BoolAnyValueMarshaler::writeTo, context); - return; - case DOUBLE_ARRAY: - ArrayAnyValueMarshaler.writeTo( - output, (List) value, DoubleAnyValueMarshaler::writeTo, context); - return; - */ } // Error prone ensures the switch statement is complete, otherwise only can happen with // unaligned versions which are not supported. diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsStatelessMarshaler.java index 014352f86b6..17f7dc8c73e 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/InstrumentationScopeMetricsStatelessMarshaler.java @@ -11,6 +11,7 @@ import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler2; import io.opentelemetry.exporter.internal.otlp.InstrumentationScopeMarshaler; import io.opentelemetry.proto.metrics.v1.internal.ScopeMetrics; +import io.opentelemetry.proto.trace.v1.internal.ScopeSpans; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.metrics.data.MetricData; import java.io.IOException; @@ -29,12 +30,12 @@ public void writeTo( MarshalerContext context) throws IOException { InstrumentationScopeMarshaler instrumentationScopeMarshaler = - context.getObject(InstrumentationScopeMarshaler.class); - byte[] schemaUrlUtf8 = context.getByteArray(); + context.getData(InstrumentationScopeMarshaler.class); + output.serializeMessage(ScopeMetrics.SCOPE, instrumentationScopeMarshaler); output.serializeRepeatedMessage( ScopeMetrics.METRICS, metrics, MetricStatelessMarshaler.INSTANCE, context); - output.serializeString(ScopeMetrics.SCHEMA_URL, schemaUrlUtf8); + output.serializeString(ScopeMetrics.SCHEMA_URL, instrumentationScope.getSchemaUrl(), context); } @Override @@ -45,18 +46,15 @@ public int getBinarySerializedSize( InstrumentationScopeMarshaler instrumentationScopeMarshaler = InstrumentationScopeMarshaler.create(instrumentationScope); context.addData(instrumentationScopeMarshaler); - // XXX - byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(instrumentationScope.getSchemaUrl()); - context.addData(schemaUrlUtf8); - // int sizeIndex = context.addSize(); int size = 0; size += MarshalerUtil.sizeMessage(ScopeMetrics.SCOPE, instrumentationScopeMarshaler); - size += MarshalerUtil.sizeBytes(ScopeMetrics.SCHEMA_URL, schemaUrlUtf8); size += MarshalerUtil.sizeRepeatedMessage( ScopeMetrics.METRICS, metrics, MetricStatelessMarshaler.INSTANCE, context); - // context.setSize(sizeIndex, size); + size += + MarshalerUtil.sizeString( + ScopeSpans.SCHEMA_URL, instrumentationScope.getSchemaUrl(), context); return size; } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsStatelessMarshaler.java index 4cafc1e879c..56d893cff74 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsStatelessMarshaler.java @@ -37,7 +37,7 @@ public void writeTo( Map> scopeMap, MarshalerContext context) throws IOException { - ResourceMarshaler resourceMarshaler = context.getObject(ResourceMarshaler.class); + ResourceMarshaler resourceMarshaler = context.getData(ResourceMarshaler.class); output.serializeMessage(ResourceMetrics.RESOURCE, resourceMarshaler); output.serializeRepeatedMessage( @@ -47,8 +47,7 @@ public void writeTo( context, SCOPE_SPAN_WRITER_KEY); - byte[] schemaUrlUtf8 = context.getByteArray(); - output.serializeString(ResourceMetrics.SCHEMA_URL, schemaUrlUtf8); + output.serializeString(ResourceMetrics.SCHEMA_URL, resource.getSchemaUrl(), context); } @Override @@ -71,9 +70,7 @@ public int getBinarySerializedSize( context, SCOPE_SPAN_SIZE_CALCULATOR_KEY); - byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(resource.getSchemaUrl()); - context.addData(schemaUrlUtf8); - size += MarshalerUtil.sizeBytes(ResourceMetrics.SCHEMA_URL, schemaUrlUtf8); + size += MarshalerUtil.sizeString(ResourceMetrics.SCHEMA_URL, resource.getSchemaUrl(), context); return size; } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansStatelessMarshaler.java index 6a03168b102..2c2076ff82f 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/InstrumentationScopeSpansStatelessMarshaler.java @@ -29,13 +29,12 @@ public void writeTo( MarshalerContext context) throws IOException { InstrumentationScopeMarshaler instrumentationScopeMarshaler = - context.getObject(InstrumentationScopeMarshaler.class); - byte[] schemaUrlUtf8 = context.getByteArray(); + context.getData(InstrumentationScopeMarshaler.class); output.serializeMessage(ScopeSpans.SCOPE, instrumentationScopeMarshaler); output.serializeRepeatedMessage( ScopeSpans.SPANS, spans, SpanStatelessMarshaler.INSTANCE, context); - output.serializeString(ScopeSpans.SCHEMA_URL, schemaUrlUtf8); + output.serializeString(ScopeSpans.SCHEMA_URL, instrumentationScope.getSchemaUrl(), context); } @Override @@ -46,18 +45,15 @@ public int getBinarySerializedSize( InstrumentationScopeMarshaler instrumentationScopeMarshaler = InstrumentationScopeMarshaler.create(instrumentationScope); context.addData(instrumentationScopeMarshaler); - // XXX - byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(instrumentationScope.getSchemaUrl()); - context.addData(schemaUrlUtf8); - // int sizeIndex = context.addSize(); int size = 0; size += MarshalerUtil.sizeMessage(ScopeSpans.SCOPE, instrumentationScopeMarshaler); - size += MarshalerUtil.sizeBytes(ScopeSpans.SCHEMA_URL, schemaUrlUtf8); size += MarshalerUtil.sizeRepeatedMessage( ScopeSpans.SPANS, spans, SpanStatelessMarshaler.INSTANCE, context); - // context.setSize(sizeIndex, size); + size += + MarshalerUtil.sizeString( + ScopeSpans.SCHEMA_URL, instrumentationScope.getSchemaUrl(), context); return size; } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansStatelessMarshaler.java index 2315185f19b..66fcee4594f 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansStatelessMarshaler.java @@ -37,7 +37,7 @@ public void writeTo( Map> scopeMap, MarshalerContext context) throws IOException { - ResourceMarshaler resourceMarshaler = context.getObject(ResourceMarshaler.class); + ResourceMarshaler resourceMarshaler = context.getData(ResourceMarshaler.class); output.serializeMessage(ResourceSpans.RESOURCE, resourceMarshaler); output.serializeRepeatedMessage( @@ -47,8 +47,7 @@ public void writeTo( context, SCOPE_SPAN_WRITER_KEY); - byte[] schemaUrlUtf8 = context.getByteArray(); - output.serializeString(ResourceSpans.SCHEMA_URL, schemaUrlUtf8); + output.serializeString(ResourceSpans.SCHEMA_URL, resource.getSchemaUrl(), context); } @Override @@ -71,9 +70,7 @@ public int getBinarySerializedSize( context, SCOPE_SPAN_SIZE_CALCULATOR_KEY); - byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(resource.getSchemaUrl()); - context.addData(schemaUrlUtf8); - size += MarshalerUtil.sizeBytes(ResourceSpans.SCHEMA_URL, schemaUrlUtf8); + size += MarshalerUtil.sizeString(ResourceSpans.SCHEMA_URL, resource.getSchemaUrl(), context); return size; } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkStatelessMarshaler.java index dbc51745e42..9726bf48531 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkStatelessMarshaler.java @@ -27,7 +27,7 @@ public void writeTo(Serializer output, LinkData link, MarshalerContext context) throws IOException { output.serializeTraceId(Span.Link.TRACE_ID, link.getSpanContext().getTraceId(), context); output.serializeSpanId(Span.Link.SPAN_ID, link.getSpanContext().getSpanId(), context); - output.serializeString(Span.Link.TRACE_STATE, context.getByteArray()); + output.serializeString(Span.Link.TRACE_STATE, context.getData(byte[].class)); output.serializeRepeatedMessage( Span.Link.ATTRIBUTES, link.getAttributes(), KeyValueStatelessMarshaler.INSTANCE, context); int droppedAttributesCount = link.getTotalAttributeCount() - link.getAttributes().size(); diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatelessMarshaler.java index 9313378811d..02615032813 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatelessMarshaler.java @@ -29,7 +29,7 @@ public void writeTo(Serializer output, SpanData span, MarshalerContext context) output.serializeTraceId(Span.TRACE_ID, span.getTraceId(), context); output.serializeSpanId(Span.SPAN_ID, span.getSpanId(), context); - byte[] traceStateUtf8 = context.getByteArray(); + byte[] traceStateUtf8 = context.getData(byte[].class); output.serializeString(Span.TRACE_STATE, traceStateUtf8); String parentSpanId = span.getParentSpanContext().isValid() ? span.getParentSpanContext().getSpanId() : null; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusStatelessMarshaler.java index 5bea9931596..9b469d0314f 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatusStatelessMarshaler.java @@ -28,7 +28,7 @@ public void writeTo(Serializer output, StatusData status, MarshalerContext conte protoStatusCode = Status.StatusCode.STATUS_CODE_ERROR; } - byte[] descriptionUtf8 = context.getByteArray(); + byte[] descriptionUtf8 = context.getData(byte[].class); output.serializeString(Status.MESSAGE, descriptionUtf8); output.serializeEnum(Status.CODE, protoStatusCode); From eac57a094ad56b3cf2d353ab590262ef96a7897b Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 11 Apr 2024 13:43:40 +0300 Subject: [PATCH 09/15] reduce visibility --- .../exporter/internal/marshal/MarshalerUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java index 42312f235ff..23893c0241a 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java @@ -556,8 +556,8 @@ public static byte[] toBytes(@Nullable String value) { } /** Returns the size of utf8 encoded string in bytes. */ - public static int getUtf8Size(String string) { - // return string.length(); + // Visible for testing + static int getUtf8Size(String string) { int size = 0; for (int i = 0; i < string.length(); i++) { char c = string.charAt(i); From 4490431e603fd7359751c80f65f1c6c6051e4dd2 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 11 Apr 2024 13:59:49 +0300 Subject: [PATCH 10/15] share TestOutputStream instance in jmh benchmarks --- .../MetricsRequestMarshalerBenchmark.java | 25 +++++++++--------- .../otlp/RequestMarshalBenchmarks.java | 26 +++++++++---------- .../internal/otlp/TestOutputStream.java | 11 +++++++- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/MetricsRequestMarshalerBenchmark.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/MetricsRequestMarshalerBenchmark.java index 5835956981d..b00806c3be3 100644 --- a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/MetricsRequestMarshalerBenchmark.java +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/MetricsRequestMarshalerBenchmark.java @@ -41,6 +41,7 @@ public class MetricsRequestMarshalerBenchmark { private static final Collection METRICS; private static final LowAllocationMetricsRequestMarshaler MARSHALER = new LowAllocationMetricsRequestMarshaler(); + private static final TestOutputStream OUTPUT = new TestOutputStream(); static { InMemoryMetricReader metricReader = InMemoryMetricReader.create(); @@ -121,26 +122,26 @@ public class MetricsRequestMarshalerBenchmark { @Benchmark public TestOutputStream marshaler() throws IOException { MetricsRequestMarshaler marshaler = MetricsRequestMarshaler.create(METRICS); - TestOutputStream bos = new TestOutputStream(); - marshaler.writeBinaryTo(bos); - return bos; + OUTPUT.reset(); + marshaler.writeBinaryTo(OUTPUT); + return OUTPUT; } @Benchmark public TestOutputStream marshalerJson() throws IOException { MetricsRequestMarshaler marshaler = MetricsRequestMarshaler.create(METRICS); - TestOutputStream bos = new TestOutputStream(); - marshaler.writeJsonTo(bos); - return bos; + OUTPUT.reset(); + marshaler.writeJsonTo(OUTPUT); + return OUTPUT; } @Benchmark public TestOutputStream marshalerLowAllocation() throws IOException { MARSHALER.initialize(METRICS); try { - TestOutputStream bos = new TestOutputStream(); - MARSHALER.writeBinaryTo(bos); - return bos; + OUTPUT.reset(); + MARSHALER.writeBinaryTo(OUTPUT); + return OUTPUT; } finally { MARSHALER.reset(); } @@ -150,9 +151,9 @@ public TestOutputStream marshalerLowAllocation() throws IOException { public TestOutputStream marshalerJsonLowAllocation() throws IOException { MARSHALER.initialize(METRICS); try { - TestOutputStream bos = new TestOutputStream(); - MARSHALER.writeJsonTo(bos); - return bos; + OUTPUT.reset(); + MARSHALER.writeJsonTo(OUTPUT); + return OUTPUT; } finally { MARSHALER.reset(); } diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java index 82ac64ec22b..d68894deb63 100644 --- a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java @@ -27,6 +27,7 @@ public class RequestMarshalBenchmarks { private static final LowAllocationTraceRequestMarshaler MARSHALER = new LowAllocationTraceRequestMarshaler(); + private static final TestOutputStream OUTPUT = new TestOutputStream(); @Benchmark @Threads(1) @@ -39,19 +40,18 @@ public int createCustomMarshal(RequestMarshalState state) { @Threads(1) public TestOutputStream marshalCustom(RequestMarshalState state) throws IOException { TraceRequestMarshaler requestMarshaler = TraceRequestMarshaler.create(state.spanDataList); - TestOutputStream customOutput = - new TestOutputStream(requestMarshaler.getBinarySerializedSize()); - requestMarshaler.writeBinaryTo(customOutput); - return customOutput; + OUTPUT.reset(requestMarshaler.getBinarySerializedSize()); + requestMarshaler.writeBinaryTo(OUTPUT); + return OUTPUT; } @Benchmark @Threads(1) public TestOutputStream marshalJson(RequestMarshalState state) throws IOException { TraceRequestMarshaler requestMarshaler = TraceRequestMarshaler.create(state.spanDataList); - TestOutputStream customOutput = new TestOutputStream(); - requestMarshaler.writeJsonTo(customOutput); - return customOutput; + OUTPUT.reset(); + requestMarshaler.writeJsonTo(OUTPUT); + return OUTPUT; } @Benchmark @@ -72,9 +72,9 @@ public TestOutputStream marshalCustomLowAllocation(RequestMarshalState state) th LowAllocationTraceRequestMarshaler requestMarshaler = MARSHALER; requestMarshaler.initialize(state.spanDataList); try { - TestOutputStream customOutput = new TestOutputStream(); - requestMarshaler.writeBinaryTo(customOutput); - return customOutput; + OUTPUT.reset(); + requestMarshaler.writeBinaryTo(OUTPUT); + return OUTPUT; } finally { requestMarshaler.reset(); } @@ -86,9 +86,9 @@ public TestOutputStream marshalJsonLowAllocation(RequestMarshalState state) thro LowAllocationTraceRequestMarshaler requestMarshaler = MARSHALER; requestMarshaler.initialize(state.spanDataList); try { - TestOutputStream customOutput = new TestOutputStream(); - requestMarshaler.writeJsonTo(customOutput); - return customOutput; + OUTPUT.reset(); + requestMarshaler.writeJsonTo(OUTPUT); + return OUTPUT; } finally { requestMarshaler.reset(); } diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/TestOutputStream.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/TestOutputStream.java index 160853e89fe..3ff1ca6472c 100644 --- a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/TestOutputStream.java +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/TestOutputStream.java @@ -8,7 +8,7 @@ import java.io.OutputStream; class TestOutputStream extends OutputStream { - private final int size; + private int size; private int count; TestOutputStream() { @@ -26,4 +26,13 @@ public void write(int b) { throw new IllegalStateException("max size exceeded"); } } + + void reset(int size) { + this.size = size; + this.count = 0; + } + + void reset() { + reset(-1); + } } From 4298acb27c2311318fbb747957536b91f96c1b6f Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 11 Apr 2024 14:00:09 +0300 Subject: [PATCH 11/15] delete blank line --- .../exporter/internal/otlp/traces/SpanMarshaler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java index a86c8bae01c..e2e83c0f129 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java @@ -197,7 +197,6 @@ private static int calculateSize( size += MarshalerUtil.sizeMessage(Span.STATUS, spanStatusMarshaler); size += MarshalerUtil.sizeByteAsFixed32(Span.FLAGS, flags.asByte()); - return size; } From 00c101f938baf032cf8e4e156256b5e0358a65a4 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 25 Apr 2024 15:20:20 +0300 Subject: [PATCH 12/15] use unsafe to speed up string marshaling --- exporters/common/build.gradle.kts | 1 + .../common/compile-stub/build.gradle.kts | 6 + .../src/main/java/sun/misc/Unsafe.java | 35 +++ .../internal/marshal/JsonSerializer.java | 4 +- .../internal/marshal/MarshalerContext.java | 46 +++- .../internal/marshal/MarshalerUtil.java | 223 +++++++++++++----- .../internal/marshal/ProtoSerializer.java | 6 +- .../exporter/internal/marshal/Serializer.java | 25 +- .../internal/marshal/UnsafeAccess.java | 69 ++++++ .../internal/marshal/UnsafeString.java | 50 ++++ .../internal/marshal/MarshalerUtilTest.java | 54 +++-- .../MetricsRequestMarshalerBenchmark.java | 16 +- .../otlp/RequestMarshalBenchmarks.java | 16 +- .../internal/otlp/StringMarshalBenchmark.java | 121 ++++++++++ .../internal/otlp/StringMarshalState.java | 37 +++ .../internal/otlp/TestOutputStream.java | 4 + ...xponentialHistogramStatelessMarshaler.java | 4 +- .../otlp/metrics/GaugeStatelessMarshaler.java | 4 +- .../metrics/HistogramStatelessMarshaler.java | 4 +- .../LowAllocationMetricsRequestMarshaler.java | 5 +- .../metrics/MetricStatelessMarshaler.java | 5 +- .../ResourceMetricsStatelessMarshaler.java | 4 +- .../otlp/metrics/SumStatelessMarshaler.java | 4 +- .../metrics/SummaryStatelessMarshaler.java | 4 +- .../LowAllocationTraceRequestMarshaler.java | 5 +- .../ResourceSpansStatelessMarshaler.java | 4 +- settings.gradle.kts | 1 + 27 files changed, 625 insertions(+), 132 deletions(-) create mode 100644 exporters/common/compile-stub/build.gradle.kts create mode 100644 exporters/common/compile-stub/src/main/java/sun/misc/Unsafe.java create mode 100644 exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/UnsafeAccess.java create mode 100644 exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/UnsafeString.java create mode 100644 exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/StringMarshalBenchmark.java create mode 100644 exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/StringMarshalState.java diff --git a/exporters/common/build.gradle.kts b/exporters/common/build.gradle.kts index b8868565287..32dedd2cc7c 100644 --- a/exporters/common/build.gradle.kts +++ b/exporters/common/build.gradle.kts @@ -14,6 +14,7 @@ dependencies { api(project(":sdk-extensions:autoconfigure-spi")) compileOnly(project(":sdk:common")) + compileOnly(project(":exporters:common:compile-stub")) compileOnly("org.codehaus.mojo:animal-sniffer-annotations") diff --git a/exporters/common/compile-stub/build.gradle.kts b/exporters/common/compile-stub/build.gradle.kts new file mode 100644 index 00000000000..f93bd1883c9 --- /dev/null +++ b/exporters/common/compile-stub/build.gradle.kts @@ -0,0 +1,6 @@ +plugins { + id("otel.java-conventions") +} + +description = "OpenTelemetry Exporter Compile Stub" +otelJava.moduleName.set("io.opentelemetry.exporter.internal.compile-stub") diff --git a/exporters/common/compile-stub/src/main/java/sun/misc/Unsafe.java b/exporters/common/compile-stub/src/main/java/sun/misc/Unsafe.java new file mode 100644 index 00000000000..8aef8001b4d --- /dev/null +++ b/exporters/common/compile-stub/src/main/java/sun/misc/Unsafe.java @@ -0,0 +1,35 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package sun.misc; + +import java.lang.reflect.Field; + +/** + * sun.misc.Unsafe from the JDK isn't found by the compiler, we provide out own trimmed down version + * that we can compile against. + */ +public class Unsafe { + + public long objectFieldOffset(Field f) { + return -1; + } + + public Object getObject(Object o, long offset) { + return null; + } + + public byte getByte(Object o, long offset) { + return 0; + } + + public int arrayBaseOffset(Class arrayClass) { + return 0; + } + + public long getLong(Object o, long offset) { + return 0; + } +} diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java index 2070e4ecb38..cf0f0cf81df 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java @@ -109,7 +109,9 @@ public void writeString(ProtoFieldInfo field, byte[] utf8Bytes) throws IOExcepti } @Override - public void writeString(ProtoFieldInfo field, String string, int utf8Length) throws IOException { + public void writeString( + ProtoFieldInfo field, String string, int utf8Length, MarshalerContext context) + throws IOException { generator.writeFieldName(field.getJsonName()); generator.writeString(string); } diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java index 5d62712e376..3c186ee0528 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerContext.java @@ -8,10 +8,10 @@ import io.opentelemetry.api.trace.SpanId; import io.opentelemetry.api.trace.TraceId; import java.util.ArrayList; -import java.util.HashMap; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Supplier; import javax.annotation.Nullable; @@ -23,7 +23,8 @@ * for objects that can be reused between marshalling attempts. */ public final class MarshalerContext { - public static final boolean MARSHAL_STRING_NO_ALLOCATION = true; + private final boolean marshalStringNoAllocation; + private final boolean marshalStringUnsafe; private int[] sizes = new int[16]; private int sizeReadIndex; @@ -32,8 +33,22 @@ public final class MarshalerContext { private int dataReadIndex; private int dataWriteIndex; + @SuppressWarnings("BooleanParameter") + public MarshalerContext() { + this(true, true); + } + + public MarshalerContext(boolean marshalStringNoAllocation, boolean marshalStringUnsafe) { + this.marshalStringNoAllocation = marshalStringNoAllocation; + this.marshalStringUnsafe = marshalStringUnsafe; + } + public boolean marshalStringNoAllocation() { - return MARSHAL_STRING_NO_ALLOCATION; + return marshalStringNoAllocation; + } + + public boolean marshalStringUnsafe() { + return marshalStringUnsafe; } public void addSize(int size) { @@ -187,15 +202,30 @@ public void reset() { listPool.reset(); } - private final Map instanceMap = new HashMap<>(); + private static final AtomicInteger KEY_INDEX = new AtomicInteger(); + + public static class Key { + final int index = KEY_INDEX.getAndIncrement(); + } + + public static Key key() { + return new Key(); + } + + private Object[] instances = new Object[16]; - /** Returns cached instance produced by the given supplier. */ @SuppressWarnings("unchecked") - public T getInstance(Object key, Supplier supplier) { - T result = (T) instanceMap.get(key); + public T getInstance(Key key, Supplier supplier) { + if (key.index >= instances.length) { + Object[] newData = new Object[instances.length * 2]; + System.arraycopy(instances, 0, newData, 0, instances.length); + instances = newData; + } + + T result = (T) instances[key.index]; if (result == null) { result = supplier.get(); - instanceMap.put(key, result); + instances[key.index] = result; } return result; } diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java index 23893c0241a..a140190ec8c 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java @@ -37,7 +37,8 @@ public final class MarshalerUtil { CodedOutputStream.computeLengthDelimitedFieldSize(TraceId.getLength() / 2); private static final int SPAN_ID_VALUE_SIZE = CodedOutputStream.computeLengthDelimitedFieldSize(SpanId.getLength() / 2); - private static final Object ATTRIBUTES_SIZE_CALCULATOR_KEY = new Object(); + private static final MarshalerContext.Key GROUPER_KEY = MarshalerContext.key(); + private static final MarshalerContext.Key ATTRIBUTES_SIZE_CALCULATOR_KEY = MarshalerContext.key(); private static final boolean JSON_AVAILABLE; @@ -83,7 +84,7 @@ public static Map>> groupByR MarshalerContext context) { Map>> result = context.getIdentityMap(); - Grouper grouper = context.getInstance(Grouper.class, Grouper::new); + Grouper grouper = context.getInstance(GROUPER_KEY, Grouper::new); grouper.initialize(result, getResource, getInstrumentationScope, context); dataList.forEach(grouper); @@ -270,12 +271,17 @@ public static int sizeRepeatedMessage( } /** Returns the size of a repeated message field. */ + @SuppressWarnings("unchecked") public static int sizeRepeatedMessage( ProtoFieldInfo field, Collection messages, StatelessMarshaler marshaler, MarshalerContext context, - Object key) { + MarshalerContext.Key key) { + if (messages instanceof List) { + return sizeRepeatedMessage(field, (List) messages, marshaler, context); + } + if (messages.isEmpty()) { return 0; } @@ -294,7 +300,7 @@ public static int sizeRepeatedMessage( Map messages, StatelessMarshaler2 marshaler, MarshalerContext context, - Object key) { + MarshalerContext.Key key) { if (messages.isEmpty()) { return 0; } @@ -537,11 +543,11 @@ public static int sizeString( return sizeBytes(field, 0); } if (context.marshalStringNoAllocation()) { - int utf8Size = MarshalerUtil.getUtf8Size(value); + int utf8Size = getUtf8Size(value, context); context.addSize(utf8Size); return sizeBytes(field, utf8Size); } else { - byte[] valueUtf8 = MarshalerUtil.toBytes(value); + byte[] valueUtf8 = toBytes(value); context.addData(valueUtf8); return sizeBytes(field, valueUtf8.length); } @@ -556,72 +562,179 @@ public static byte[] toBytes(@Nullable String value) { } /** Returns the size of utf8 encoded string in bytes. */ + private static int getUtf8Size(String string, MarshalerContext context) { + return getUtf8Size(string, context.marshalStringUnsafe()); + } + // Visible for testing - static int getUtf8Size(String string) { - int size = 0; - for (int i = 0; i < string.length(); i++) { + static int getUtf8Size(String string, boolean useUnsafe) { + if (useUnsafe && UnsafeString.isAvailable() && UnsafeString.isLatin1(string)) { + byte[] bytes = UnsafeString.getBytes(string); + // latin1 bytes with negative value (most significant bit set) are encoded as 2 bytes in utf8 + return string.length() + countNegative(bytes); + } + + return encodedUtf8Length(string); + } + + private static int countNegative(byte[] bytes) { + int count = 0; + int offset = 0; + // We are processing one long (8 bytes) at a time. In the inner loop we are keeping counts in a + // long where each byte in the long is a separate counter. Due to this the inner loop can + // process a maximum of 8*255 bytes at a time without overflow. + for (int i = 1; i <= bytes.length / (8 * 255) + 1; i++) { + long tmp = 0; // each byte in this long is a separate counter + int limit = Math.min(i * 8 * 255, bytes.length & ~7); + for (; offset < limit; offset += 8) { + long value = UnsafeString.getLong(bytes, offset); + // Mask the value keeping only the most significant bit in each byte and then shift this bit + // to the position of the least significant bit in each byte. If the input byte was not + // negative then after this transformation it will be zero, if it was negative then it will + // be one. + tmp += (value & 0x8080808080808080L) >>> 7; + } + // sum up counts + for (int j = 0; j < 8; j++) { + count += (int) (tmp & 0xff); + tmp = tmp >>> 8; + } + } + + // handle remaining bytes + for (int i = offset; i < bytes.length; i++) { + // same as if (bytes[i] < 0) count++; + count += bytes[i] >>> 31; + } + return count; + } + + // adapted from + // https://github.com/protocolbuffers/protobuf/blob/b618f6750aed641a23d5f26fbbaf654668846d24/java/core/src/main/java/com/google/protobuf/Utf8.java#L217 + private static int encodedUtf8Length(String string) { + // Warning to maintainers: this implementation is highly optimized. + int utf16Length = string.length(); + int utf8Length = utf16Length; + int i = 0; + + // This loop optimizes for pure ASCII. + while (i < utf16Length && string.charAt(i) < 0x80) { + i++; + } + + // This loop optimizes for chars less than 0x800. + for (; i < utf16Length; i++) { char c = string.charAt(i); - if (c < 0x80) { - // 1 byte, 7 bits - size += 1; - } else if (c < 0x800) { - // 2 bytes, 11 bits - size += 2; - } else if (!Character.isSurrogate(c)) { - // 3 bytes, 16 bits - size += 3; + if (c < 0x800) { + utf8Length += ((0x7f - c) >>> 31); // branch free! } else { - // 4 bytes, 21 bits - if (Character.isHighSurrogate(c) && i + 1 < string.length()) { - char d = string.charAt(i + 1); - if (Character.isLowSurrogate(d)) { - i += 1; - size += 4; - continue; + utf8Length += encodedUtf8LengthGeneral(string, i); + break; + } + } + + if (utf8Length < utf16Length) { + // Necessary and sufficient condition for overflow because of maximum 3x expansion + throw new IllegalArgumentException( + "UTF-8 length does not fit in int: " + (utf8Length + (1L << 32))); + } + + return utf8Length; + } + + // adapted from + // https://github.com/protocolbuffers/protobuf/blob/b618f6750aed641a23d5f26fbbaf654668846d24/java/core/src/main/java/com/google/protobuf/Utf8.java#L247 + private static int encodedUtf8LengthGeneral(String string, int start) { + int utf16Length = string.length(); + int utf8Length = 0; + for (int i = start; i < utf16Length; i++) { + char c = string.charAt(i); + if (c < 0x800) { + utf8Length += (0x7f - c) >>> 31; // branch free! + } else { + utf8Length += 2; + if (Character.isSurrogate(c)) { + // Check that we have a well-formed surrogate pair. + if (Character.codePointAt(string, i) != c) { + i++; + } else { + // invalid sequence + // At this point we have accumulated 3 byes of length (2 in this method and 1 in caller) + // for current character, reduce the length to 1 bytes as we are going to encode the + // invalid character as ? + utf8Length -= 2; } } - // invalid characters are replaced with ? - size += 1; } } - return size; + return utf8Length; } /** Write utf8 encoded string to output stream. */ - public static void writeUtf8(CodedOutputStream output, String string) throws IOException { - for (int i = 0; i < string.length(); i++) { - char c = string.charAt(i); + static void writeUtf8( + CodedOutputStream output, String string, int utf8Length, MarshalerContext context) + throws IOException { + writeUtf8(output, string, utf8Length, context.marshalStringUnsafe()); + } + + // Visible for testing + static void writeUtf8(CodedOutputStream output, String string, int utf8Length, boolean useUnsafe) + throws IOException { + // if the length of the latin1 string and the utf8 output are the same then the string must be + // composed of only 7bit characters and can be directly copied to the output + if (useUnsafe + && UnsafeString.isAvailable() + && string.length() == utf8Length + && UnsafeString.isLatin1(string)) { + byte[] bytes = UnsafeString.getBytes(string); + output.write(bytes, 0, bytes.length); + } else { + encodeUtf8(output, string); + } + } + + // encode utf8 the same way as length is computed in encodedUtf8Length + // adapted from + // https://github.com/protocolbuffers/protobuf/blob/b618f6750aed641a23d5f26fbbaf654668846d24/java/core/src/main/java/com/google/protobuf/Utf8.java#L1016 + private static void encodeUtf8(CodedOutputStream output, String in) throws IOException { + int utf16Length = in.length(); + int i = 0; + // Designed to take advantage of + // https://wiki.openjdk.java.net/display/HotSpotInternals/RangeCheckElimination + for (char c; i < utf16Length && (c = in.charAt(i)) < 0x80; i++) { + output.write((byte) c); + } + if (i == utf16Length) { + return; + } + + for (char c; i < utf16Length; i++) { + c = in.charAt(i); if (c < 0x80) { // 1 byte, 7 bits output.write((byte) c); - } else if (c < 0x800) { - // 2 bytes, 11 bits - output.write((byte) (0xc0 | (c >> 6))); - output.write((byte) (0x80 | (c & 0x3f))); + } else if (c < 0x800) { // 11 bits, two UTF-8 bytes + output.write((byte) ((0xF << 6) | (c >>> 6))); + output.write((byte) (0x80 | (0x3F & c))); } else if (!Character.isSurrogate(c)) { - // 3 bytes, 16 bits - output.write((byte) (0xe0 | (c >> 12))); - output.write((byte) (0x80 | ((c >> 6) & 0x3f))); - output.write((byte) (0x80 | (c & 0x3f))); + // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes + output.write((byte) ((0xF << 5) | (c >>> 12))); + output.write((byte) (0x80 | (0x3F & (c >>> 6)))); + output.write((byte) (0x80 | (0x3F & c))); } else { - // 4 bytes, 21 bits - int codePoint = -1; - if (Character.isHighSurrogate(c) && i + 1 < string.length()) { - char d = string.charAt(i + 1); - if (Character.isLowSurrogate(d)) { - codePoint = Character.toCodePoint(c, d); - } - } - // invalid character - if (codePoint == -1) { - output.write((byte) '?'); - } else { - output.write((byte) (0xf0 | (codePoint >> 18))); - output.write((byte) (0x80 | ((codePoint >> 12) & 0x3f))); - output.write((byte) (0x80 | ((codePoint >> 6) & 0x3f))); - output.write((byte) (0x80 | (codePoint & 0x3f))); + // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, + // four UTF-8 bytes + int codePoint = Character.codePointAt(in, i); + if (codePoint != c) { + output.write((byte) ((0xF << 4) | (codePoint >>> 18))); + output.write((byte) (0x80 | (0x3F & (codePoint >>> 12)))); + output.write((byte) (0x80 | (0x3F & (codePoint >>> 6)))); + output.write((byte) (0x80 | (0x3F & codePoint))); i++; + } else { + // invalid sequence + output.write((byte) '?'); } } } diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java index da84e98b05b..515392af85d 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java @@ -147,11 +147,13 @@ public void writeString(ProtoFieldInfo field, byte[] utf8Bytes) throws IOExcepti } @Override - public void writeString(ProtoFieldInfo field, String string, int utf8Length) throws IOException { + public void writeString( + ProtoFieldInfo field, String string, int utf8Length, MarshalerContext context) + throws IOException { output.writeUInt32NoTag(field.getTag()); output.writeUInt32NoTag(utf8Length); - MarshalerUtil.writeUtf8(output, string); + MarshalerUtil.writeUtf8(output, string, utf8Length, context); } @Override diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java index 7dc879ac0b5..0385c3df742 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java @@ -29,7 +29,7 @@ * at any time. */ public abstract class Serializer implements AutoCloseable { - private static final Object ATTRIBUTES_WRITER_KEY = new Object(); + private static final MarshalerContext.Key ATTRIBUTES_WRITER_KEY = MarshalerContext.key(); Serializer() {} @@ -212,21 +212,13 @@ public void serializeString(ProtoFieldInfo field, byte[] utf8Bytes) throws IOExc * Serializes a protobuf {@code string} field. {@code string} is the value to be serialized and * {@code utf8Length} is the length of the string after it is encoded in UTF8. */ - public void serializeString(ProtoFieldInfo field, String string, int utf8Length) - throws IOException { - if (string.isEmpty()) { - return; - } - writeString(field, string, utf8Length); - } - public void serializeString( ProtoFieldInfo field, @Nullable String string, MarshalerContext context) throws IOException { if (string == null || string.isEmpty()) { return; } if (context.marshalStringNoAllocation()) { - writeString(field, string, context.getSize()); + writeString(field, string, context.getSize(), context); } else { byte[] valueUtf8 = context.getData(byte[].class); writeString(field, valueUtf8); @@ -236,7 +228,8 @@ public void serializeString( /** Writes a protobuf {@code string} field, even if it matches the default value. */ public abstract void writeString(ProtoFieldInfo field, byte[] utf8Bytes) throws IOException; - public abstract void writeString(ProtoFieldInfo field, String string, int utf8Length) + public abstract void writeString( + ProtoFieldInfo field, String string, int utf8Length, MarshalerContext context) throws IOException; /** Serializes a protobuf {@code bytes} field. */ @@ -392,13 +385,19 @@ public abstract void serializeRepeatedMessage( MarshalerContext context) throws IOException; + @SuppressWarnings("unchecked") public void serializeRepeatedMessage( ProtoFieldInfo field, Collection messages, StatelessMarshaler marshaler, MarshalerContext context, - Object key) + MarshalerContext.Key key) throws IOException { + if (messages instanceof List) { + serializeRepeatedMessage(field, (List) messages, marshaler, context); + return; + } + writeStartRepeated(field); if (!messages.isEmpty()) { @@ -415,7 +414,7 @@ public void serializeRepeatedMessage( Map messages, StatelessMarshaler2 marshaler, MarshalerContext context, - Object key) + MarshalerContext.Key key) throws IOException { writeStartRepeated(field); diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/UnsafeAccess.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/UnsafeAccess.java new file mode 100644 index 00000000000..47100bce0af --- /dev/null +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/UnsafeAccess.java @@ -0,0 +1,69 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.marshal; + +import java.lang.reflect.Field; +import sun.misc.Unsafe; + +class UnsafeAccess { + private static final boolean available = checkUnsafe(); + + static boolean isAvailable() { + return available; + } + + private static boolean checkUnsafe() { + try { + Class.forName("sun.misc.Unsafe", false, UnsafeAccess.class.getClassLoader()); + return UnsafeHolder.UNSAFE != null; + } catch (ClassNotFoundException e) { + return false; + } + } + + static long objectFieldOffset(Field field) { + return UnsafeHolder.UNSAFE.objectFieldOffset(field); + } + + static Object getObject(Object object, long offset) { + return UnsafeHolder.UNSAFE.getObject(object, offset); + } + + static byte getByte(Object object, long offset) { + return UnsafeHolder.UNSAFE.getByte(object, offset); + } + + static int arrayBaseOffset(Class arrayClass) { + return UnsafeHolder.UNSAFE.arrayBaseOffset(arrayClass); + } + + static long getLong(Object o, long offset) { + return UnsafeHolder.UNSAFE.getLong(o, offset); + } + + private UnsafeAccess() {} + + private static class UnsafeHolder { + public static final Unsafe UNSAFE; + + static { + UNSAFE = getUnsafe(); + } + + private UnsafeHolder() {} + + @SuppressWarnings("NullAway") + private static Unsafe getUnsafe() { + try { + Field field = Unsafe.class.getDeclaredField("theUnsafe"); + field.setAccessible(true); + return (Unsafe) field.get(null); + } catch (Exception ignored) { + return null; + } + } + } +} diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/UnsafeString.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/UnsafeString.java new file mode 100644 index 00000000000..c581e7525fb --- /dev/null +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/UnsafeString.java @@ -0,0 +1,50 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.marshal; + +import java.lang.reflect.Field; + +class UnsafeString { + private static final long valueOffset = getStringFieldOffset("value", byte[].class); + private static final long coderOffset = getStringFieldOffset("coder", byte.class); + private static final int byteArrayBaseOffset = UnsafeAccess.arrayBaseOffset(byte[].class); + private static final boolean available = valueOffset != -1 && coderOffset != -1; + + static boolean isAvailable() { + return available; + } + + static boolean isLatin1(String string) { + // 0 represents latin1, 1 utf16 + return UnsafeAccess.getByte(string, coderOffset) == 0; + } + + static byte[] getBytes(String string) { + return (byte[]) UnsafeAccess.getObject(string, valueOffset); + } + + static long getLong(byte[] bytes, int index) { + return UnsafeAccess.getLong(bytes, byteArrayBaseOffset + index); + } + + private static long getStringFieldOffset(String fieldName, Class expectedType) { + if (!UnsafeAccess.isAvailable()) { + return -1; + } + + try { + Field field = String.class.getDeclaredField(fieldName); + if (field.getType() != expectedType) { + return -1; + } + return UnsafeAccess.objectFieldOffset(field); + } catch (Exception exception) { + return -1; + } + } + + private UnsafeString() {} +} diff --git a/exporters/common/src/test/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtilTest.java b/exporters/common/src/test/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtilTest.java index 5e7c37f03f9..a769c790aef 100644 --- a/exporters/common/src/test/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtilTest.java +++ b/exporters/common/src/test/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtilTest.java @@ -11,37 +11,57 @@ import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; -import org.junit.jupiter.api.Test; +import java.util.Random; +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; class MarshalerUtilTest { - @Test + @ParameterizedTest + @ValueSource(strings = {"true", "false"}) @SuppressWarnings("AvoidEscapedUnicodeCharacters") - void encodeUtf8() { - assertThat(getUtf8Size("")).isEqualTo(0); - assertThat(testUtf8("")).isEqualTo(""); + void encodeUtf8(boolean useUnsafe) { + assertThat(getUtf8Size("", useUnsafe)).isEqualTo(0); + assertThat(testUtf8("", 0, useUnsafe)).isEqualTo(""); - assertThat(getUtf8Size("a")).isEqualTo(1); - assertThat(testUtf8("a")).isEqualTo("a"); + assertThat(getUtf8Size("a", useUnsafe)).isEqualTo(1); + assertThat(testUtf8("a", 1, useUnsafe)).isEqualTo("a"); - assertThat(getUtf8Size("©")).isEqualTo(2); - assertThat(testUtf8("©")).isEqualTo("©"); + assertThat(getUtf8Size("©", useUnsafe)).isEqualTo(2); + assertThat(testUtf8("©", 2, useUnsafe)).isEqualTo("©"); - assertThat(getUtf8Size("∆")).isEqualTo(3); - assertThat(testUtf8("∆")).isEqualTo("∆"); + assertThat(getUtf8Size("∆", useUnsafe)).isEqualTo(3); + assertThat(testUtf8("∆", 3, useUnsafe)).isEqualTo("∆"); - assertThat(getUtf8Size("😀")).isEqualTo(4); - assertThat(testUtf8("😀")).isEqualTo("😀"); + assertThat(getUtf8Size("😀", useUnsafe)).isEqualTo(4); + assertThat(testUtf8("😀", 4, useUnsafe)).isEqualTo("😀"); // test that invalid characters are replaced with ? - assertThat(getUtf8Size("\uD83D😀\uDE00")).isEqualTo(6); - assertThat(testUtf8("\uD83D😀\uDE00")).isEqualTo("?😀?"); + assertThat(getUtf8Size("\uD83D😀\uDE00", useUnsafe)).isEqualTo(6); + assertThat(testUtf8("\uD83D😀\uDE00", 6, useUnsafe)).isEqualTo("?😀?"); + + // the same invalid sequence as encoded by the jdk + byte[] bytes = "\uD83D😀\uDE00".getBytes(StandardCharsets.UTF_8); + assertThat(bytes.length).isEqualTo(6); + assertThat(new String(bytes, StandardCharsets.UTF_8)).isEqualTo("?😀?"); + } + + @RepeatedTest(1000) + void testUtf8SizeLatin1() { + Random random = new Random(); + byte[] bytes = new byte[15001]; + random.nextBytes(bytes); + String string = new String(bytes, StandardCharsets.ISO_8859_1); + int utf8Size = string.getBytes(StandardCharsets.UTF_8).length; + assertThat(getUtf8Size(string, false)).isEqualTo(utf8Size); + assertThat(getUtf8Size(string, true)).isEqualTo(utf8Size); } - private static String testUtf8(String string) { + private static String testUtf8(String string, int utf8Length, boolean useUnsafe) { try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(outputStream); - writeUtf8(codedOutputStream, string); + writeUtf8(codedOutputStream, string, utf8Length, useUnsafe); codedOutputStream.flush(); return new String(outputStream.toByteArray(), StandardCharsets.UTF_8); } catch (Exception exception) { diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/MetricsRequestMarshalerBenchmark.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/MetricsRequestMarshalerBenchmark.java index b00806c3be3..03bab984d0f 100644 --- a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/MetricsRequestMarshalerBenchmark.java +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/MetricsRequestMarshalerBenchmark.java @@ -120,40 +120,40 @@ public class MetricsRequestMarshalerBenchmark { } @Benchmark - public TestOutputStream marshaler() throws IOException { + public int marshaler() throws IOException { MetricsRequestMarshaler marshaler = MetricsRequestMarshaler.create(METRICS); OUTPUT.reset(); marshaler.writeBinaryTo(OUTPUT); - return OUTPUT; + return OUTPUT.getCount(); } @Benchmark - public TestOutputStream marshalerJson() throws IOException { + public int marshalerJson() throws IOException { MetricsRequestMarshaler marshaler = MetricsRequestMarshaler.create(METRICS); OUTPUT.reset(); marshaler.writeJsonTo(OUTPUT); - return OUTPUT; + return OUTPUT.getCount(); } @Benchmark - public TestOutputStream marshalerLowAllocation() throws IOException { + public int marshalerLowAllocation() throws IOException { MARSHALER.initialize(METRICS); try { OUTPUT.reset(); MARSHALER.writeBinaryTo(OUTPUT); - return OUTPUT; + return OUTPUT.getCount(); } finally { MARSHALER.reset(); } } @Benchmark - public TestOutputStream marshalerJsonLowAllocation() throws IOException { + public int marshalerJsonLowAllocation() throws IOException { MARSHALER.initialize(METRICS); try { OUTPUT.reset(); MARSHALER.writeJsonTo(OUTPUT); - return OUTPUT; + return OUTPUT.getCount(); } finally { MARSHALER.reset(); } diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java index d68894deb63..7080c530246 100644 --- a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/RequestMarshalBenchmarks.java @@ -38,20 +38,20 @@ public int createCustomMarshal(RequestMarshalState state) { @Benchmark @Threads(1) - public TestOutputStream marshalCustom(RequestMarshalState state) throws IOException { + public int marshalCustom(RequestMarshalState state) throws IOException { TraceRequestMarshaler requestMarshaler = TraceRequestMarshaler.create(state.spanDataList); OUTPUT.reset(requestMarshaler.getBinarySerializedSize()); requestMarshaler.writeBinaryTo(OUTPUT); - return OUTPUT; + return OUTPUT.getCount(); } @Benchmark @Threads(1) - public TestOutputStream marshalJson(RequestMarshalState state) throws IOException { + public int marshalJson(RequestMarshalState state) throws IOException { TraceRequestMarshaler requestMarshaler = TraceRequestMarshaler.create(state.spanDataList); OUTPUT.reset(); requestMarshaler.writeJsonTo(OUTPUT); - return OUTPUT; + return OUTPUT.getCount(); } @Benchmark @@ -68,13 +68,13 @@ public int createCustomMarshalLowAllocation(RequestMarshalState state) { @Benchmark @Threads(1) - public TestOutputStream marshalCustomLowAllocation(RequestMarshalState state) throws IOException { + public int marshalCustomLowAllocation(RequestMarshalState state) throws IOException { LowAllocationTraceRequestMarshaler requestMarshaler = MARSHALER; requestMarshaler.initialize(state.spanDataList); try { OUTPUT.reset(); requestMarshaler.writeBinaryTo(OUTPUT); - return OUTPUT; + return OUTPUT.getCount(); } finally { requestMarshaler.reset(); } @@ -82,13 +82,13 @@ public TestOutputStream marshalCustomLowAllocation(RequestMarshalState state) th @Benchmark @Threads(1) - public TestOutputStream marshalJsonLowAllocation(RequestMarshalState state) throws IOException { + public int marshalJsonLowAllocation(RequestMarshalState state) throws IOException { LowAllocationTraceRequestMarshaler requestMarshaler = MARSHALER; requestMarshaler.initialize(state.spanDataList); try { OUTPUT.reset(); requestMarshaler.writeJsonTo(OUTPUT); - return OUTPUT; + return OUTPUT.getCount(); } finally { requestMarshaler.reset(); } diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/StringMarshalBenchmark.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/StringMarshalBenchmark.java new file mode 100644 index 00000000000..f375a200185 --- /dev/null +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/StringMarshalBenchmark.java @@ -0,0 +1,121 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp; + +import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.exporter.internal.marshal.MarshalerContext; +import io.opentelemetry.exporter.internal.marshal.Serializer; +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +@BenchmarkMode({Mode.AverageTime}) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 10, time = 1) +@Fork(1) +public class StringMarshalBenchmark { + private static final TestMarshaler MARSHALER = new TestMarshaler(); + private static final TestOutputStream OUTPUT = new TestOutputStream(); + + @Benchmark + @Threads(1) + public int marshalAsciiString(StringMarshalState state) throws IOException { + OUTPUT.reset(); + Marshaler marshaler = StringAnyValueMarshaler.create(state.asciiString); + marshaler.writeBinaryTo(OUTPUT); + return OUTPUT.getCount(); + } + + @Benchmark + @Threads(1) + public int marshalLatin1String(StringMarshalState state) throws IOException { + OUTPUT.reset(); + Marshaler marshaler = StringAnyValueMarshaler.create(state.latin1String); + marshaler.writeBinaryTo(OUTPUT); + return OUTPUT.getCount(); + } + + @Benchmark + @Threads(1) + public int marshalUnicodeString(StringMarshalState state) throws IOException { + OUTPUT.reset(); + Marshaler marshaler = StringAnyValueMarshaler.create(state.unicodeString); + marshaler.writeBinaryTo(OUTPUT); + return OUTPUT.getCount(); + } + + @Benchmark + @Threads(1) + public int marshalAsciiStringLowAllocation(StringMarshalState state) throws IOException { + OUTPUT.reset(); + try { + MARSHALER.initialize(state.asciiString); + MARSHALER.writeBinaryTo(OUTPUT); + return OUTPUT.getCount(); + } finally { + MARSHALER.reset(); + } + } + + @Benchmark + @Threads(1) + public int marshalLatin1StringLowAllocation(StringMarshalState state) throws IOException { + OUTPUT.reset(); + try { + MARSHALER.initialize(state.latin1String); + MARSHALER.writeBinaryTo(OUTPUT); + return OUTPUT.getCount(); + } finally { + MARSHALER.reset(); + } + } + + @Benchmark + @Threads(1) + public int marshalUnicodeStringLowAllocation(StringMarshalState state) throws IOException { + OUTPUT.reset(); + try { + MARSHALER.initialize(state.unicodeString); + MARSHALER.writeBinaryTo(OUTPUT); + return OUTPUT.getCount(); + } finally { + MARSHALER.reset(); + } + } + + private static class TestMarshaler extends Marshaler { + private final MarshalerContext context = new MarshalerContext(); + private int size; + private String value; + + public void initialize(String string) { + value = string; + size = StringAnyValueStatelessMarshaler.INSTANCE.getBinarySerializedSize(string, context); + } + + public void reset() { + context.reset(); + } + + @Override + public int getBinarySerializedSize() { + return size; + } + + @Override + public void writeTo(Serializer output) throws IOException { + StringAnyValueStatelessMarshaler.INSTANCE.writeTo(output, value, context); + } + } +} diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/StringMarshalState.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/StringMarshalState.java new file mode 100644 index 00000000000..684b6c65080 --- /dev/null +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/StringMarshalState.java @@ -0,0 +1,37 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp; + +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +@State(Scope.Benchmark) +public class StringMarshalState { + + @Param({"16", "512"}) + int stringSize; + + String asciiString; + String latin1String; + String unicodeString; + + @Setup + public void setup() { + asciiString = makeString('a', stringSize); + latin1String = makeString('ä', stringSize); + unicodeString = makeString('∆', stringSize); + } + + private static String makeString(char c, int size) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < size; i++) { + sb.append(c); + } + return sb.toString(); + } +} diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/TestOutputStream.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/TestOutputStream.java index 3ff1ca6472c..cfaba56ec3e 100644 --- a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/TestOutputStream.java +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/TestOutputStream.java @@ -35,4 +35,8 @@ void reset(int size) { void reset() { reset(-1); } + + int getCount() { + return count; + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramStatelessMarshaler.java index 3340c55b67c..3c43109d15a 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ExponentialHistogramStatelessMarshaler.java @@ -17,8 +17,8 @@ final class ExponentialHistogramStatelessMarshaler implements StatelessMarshaler { static final ExponentialHistogramStatelessMarshaler INSTANCE = new ExponentialHistogramStatelessMarshaler(); - private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); - private static final Object DATA_POINT_WRITER_KEY = new Object(); + private static final MarshalerContext.Key DATA_POINT_SIZE_CALCULATOR_KEY = MarshalerContext.key(); + private static final MarshalerContext.Key DATA_POINT_WRITER_KEY = MarshalerContext.key(); @Override public void writeTo( diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeStatelessMarshaler.java index e17d370f04e..2287deec2ad 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/GaugeStatelessMarshaler.java @@ -16,8 +16,8 @@ final class GaugeStatelessMarshaler implements StatelessMarshaler> { static final GaugeStatelessMarshaler INSTANCE = new GaugeStatelessMarshaler(); - private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); - private static final Object DATA_POINT_WRITER_KEY = new Object(); + private static final MarshalerContext.Key DATA_POINT_SIZE_CALCULATOR_KEY = MarshalerContext.key(); + private static final MarshalerContext.Key DATA_POINT_WRITER_KEY = MarshalerContext.key(); @Override public void writeTo( diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramStatelessMarshaler.java index a45404e0ab0..2d91cd65c23 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/HistogramStatelessMarshaler.java @@ -15,8 +15,8 @@ final class HistogramStatelessMarshaler implements StatelessMarshaler { static final HistogramStatelessMarshaler INSTANCE = new HistogramStatelessMarshaler(); - private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); - private static final Object DATA_POINT_WRITER_KEY = new Object(); + private static final MarshalerContext.Key DATA_POINT_SIZE_CALCULATOR_KEY = MarshalerContext.key(); + private static final MarshalerContext.Key DATA_POINT_WRITER_KEY = MarshalerContext.key(); @Override public void writeTo(Serializer output, HistogramData histogram, MarshalerContext context) diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshaler.java index 03d3abb4e02..df9c993a33a 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/LowAllocationMetricsRequestMarshaler.java @@ -26,8 +26,9 @@ * at any time. */ public final class LowAllocationMetricsRequestMarshaler extends Marshaler { - private static final Object RESOURCE_METRIC_SIZE_CALCULATOR_KEY = new Object(); - private static final Object RESOURCE_METRIC_WRITER_KEY = new Object(); + private static final MarshalerContext.Key RESOURCE_METRIC_SIZE_CALCULATOR_KEY = + MarshalerContext.key(); + private static final MarshalerContext.Key RESOURCE_METRIC_WRITER_KEY = MarshalerContext.key(); private final MarshalerContext context = new MarshalerContext(); diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricStatelessMarshaler.java index 538abdb70e8..4e502dee570 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricStatelessMarshaler.java @@ -22,12 +22,13 @@ import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.data.MetricDataType; import java.io.IOException; -import java.util.HashMap; +import java.util.EnumMap; import java.util.Map; final class MetricStatelessMarshaler implements StatelessMarshaler { static final MetricStatelessMarshaler INSTANCE = new MetricStatelessMarshaler(); - private static final Map DATA_HANDLERS = new HashMap<>(); + private static final Map DATA_HANDLERS = + new EnumMap<>(MetricDataType.class); static { DATA_HANDLERS.put( diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsStatelessMarshaler.java index 56d893cff74..69fe2d55276 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/ResourceMetricsStatelessMarshaler.java @@ -27,8 +27,8 @@ public final class ResourceMetricsStatelessMarshaler implements StatelessMarshaler2>> { static final ResourceMetricsStatelessMarshaler INSTANCE = new ResourceMetricsStatelessMarshaler(); - private static final Object SCOPE_SPAN_WRITER_KEY = new Object(); - private static final Object SCOPE_SPAN_SIZE_CALCULATOR_KEY = new Object(); + private static final MarshalerContext.Key SCOPE_SPAN_WRITER_KEY = MarshalerContext.key(); + private static final MarshalerContext.Key SCOPE_SPAN_SIZE_CALCULATOR_KEY = MarshalerContext.key(); @Override public void writeTo( diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumStatelessMarshaler.java index c007eddacae..98c142e0258 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SumStatelessMarshaler.java @@ -16,8 +16,8 @@ final class SumStatelessMarshaler implements StatelessMarshaler> { static final SumStatelessMarshaler INSTANCE = new SumStatelessMarshaler(); - private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); - private static final Object DATA_POINT_WRITER_KEY = new Object(); + private static final MarshalerContext.Key DATA_POINT_SIZE_CALCULATOR_KEY = MarshalerContext.key(); + private static final MarshalerContext.Key DATA_POINT_WRITER_KEY = MarshalerContext.key(); @Override public void writeTo(Serializer output, SumData sum, MarshalerContext context) diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryStatelessMarshaler.java index 9f1fea984a5..f50afd91ec4 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/SummaryStatelessMarshaler.java @@ -15,8 +15,8 @@ final class SummaryStatelessMarshaler implements StatelessMarshaler { static final SummaryStatelessMarshaler INSTANCE = new SummaryStatelessMarshaler(); - private static final Object DATA_POINT_SIZE_CALCULATOR_KEY = new Object(); - private static final Object DATA_POINT_WRITER_KEY = new Object(); + private static final MarshalerContext.Key DATA_POINT_SIZE_CALCULATOR_KEY = MarshalerContext.key(); + private static final MarshalerContext.Key DATA_POINT_WRITER_KEY = MarshalerContext.key(); @Override public void writeTo(Serializer output, SummaryData summary, MarshalerContext context) diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java index 6211d7f00f0..8513fe1d3cb 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/LowAllocationTraceRequestMarshaler.java @@ -27,8 +27,9 @@ */ @SuppressWarnings({"UnusedNestedClass", "UnusedVariable", "CheckedExceptionNotThrown"}) public final class LowAllocationTraceRequestMarshaler extends Marshaler { - private static final Object RESOURCE_SPAN_SIZE_CALCULATOR_KEY = new Object(); - private static final Object RESOURCE_SPAN_WRITER_KEY = new Object(); + private static final MarshalerContext.Key RESOURCE_SPAN_SIZE_CALCULATOR_KEY = + MarshalerContext.key(); + private static final MarshalerContext.Key RESOURCE_SPAN_WRITER_KEY = MarshalerContext.key(); private final MarshalerContext context = new MarshalerContext(); diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansStatelessMarshaler.java index 66fcee4594f..82baea20146 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansStatelessMarshaler.java @@ -27,8 +27,8 @@ public final class ResourceSpansStatelessMarshaler implements StatelessMarshaler2>> { static final ResourceSpansStatelessMarshaler INSTANCE = new ResourceSpansStatelessMarshaler(); - private static final Object SCOPE_SPAN_WRITER_KEY = new Object(); - private static final Object SCOPE_SPAN_SIZE_CALCULATOR_KEY = new Object(); + private static final MarshalerContext.Key SCOPE_SPAN_WRITER_KEY = MarshalerContext.key(); + private static final MarshalerContext.Key SCOPE_SPAN_SIZE_CALCULATOR_KEY = MarshalerContext.key(); @Override public void writeTo( diff --git a/settings.gradle.kts b/settings.gradle.kts index e6fbf76cc34..e19fa2beb67 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -32,6 +32,7 @@ include(":dependencyManagement") include(":extensions:kotlin") include(":extensions:trace-propagators") include(":exporters:common") +include(":exporters:common:compile-stub") include(":exporters:sender:grpc-managed-channel") include(":exporters:sender:jdk") include(":exporters:sender:okhttp") From d539ac2f0898f11b6005cac22f319e989e3e06ce Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 25 Apr 2024 15:30:57 +0300 Subject: [PATCH 13/15] update trace flags marshaling --- .../otlp/traces/SpanLinkStatelessMarshaler.java | 11 ++++++++--- .../internal/otlp/traces/SpanStatelessMarshaler.java | 10 ++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkStatelessMarshaler.java index 9726bf48531..d2b73e041d9 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkStatelessMarshaler.java @@ -32,7 +32,10 @@ public void writeTo(Serializer output, LinkData link, MarshalerContext context) Span.Link.ATTRIBUTES, link.getAttributes(), KeyValueStatelessMarshaler.INSTANCE, context); int droppedAttributesCount = link.getTotalAttributeCount() - link.getAttributes().size(); output.serializeUInt32(Span.Link.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); - output.serializeByteAsFixed32(Span.Link.FLAGS, link.getSpanContext().getTraceFlags().asByte()); + output.serializeFixed32( + Span.Link.FLAGS, + SpanFlags.withParentIsRemoteFlags( + link.getSpanContext().getTraceFlags(), link.getSpanContext().isRemote())); } @Override @@ -57,8 +60,10 @@ public int getBinarySerializedSize(LinkData link, MarshalerContext context) { int droppedAttributesCount = link.getTotalAttributeCount() - link.getAttributes().size(); size += MarshalerUtil.sizeUInt32(Span.Link.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount); size += - MarshalerUtil.sizeByteAsFixed32( - Span.Link.FLAGS, link.getSpanContext().getTraceFlags().asByte()); + MarshalerUtil.sizeFixed32( + Span.Link.FLAGS, + SpanFlags.withParentIsRemoteFlags( + link.getSpanContext().getTraceFlags(), link.getSpanContext().isRemote())); return size; } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatelessMarshaler.java index 02615032813..16858c2cbd8 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanStatelessMarshaler.java @@ -59,7 +59,10 @@ public void writeTo(Serializer output, SpanData span, MarshalerContext context) output.serializeMessage( Span.STATUS, span.getStatus(), SpanStatusStatelessMarshaler.INSTANCE, context); - output.serializeByteAsFixed32(Span.FLAGS, span.getSpanContext().getTraceFlags().asByte()); + output.serializeFixed32( + Span.FLAGS, + SpanFlags.withParentIsRemoteFlags( + span.getSpanContext().getTraceFlags(), span.getParentSpanContext().isRemote())); } @Override @@ -109,7 +112,10 @@ public int getBinarySerializedSize(SpanData span, MarshalerContext context) { Span.STATUS, span.getStatus(), SpanStatusStatelessMarshaler.INSTANCE, context); size += - MarshalerUtil.sizeByteAsFixed32(Span.FLAGS, span.getSpanContext().getTraceFlags().asByte()); + MarshalerUtil.sizeFixed32( + Span.FLAGS, + SpanFlags.withParentIsRemoteFlags( + span.getSpanContext().getTraceFlags(), span.getParentSpanContext().isRemote())); return size; } From ce1814a4df8efecfa5ed019a7a74c1836b37aa0b Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 25 Apr 2024 16:19:26 +0300 Subject: [PATCH 14/15] change methods back from public to pacakge private --- .../exporter/internal/marshal/CodedOutputStream.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/CodedOutputStream.java b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/CodedOutputStream.java index 5c728e6817c..8cc17a7834b 100644 --- a/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/CodedOutputStream.java +++ b/exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/CodedOutputStream.java @@ -213,7 +213,7 @@ static int computeInt32SizeNoTag(final int value) { } /** Compute the number of bytes that would be needed to encode a {@code uint32} field. */ - public static int computeUInt32SizeNoTag(final int value) { + static int computeUInt32SizeNoTag(final int value) { if ((value & (~0 << 7)) == 0) { return 1; } @@ -329,7 +329,7 @@ public static int computeByteArraySizeNoTag(final byte[] value) { return computeLengthDelimitedFieldSize(value.length); } - public static int computeLengthDelimitedFieldSize(int fieldLength) { + static int computeLengthDelimitedFieldSize(int fieldLength) { return computeUInt32SizeNoTag(fieldLength) + fieldLength; } From 8edb3d9b0018b947367819a9e00992b42057dd32 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 25 Apr 2024 16:29:31 +0300 Subject: [PATCH 15/15] remove commented out code --- .../otlp/traces/ResourceSpansMarshaler.java | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java index 313b90c4fbc..0e9d5a91e09 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ResourceSpansMarshaler.java @@ -78,26 +78,6 @@ public void writeTo(Serializer output) throws IOException { output.serializeString(ResourceSpans.SCHEMA_URL, schemaUrlUtf8); } - /* - public static void writeTo( - Serializer output, - Map> scopeMap, - MarshalerContext context) - throws IOException { - ResourceMarshaler resourceMarshaler = context.getObject(ResourceMarshaler.class); - output.serializeMessage(ResourceSpans.RESOURCE, resourceMarshaler); - - ScopeSpanListWriter scopeSpanListWriter = - context.getInstance(ScopeSpanListWriter.class, ScopeSpanListWriter::new); - scopeSpanListWriter.initialize(output, ResourceSpans.SCOPE_SPANS, context); - scopeMap.forEach(scopeSpanListWriter); - - byte[] schemaUrlUtf8 = context.getByteArray(); - output.serializeString(ResourceSpans.SCHEMA_URL, schemaUrlUtf8); - } - - */ - private static int calculateSize( ResourceMarshaler resourceMarshaler, byte[] schemaUrlUtf8, @@ -108,40 +88,9 @@ private static int calculateSize( size += MarshalerUtil.sizeRepeatedMessage( ResourceSpans.SCOPE_SPANS, instrumentationScopeSpansMarshalers); - return size; } - /* - public static int calculateSize( - MarshalerContext context, - Resource resource, - Map> scopeMap) { - - int size = 0; - int sizeIndex = context.addSize(); - - ResourceMarshaler resourceMarshaler = ResourceMarshaler.create(resource); - context.addData(resourceMarshaler); - size += MarshalerUtil.sizeMessage(ResourceSpans.RESOURCE, resourceMarshaler); - - ScopeSpanListSizeCalculator scopeSpanListSizeCalculator = - context.getInstance(ScopeSpanListSizeCalculator.class, ScopeSpanListSizeCalculator::new); - scopeSpanListSizeCalculator.initialize(ResourceSpans.SCOPE_SPANS, context); - scopeMap.forEach(scopeSpanListSizeCalculator); - size += scopeSpanListSizeCalculator.getSize(); - - byte[] schemaUrlUtf8 = MarshalerUtil.toBytes(resource.getSchemaUrl()); - context.addData(schemaUrlUtf8); - size += MarshalerUtil.sizeBytes(ResourceSpans.SCHEMA_URL, schemaUrlUtf8); - - context.setSize(sizeIndex, size); - - return size; - } - - */ - private static Map>> groupByResourceAndScope(Collection spanDataList) { return MarshalerUtil.groupByResourceAndScope(