diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Custom/Serializer/OtlpTagWriter.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Custom/Serializer/OtlpTagWriter.cs index a2a8cdb5bcb..ba112777002 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Custom/Serializer/OtlpTagWriter.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Custom/Serializer/OtlpTagWriter.cs @@ -40,9 +40,20 @@ protected override void WriteStringTag(ref OtlpTagWriterState state, string key, { state.Cursor = Writer.WriteStringWithTag(ref state.Buffer, state.Cursor, FieldNumberConstants.KeyValue_key, key); - int stringSize = Encoding.UTF8.GetByteCount(value.ToString()); - state.Cursor = Writer.WriteTagAndLengthPrefix(ref state.Buffer, state.Cursor, stringSize + 2, FieldNumberConstants.KeyValue_value, WireType.LEN); - state.Cursor = Writer.WriteStringWithTag(ref state.Buffer, state.Cursor, FieldNumberConstants.AnyValue_string_value, value.ToString()); +#if NETFRAMEWORK || NETSTANDARD2_0 + int numberOfUtf8CharsInString; + unsafe + { + fixed (char* p = value) + { + numberOfUtf8CharsInString = Encoding.UTF8.GetByteCount(p, value.Length); + } + } +#else + int numberOfUtf8CharsInString = Encoding.UTF8.GetByteCount(value); +#endif + state.Cursor = Writer.WriteTagAndLengthPrefix(ref state.Buffer, state.Cursor, numberOfUtf8CharsInString + 2, FieldNumberConstants.KeyValue_value, WireType.LEN); + state.Cursor = Writer.WriteStringWithTag(ref state.Buffer, state.Cursor, FieldNumberConstants.AnyValue_string_value, value, numberOfUtf8CharsInString); } protected override void WriteArrayTag(ref OtlpTagWriterState state, string key, ref OtlpTagWriterArrayState value) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Custom/Serializer/Writer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Custom/Serializer/Writer.cs index 1da3e7ab736..51be2d2dad7 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Custom/Serializer/Writer.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Custom/Serializer/Writer.cs @@ -18,31 +18,59 @@ internal class Writer [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int WriteStringWithTag(ref byte[] buffer, int cursor, int fieldNumber, string value) { - int stringSize = Utf8Encoding.GetByteCount(value); + return WriteStringWithTag(ref buffer, cursor, fieldNumber, value.AsSpan()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static int WriteStringWithTag( + ref byte[] buffer, + int cursor, + int fieldNumber, + ReadOnlySpan value, + int numberOfUtf8CharsInString = -1) + { + if (numberOfUtf8CharsInString < 0) + { +#if NETFRAMEWORK || NETSTANDARD2_0 + unsafe + { + fixed (char* strPtr = value) + { + numberOfUtf8CharsInString = Encoding.UTF8.GetByteCount(strPtr, value.Length); + } + } +#else + numberOfUtf8CharsInString = Encoding.UTF8.GetByteCount(value); +#endif + } cursor = WriteTag(ref buffer, cursor, fieldNumber, WireType.LEN); - cursor = WriteLength(ref buffer, cursor, stringSize); + cursor = WriteLength(ref buffer, cursor, numberOfUtf8CharsInString); - if (cursor + stringSize > buffer.Length) + while (cursor + numberOfUtf8CharsInString > buffer.Length) { - byte[] values = Utf8Encoding.GetBytes(value); + GrowBuffer(ref buffer); + } - foreach (var v in values) +#if NETFRAMEWORK || NETSTANDARD2_0 + unsafe + { + fixed (char* strPtr = value) { - cursor = WriteSingleByte(ref buffer, cursor, v); + fixed (byte* bufferPtr = buffer) + { + Encoding.UTF8.GetBytes(strPtr, value.Length, bufferPtr + cursor, numberOfUtf8CharsInString); + } } - - return cursor; } - else - { - _ = Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, cursor); +#else + _ = Encoding.UTF8.GetBytes(value, buffer.AsSpan().Slice(cursor)); +#endif - cursor += stringSize; + cursor += numberOfUtf8CharsInString; - return cursor; - } + return cursor; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -284,7 +312,7 @@ internal static int WriteSingleByte(ref byte[] buffer, int cursor, byte value) { if (buffer.Length == cursor) { - RefreshBuffer(ref buffer); + GrowBuffer(ref buffer); } buffer[cursor++] = value; @@ -292,7 +320,7 @@ internal static int WriteSingleByte(ref byte[] buffer, int cursor, byte value) return cursor; } - internal static void RefreshBuffer(ref byte[] buffer) + internal static void GrowBuffer(ref byte[] buffer) { var newBuffer = new byte[buffer.Length * 2]; diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj index 2c933d89a33..245eb3ea0be 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj @@ -16,6 +16,7 @@ https://github.com/open-telemetry/opentelemetry-dotnet/pull/5520#discussion_r1556221048 and https://github.com/dotnet/runtime/issues/92509 --> $(NoWarn);SYSLIB1100;SYSLIB1101 + true