[otlp] Switch to TagWriter for handling of tags/attributes (#5585)

This commit is contained in:
Mikel Blanchard 2024-05-02 22:53:50 -07:00 committed by GitHub
parent e95ae72649
commit ac0d1d1fab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 227 additions and 223 deletions

View File

@ -237,19 +237,18 @@ internal static class ActivityExtensions
};
int maxTags = sdkLimitOptions.SpanLinkAttributeCountLimit ?? int.MaxValue;
var otlpLinkAttributes = otlpLink.Attributes;
foreach (ref readonly var tag in activityLink.EnumerateTagObjects())
{
if (OtlpTagTransformer.Instance.TryTransformTag(tag, out var attribute, sdkLimitOptions.AttributeValueLengthLimit))
if (otlpLinkAttributes.Count == maxTags)
{
if (otlpLink.Attributes.Count < maxTags)
{
otlpLink.Attributes.Add(attribute);
}
else
{
otlpLink.DroppedAttributesCount++;
}
otlpLink.DroppedAttributesCount++;
continue;
}
OtlpTagWriter.Instance.TryWriteTag(ref otlpLinkAttributes, tag, sdkLimitOptions.AttributeValueLengthLimit);
}
otlpLink.Flags = ToOtlpSpanFlags(activityLink.Context.TraceFlags, activityLink.Context.IsRemote);
@ -267,19 +266,18 @@ internal static class ActivityExtensions
};
int maxTags = sdkLimitOptions.SpanEventAttributeCountLimit ?? int.MaxValue;
var otlpEventAttributes = otlpEvent.Attributes;
foreach (ref readonly var tag in activityEvent.EnumerateTagObjects())
{
if (OtlpTagTransformer.Instance.TryTransformTag(tag, out var attribute, sdkLimitOptions.AttributeValueLengthLimit))
if (otlpEventAttributes.Count == maxTags)
{
if (otlpEvent.Attributes.Count < maxTags)
{
otlpEvent.Attributes.Add(attribute);
}
else
{
otlpEvent.DroppedAttributesCount++;
}
otlpEvent.DroppedAttributesCount++;
continue;
}
OtlpTagWriter.Instance.TryWriteTag(ref otlpEventAttributes, tag, sdkLimitOptions.AttributeValueLengthLimit);
}
return otlpEvent;
@ -322,6 +320,8 @@ internal static class ActivityExtensions
public void EnumerateTags(Activity activity, int maxTags)
{
var otlpSpanAttributes = this.Span.Attributes;
foreach (ref readonly var tag in activity.EnumerateTagObjects())
{
if (tag.Value == null)
@ -341,26 +341,22 @@ internal static class ActivityExtensions
continue;
}
if (OtlpTagTransformer.Instance.TryTransformTag(tag, out var attribute, this.SdkLimitOptions.AttributeValueLengthLimit))
if (otlpSpanAttributes.Count == maxTags)
{
if (this.Span.Attributes.Count < maxTags)
{
this.Span.Attributes.Add(attribute);
}
else
{
this.Span.DroppedAttributesCount++;
}
this.Span.DroppedAttributesCount++;
}
else
{
OtlpTagWriter.Instance.TryWriteTag(ref otlpSpanAttributes, tag, this.SdkLimitOptions.AttributeValueLengthLimit);
}
if (attribute.Value.ValueCase == AnyValue.ValueOneofCase.StringValue)
{
// Note: tag.Value is used and not attribute.Value here because attribute.Value may be truncated
PeerServiceResolver.InspectTag(ref this, key, tag.Value as string);
}
else if (attribute.Value.ValueCase == AnyValue.ValueOneofCase.IntValue)
{
PeerServiceResolver.InspectTag(ref this, key, attribute.Value.IntValue);
}
if (tag.Value is string tagStringValue)
{
PeerServiceResolver.InspectTag(ref this, key, tagStringValue);
}
else if (tag.Value is int tagIntValue)
{
PeerServiceResolver.InspectTag(ref this, key, tagIntValue);
}
}
}

View File

