Skip to content

Commit 8a3329b

Browse files
jsuerethjack-berg
andauthored
Fix repeated string serialization for JSON. (#6888)
Co-authored-by: Jack Berg <[email protected]>
1 parent 6487ac2 commit 8a3329b

File tree

6 files changed

+55
-7
lines changed

6 files changed

+55
-7
lines changed

exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/JsonSerializer.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,22 @@ public void writeString(
122122
generator.writeString(string);
123123
}
124124

125+
@Override
126+
public void writeRepeatedString(ProtoFieldInfo field, byte[][] utf8Bytes) throws IOException {
127+
generator.writeArrayFieldStart(field.getJsonName());
128+
for (byte[] value : utf8Bytes) {
129+
// Marshalers encoded String into UTF-8 bytes to optimize for binary serialization where
130+
// we are able to avoid the encoding process happening twice, one for size computation and one
131+
// for actual writing. JsonGenerator actually has a writeUTF8String that would be able to
132+
// accept
133+
// this, but it only works when writing to an OutputStream, but not to a String like we do for
134+
// writing to logs. It's wasteful to take a String, convert it to bytes, and convert back to
135+
// the same String but we can see if this can be improved in the future.
136+
generator.writeString(new String(value, StandardCharsets.UTF_8));
137+
}
138+
generator.writeEndArray();
139+
}
140+
125141
@Override
126142
public void writeBytes(ProtoFieldInfo field, byte[] value) throws IOException {
127143
generator.writeBinaryField(field.getJsonName(), value);

exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/MarshalerUtil.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,16 @@ private static int sizeRepeatedFixed64(ProtoFieldInfo field, int numValues) {
110110
return size;
111111
}
112112

113+
/** Returns the size of a repeated string field. */
114+
@SuppressWarnings("AvoidObjectArrays")
115+
public static int sizeRepeatedString(ProtoFieldInfo field, byte[][] utf8Bytes) {
116+
int size = 0;
117+
for (byte[] i : utf8Bytes) {
118+
size += MarshalerUtil.sizeBytes(field, i);
119+
}
120+
return size;
121+
}
122+
113123
/**
114124
* Returns the size of a repeated uint64 field.
115125
*

exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/ProtoSerializer.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,13 @@ public void writeString(
163163
StatelessMarshalerUtil.writeUtf8(output, string, utf8Length, context);
164164
}
165165

166+
@Override
167+
public void writeRepeatedString(ProtoFieldInfo field, byte[][] utf8Bytes) throws IOException {
168+
for (byte[] value : utf8Bytes) {
169+
writeString(field, value);
170+
}
171+
}
172+
166173
@Override
167174
public void writeBytes(ProtoFieldInfo field, byte[] value) throws IOException {
168175
output.writeUInt32NoTag(field.getTag());

exporters/common/src/main/java/io/opentelemetry/exporter/internal/marshal/Serializer.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,18 @@ public void serializeString(ProtoFieldInfo field, byte[] utf8Bytes) throws IOExc
220220
writeString(field, utf8Bytes);
221221
}
222222

223+
/**
224+
* Serializes a protobuf {@code repeated string} field. {@code utf8Bytes} is the UTF8 encoded
225+
* bytes of the strings to serialize.
226+
*/
227+
@SuppressWarnings("AvoidObjectArrays")
228+
public void serializeRepeatedString(ProtoFieldInfo field, byte[][] utf8Bytes) throws IOException {
229+
if (utf8Bytes.length == 0) {
230+
return;
231+
}
232+
writeRepeatedString(field, utf8Bytes);
233+
}
234+
223235
/**
224236
* Serializes a protobuf {@code string} field. {@code string} is the value to be serialized and
225237
* {@code utf8Length} is the length of the string after it is encoded in UTF8. This method reads
@@ -246,6 +258,11 @@ public abstract void writeString(
246258
ProtoFieldInfo field, String string, int utf8Length, MarshalerContext context)
247259
throws IOException;
248260

261+
/** Writes a protobuf {@code repeated string} field, even if it matches the default value. */
262+
@SuppressWarnings("AvoidObjectArrays")
263+
public abstract void writeRepeatedString(ProtoFieldInfo field, byte[][] utf8Bytes)
264+
throws IOException;
265+
249266
/** Serializes a protobuf {@code bytes} field. */
250267
public void serializeBytes(ProtoFieldInfo field, byte[] value) throws IOException {
251268
if (value.length == 0) {

exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/ProfileMarshaler.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,7 @@ protected void writeTo(Serializer output) throws IOException {
149149
output.serializeRepeatedMessage(Profile.ATTRIBUTE_TABLE, attributeMarshalers);
150150
output.serializeRepeatedMessage(Profile.ATTRIBUTE_UNITS, attributeUnitMarshalers);
151151
output.serializeRepeatedMessage(Profile.LINK_TABLE, linkMarshalers);
152-
for (byte[] i : stringTable) {
153-
output.serializeString(Profile.STRING_TABLE, i);
154-
}
152+
output.serializeRepeatedString(Profile.STRING_TABLE, stringTable);
155153
output.serializeInt64(Profile.DROP_FRAMES, dropFrames);
156154
output.serializeInt64(Profile.KEEP_FRAMES, keepFrames);
157155
output.serializeInt64(Profile.TIME_NANOS, timeNanos);
@@ -192,9 +190,7 @@ private static int calculateSize(
192190
size += MarshalerUtil.sizeRepeatedMessage(Profile.ATTRIBUTE_TABLE, attributeMarshalers);
193191
size += MarshalerUtil.sizeRepeatedMessage(Profile.ATTRIBUTE_UNITS, attributeUnitMarshalers);
194192
size += MarshalerUtil.sizeRepeatedMessage(Profile.LINK_TABLE, linkMarshalers);
195-
for (byte[] i : stringTable) {
196-
size += MarshalerUtil.sizeBytes(Profile.STRING_TABLE, i);
197-
}
193+
size += MarshalerUtil.sizeRepeatedString(Profile.STRING_TABLE, stringTable);
198194
size += MarshalerUtil.sizeInt64(Profile.DROP_FRAMES, dropFrames);
199195
size += MarshalerUtil.sizeInt64(Profile.KEEP_FRAMES, keepFrames);
200196
size += MarshalerUtil.sizeInt64(Profile.TIME_NANOS, timeNanos);

exporters/otlp/profiles/src/test/java/io/opentelemetry/exporter/otlp/profiles/ProfilesRequestMarshalerTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ private static ProfileData sampleProfileData() {
275275
Attributes.empty(),
276276
Collections.emptyList(),
277277
Collections.emptyList(),
278-
Collections.emptyList(),
278+
listOf("foo", "bar"),
279279
3,
280280
4,
281281
5,
@@ -304,6 +304,8 @@ private static Profile.Builder sampleProfileBuilder() {
304304
.AGGREGATION_TEMPORALITY_CUMULATIVE)
305305
.build())
306306
.addAllComment(listOf(8L, 9L))
307+
.addStringTable("foo")
308+
.addStringTable("bar")
307309
.setDefaultSampleType(10);
308310
}
309311

0 commit comments

Comments
 (0)