Skip to content

Commit

Permalink
Fix json repeated string parsing.
Browse files Browse the repository at this point in the history
  • Loading branch information
jsuereth committed Nov 15, 2024
1 parent 1211b37 commit 144e141
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,22 @@ public void writeString(
generator.writeString(string);
}

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

@Override
public void writeBytes(ProtoFieldInfo field, byte[] value) throws IOException {
generator.writeBinaryField(field.getJsonName(), value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,13 @@ public void writeString(
StatelessMarshalerUtil.writeUtf8(output, string, utf8Length, context);
}

@Override
public void writeRepeatedString(ProtoFieldInfo field, byte[][] utf8Bytes) throws IOException {
for (byte[] value : utf8Bytes) {
writeString(field, value);
}
}

@Override
public void writeBytes(ProtoFieldInfo field, byte[] value) throws IOException {
output.writeUInt32NoTag(field.getTag());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,18 @@ public void serializeString(ProtoFieldInfo field, byte[] utf8Bytes) throws IOExc
writeString(field, utf8Bytes);
}

/**
* Serializes a protobuf {@code repeated string} field. {@code utf8Bytes} is the UTF8 encoded
* bytes of the strings to serialize.
*/
@SuppressWarnings("AvoidObjectArrays")
public void serializeRepeatedString(ProtoFieldInfo field, byte[][] utf8Bytes) throws IOException {
if (utf8Bytes.length == 0) {
return;
}
writeRepeatedString(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. This method reads
Expand All @@ -246,6 +258,11 @@ public abstract void writeString(
ProtoFieldInfo field, String string, int utf8Length, MarshalerContext context)
throws IOException;

/** Writes a protobuf {@code repeated string} field, even if it matches the default value. */
@SuppressWarnings("AvoidObjectArrays")
public abstract void writeRepeatedString(ProtoFieldInfo field, byte[][] utf8Bytes)
throws IOException;

/** Serializes a protobuf {@code bytes} field. */
public void serializeBytes(ProtoFieldInfo field, byte[] value) throws IOException {
if (value.length == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,10 @@ protected void writeTo(Serializer output) throws IOException {
output.writeString(ResourceEntityRefExperimental.SCHEMA_URL, schemaUrlUtf8);
}
output.writeString(ResourceEntityRefExperimental.TYPE, typeUtf8);
for (byte[] keyUtf8 : identityAttributeKeysUtf8) {
output.serializeString(ResourceEntityRefExperimental.IDENTITY_ATTRIBUTES, keyUtf8);
}
for (byte[] keyUtf8 : descriptiveAttributeKeysUtf8) {
output.serializeString(ResourceEntityRefExperimental.DESCRIPTION_ATTRIBUTES, keyUtf8);
}
output.writeRepeatedString(
ResourceEntityRefExperimental.IDENTITY_ATTRIBUTES, identityAttributeKeysUtf8);
output.writeRepeatedString(
ResourceEntityRefExperimental.DESCRIPTION_ATTRIBUTES, descriptiveAttributeKeysUtf8);
}

public static ResourceEntityRefMarshaler createForEntity(Entity e) {
Expand Down Expand Up @@ -81,6 +79,7 @@ private static int calculateSize(
size += MarshalerUtil.sizeBytes(ResourceEntityRefExperimental.SCHEMA_URL, schemaUrlUtf8);
}
size += MarshalerUtil.sizeBytes(ResourceEntityRefExperimental.TYPE, typeUtf8);
// TODO - we need repeated string support.
for (byte[] keyUtf8 : identityAttributeKeysUtf8) {
size += MarshalerUtil.sizeBytes(ResourceEntityRefExperimental.IDENTITY_ATTRIBUTES, keyUtf8);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.exporter.internal.otlp;

import static org.assertj.core.api.Assertions.assertThat;

import io.opentelemetry.sdk.resources.Entity;
import io.opentelemetry.sdk.resources.Resource;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test;

public class ResourceEntityTest {
@Test
void toJsonResourceWithEntity() throws Exception {
Resource resource =
Resource.builder()
.add(
Entity.builder()
.setSchemaUrl("http://example.com/1.0")
.setEntityType("test")
.withIdentifying(attr -> attr.put("test.id", 1))
.withDescriptive(attr -> attr.put("test.name", "one"))
.build())
.build();

ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
ResourceMarshaler.create(resource).writeJsonTo(out);
} finally {
out.close();
}

String json = new String(out.toByteArray(), StandardCharsets.UTF_8);
assertThat(json)
.isEqualTo(
"{\"attributes\":[{\"key\":\"test.id\",\"value\":{\"intValue\":\"1\"}},{\"key\":\"test.name\",\"value\":{\"stringValue\":\"one\"}}],"
+ "\"entityRefs\":[{\"schemaUrl\":\"http://example.com/1.0\",\"type\":\"test\",\"idAttrKeys\":[\"test.id\"],\"descrAttrKeys\":[\"test.name\"]}]}");
}
}

0 comments on commit 144e141

Please sign in to comment.