@ -414,12 +414,11 @@ internal static class MetricItemExtensions
otlpExemplar.AsDouble = Convert.ToDouble(value);
}
var otlpExemplarFilteredAttributes = otlpExemplar.FilteredAttributes;
foreach (var tag in exemplar.FilteredTags)
{
if (OtlpTagTransformer.Instance.TryTransformTag(tag, out var result))
{
otlpExemplar.FilteredAttributes.Add(result);
}
OtlpTagWriter.Instance.TryWriteTag(ref otlpExemplarFilteredAttributes, tag);
}
return otlpExemplar;
@ -429,10 +428,7 @@ internal static class MetricItemExtensions
{
foreach (var tag in tags)
{
if (OtlpTagTransformer.Instance.TryTransformTag(tag, out var result))
{
attributes.Add(result);
}
OtlpTagWriter.Instance.TryWriteTag(ref attributes, tag);
}
}
@ -440,10 +436,7 @@ internal static class MetricItemExtensions
{
foreach (var tag in meterTags)
{
if (OtlpTagTransformer.Instance.TryTransformTag(tag, out var result))
{
attributes.Add(result);
}
OtlpTagWriter.Instance.TryWriteTag(ref attributes, tag);
}
}
}

View File

@ -137,15 +137,15 @@ internal sealed class OtlpLogRecordTransformer
if (!string.IsNullOrEmpty(logRecord.EventId.Name))
{
AddStringAttribute(otlpLogRecord, ExperimentalOptions.LogRecordEventNameAttribute, logRecord.EventId.Name, attributeValueLengthLimit, attributeCountLimit);
AddStringAttribute(otlpLogRecord, ExperimentalOptions.LogRecordEventNameAttribute, logRecord.EventId.Name, attributeCountLimit, attributeValueLengthLimit);
}
}
if (logRecord.Exception != null)
{
AddStringAttribute(otlpLogRecord, SemanticConventions.AttributeExceptionType, logRecord.Exception.GetType().Name, attributeValueLengthLimit, attributeCountLimit);
AddStringAttribute(otlpLogRecord, SemanticConventions.AttributeExceptionMessage, logRecord.Exception.Message, attributeValueLengthLimit, attributeCountLimit);
AddStringAttribute(otlpLogRecord, SemanticConventions.AttributeExceptionStacktrace, logRecord.Exception.ToInvariantString(), attributeValueLengthLimit, attributeCountLimit);
AddStringAttribute(otlpLogRecord, SemanticConventions.AttributeExceptionType, logRecord.Exception.GetType().Name, attributeCountLimit, attributeValueLengthLimit);
AddStringAttribute(otlpLogRecord, SemanticConventions.AttributeExceptionMessage, logRecord.Exception.Message, attributeCountLimit, attributeValueLengthLimit);
AddStringAttribute(otlpLogRecord, SemanticConventions.AttributeExceptionStacktrace, logRecord.Exception.ToInvariantString(), attributeCountLimit, attributeValueLengthLimit);
}
bool bodyPopulatedFromFormattedMessage = false;
@ -166,9 +166,9 @@ internal sealed class OtlpLogRecordTransformer
{
otlpLogRecord.Body = new OtlpCommon.AnyValue { StringValue = attribute.Value as string };
}
else if (OtlpTagTransformer.Instance.TryTransformTag(attribute, out var result, attributeValueLengthLimit))
else
{
AddAttribute(otlpLogRecord, result, attributeCountLimit);
AddAttribute(otlpLogRecord, attribute, attributeCountLimit, attributeValueLengthLimit);
}
}
@ -224,10 +224,7 @@ internal sealed class OtlpLogRecordTransformer
}
else
{
if (OtlpTagTransformer.Instance.TryTransformTag(scopeItem, out var result, attributeValueLengthLimit))
{
AddAttribute(otlpLog, result, attributeCountLimit);
}
AddAttribute(otlpLog, scopeItem, attributeCountLimit, attributeValueLengthLimit);
}
}
}
@ -241,36 +238,34 @@ internal sealed class OtlpLogRecordTransformer
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void AddAttribute(OtlpLogs.LogRecord logRecord, OtlpCommon.KeyValue attribute, int maxAttributeCount)
private static void AddAttribute(OtlpLogs.LogRecord logRecord, KeyValuePair<string, object> attribute, int maxAttributeCount, int? maxValueLength)
{
if (logRecord.Attributes.Count < maxAttributeCount)
var logRecordAttributes = logRecord.Attributes;
if (logRecordAttributes.Count == maxAttributeCount)
{
logRecord.Attributes.Add(attribute);
logRecord.DroppedAttributesCount++;
}
else
{
logRecord.DroppedAttributesCount++;
OtlpTagWriter.Instance.TryWriteTag(ref logRecordAttributes, attribute, maxValueLength);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void AddStringAttribute(OtlpLogs.LogRecord logRecord, string key, string value, int? maxValueLength, int maxAttributeCount)
private static void AddStringAttribute(OtlpLogs.LogRecord logRecord, string key, string value, int maxAttributeCount, int? maxValueLength)
{
var attributeItem = new KeyValuePair<string, object>(key, value);
if (OtlpTagTransformer.Instance.TryTransformTag(attributeItem, out var result, maxValueLength))
{
AddAttribute(logRecord, result, maxAttributeCount);
}
AddAttribute(logRecord, attributeItem, maxAttributeCount, maxValueLength);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void AddIntAttribute(OtlpLogs.LogRecord logRecord, string key, int value, int maxAttributeCount)
{
var attributeItem = new KeyValuePair<string, object>(key, value);
if (OtlpTagTransformer.Instance.TryTransformTag(attributeItem, out var result))
{
AddAttribute(logRecord, result, maxAttributeCount);
}
AddAttribute(logRecord, attributeItem, maxAttributeCount, maxValueLength: null);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@ -1,118 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#nullable enable
using System.Diagnostics;
using OpenTelemetry.Internal;
using OtlpCommon = OpenTelemetry.Proto.Common.V1;
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation;
internal sealed class OtlpTagTransformer : TagTransformer<OtlpCommon.KeyValue>
{
private OtlpTagTransformer()
{
}
public static OtlpTagTransformer Instance { get; } = new();
protected override OtlpCommon.KeyValue TransformIntegralTag(string key, long value)
{
return new OtlpCommon.KeyValue { Key = key, Value = ToAnyValue(value) };
}
protected override OtlpCommon.KeyValue TransformFloatingPointTag(string key, double value)
{
return new OtlpCommon.KeyValue { Key = key, Value = ToAnyValue(value) };
}
protected override OtlpCommon.KeyValue TransformBooleanTag(string key, bool value)
{
return new OtlpCommon.KeyValue { Key = key, Value = ToAnyValue(value) };
}
protected override OtlpCommon.KeyValue TransformStringTag(string key, string value)
{
return new OtlpCommon.KeyValue { Key = key, Value = ToAnyValue(value) };
}
protected override OtlpCommon.KeyValue TransformArrayTag(string key, Array array)
{
var arrayValue = new OtlpCommon.ArrayValue();
foreach (var item in array)
{
arrayValue.Values.Add(ToAnyValue(item));
}
return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { ArrayValue = arrayValue } };
}
protected override void OnUnsupportedTagDropped(
string tagKey,
string tagValueTypeFullName)
{
OpenTelemetryProtocolExporterEventSource.Log.UnsupportedAttributeType(
tagValueTypeFullName,
tagKey);
}
private static OtlpCommon.AnyValue ToAnyValue(long value)
=> new() { IntValue = value };
private static OtlpCommon.AnyValue ToAnyValue(double value)
=> new() { DoubleValue = value };
private static OtlpCommon.AnyValue ToAnyValue(bool value)
=> new() { BoolValue = value };
private static OtlpCommon.AnyValue ToAnyValue(string value)
=> new() { StringValue = value };
private static OtlpCommon.AnyValue ToAnyValue(object? value)
{
if (value == null)
{
return new();
}
return value switch
{
char => ToAnyValue(Convert.ToString(value)!),
string s =>
/* Note: No need to call TruncateString here. That is taken care of
in base class via ConvertToStringArrayThenTransformArrayTag */
ToAnyValue(s),
bool b => ToAnyValue(b),
byte b => ToAnyValue(b),
sbyte b => ToAnyValue(b),
short s => ToAnyValue(s),
ushort s => ToAnyValue(s),
int i => ToAnyValue(i),
uint i => ToAnyValue(i),
long l => ToAnyValue(l),
float f => ToAnyValue(f),
double d => ToAnyValue(d),
_ => DefaultCase(value),
};
static OtlpCommon.AnyValue DefaultCase(object value)
{
// Note: This should never be executed. In the base class the
// default case in TransformArrayTagInternal converts everything
// not explicitly supported to strings
Debug.Fail("Default case executed");
var stringValue = Convert.ToString(value);
if (stringValue == null)
{
return new();
}
return ToAnyValue(stringValue);
}
}
}

View File

@ -0,0 +1,107 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#nullable enable
using Google.Protobuf.Collections;
using OpenTelemetry.Internal;
using OtlpCommon = OpenTelemetry.Proto.Common.V1;
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation;
internal sealed class OtlpTagWriter : TagWriter<RepeatedField<OtlpCommon.KeyValue>, OtlpCommon.ArrayValue>
{
private OtlpTagWriter()
: base(new OtlpArrayTagWriter())
{
}
public static OtlpTagWriter Instance { get; } = new();
internal static OtlpCommon.AnyValue ToAnyValue(long value)
=> new() { IntValue = value };
internal static OtlpCommon.AnyValue ToAnyValue(double value)
=> new() { DoubleValue = value };
internal static OtlpCommon.AnyValue ToAnyValue(bool value)
=> new() { BoolValue = value };
internal static OtlpCommon.AnyValue ToAnyValue(string value)
=> new() { StringValue = value };
protected override void WriteIntegralTag(ref RepeatedField<OtlpCommon.KeyValue> tags, string key, long value)
{
tags.Add(new OtlpCommon.KeyValue { Key = key, Value = ToAnyValue(value) });
}
protected override void WriteFloatingPointTag(ref RepeatedField<OtlpCommon.KeyValue> tags, string key, double value)
{
tags.Add(new OtlpCommon.KeyValue { Key = key, Value = ToAnyValue(value) });
}
protected override void WriteBooleanTag(ref RepeatedField<OtlpCommon.KeyValue> tags, string key, bool value)
{
tags.Add(new OtlpCommon.KeyValue { Key = key, Value = ToAnyValue(value) });
}
protected override void WriteStringTag(ref RepeatedField<OtlpCommon.KeyValue> tags, string key, string value)
{
tags.Add(new OtlpCommon.KeyValue { Key = key, Value = ToAnyValue(value) });
}
protected override void WriteArrayTag(ref RepeatedField<OtlpCommon.KeyValue> tags, string key, ref OtlpCommon.ArrayValue value)
{
tags.Add(new OtlpCommon.KeyValue
{
Key = key,
Value = new OtlpCommon.AnyValue
{
ArrayValue = value,
},
});
}
protected override void OnUnsupportedTagDropped(
string tagKey,
string tagValueTypeFullName)
{
OpenTelemetryProtocolExporterEventSource.Log.UnsupportedAttributeType(
tagValueTypeFullName,
tagKey);
}
private sealed class OtlpArrayTagWriter : ArrayTagWriter<OtlpCommon.ArrayValue>
{
public override OtlpCommon.ArrayValue BeginWriteArray() => new();
public override void WriteNullValue(ref OtlpCommon.ArrayValue array)
{
array.Values.Add(new OtlpCommon.AnyValue());
}
public override void WriteIntegralValue(ref OtlpCommon.ArrayValue array, long value)
{
array.Values.Add(ToAnyValue(value));
}
public override void WriteFloatingPointValue(ref OtlpCommon.ArrayValue array, double value)
{
array.Values.Add(ToAnyValue(value));
}
public override void WriteBooleanValue(ref OtlpCommon.ArrayValue array, bool value)
{
array.Values.Add(ToAnyValue(value));
}
public override void WriteStringValue(ref OtlpCommon.ArrayValue array, string value)
{
array.Values.Add(ToAnyValue(value));
}
public override void EndWriteArray(ref OtlpCommon.ArrayValue array)
{
}
}
}

View File

@ -13,12 +13,11 @@ internal static class ResourceExtensions
{
var processResource = new OtlpResource.Resource();
var processResourceAttributes = processResource.Attributes;
foreach (KeyValuePair<string, object> attribute in resource.Attributes)
{
if (OtlpTagTransformer.Instance.TryTransformTag(attribute, out var result))
{
processResource.Attributes.Add(result);
}
OtlpTagWriter.Instance.TryWriteTag(ref processResourceAttributes, attribute);
}
if (!processResource.Attributes.Any(kvp => kvp.Key == ResourceSemanticConventions.AttributeServiceName))

View File

@ -39,7 +39,8 @@
<ItemGroup>
<Compile Include="$(RepoRoot)\src\Shared\PeriodicExportingMetricReaderHelper.cs" Link="Includes\PeriodicExportingMetricReaderHelper.cs" />
<Compile Include="$(RepoRoot)\src\Shared\PeerServiceResolver.cs" Link="Includes\PeerServiceResolver.cs" />
<Compile Include="$(RepoRoot)\src\Shared\TagTransformer.cs" Link="Includes\TagTransformer.cs" />
<Compile Include="$(RepoRoot)\src\Shared\TagWriter\ArrayTagWriter.cs" Link="Includes\TagWriter\ArrayTagWriter.cs" />
<Compile Include="$(RepoRoot)\src\Shared\TagWriter\TagWriter.cs" Link="Includes\TagWriter\TagWriter.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -6,7 +6,6 @@
using System.Buffers;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
namespace OpenTelemetry.Internal;
@ -80,7 +79,7 @@ internal abstract class TagWriter<TTagState, TArrayState>
default:
try
{
var stringValue = TruncateString(Convert.ToString(tag.Value, CultureInfo.InvariantCulture), tagValueMaxLength);
var stringValue = TruncateString(Convert.ToString(tag.Value/*TODO: , CultureInfo.InvariantCulture*/), tagValueMaxLength);
if (stringValue == null)
{
return this.LogUnsupportedTagTypeAndReturnFalse(tag.Key, tag.Value);
@ -203,7 +202,7 @@ internal abstract class TagWriter<TTagState, TArrayState>
var item = array.GetValue(i);
stringArray[i] = item == null
? null
: TruncateString(Convert.ToString(item, CultureInfo.InvariantCulture), tagValueMaxLength);
: TruncateString(Convert.ToString(item/*TODO: , CultureInfo.InvariantCulture*/), tagValueMaxLength);
}
this.WriteStringsToArray(ref arrayState, new(stringArray, 0, array.Length));
@ -222,47 +221,47 @@ internal abstract class TagWriter<TTagState, TArrayState>
{
if (typeof(TItem) == typeof(char))
{
this.arrayWriter.WriteStringTag(ref arrayState, Convert.ToString((char)(object)item)!);
this.arrayWriter.WriteStringValue(ref arrayState, Convert.ToString((char)(object)item)!);
}
else if (typeof(TItem) == typeof(bool))
{
this.arrayWriter.WriteBooleanTag(ref arrayState, (bool)(object)item);
this.arrayWriter.WriteBooleanValue(ref arrayState, (bool)(object)item);
}
else if (typeof(TItem) == typeof(byte))
{
this.arrayWriter.WriteIntegralTag(ref arrayState, (byte)(object)item);
this.arrayWriter.WriteIntegralValue(ref arrayState, (byte)(object)item);
}
else if (typeof(TItem) == typeof(sbyte))
{
this.arrayWriter.WriteIntegralTag(ref arrayState, (sbyte)(object)item);
this.arrayWriter.WriteIntegralValue(ref arrayState, (sbyte)(object)item);
}
else if (typeof(TItem) == typeof(short))
{
this.arrayWriter.WriteIntegralTag(ref arrayState, (short)(object)item);
this.arrayWriter.WriteIntegralValue(ref arrayState, (short)(object)item);
}
else if (typeof(TItem) == typeof(ushort))
{
this.arrayWriter.WriteIntegralTag(ref arrayState, (ushort)(object)item);
this.arrayWriter.WriteIntegralValue(ref arrayState, (ushort)(object)item);
}
else if (typeof(TItem) == typeof(int))
{
this.arrayWriter.WriteIntegralTag(ref arrayState, (int)(object)item);
this.arrayWriter.WriteIntegralValue(ref arrayState, (int)(object)item);
}
else if (typeof(TItem) == typeof(uint))
{
this.arrayWriter.WriteIntegralTag(ref arrayState, (uint)(object)item);
this.arrayWriter.WriteIntegralValue(ref arrayState, (uint)(object)item);
}
else if (typeof(TItem) == typeof(long))
{
this.arrayWriter.WriteIntegralTag(ref arrayState, (long)(object)item);
this.arrayWriter.WriteIntegralValue(ref arrayState, (long)(object)item);
}
else if (typeof(TItem) == typeof(float))
{
this.arrayWriter.WriteFloatingPointTag(ref arrayState, (float)(object)item);
this.arrayWriter.WriteFloatingPointValue(ref arrayState, (float)(object)item);
}
else if (typeof(TItem) == typeof(double))
{
this.arrayWriter.WriteFloatingPointTag(ref arrayState, (double)(object)item);
this.arrayWriter.WriteFloatingPointValue(ref arrayState, (double)(object)item);
}
else
{
@ -279,11 +278,11 @@ internal abstract class TagWriter<TTagState, TArrayState>
{
if (item == null)
{
this.arrayWriter.WriteNullTag(ref arrayState);
this.arrayWriter.WriteNullValue(ref arrayState);
}
else
{
this.arrayWriter.WriteStringTag(ref arrayState, item);
this.arrayWriter.WriteStringValue(ref arrayState, item);
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
using Google.Protobuf.Collections;
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation;
using Xunit;
using OtlpCommon = OpenTelemetry.Proto.Common.V1;
@ -13,19 +14,19 @@ public class OtlpAttributeTests
public void NullValueAttribute()
{
var kvp = new KeyValuePair<string, object>("key", null);
Assert.False(OtlpTagTransformer.Instance.TryTransformTag(kvp, out var _));
Assert.False(TryTransformTag(kvp, out var _));
}
[Fact]
public void EmptyArrays()
{
var kvp = new KeyValuePair<string, object>("key", Array.Empty<int>());
Assert.True(OtlpTagTransformer.Instance.TryTransformTag(kvp, out var attribute));
Assert.True(TryTransformTag(kvp, out var attribute));
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase);
Assert.Empty(attribute.Value.ArrayValue.Values);
kvp = new KeyValuePair<string, object>("key", Array.Empty<object>());
Assert.True(OtlpTagTransformer.Instance.TryTransformTag(kvp, out attribute));
Assert.True(TryTransformTag(kvp, out attribute));
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase);
Assert.Empty(attribute.Value.ArrayValue.Values);
}
@ -48,7 +49,7 @@ public class OtlpAttributeTests
public void IntegralTypesSupported(object value)
{
var kvp = new KeyValuePair<string, object>("key", value);
Assert.True(OtlpTagTransformer.Instance.TryTransformTag(kvp, out var attribute));
Assert.True(TryTransformTag(kvp, out var attribute));
switch (value)
{
@ -77,7 +78,7 @@ public class OtlpAttributeTests
public void FloatingPointTypesSupported(object value)
{
var kvp = new KeyValuePair<string, object>("key", value);
Assert.True(OtlpTagTransformer.Instance.TryTransformTag(kvp, out var attribute));
Assert.True(TryTransformTag(kvp, out var attribute));
switch (value)
{
@ -104,7 +105,7 @@ public class OtlpAttributeTests
public void BooleanTypeSupported(object value)
{
var kvp = new KeyValuePair<string, object>("key", value);
Assert.True(OtlpTagTransformer.Instance.TryTransformTag(kvp, out var attribute));
Assert.True(TryTransformTag(kvp, out var attribute));
switch (value)
{
@ -131,7 +132,7 @@ public class OtlpAttributeTests
public void StringTypesSupported(object value)
{
var kvp = new KeyValuePair<string, object>("key", value);
Assert.True(OtlpTagTransformer.Instance.TryTransformTag(kvp, out var attribute));
Assert.True(TryTransformTag(kvp, out var attribute));
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.StringValue, attribute.Value.ValueCase);
Assert.Equal(Convert.ToString(value), attribute.Value.StringValue);
}
@ -143,12 +144,12 @@ public class OtlpAttributeTests
var stringArray = new string[] { "a", "b", "c", string.Empty, null };
var kvp = new KeyValuePair<string, object>("key", charArray);
Assert.True(OtlpTagTransformer.Instance.TryTransformTag(kvp, out var attribute));
Assert.True(TryTransformTag(kvp, out var attribute));
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase);
Assert.Equal(charArray.Select(x => x.ToString()), attribute.Value.ArrayValue.Values.Select(x => x.StringValue));
kvp = new KeyValuePair<string, object>("key", stringArray);
Assert.True(OtlpTagTransformer.Instance.TryTransformTag(kvp, out attribute));
Assert.True(TryTransformTag(kvp, out attribute));
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase);
for (var i = 0; i < stringArray.Length; ++i)
@ -188,7 +189,7 @@ public class OtlpAttributeTests
foreach (var value in testValues)
{
var kvp = new KeyValuePair<string, object>("key", value);
Assert.True(OtlpTagTransformer.Instance.TryTransformTag(kvp, out var attribute));
Assert.True(TryTransformTag(kvp, out var attribute));
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.StringValue, attribute.Value.ValueCase);
Assert.Equal(value.ToString(), attribute.Value.StringValue);
}
@ -196,7 +197,7 @@ public class OtlpAttributeTests
foreach (var value in testArrayValues)
{
var kvp = new KeyValuePair<string, object>("key", value);
Assert.True(OtlpTagTransformer.Instance.TryTransformTag(kvp, out var attribute));
Assert.True(TryTransformTag(kvp, out var attribute));
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase);
var array = value as Array;
@ -220,10 +221,25 @@ public class OtlpAttributeTests
public void ExceptionInToStringIsCaught()
{
var kvp = new KeyValuePair<string, object>("key", new MyToStringMethodThrowsAnException());
Assert.False(OtlpTagTransformer.Instance.TryTransformTag(kvp, out var _));
Assert.False(TryTransformTag(kvp, out var _));
kvp = new KeyValuePair<string, object>("key", new object[] { 1, false, new MyToStringMethodThrowsAnException() });
Assert.False(OtlpTagTransformer.Instance.TryTransformTag(kvp, out var _));
Assert.False(TryTransformTag(kvp, out var _));
}
private static bool TryTransformTag(KeyValuePair<string, object> tag, out OtlpCommon.KeyValue attribute)
{
var destination = new RepeatedField<OtlpCommon.KeyValue>();
if (OtlpTagWriter.Instance.TryWriteTag(ref destination, tag))
{
Assert.NotEmpty(destination);
attribute = destination[0];
return true;
}
attribute = null;
return false;
}
private class MyToStringMethodThrowsAnException

View File

@ -61,6 +61,21 @@ internal static class OtlpTestHelpers
AssertOtlpAttributeValue(stringArray[j], actual[i].Value.ArrayValue.Values[j]);
}
expectedSize++;
}
else
{
var source = (Array)current;
Assert.Equal(source.Length, actual[i].Value.ArrayValue.Values.Count);
for (int j = 0; j < source.Length; j++)
{
var item = source.GetValue(j);
AssertOtlpAttributeValue(item, actual[i].Value.ArrayValue.Values[j]);
}
expectedSize++;
}
}

View File

@ -319,6 +319,7 @@ public class OtlpTraceExporterTests
new KeyValuePair<string, object>("int_array", new int[] { 1, 2 }),
new KeyValuePair<string, object>("double_array", new double[] { 1.0, 2.09 }),
new KeyValuePair<string, object>("string_array", new string[] { "a", "b" }),
new KeyValuePair<string, object>("datetime_array", new DateTime[] { DateTime.UtcNow, DateTime.Now }),
};
foreach (var kvp in attributes)