-
Notifications
You must be signed in to change notification settings - Fork 848
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Low allocation OTLP logs marshaler (#6429)
- Loading branch information
Showing
19 changed files
with
1,245 additions
and
195 deletions.
There are no files selected for viewing
148 changes: 148 additions & 0 deletions
148
...n/src/jmh/java/io/opentelemetry/exporter/internal/otlp/LogsRequestMarshalerBenchmark.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
/* | ||
* 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.Attributes; | ||
import io.opentelemetry.api.incubator.events.EventLogger; | ||
import io.opentelemetry.api.incubator.logs.AnyValue; | ||
import io.opentelemetry.api.logs.Logger; | ||
import io.opentelemetry.api.logs.Severity; | ||
import io.opentelemetry.exporter.internal.otlp.logs.LogsRequestMarshaler; | ||
import io.opentelemetry.exporter.internal.otlp.logs.LowAllocationLogsRequestMarshaler; | ||
import io.opentelemetry.sdk.logs.SdkLoggerProvider; | ||
import io.opentelemetry.sdk.logs.data.LogRecordData; | ||
import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; | ||
import io.opentelemetry.sdk.logs.internal.SdkEventLoggerProvider; | ||
import io.opentelemetry.sdk.resources.Resource; | ||
import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; | ||
import java.io.IOException; | ||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
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.Warmup; | ||
|
||
@BenchmarkMode({Mode.AverageTime}) | ||
@OutputTimeUnit(TimeUnit.MICROSECONDS) | ||
@Warmup(iterations = 5, time = 1) | ||
@Measurement(iterations = 10, time = 1) | ||
@Fork(1) | ||
public class LogsRequestMarshalerBenchmark { | ||
|
||
private static final Collection<LogRecordData> LOGS; | ||
private static final LowAllocationLogsRequestMarshaler MARSHALER = | ||
new LowAllocationLogsRequestMarshaler(); | ||
private static final TestOutputStream OUTPUT = new TestOutputStream(); | ||
|
||
static { | ||
InMemoryLogRecordExporter logRecordExporter = InMemoryLogRecordExporter.create(); | ||
SdkLoggerProvider loggerProvider = | ||
SdkLoggerProvider.builder() | ||
.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())) | ||
.addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter)) | ||
.build(); | ||
|
||
Logger logger1 = loggerProvider.get("logger"); | ||
logger1 | ||
.logRecordBuilder() | ||
.setBody("Hello world from this log...") | ||
.setAllAttributes( | ||
Attributes.builder() | ||
.put("key_bool", true) | ||
.put("key_String", "string") | ||
.put("key_int", 100L) | ||
.put("key_double", 100.3) | ||
.build()) | ||
.setSeverity(Severity.INFO) | ||
.setSeverityText("INFO") | ||
.emit(); | ||
|
||
SdkEventLoggerProvider eventLoggerProvider = SdkEventLoggerProvider.create(loggerProvider); | ||
EventLogger eventLogger = eventLoggerProvider.get("event-logger"); | ||
eventLogger | ||
.builder("namespace.my-event-name") | ||
// Helper methods to set primitive types | ||
.put("stringKey", "value") | ||
.put("longKey", 1L) | ||
.put("doubleKey", 1.0) | ||
.put("boolKey", true) | ||
// Helper methods to set primitive array types | ||
.put("stringArrKey", "value1", "value2") | ||
.put("longArrKey", 1L, 2L) | ||
.put("doubleArrKey", 1.0, 2.0) | ||
.put("boolArrKey", true, false) | ||
// Set AnyValue types to encode complex data | ||
.put( | ||
"anyValueKey", AnyValue.of(Collections.singletonMap("childKey1", AnyValue.of("value")))) | ||
.emit(); | ||
|
||
LOGS = logRecordExporter.getFinishedLogRecordItems(); | ||
} | ||
|
||
@Benchmark | ||
public int marshalStateful() throws IOException { | ||
LogsRequestMarshaler marshaler = LogsRequestMarshaler.create(LOGS); | ||
OUTPUT.reset(); | ||
marshaler.writeBinaryTo(OUTPUT); | ||
return OUTPUT.getCount(); | ||
} | ||
|
||
@Benchmark | ||
public int marshalStatefulJson() throws IOException { | ||
LogsRequestMarshaler marshaler = LogsRequestMarshaler.create(LOGS); | ||
OUTPUT.reset(); | ||
marshaler.writeJsonTo(OUTPUT); | ||
return OUTPUT.getCount(); | ||
} | ||
|
||
@Benchmark | ||
public int marshalStateless() throws IOException { | ||
MARSHALER.initialize(LOGS); | ||
try { | ||
OUTPUT.reset(); | ||
MARSHALER.writeBinaryTo(OUTPUT); | ||
return OUTPUT.getCount(); | ||
} finally { | ||
MARSHALER.reset(); | ||
} | ||
} | ||
|
||
@Benchmark | ||
public int marshalStatelessJson() throws IOException { | ||
MARSHALER.initialize(LOGS); | ||
try { | ||
OUTPUT.reset(); | ||
MARSHALER.writeJsonTo(OUTPUT); | ||
return OUTPUT.getCount(); | ||
} finally { | ||
MARSHALER.reset(); | ||
} | ||
} | ||
} |
110 changes: 110 additions & 0 deletions
110
...mon/src/main/java/io/opentelemetry/exporter/internal/otlp/AnyValueStatelessMarshaler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.exporter.internal.otlp; | ||
|
||
import io.opentelemetry.api.incubator.logs.AnyValue; | ||
import io.opentelemetry.api.incubator.logs.KeyAnyValue; | ||
import io.opentelemetry.exporter.internal.marshal.MarshalerContext; | ||
import io.opentelemetry.exporter.internal.marshal.Serializer; | ||
import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; | ||
import io.opentelemetry.exporter.internal.marshal.StatelessMarshalerUtil; | ||
import java.io.IOException; | ||
import java.nio.ByteBuffer; | ||
import java.util.List; | ||
|
||
/** | ||
* A Marshaler of key value pairs. See {@link AnyValueMarshaler}. | ||
* | ||
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change | ||
* at any time. | ||
*/ | ||
public final class AnyValueStatelessMarshaler implements StatelessMarshaler<AnyValue<?>> { | ||
|
||
public static final AnyValueStatelessMarshaler INSTANCE = new AnyValueStatelessMarshaler(); | ||
|
||
private AnyValueStatelessMarshaler() {} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Override | ||
public void writeTo(Serializer output, AnyValue<?> value, MarshalerContext context) | ||
throws IOException { | ||
switch (value.getType()) { | ||
case STRING: | ||
StringAnyValueStatelessMarshaler.INSTANCE.writeTo( | ||
output, (String) value.getValue(), context); | ||
return; | ||
case BOOLEAN: | ||
BoolAnyValueStatelessMarshaler.INSTANCE.writeTo( | ||
output, (Boolean) value.getValue(), context); | ||
return; | ||
case LONG: | ||
IntAnyValueStatelessMarshaler.INSTANCE.writeTo(output, (Long) value.getValue(), context); | ||
return; | ||
case DOUBLE: | ||
DoubleAnyValueStatelessMarshaler.INSTANCE.writeTo( | ||
output, (Double) value.getValue(), context); | ||
return; | ||
case ARRAY: | ||
output.serializeMessageWithContext( | ||
io.opentelemetry.proto.common.v1.internal.AnyValue.ARRAY_VALUE, | ||
(List<AnyValue<?>>) value.getValue(), | ||
ArrayAnyValueStatelessMarshaler.INSTANCE, | ||
context); | ||
return; | ||
case KEY_VALUE_LIST: | ||
output.serializeMessageWithContext( | ||
io.opentelemetry.proto.common.v1.internal.AnyValue.KVLIST_VALUE, | ||
(List<KeyAnyValue>) value.getValue(), | ||
KeyValueListAnyValueStatelessMarshaler.INSTANCE, | ||
context); | ||
return; | ||
case BYTES: | ||
BytesAnyValueStatelessMarshaler.INSTANCE.writeTo( | ||
output, (ByteBuffer) value.getValue(), 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 value type."); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Override | ||
public int getBinarySerializedSize(AnyValue<?> value, MarshalerContext context) { | ||
switch (value.getType()) { | ||
case STRING: | ||
return StringAnyValueStatelessMarshaler.INSTANCE.getBinarySerializedSize( | ||
(String) value.getValue(), context); | ||
case BOOLEAN: | ||
return BoolAnyValueStatelessMarshaler.INSTANCE.getBinarySerializedSize( | ||
(Boolean) value.getValue(), context); | ||
case LONG: | ||
return IntAnyValueStatelessMarshaler.INSTANCE.getBinarySerializedSize( | ||
(Long) value.getValue(), context); | ||
case DOUBLE: | ||
return DoubleAnyValueStatelessMarshaler.INSTANCE.getBinarySerializedSize( | ||
(Double) value.getValue(), context); | ||
case ARRAY: | ||
return StatelessMarshalerUtil.sizeMessageWithContext( | ||
io.opentelemetry.proto.common.v1.internal.AnyValue.ARRAY_VALUE, | ||
(List<AnyValue<?>>) value.getValue(), | ||
ArrayAnyValueStatelessMarshaler.INSTANCE, | ||
context); | ||
case KEY_VALUE_LIST: | ||
return StatelessMarshalerUtil.sizeMessageWithContext( | ||
io.opentelemetry.proto.common.v1.internal.AnyValue.KVLIST_VALUE, | ||
(List<KeyAnyValue>) value.getValue(), | ||
KeyValueListAnyValueStatelessMarshaler.INSTANCE, | ||
context); | ||
case BYTES: | ||
return BytesAnyValueStatelessMarshaler.INSTANCE.getBinarySerializedSize( | ||
(ByteBuffer) value.getValue(), context); | ||
} | ||
// Error prone ensures the switch statement is complete, otherwise only can happen with | ||
// unaligned versions which are not supported. | ||
throw new IllegalArgumentException("Unsupported value type."); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.