From dff199603d11775dea6d847e4eb27c29f182f28e Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Mon, 2 May 2022 15:13:44 -0700 Subject: [PATCH] Fix handling of OTLP ArrayValue attributes (#3238) * Fix handling of OTLP ArrayValue attributes * Update changelog Co-authored-by: Cijo Thomas --- .../CHANGELOG.md | 3 + .../Implementation/ActivityExtensions.cs | 22 +++++-- .../OtlpTestHelpers.cs | 62 +++++++++---------- .../OtlpTraceExporterTests.cs | 9 ++- 4 files changed, 54 insertions(+), 42 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index 9b24b75040c..e88e696600e 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -15,6 +15,9 @@ option can still be used with .NET5.0 apps. ([#3147](https://github.com/open-telemetry/opentelemetry-dotnet/issues/3147)) +* Fix handling of array-valued attributes for the OTLP trace exporter. + ([#3238](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3238)) + ## 1.3.0-beta.1 Released 2022-Apr-15 diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs index d5ef774889e..fbc123db6b7 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs @@ -396,6 +396,8 @@ public bool ForEach(KeyValuePair activityTag) this.Created = true; } + OtlpCommon.ArrayValue arrayValue; + switch (activityTag.Value) { case string s: @@ -416,39 +418,49 @@ public bool ForEach(KeyValuePair activityTag) PooledList.Add(ref this.Tags, CreateOtlpKeyValue(key, new OtlpCommon.AnyValue { DoubleValue = d })); break; case int[] intArray: + arrayValue = new OtlpCommon.ArrayValue(); foreach (var item in intArray) { - PooledList.Add(ref this.Tags, CreateOtlpKeyValue(key, new OtlpCommon.AnyValue { IntValue = item })); + arrayValue.Values.Add(new OtlpCommon.AnyValue { IntValue = item }); } + PooledList.Add(ref this.Tags, CreateOtlpKeyValue(key, new OtlpCommon.AnyValue { ArrayValue = arrayValue })); break; case double[] doubleArray: + arrayValue = new OtlpCommon.ArrayValue(); foreach (var item in doubleArray) { - PooledList.Add(ref this.Tags, CreateOtlpKeyValue(key, new OtlpCommon.AnyValue { DoubleValue = item })); + arrayValue.Values.Add(new OtlpCommon.AnyValue { DoubleValue = item }); } + PooledList.Add(ref this.Tags, CreateOtlpKeyValue(key, new OtlpCommon.AnyValue { ArrayValue = arrayValue })); break; case bool[] boolArray: + arrayValue = new OtlpCommon.ArrayValue(); foreach (var item in boolArray) { - PooledList.Add(ref this.Tags, CreateOtlpKeyValue(key, new OtlpCommon.AnyValue { BoolValue = item })); + arrayValue.Values.Add(new OtlpCommon.AnyValue { BoolValue = item }); } + PooledList.Add(ref this.Tags, CreateOtlpKeyValue(key, new OtlpCommon.AnyValue { ArrayValue = arrayValue })); break; case string[] stringArray: + arrayValue = new OtlpCommon.ArrayValue(); foreach (var item in stringArray) { - PooledList.Add(ref this.Tags, CreateOtlpKeyValue(key, item == null ? null : new OtlpCommon.AnyValue { StringValue = item })); + arrayValue.Values.Add(item == null ? new OtlpCommon.AnyValue() : new OtlpCommon.AnyValue { StringValue = item }); } + PooledList.Add(ref this.Tags, CreateOtlpKeyValue(key, new OtlpCommon.AnyValue { ArrayValue = arrayValue })); break; case long[] longArray: + arrayValue = new OtlpCommon.ArrayValue(); foreach (var item in longArray) { - PooledList.Add(ref this.Tags, CreateOtlpKeyValue(key, new OtlpCommon.AnyValue { IntValue = item })); + arrayValue.Values.Add(new OtlpCommon.AnyValue { IntValue = item }); } + PooledList.Add(ref this.Tags, CreateOtlpKeyValue(key, new OtlpCommon.AnyValue { ArrayValue = arrayValue })); break; default: PooledList.Add(ref this.Tags, CreateOtlpKeyValue(key, new OtlpCommon.AnyValue { StringValue = activityTag.Value.ToString() })); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTestHelpers.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTestHelpers.cs index 7b0da3aeee2..0cb994bbeb0 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTestHelpers.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTestHelpers.cs @@ -33,58 +33,56 @@ public static void AssertOtlpAttributes( for (int i = 0; i < expectedAttributes.Count; i++) { var current = expectedAttributes[i].Value; + Assert.Equal(expectedAttributes[i].Key, actual[i].Key); if (current.GetType().IsArray) { + Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, actual[i].Value.ValueCase); if (current is bool[] boolArray) { - int index = 0; - foreach (var item in boolArray) + Assert.Equal(boolArray.Length, actual[i].Value.ArrayValue.Values.Count); + for (var j = 0; j < boolArray.Length; ++j) { - Assert.Equal(expectedAttributes[i].Key, actual[i + index].Key); - AssertOtlpAttributeValue(item, actual[i + index]); - index++; - expectedSize++; + AssertOtlpAttributeValue(boolArray[j], actual[i].Value.ArrayValue.Values[j]); } + + expectedSize++; } else if (current is int[] intArray) { - int index = 1; - foreach (var item in intArray) + Assert.Equal(intArray.Length, actual[i].Value.ArrayValue.Values.Count); + for (var j = 0; j < intArray.Length; ++j) { - Assert.Equal(expectedAttributes[i].Key, actual[i + index].Key); - AssertOtlpAttributeValue(item, actual[i + index]); - index++; - expectedSize++; + AssertOtlpAttributeValue(intArray[j], actual[i].Value.ArrayValue.Values[j]); } + + expectedSize++; } else if (current is double[] doubleArray) { - int index = 2; - foreach (var item in doubleArray) + Assert.Equal(doubleArray.Length, actual[i].Value.ArrayValue.Values.Count); + for (var j = 0; j < doubleArray.Length; ++j) { - Assert.Equal(expectedAttributes[i].Key, actual[i + index].Key); - AssertOtlpAttributeValue(item, actual[i + index]); - index++; - expectedSize++; + AssertOtlpAttributeValue(doubleArray[j], actual[i].Value.ArrayValue.Values[j]); } + + expectedSize++; } else if (current is string[] stringArray) { - int index = 3; - foreach (var item in stringArray) + Assert.Equal(stringArray.Length, actual[i].Value.ArrayValue.Values.Count); + for (var j = 0; j < stringArray.Length; ++j) { - Assert.Equal(expectedAttributes[i].Key, actual[i + index].Key); - AssertOtlpAttributeValue(item, actual[i + index]); - index++; - expectedSize++; + AssertOtlpAttributeValue(stringArray[j], actual[i].Value.ArrayValue.Values[j]); } + + expectedSize++; } } else { Assert.Equal(expectedAttributes[i].Key, actual[i].Key); - AssertOtlpAttributeValue(current, actual[i]); + AssertOtlpAttributeValue(current, actual[i].Value); expectedSize++; } } @@ -92,27 +90,27 @@ public static void AssertOtlpAttributes( Assert.Equal(expectedSize, actual.Count); } - private static void AssertOtlpAttributeValue(object expected, OtlpCommon.KeyValue actual) + private static void AssertOtlpAttributeValue(object expected, OtlpCommon.AnyValue actual) { switch (expected) { case string s: - Assert.Equal(s, actual.Value.StringValue); + Assert.Equal(s, actual.StringValue); break; case bool b: - Assert.Equal(b, actual.Value.BoolValue); + Assert.Equal(b, actual.BoolValue); break; case long l: - Assert.Equal(l, actual.Value.IntValue); + Assert.Equal(l, actual.IntValue); break; case double d: - Assert.Equal(d, actual.Value.DoubleValue); + Assert.Equal(d, actual.DoubleValue); break; case int i: - Assert.Equal(i, actual.Value.IntValue); + Assert.Equal(i, actual.IntValue); break; default: - Assert.Equal(expected.ToString(), actual.Value.StringValue); + Assert.Equal(expected.ToString(), actual.StringValue); break; } } diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs index 33062c9c930..202b1212d55 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs @@ -333,13 +333,12 @@ public void ToOtlpSpanActivitiesWithNullArrayTest() Assert.NotNull(otlpSpan); - var stringArray = otlpSpan.Attributes.Where(kvp => kvp.Key == "stringArray").ToList(); + var stringArray = otlpSpan.Attributes.FirstOrDefault(kvp => kvp.Key == "stringArray"); Assert.NotNull(stringArray); - Assert.Equal(3, stringArray.Count); - Assert.Equal("test", stringArray[0].Value.StringValue); - Assert.Equal(string.Empty, stringArray[1].Value.StringValue); - Assert.Null(stringArray[2].Value); + Assert.Equal("test", stringArray.Value.ArrayValue.Values[0].StringValue); + Assert.Equal(string.Empty, stringArray.Value.ArrayValue.Values[1].StringValue); + Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.None, stringArray.Value.ArrayValue.Values[2].ValueCase); } [Theory]