From 3d44019f0e0f28eeb7cec157aa235ec142a669f6 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Fri, 13 May 2022 08:47:36 -0700 Subject: [PATCH 01/30] WIP generalize transforming tags --- .../JaegerActivityExtensions.cs | 25 ++-- .../Implementation/JaegerTagTransformer.cs | 45 +++++++ .../OpenTelemetry.Exporter.Jaeger.csproj | 2 + .../Implementation/OtlpCommonExtensions.cs | 17 +-- .../Implementation/OtlpKeyValueTransformer.cs | 44 +++++++ ...etry.Exporter.OpenTelemetryProtocol.csproj | 1 + src/OpenTelemetry/Internal/TagTransformer.cs | 123 ++++++++++++++++++ src/OpenTelemetry/OpenTelemetry.csproj | 1 + .../JaegerActivityConversionTest.cs | 37 ++++-- 9 files changed, 256 insertions(+), 39 deletions(-) create mode 100644 src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs create mode 100644 src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs create mode 100644 src/OpenTelemetry/Internal/TagTransformer.cs diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs index 33a3f8ee332..7c79d036125 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs @@ -45,6 +45,8 @@ internal static class JaegerActivityExtensions private const long TicksPerMicrosecond = TimeSpan.TicksPerMillisecond / 1000; private const long UnixEpochMicroseconds = UnixEpochTicks / TicksPerMicrosecond; // 62,135,596,800,000,000 + private static JaegerTagTransformer tagTransformer = new JaegerTagTransformer(); + public static JaegerSpan ToJaegerSpan(this Activity activity) { var jaegerTags = new TagEnumerationState @@ -232,16 +234,7 @@ public static JaegerSpanRef ToJaegerSpanRef(this in ActivityLink link) public static JaegerTag ToJaegerTag(this KeyValuePair attribute) { - return attribute.Value switch - { - string s => new JaegerTag(attribute.Key, JaegerTagType.STRING, vStr: s), - int i => new JaegerTag(attribute.Key, JaegerTagType.LONG, vLong: Convert.ToInt64(i)), - long l => new JaegerTag(attribute.Key, JaegerTagType.LONG, vLong: l), - float f => new JaegerTag(attribute.Key, JaegerTagType.DOUBLE, vDouble: Convert.ToDouble(f)), - double d => new JaegerTag(attribute.Key, JaegerTagType.DOUBLE, vDouble: d), - bool b => new JaegerTag(attribute.Key, JaegerTagType.BOOL, vBool: b), - _ => new JaegerTag(attribute.Key, JaegerTagType.STRING, vStr: attribute.Value.ToString()), - }; + return tagTransformer.TransformTag(attribute); } public static long ToEpochMicroseconds(this DateTime utcDateTime) @@ -316,14 +309,16 @@ private struct TagEnumerationState : IActivityEnumerator activityTag) { - if (activityTag.Value is Array) - { - ProcessJaegerTagArray(ref this.Tags, activityTag); - } - else if (activityTag.Value != null) + if (activityTag.Value != null) { var key = activityTag.Key; var jaegerTag = activityTag.ToJaegerTag(); + + if (jaegerTag.Equals(default(JaegerTag))) + { + return true; + } + if (jaegerTag.VStr != null) { PeerServiceResolver.InspectTag(ref this, key, jaegerTag.VStr); diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs new file mode 100644 index 00000000000..27ce9097e9c --- /dev/null +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs @@ -0,0 +1,45 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Exporter.Jaeger.Implementation +{ + internal class JaegerTagTransformer : TagTransformer + { + public override bool JsonifyArrays => true; + + public override JaegerTag TransformIntegralTag(string key, long value) + { + return new JaegerTag(key, JaegerTagType.LONG, vLong: value); + } + + public override JaegerTag TransformFloatingPointTag(string key, double value) + { + return new JaegerTag(key, JaegerTagType.DOUBLE, vDouble: value); + } + + public override JaegerTag TransformBooleanTag(string key, bool value) + { + return new JaegerTag(key, JaegerTagType.BOOL, vBool: value); + } + + public override JaegerTag TransformStringTag(string key, string value) + { + return new JaegerTag(key, JaegerTagType.STRING, vStr: value); + } + } +} diff --git a/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj b/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj index 5b8c06244cc..4f51b3ecab5 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj +++ b/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj @@ -33,10 +33,12 @@ + + diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs index 4185969a483..2c692f8c55c 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs @@ -23,23 +23,12 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation { internal static class OtlpCommonExtensions { + private static OtlpKeyValueTransformer tagTransformer = new OtlpKeyValueTransformer(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OtlpCommon.KeyValue ToOtlpAttribute(this KeyValuePair kvp) { - if (kvp.Value == null) - { - return null; - } - - var value = ToOtlpValue(kvp.Value); - - if (value == null) - { - OpenTelemetryProtocolExporterEventSource.Log.UnsupportedAttributeType(kvp.Value.GetType().ToString(), kvp.Key); - return null; - } - - return new OtlpCommon.KeyValue { Key = kvp.Key, Value = value }; + return tagTransformer.TransformTag(kvp); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs new file mode 100644 index 00000000000..febded582b4 --- /dev/null +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs @@ -0,0 +1,44 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using OpenTelemetry.Internal; +using OtlpCommon = Opentelemetry.Proto.Common.V1; + +namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation +{ + internal class OtlpKeyValueTransformer : TagTransformer + { + public override OtlpCommon.KeyValue TransformIntegralTag(string key, long value) + { + return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { IntValue = value } }; + } + + public override OtlpCommon.KeyValue TransformFloatingPointTag(string key, double value) + { + return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { DoubleValue = value } }; + } + + public override OtlpCommon.KeyValue TransformBooleanTag(string key, bool value) + { + return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { BoolValue = value } }; + } + + public override OtlpCommon.KeyValue TransformStringTag(string key, string value) + { + return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { StringValue = value } }; + } + } +} diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj index e01f6ec65b5..262cfba18ce 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj @@ -49,6 +49,7 @@ + diff --git a/src/OpenTelemetry/Internal/TagTransformer.cs b/src/OpenTelemetry/Internal/TagTransformer.cs new file mode 100644 index 00000000000..cd998a4a975 --- /dev/null +++ b/src/OpenTelemetry/Internal/TagTransformer.cs @@ -0,0 +1,123 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenTelemetry.Internal; + +internal abstract class TagTransformer +{ + public virtual bool JsonifyArrays => false; + + public abstract T TransformIntegralTag(string key, long value); + + public abstract T TransformFloatingPointTag(string key, double value); + + public abstract T TransformBooleanTag(string key, bool value); + + public abstract T TransformStringTag(string key, string value); + + public T TransformTag(KeyValuePair tag) + { + if (tag.Value == null) + { + return default; + } + + T result = default; + switch (tag.Value) + { + case char: + case string: + return this.TransformStringTag(tag.Key, Convert.ToString(tag.Value)); + case bool b: + return this.TransformBooleanTag(tag.Key, b); + case byte: + case sbyte: + case short: + case ushort: + case int: + case uint: + case long: + return this.TransformIntegralTag(tag.Key, Convert.ToInt64(tag.Value)); + case float: + case double: + return this.TransformFloatingPointTag(tag.Key, Convert.ToDouble(tag.Value)); + case Array array: + return this.JsonifyArrays + ? this.ToJsonArray(tag.Key, array) + : default; + + // All other types are converted to strings including the following + // built-in value types: + // case nint: Pointer type. + // case nuint: Pointer type. + // case ulong: May throw an exception on overflow. + // case decimal: Converting to double produces rounding errors. + default: + try + { + result = this.TransformStringTag(tag.Key, tag.Value.ToString()); + } + catch + { + } + + break; + } + + // if (result == null) + // { + // // OpenTelemetryProtocolExporterEventSource.Log.UnsupportedAttributeType(kvp.Value.GetType().ToString(), kvp.Key); + // } + + return result; + } + + private T ToJsonArray(string key, Array array) + { + return array switch + { + char[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), + string[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), + bool[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), + byte[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), + sbyte[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), + short[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), + ushort[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), + int[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), + uint[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), + long[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), + float[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), + double[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), + _ => this.StringifyArray(key, array), + }; + } + + private T StringifyArray(string key, Array array) + { + try + { + return this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize((array as object[]).Select(x => x?.ToString()))); + } + catch + { + return default; + } + } +} diff --git a/src/OpenTelemetry/OpenTelemetry.csproj b/src/OpenTelemetry/OpenTelemetry.csproj index a247eba4f37..f8e5910d7dc 100644 --- a/src/OpenTelemetry/OpenTelemetry.csproj +++ b/src/OpenTelemetry/OpenTelemetry.csproj @@ -19,6 +19,7 @@ + diff --git a/test/OpenTelemetry.Exporter.Jaeger.Tests/Implementation/JaegerActivityConversionTest.cs b/test/OpenTelemetry.Exporter.Jaeger.Tests/Implementation/JaegerActivityConversionTest.cs index 44567a04294..0b31b68c79c 100644 --- a/test/OpenTelemetry.Exporter.Jaeger.Tests/Implementation/JaegerActivityConversionTest.cs +++ b/test/OpenTelemetry.Exporter.Jaeger.Tests/Implementation/JaegerActivityConversionTest.cs @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + using System; using System.Collections.Generic; using System.Diagnostics; @@ -298,24 +299,29 @@ public void JaegerActivityConverterTest_ConvertActivityToJaegerSpan_NoLinks() Assert.Equal(true, tag.VBool); tag = tags[6]; - Assert.Equal(JaegerTagType.LONG, tag.VType); + Assert.Equal(JaegerTagType.STRING, tag.VType); Assert.Equal("int_array", tag.Key); - Assert.Equal(1, tag.VLong); + Assert.Equal(System.Text.Json.JsonSerializer.Serialize(new[] { 1, 2 }), tag.VStr); - tag = tags[8]; - Assert.Equal(JaegerTagType.BOOL, tag.VType); + tag = tags[7]; + Assert.Equal(JaegerTagType.STRING, tag.VType); Assert.Equal("bool_array", tag.Key); - Assert.Equal(true, tag.VBool); + Assert.Equal(System.Text.Json.JsonSerializer.Serialize(new[] { true, false }), tag.VStr); - tag = tags[10]; - Assert.Equal(JaegerTagType.DOUBLE, tag.VType); + tag = tags[8]; + Assert.Equal(JaegerTagType.STRING, tag.VType); Assert.Equal("double_array", tag.Key); - Assert.Equal(1, tag.VDouble); + Assert.Equal(System.Text.Json.JsonSerializer.Serialize(new[] { 1, 1.1 }), tag.VStr); - tag = tags[12]; + tag = tags[9]; Assert.Equal(JaegerTagType.STRING, tag.VType); Assert.Equal("string_array", tag.Key); - Assert.Equal("a", tag.VStr); + Assert.Equal(System.Text.Json.JsonSerializer.Serialize(new[] { "a", "b" }), tag.VStr); + + tag = tags[10]; + Assert.Equal(JaegerTagType.STRING, tag.VType); + Assert.Equal("obj_array", tag.Key); + Assert.Equal(System.Text.Json.JsonSerializer.Serialize(new[] { 1.ToString(), false.ToString(), new object().ToString(), "string", string.Empty, null }), tag.VStr); // The second to last tag should be span.kind in this case tag = tags[tags.Length - 2]; @@ -635,6 +641,8 @@ internal static Activity CreateTestActivity( var attributes = new Dictionary { + { "exceptionFromToString", new MyToStringMethodThrowsAnException() }, + { "exceptionFromToStringInArray", new MyToStringMethodThrowsAnException[] { new MyToStringMethodThrowsAnException() } }, { "stringKey", "value" }, { "longKey", 1L }, { "longKey2", 1 }, @@ -645,6 +653,7 @@ internal static Activity CreateTestActivity( { "bool_array", new bool[] { true, false } }, { "double_array", new double[] { 1.0, 1.1 } }, { "string_array", new string[] { "a", "b" } }, + { "obj_array", new object[] { 1, false, new object(), "string", string.Empty, null } }, }; if (additionalAttributes != null) { @@ -847,5 +856,13 @@ public override string ToString() return this.Name; } } + + private class MyToStringMethodThrowsAnException + { + public override string ToString() + { + throw new Exception("Nope."); + } + } } } From 6653468c3fd2ce099d254a653177eb93dadc5fd1 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Tue, 17 May 2022 15:24:15 -0700 Subject: [PATCH 02/30] Make abstract methods protected --- .../Implementation/JaegerTagTransformer.cs | 10 +++++----- .../Implementation/OtlpKeyValueTransformer.cs | 8 ++++---- src/OpenTelemetry/Internal/TagTransformer.cs | 18 +++++++++--------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs index 27ce9097e9c..a3124588008 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs @@ -20,24 +20,24 @@ namespace OpenTelemetry.Exporter.Jaeger.Implementation { internal class JaegerTagTransformer : TagTransformer { - public override bool JsonifyArrays => true; + protected override bool JsonifyArrays => true; - public override JaegerTag TransformIntegralTag(string key, long value) + protected override JaegerTag TransformIntegralTag(string key, long value) { return new JaegerTag(key, JaegerTagType.LONG, vLong: value); } - public override JaegerTag TransformFloatingPointTag(string key, double value) + protected override JaegerTag TransformFloatingPointTag(string key, double value) { return new JaegerTag(key, JaegerTagType.DOUBLE, vDouble: value); } - public override JaegerTag TransformBooleanTag(string key, bool value) + protected override JaegerTag TransformBooleanTag(string key, bool value) { return new JaegerTag(key, JaegerTagType.BOOL, vBool: value); } - public override JaegerTag TransformStringTag(string key, string value) + protected override JaegerTag TransformStringTag(string key, string value) { return new JaegerTag(key, JaegerTagType.STRING, vStr: value); } diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs index febded582b4..ae7bdd04eb2 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs @@ -21,22 +21,22 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation { internal class OtlpKeyValueTransformer : TagTransformer { - public override OtlpCommon.KeyValue TransformIntegralTag(string key, long value) + protected override OtlpCommon.KeyValue TransformIntegralTag(string key, long value) { return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { IntValue = value } }; } - public override OtlpCommon.KeyValue TransformFloatingPointTag(string key, double value) + protected override OtlpCommon.KeyValue TransformFloatingPointTag(string key, double value) { return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { DoubleValue = value } }; } - public override OtlpCommon.KeyValue TransformBooleanTag(string key, bool value) + protected override OtlpCommon.KeyValue TransformBooleanTag(string key, bool value) { return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { BoolValue = value } }; } - public override OtlpCommon.KeyValue TransformStringTag(string key, string value) + protected override OtlpCommon.KeyValue TransformStringTag(string key, string value) { return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { StringValue = value } }; } diff --git a/src/OpenTelemetry/Internal/TagTransformer.cs b/src/OpenTelemetry/Internal/TagTransformer.cs index cd998a4a975..3363abefdca 100644 --- a/src/OpenTelemetry/Internal/TagTransformer.cs +++ b/src/OpenTelemetry/Internal/TagTransformer.cs @@ -22,15 +22,7 @@ namespace OpenTelemetry.Internal; internal abstract class TagTransformer { - public virtual bool JsonifyArrays => false; - - public abstract T TransformIntegralTag(string key, long value); - - public abstract T TransformFloatingPointTag(string key, double value); - - public abstract T TransformBooleanTag(string key, bool value); - - public abstract T TransformStringTag(string key, string value); + protected virtual bool JsonifyArrays => false; public T TransformTag(KeyValuePair tag) { @@ -89,6 +81,14 @@ public T TransformTag(KeyValuePair tag) return result; } + protected abstract T TransformIntegralTag(string key, long value); + + protected abstract T TransformFloatingPointTag(string key, double value); + + protected abstract T TransformBooleanTag(string key, bool value); + + protected abstract T TransformStringTag(string key, string value); + private T ToJsonArray(string key, Array array) { return array switch From bd597449633dc313e61d7e55cc42b18cd934336a Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Tue, 17 May 2022 15:58:53 -0700 Subject: [PATCH 03/30] Add ZipkinTagTransformer --- .../Implementation/ZipkinSpan.cs | 27 +-------- .../Implementation/ZipkinTagTransformer.cs | 57 +++++++++++++++++++ .../OpenTelemetry.Exporter.Zipkin.csproj | 1 + .../ZipkinExporter.cs | 4 +- 4 files changed, 64 insertions(+), 25 deletions(-) create mode 100644 src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs index 1ee3b7cf236..e79cbbc23c4 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs @@ -91,7 +91,7 @@ public void Return() this.Tags.Return(); } - public void Write(Utf8JsonWriter writer) + public void Write(Utf8JsonWriter writer, ZipkinTagTransformer tagTransformer) { writer.WriteStartObject(); @@ -178,12 +178,12 @@ public void Write(Utf8JsonWriter writer) { foreach (var tag in this.LocalEndpoint.Tags ?? Enumerable.Empty>()) { - writer.WriteString(tag.Key, ConvertObjectToString(tag.Value)); + tagTransformer.TransformTag(tag); } foreach (var tag in this.Tags) { - writer.WriteString(tag.Key, ConvertObjectToString(tag.Value)); + tagTransformer.TransformTag(tag); } } finally @@ -196,26 +196,5 @@ public void Write(Utf8JsonWriter writer) writer.WriteEndObject(); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static string ConvertObjectToString(object obj) - { - return obj switch - { - string stringVal => stringVal, - bool boolVal => GetBoolString(boolVal), - int[] arrayValue => string.Join(",", arrayValue), - long[] arrayValue => string.Join(",", arrayValue), - double[] arrayValue => string.Join(",", arrayValue), - bool[] arrayValue => string.Join(",", arrayValue.Select(GetBoolString)), - _ => obj.ToString(), - }; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static string GetBoolString(bool value) - { - return value ? "true" : "false"; - } } } diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs new file mode 100644 index 00000000000..aa2223c1734 --- /dev/null +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs @@ -0,0 +1,57 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Text.Json; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Exporter.Zipkin.Implementation +{ + internal class ZipkinTagTransformer : TagTransformer + { + private readonly Utf8JsonWriter writer; + + public ZipkinTagTransformer(Utf8JsonWriter writer) + { + this.writer = writer; + } + + protected override bool JsonifyArrays => true; + + protected override bool TransformIntegralTag(string key, long value) + { + this.writer.WriteString(key, value.ToString()); + return true; + } + + protected override bool TransformFloatingPointTag(string key, double value) + { + this.writer.WriteString(key, value.ToString()); + return true; + } + + protected override bool TransformBooleanTag(string key, bool value) + { + this.writer.WriteString(key, value ? "true" : "false"); + return true; + } + + protected override bool TransformStringTag(string key, string value) + { + this.writer.WriteString(key, value.ToString()); + return true; + } + } +} diff --git a/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj b/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj index bd7d123d74f..c3eca2e116a 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj +++ b/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj @@ -28,6 +28,7 @@ + diff --git a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs index 1927a4f754e..650f86e0814 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs @@ -197,6 +197,7 @@ private sealed class JsonContent : HttpContent private readonly ZipkinExporter exporter; private readonly Batch batch; private Utf8JsonWriter writer; + private ZipkinTagTransformer tagTransformer; public JsonContent(ZipkinExporter exporter, in Batch batch) { @@ -232,6 +233,7 @@ private void SerializeToStreamInternal(Stream stream) if (this.writer == null) { this.writer = new Utf8JsonWriter(stream); + this.tagTransformer = new ZipkinTagTransformer(this.writer); } else { @@ -244,7 +246,7 @@ private void SerializeToStreamInternal(Stream stream) { var zipkinSpan = activity.ToZipkinSpan(this.exporter.LocalEndpoint, this.exporter.options.UseShortTraceIds); - zipkinSpan.Write(this.writer); + zipkinSpan.Write(this.writer, this.tagTransformer); zipkinSpan.Return(); if (this.writer.BytesPending >= this.exporter.maxPayloadSizeInBytes) From 84a1ee7a481eae5943574f828bc347d50df5523a Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Tue, 17 May 2022 16:07:17 -0700 Subject: [PATCH 04/30] Simplify ZipkinTagTransformer --- .../Implementation/ZipkinSpan.cs | 4 +-- .../Implementation/ZipkinTagTransformer.cs | 34 +++---------------- .../ZipkinExporter.cs | 2 +- 3 files changed, 8 insertions(+), 32 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs index e79cbbc23c4..9c42239c46c 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs @@ -178,12 +178,12 @@ public void Write(Utf8JsonWriter writer, ZipkinTagTransformer tagTransformer) { foreach (var tag in this.LocalEndpoint.Tags ?? Enumerable.Empty>()) { - tagTransformer.TransformTag(tag); + writer.WriteString(tag.Key, tagTransformer.TransformTag(tag)); } foreach (var tag in this.Tags) { - tagTransformer.TransformTag(tag); + writer.WriteString(tag.Key, tagTransformer.TransformTag(tag)); } } finally diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs index aa2223c1734..d07957d0426 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs @@ -14,44 +14,20 @@ // limitations under the License. // -using System.Text.Json; using OpenTelemetry.Internal; namespace OpenTelemetry.Exporter.Zipkin.Implementation { - internal class ZipkinTagTransformer : TagTransformer + internal class ZipkinTagTransformer : TagTransformer { - private readonly Utf8JsonWriter writer; - - public ZipkinTagTransformer(Utf8JsonWriter writer) - { - this.writer = writer; - } - protected override bool JsonifyArrays => true; - protected override bool TransformIntegralTag(string key, long value) - { - this.writer.WriteString(key, value.ToString()); - return true; - } + protected override string TransformIntegralTag(string key, long value) => value.ToString(); - protected override bool TransformFloatingPointTag(string key, double value) - { - this.writer.WriteString(key, value.ToString()); - return true; - } + protected override string TransformFloatingPointTag(string key, double value) => value.ToString(); - protected override bool TransformBooleanTag(string key, bool value) - { - this.writer.WriteString(key, value ? "true" : "false"); - return true; - } + protected override string TransformBooleanTag(string key, bool value) => value ? "true" : "false"; - protected override bool TransformStringTag(string key, string value) - { - this.writer.WriteString(key, value.ToString()); - return true; - } + protected override string TransformStringTag(string key, string value) => value; } } diff --git a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs index 650f86e0814..b3fd9d2d642 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs @@ -233,7 +233,7 @@ private void SerializeToStreamInternal(Stream stream) if (this.writer == null) { this.writer = new Utf8JsonWriter(stream); - this.tagTransformer = new ZipkinTagTransformer(this.writer); + this.tagTransformer = new ZipkinTagTransformer(); } else { From 9cbb855af2afe32782b814850d4c1d1b6f181316 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Tue, 17 May 2022 17:40:31 -0700 Subject: [PATCH 05/30] Refactor OTLP array attribute transform --- .../Implementation/OtlpCommonExtensions.cs | 91 ------------------- .../Implementation/OtlpKeyValueTransformer.cs | 64 +++++++++++++ src/OpenTelemetry/Internal/TagTransformer.cs | 30 +++++- 3 files changed, 93 insertions(+), 92 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs index 7ff1502424a..fd8b75de51b 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs @@ -14,7 +14,6 @@ // limitations under the License. // -using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using OtlpCommon = Opentelemetry.Proto.Common.V1; @@ -30,95 +29,5 @@ public static OtlpCommon.KeyValue ToOtlpAttribute(this KeyValuePair +using System; using OpenTelemetry.Internal; using OtlpCommon = Opentelemetry.Proto.Common.V1; @@ -40,5 +41,68 @@ protected override OtlpCommon.KeyValue TransformStringTag(string key, string val { return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { StringValue = value } }; } + + protected override OtlpCommon.KeyValue TransformIntegralArrayTag(string key, Array array) + { + var arrayValue = new OtlpCommon.ArrayValue(); + + foreach (var item in array) + { + var anyValue = new OtlpCommon.AnyValue { IntValue = Convert.ToInt64(item) }; + arrayValue.Values.Add(anyValue); + } + + return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { ArrayValue = arrayValue } }; + } + + protected override OtlpCommon.KeyValue TransformFloatingPointArrayTag(string key, Array array) + { + var arrayValue = new OtlpCommon.ArrayValue(); + + foreach (var item in array) + { + var anyValue = new OtlpCommon.AnyValue { DoubleValue = Convert.ToDouble(item) }; + arrayValue.Values.Add(anyValue); + } + + return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { ArrayValue = arrayValue } }; + } + + protected override OtlpCommon.KeyValue TransformBooleanArrayTag(string key, Array array) + { + var arrayValue = new OtlpCommon.ArrayValue(); + + foreach (var item in array) + { + var anyValue = new OtlpCommon.AnyValue { BoolValue = Convert.ToBoolean(item) }; + arrayValue.Values.Add(anyValue); + } + + return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { ArrayValue = arrayValue } }; + } + + protected override OtlpCommon.KeyValue TransformStringArrayTag(string key, Array array) + { + var arrayValue = new OtlpCommon.ArrayValue(); + + foreach (var item in array) + { + try + { + var value = item != null + ? Convert.ToString(item) + : null; + + var anyValue = item != null ? new OtlpCommon.AnyValue { StringValue = value } : new OtlpCommon.AnyValue { }; + arrayValue.Values.Add(anyValue); + } + catch + { + return default; + } + } + + return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { ArrayValue = arrayValue } }; + } } } diff --git a/src/OpenTelemetry/Internal/TagTransformer.cs b/src/OpenTelemetry/Internal/TagTransformer.cs index 3363abefdca..1c29a43eb6b 100644 --- a/src/OpenTelemetry/Internal/TagTransformer.cs +++ b/src/OpenTelemetry/Internal/TagTransformer.cs @@ -53,7 +53,7 @@ public T TransformTag(KeyValuePair tag) case Array array: return this.JsonifyArrays ? this.ToJsonArray(tag.Key, array) - : default; + : this.TransformArrayTag(tag.Key, array); // All other types are converted to strings including the following // built-in value types: @@ -89,6 +89,34 @@ public T TransformTag(KeyValuePair tag) protected abstract T TransformStringTag(string key, string value); + protected virtual T TransformIntegralArrayTag(string key, Array array) => default; + + protected virtual T TransformFloatingPointArrayTag(string key, Array array) => default; + + protected virtual T TransformBooleanArrayTag(string key, Array array) => default; + + protected virtual T TransformStringArrayTag(string key, Array array) => default; + + protected virtual T TransformArrayTag(string key, Array array) + { + return array switch + { + char[] => this.TransformStringArrayTag(key, array), + string[] => this.TransformStringArrayTag(key, array), + bool[] => this.TransformBooleanArrayTag(key, array), + byte[] => this.TransformIntegralArrayTag(key, array), + sbyte[] => this.TransformIntegralArrayTag(key, array), + short[] => this.TransformIntegralArrayTag(key, array), + ushort[] => this.TransformIntegralArrayTag(key, array), + int[] => this.TransformIntegralArrayTag(key, array), + uint[] => this.TransformIntegralArrayTag(key, array), + long[] => this.TransformIntegralArrayTag(key, array), + float[] => this.TransformFloatingPointArrayTag(key, array), + double[] => this.TransformFloatingPointArrayTag(key, array), + _ => this.TransformStringArrayTag(key, array), + }; + } + private T ToJsonArray(string key, Array array) { return array switch From 493ed24fc09937437f2d1b1b38799665c117e843 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Fri, 20 May 2022 12:43:34 -0700 Subject: [PATCH 06/30] Unused using --- src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs index 9c42239c46c..08d4a490c3d 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs @@ -17,7 +17,6 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Runtime.CompilerServices; using System.Text.Json; using System.Threading; using OpenTelemetry.Internal; From 0ad99febf4e2a34c2051d5fc53af56ecb69f9496 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Fri, 20 May 2022 13:01:45 -0700 Subject: [PATCH 07/30] Change Zipkin test. Array values are now represented as JSON arrays. --- test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs b/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs index 2e34b9d465e..37b715501a6 100644 --- a/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs +++ b/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs @@ -359,7 +359,7 @@ public void IntegrationTest( } Assert.Equal( - $@"[{{""traceId"":""{traceId}"",""name"":""Name"",{parentId}""id"":""{ZipkinActivityConversionExtensions.EncodeSpanId(context.SpanId)}"",""kind"":""CLIENT"",""timestamp"":{timestamp},""duration"":60000000,""localEndpoint"":{{""serviceName"":""{serviceName}""{ipInformation}}},""remoteEndpoint"":{{""serviceName"":""http://localhost:44312/""}},""annotations"":[{{""timestamp"":{eventTimestamp},""value"":""Event1""}},{{""timestamp"":{eventTimestamp},""value"":""Event2""}}],""tags"":{{{resourceTags}""stringKey"":""value"",""longKey"":""1"",""longKey2"":""1"",""doubleKey"":""1"",""doubleKey2"":""1"",""longArrayKey"":""1,2"",""boolKey"":""true"",""boolArrayKey"":""true,false"",""http.host"":""http://localhost:44312/"",{statusTag}{errorTag}""otel.library.name"":""CreateTestActivity"",""peer.service"":""http://localhost:44312/""}}}}]", + $@"[{{""traceId"":""{traceId}"",""name"":""Name"",{parentId}""id"":""{ZipkinActivityConversionExtensions.EncodeSpanId(context.SpanId)}"",""kind"":""CLIENT"",""timestamp"":{timestamp},""duration"":60000000,""localEndpoint"":{{""serviceName"":""{serviceName}""{ipInformation}}},""remoteEndpoint"":{{""serviceName"":""http://localhost:44312/""}},""annotations"":[{{""timestamp"":{eventTimestamp},""value"":""Event1""}},{{""timestamp"":{eventTimestamp},""value"":""Event2""}}],""tags"":{{{resourceTags}""stringKey"":""value"",""longKey"":""1"",""longKey2"":""1"",""doubleKey"":""1"",""doubleKey2"":""1"",""longArrayKey"":""[1,2]"",""boolKey"":""true"",""boolArrayKey"":""[true,false]"",""http.host"":""http://localhost:44312/"",{statusTag}{errorTag}""otel.library.name"":""CreateTestActivity"",""peer.service"":""http://localhost:44312/""}}}}]", Responses[requestId]); } From e8a52a40761d7f31bf29c9d0a5d36a6327b36002 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Fri, 20 May 2022 15:59:47 -0700 Subject: [PATCH 08/30] net462 and netcoreapp3.1 runtimes are confused about pointer types --- src/OpenTelemetry/Internal/TagTransformer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry/Internal/TagTransformer.cs b/src/OpenTelemetry/Internal/TagTransformer.cs index 1c29a43eb6b..0986d47fa7a 100644 --- a/src/OpenTelemetry/Internal/TagTransformer.cs +++ b/src/OpenTelemetry/Internal/TagTransformer.cs @@ -108,9 +108,9 @@ protected virtual T TransformArrayTag(string key, Array array) sbyte[] => this.TransformIntegralArrayTag(key, array), short[] => this.TransformIntegralArrayTag(key, array), ushort[] => this.TransformIntegralArrayTag(key, array), - int[] => this.TransformIntegralArrayTag(key, array), + int[] => array is nint[] ? this.TransformStringArrayTag(key, array) : this.TransformIntegralArrayTag(key, array), uint[] => this.TransformIntegralArrayTag(key, array), - long[] => this.TransformIntegralArrayTag(key, array), + long[] => array is nuint[] ? this.TransformStringArrayTag(key, array) : this.TransformIntegralArrayTag(key, array), float[] => this.TransformFloatingPointArrayTag(key, array), double[] => this.TransformFloatingPointArrayTag(key, array), _ => this.TransformStringArrayTag(key, array), From 643742e340d8714b2c1518c581c794163faf8e97 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Mon, 23 May 2022 17:36:35 -0700 Subject: [PATCH 09/30] Handle array values better --- .../Implementation/JaegerTagTransformer.cs | 2 - .../Implementation/OtlpKeyValueTransformer.cs | 71 ++++++---------- ...etry.Exporter.OpenTelemetryProtocol.csproj | 1 + .../Implementation/ZipkinTagTransformer.cs | 2 - .../Internal/TagAndValueTransformer.cs | 56 +++++++++++++ src/OpenTelemetry/Internal/TagTransformer.cs | 82 ++++++++----------- 6 files changed, 112 insertions(+), 102 deletions(-) create mode 100644 src/OpenTelemetry/Internal/TagAndValueTransformer.cs diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs index a3124588008..5434ed0200a 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs @@ -20,8 +20,6 @@ namespace OpenTelemetry.Exporter.Jaeger.Implementation { internal class JaegerTagTransformer : TagTransformer { - protected override bool JsonifyArrays => true; - protected override JaegerTag TransformIntegralTag(string key, long value) { return new JaegerTag(key, JaegerTagType.LONG, vLong: value); diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs index caf855a81b6..6faab48eab4 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs @@ -20,89 +20,64 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation { - internal class OtlpKeyValueTransformer : TagTransformer + internal class OtlpKeyValueTransformer : TagAndValueTransformer { protected override OtlpCommon.KeyValue TransformIntegralTag(string key, long value) { - return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { IntValue = value } }; + return new OtlpCommon.KeyValue { Key = key, Value = this.TransformIntegralValue(value) }; } protected override OtlpCommon.KeyValue TransformFloatingPointTag(string key, double value) { - return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { DoubleValue = value } }; + return new OtlpCommon.KeyValue { Key = key, Value = this.TransformFloatingPointValue(value) }; } protected override OtlpCommon.KeyValue TransformBooleanTag(string key, bool value) { - return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { BoolValue = value } }; + return new OtlpCommon.KeyValue { Key = key, Value = this.TransformBooleanValue(value) }; } protected override OtlpCommon.KeyValue TransformStringTag(string key, string value) { - return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { StringValue = value } }; + return new OtlpCommon.KeyValue { Key = key, Value = this.TransformStringValue(value) }; } - protected override OtlpCommon.KeyValue TransformIntegralArrayTag(string key, Array array) + protected override OtlpCommon.KeyValue TransformArrayTag(string key, Array array) { - var arrayValue = new OtlpCommon.ArrayValue(); - - foreach (var item in array) - { - var anyValue = new OtlpCommon.AnyValue { IntValue = Convert.ToInt64(item) }; - arrayValue.Values.Add(anyValue); - } - - return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { ArrayValue = arrayValue } }; + return new OtlpCommon.KeyValue { Key = key, Value = this.TransformArrayValue(array) }; } - protected override OtlpCommon.KeyValue TransformFloatingPointArrayTag(string key, Array array) + protected override OtlpCommon.AnyValue TransformIntegralValue(long value) { - var arrayValue = new OtlpCommon.ArrayValue(); - - foreach (var item in array) - { - var anyValue = new OtlpCommon.AnyValue { DoubleValue = Convert.ToDouble(item) }; - arrayValue.Values.Add(anyValue); - } - - return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { ArrayValue = arrayValue } }; + return new OtlpCommon.AnyValue { IntValue = value }; } - protected override OtlpCommon.KeyValue TransformBooleanArrayTag(string key, Array array) + protected override OtlpCommon.AnyValue TransformFloatingPointValue(double value) { - var arrayValue = new OtlpCommon.ArrayValue(); + return new OtlpCommon.AnyValue { DoubleValue = value }; + } - foreach (var item in array) - { - var anyValue = new OtlpCommon.AnyValue { BoolValue = Convert.ToBoolean(item) }; - arrayValue.Values.Add(anyValue); - } + protected override OtlpCommon.AnyValue TransformBooleanValue(bool value) + { + return new OtlpCommon.AnyValue { BoolValue = value }; + } - return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { ArrayValue = arrayValue } }; + protected override OtlpCommon.AnyValue TransformStringValue(string value) + { + return new OtlpCommon.AnyValue { StringValue = value }; } - protected override OtlpCommon.KeyValue TransformStringArrayTag(string key, Array array) + protected override OtlpCommon.AnyValue TransformArrayValue(Array array) { var arrayValue = new OtlpCommon.ArrayValue(); foreach (var item in array) { - try - { - var value = item != null - ? Convert.ToString(item) - : null; - - var anyValue = item != null ? new OtlpCommon.AnyValue { StringValue = value } : new OtlpCommon.AnyValue { }; - arrayValue.Values.Add(anyValue); - } - catch - { - return default; - } + var value = item != null ? this.TransformValue(item) : new OtlpCommon.AnyValue(); + arrayValue.Values.Add(value); } - return new OtlpCommon.KeyValue { Key = key, Value = new OtlpCommon.AnyValue { ArrayValue = arrayValue } }; + return new OtlpCommon.AnyValue { ArrayValue = arrayValue }; } } } diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj index 262cfba18ce..fdb451dd39f 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj @@ -50,6 +50,7 @@ + diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs index d07957d0426..6b8e8b16ff3 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs @@ -20,8 +20,6 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation { internal class ZipkinTagTransformer : TagTransformer { - protected override bool JsonifyArrays => true; - protected override string TransformIntegralTag(string key, long value) => value.ToString(); protected override string TransformFloatingPointTag(string key, double value) => value.ToString(); diff --git a/src/OpenTelemetry/Internal/TagAndValueTransformer.cs b/src/OpenTelemetry/Internal/TagAndValueTransformer.cs new file mode 100644 index 00000000000..43bc473e64f --- /dev/null +++ b/src/OpenTelemetry/Internal/TagAndValueTransformer.cs @@ -0,0 +1,56 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using OpenTelemetry.Internal; + +internal abstract class TagAndValueTransformer : TagTransformer +{ + public TValue TransformValue(object value) + { + switch (value) + { + case char: + case string: + return this.TransformStringValue(Convert.ToString(value)); + case bool b: + return this.TransformBooleanValue(b); + case byte: + case sbyte: + case short: + case ushort: + case int: + case uint: + case long: + return this.TransformIntegralValue(Convert.ToInt64(value)); + case float: + case double: + return this.TransformFloatingPointValue(Convert.ToDouble(value)); + default: + return default(TValue); + } + } + + protected abstract TValue TransformIntegralValue(long value); + + protected abstract TValue TransformFloatingPointValue(double value); + + protected abstract TValue TransformBooleanValue(bool value); + + protected abstract TValue TransformStringValue(string value); + + protected abstract TValue TransformArrayValue(Array value); +} diff --git a/src/OpenTelemetry/Internal/TagTransformer.cs b/src/OpenTelemetry/Internal/TagTransformer.cs index 0986d47fa7a..f6e83e2fb6a 100644 --- a/src/OpenTelemetry/Internal/TagTransformer.cs +++ b/src/OpenTelemetry/Internal/TagTransformer.cs @@ -16,14 +16,11 @@ using System; using System.Collections.Generic; -using System.Linq; namespace OpenTelemetry.Internal; internal abstract class TagTransformer { - protected virtual bool JsonifyArrays => false; - public T TransformTag(KeyValuePair tag) { if (tag.Value == null) @@ -51,9 +48,7 @@ public T TransformTag(KeyValuePair tag) case double: return this.TransformFloatingPointTag(tag.Key, Convert.ToDouble(tag.Value)); case Array array: - return this.JsonifyArrays - ? this.ToJsonArray(tag.Key, array) - : this.TransformArrayTag(tag.Key, array); + return this.TransformArrayTagInternal(tag.Key, array); // All other types are converted to strings including the following // built-in value types: @@ -68,6 +63,7 @@ public T TransformTag(KeyValuePair tag) } catch { + // If ToString throws an exception then the tag is ignored. } break; @@ -89,63 +85,49 @@ public T TransformTag(KeyValuePair tag) protected abstract T TransformStringTag(string key, string value); - protected virtual T TransformIntegralArrayTag(string key, Array array) => default; - - protected virtual T TransformFloatingPointArrayTag(string key, Array array) => default; - - protected virtual T TransformBooleanArrayTag(string key, Array array) => default; - - protected virtual T TransformStringArrayTag(string key, Array array) => default; + protected virtual T TransformArrayTag(string key, Array array) => + this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(array)); - protected virtual T TransformArrayTag(string key, Array array) + private T TransformArrayTagInternal(string key, Array array) { + // This switch ensures the values of the resultant array-valued tag are of the same type. return array switch { - char[] => this.TransformStringArrayTag(key, array), - string[] => this.TransformStringArrayTag(key, array), - bool[] => this.TransformBooleanArrayTag(key, array), - byte[] => this.TransformIntegralArrayTag(key, array), - sbyte[] => this.TransformIntegralArrayTag(key, array), - short[] => this.TransformIntegralArrayTag(key, array), - ushort[] => this.TransformIntegralArrayTag(key, array), - int[] => array is nint[] ? this.TransformStringArrayTag(key, array) : this.TransformIntegralArrayTag(key, array), - uint[] => this.TransformIntegralArrayTag(key, array), - long[] => array is nuint[] ? this.TransformStringArrayTag(key, array) : this.TransformIntegralArrayTag(key, array), - float[] => this.TransformFloatingPointArrayTag(key, array), - double[] => this.TransformFloatingPointArrayTag(key, array), - _ => this.TransformStringArrayTag(key, array), + char[] => this.TransformArrayTag(key, array), + string[] => this.TransformArrayTag(key, array), + bool[] => this.TransformArrayTag(key, array), + byte[] => this.TransformArrayTag(key, array), + sbyte[] => this.TransformArrayTag(key, array), + short[] => this.TransformArrayTag(key, array), + ushort[] => this.TransformArrayTag(key, array), + int[] => this.TransformArrayTag(key, array), + uint[] => this.TransformArrayTag(key, array), + long[] => this.TransformArrayTag(key, array), + float[] => this.TransformArrayTag(key, array), + double[] => this.TransformArrayTag(key, array), + _ => this.ConvertToStringArrayThenTransformArrayTag(key, array), }; } - private T ToJsonArray(string key, Array array) - { - return array switch - { - char[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), - string[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), - bool[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), - byte[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), - sbyte[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), - short[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), - ushort[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), - int[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), - uint[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), - long[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), - float[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), - double[] arr => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(arr)), - _ => this.StringifyArray(key, array), - }; - } - - private T StringifyArray(string key, Array array) + private T ConvertToStringArrayThenTransformArrayTag(string key, Array array) { try { - return this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize((array as object[]).Select(x => x?.ToString()))); + var stringArray = new string[array.Length]; + + for (var i = 0; i < array.Length; ++i) + { + stringArray[i] = array.GetValue(i)?.ToString(); + } + + return this.TransformArrayTag(key, stringArray); } catch { - return default; + // If an exception is thrown when calling ToString + // on any element of the array, then the entire array value + // is ignored. + return default(T); } } } From 347ab44119fb0f993f836688f5e3155bfde0ddfd Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Mon, 23 May 2022 17:41:21 -0700 Subject: [PATCH 10/30] Fix namespace --- src/OpenTelemetry/Internal/TagAndValueTransformer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/OpenTelemetry/Internal/TagAndValueTransformer.cs b/src/OpenTelemetry/Internal/TagAndValueTransformer.cs index 43bc473e64f..9b2321ce04e 100644 --- a/src/OpenTelemetry/Internal/TagAndValueTransformer.cs +++ b/src/OpenTelemetry/Internal/TagAndValueTransformer.cs @@ -15,7 +15,8 @@ // using System; -using OpenTelemetry.Internal; + +namespace OpenTelemetry.Internal; internal abstract class TagAndValueTransformer : TagTransformer { From 181e2fa37f07eb3382f112db5df9d46e3d5e69e9 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Tue, 24 May 2022 11:28:44 -0700 Subject: [PATCH 11/30] Handle exceptions when transforming array values --- .../Implementation/OtlpKeyValueTransformer.cs | 11 ++++++-- .../Internal/TagAndValueTransformer.cs | 3 ++- src/OpenTelemetry/Internal/TagTransformer.cs | 25 ++++++++++--------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs index 6faab48eab4..6861c153f47 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs @@ -73,8 +73,15 @@ protected override OtlpCommon.AnyValue TransformArrayValue(Array array) foreach (var item in array) { - var value = item != null ? this.TransformValue(item) : new OtlpCommon.AnyValue(); - arrayValue.Values.Add(value); + try + { + var value = item != null ? this.TransformValue(item) : new OtlpCommon.AnyValue(); + arrayValue.Values.Add(value); + } + catch + { + return null; + } } return new OtlpCommon.AnyValue { ArrayValue = arrayValue }; diff --git a/src/OpenTelemetry/Internal/TagAndValueTransformer.cs b/src/OpenTelemetry/Internal/TagAndValueTransformer.cs index 9b2321ce04e..2dfe9b1b413 100644 --- a/src/OpenTelemetry/Internal/TagAndValueTransformer.cs +++ b/src/OpenTelemetry/Internal/TagAndValueTransformer.cs @@ -41,7 +41,8 @@ public TValue TransformValue(object value) case double: return this.TransformFloatingPointValue(Convert.ToDouble(value)); default: - return default(TValue); + // This could throw an exception. The caller is expected to handle. + return this.TransformStringValue(value.ToString()); } } diff --git a/src/OpenTelemetry/Internal/TagTransformer.cs b/src/OpenTelemetry/Internal/TagTransformer.cs index f6e83e2fb6a..c716968c353 100644 --- a/src/OpenTelemetry/Internal/TagTransformer.cs +++ b/src/OpenTelemetry/Internal/TagTransformer.cs @@ -28,7 +28,6 @@ public T TransformTag(KeyValuePair tag) return default; } - T result = default; switch (tag.Value) { case char: @@ -48,7 +47,16 @@ public T TransformTag(KeyValuePair tag) case double: return this.TransformFloatingPointTag(tag.Key, Convert.ToDouble(tag.Value)); case Array array: - return this.TransformArrayTagInternal(tag.Key, array); + try + { + return this.TransformArrayTagInternal(tag.Key, array); + } + catch + { + // If ToString throws an exception then the tag is ignored. + // OpenTelemetrySdkEventSource.Log.UnsupportedAttributeType(tag.Value.GetType().ToString(), tag.Key); + return default(T); + } // All other types are converted to strings including the following // built-in value types: @@ -59,22 +67,15 @@ public T TransformTag(KeyValuePair tag) default: try { - result = this.TransformStringTag(tag.Key, tag.Value.ToString()); + return this.TransformStringTag(tag.Key, tag.Value.ToString()); } catch { // If ToString throws an exception then the tag is ignored. + // OpenTelemetrySdkEventSource.Log.UnsupportedAttributeType(tag.Value.GetType().ToString(), tag.Key); + return default(T); } - - break; } - - // if (result == null) - // { - // // OpenTelemetryProtocolExporterEventSource.Log.UnsupportedAttributeType(kvp.Value.GetType().ToString(), kvp.Key); - // } - - return result; } protected abstract T TransformIntegralTag(string key, long value); From a2c2d69a4511972bb3b3ce5fb227a5ef0acdb8ca Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Tue, 24 May 2022 11:30:01 -0700 Subject: [PATCH 12/30] Log when transform fails --- .../OpenTelemetryProtocolExporterEventSource.cs | 6 ------ src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs | 6 ++++++ src/OpenTelemetry/Internal/TagTransformer.cs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OpenTelemetryProtocolExporterEventSource.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OpenTelemetryProtocolExporterEventSource.cs index 9e3c905d748..17db6324a1b 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OpenTelemetryProtocolExporterEventSource.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OpenTelemetryProtocolExporterEventSource.cs @@ -79,11 +79,5 @@ public void CouldNotTranslateLogRecord(string exceptionMessage) { this.WriteEvent(9, exceptionMessage); } - - [Event(10, Message = "Unsupported attribute type '{0}' for '{1}'. Attribute will not be exported.", Level = EventLevel.Warning)] - public void UnsupportedAttributeType(string type, string key) - { - this.WriteEvent(10, type.ToString(), key); - } } } diff --git a/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs b/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs index c80d41f28e5..0db72d4cba7 100644 --- a/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs +++ b/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs @@ -384,6 +384,12 @@ public void MetricViewIgnored(string instrumentName, string meterName, string re this.WriteEvent(41, instrumentName, meterName, reason, fix); } + [Event(42, Message = "Unsupported attribute type '{0}' for '{1}'. Attribute will not be exported.", Level = EventLevel.Warning)] + public void UnsupportedAttributeType(string type, string key) + { + this.WriteEvent(42, type.ToString(), key); + } + #if DEBUG public class OpenTelemetryEventListener : EventListener { diff --git a/src/OpenTelemetry/Internal/TagTransformer.cs b/src/OpenTelemetry/Internal/TagTransformer.cs index c716968c353..2cc658eed9a 100644 --- a/src/OpenTelemetry/Internal/TagTransformer.cs +++ b/src/OpenTelemetry/Internal/TagTransformer.cs @@ -54,7 +54,7 @@ public T TransformTag(KeyValuePair tag) catch { // If ToString throws an exception then the tag is ignored. - // OpenTelemetrySdkEventSource.Log.UnsupportedAttributeType(tag.Value.GetType().ToString(), tag.Key); + OpenTelemetrySdkEventSource.Log.UnsupportedAttributeType(tag.Value.GetType().ToString(), tag.Key); return default(T); } @@ -72,7 +72,7 @@ public T TransformTag(KeyValuePair tag) catch { // If ToString throws an exception then the tag is ignored. - // OpenTelemetrySdkEventSource.Log.UnsupportedAttributeType(tag.Value.GetType().ToString(), tag.Key); + OpenTelemetrySdkEventSource.Log.UnsupportedAttributeType(tag.Value.GetType().ToString(), tag.Key); return default(T); } } From 38d17a70bb3bb900484b714ca490dfb85c8fa3e8 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 10:45:24 -0700 Subject: [PATCH 13/30] TransformTag -> TryTransformTag --- .../JaegerActivityExtensions.cs | 4 ++- .../Implementation/OtlpCommonExtensions.cs | 4 ++- .../Implementation/ZipkinSpan.cs | 10 ++++-- src/OpenTelemetry/Internal/TagTransformer.cs | 32 +++++++++++++------ 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs index 7c79d036125..fbfcaf99a1a 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs @@ -234,7 +234,9 @@ public static JaegerSpanRef ToJaegerSpanRef(this in ActivityLink link) public static JaegerTag ToJaegerTag(this KeyValuePair attribute) { - return tagTransformer.TransformTag(attribute); + // TODO: Check status of try + tagTransformer.TryTransformTag(attribute, out var result); + return result; } public static long ToEpochMicroseconds(this DateTime utcDateTime) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs index fd8b75de51b..be12f0ec24a 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs @@ -27,7 +27,9 @@ internal static class OtlpCommonExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OtlpCommon.KeyValue ToOtlpAttribute(this KeyValuePair kvp) { - return tagTransformer.TransformTag(kvp); + // TODO: Check status of try + tagTransformer.TryTransformTag(kvp, out var result); + return result; } } } diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs index 08d4a490c3d..228bf66df2b 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs @@ -177,12 +177,18 @@ public void Write(Utf8JsonWriter writer, ZipkinTagTransformer tagTransformer) { foreach (var tag in this.LocalEndpoint.Tags ?? Enumerable.Empty>()) { - writer.WriteString(tag.Key, tagTransformer.TransformTag(tag)); + if (tagTransformer.TryTransformTag(tag, out var result)) + { + writer.WriteString(tag.Key, result); + } } foreach (var tag in this.Tags) { - writer.WriteString(tag.Key, tagTransformer.TransformTag(tag)); + if (tagTransformer.TryTransformTag(tag, out var result)) + { + writer.WriteString(tag.Key, result); + } } } finally diff --git a/src/OpenTelemetry/Internal/TagTransformer.cs b/src/OpenTelemetry/Internal/TagTransformer.cs index 2cc658eed9a..92938c09be6 100644 --- a/src/OpenTelemetry/Internal/TagTransformer.cs +++ b/src/OpenTelemetry/Internal/TagTransformer.cs @@ -21,20 +21,24 @@ namespace OpenTelemetry.Internal; internal abstract class TagTransformer { - public T TransformTag(KeyValuePair tag) + public bool TryTransformTag(KeyValuePair tag, out T result) { + result = default(T); + if (tag.Value == null) { - return default; + return false; } switch (tag.Value) { case char: case string: - return this.TransformStringTag(tag.Key, Convert.ToString(tag.Value)); + result = this.TransformStringTag(tag.Key, Convert.ToString(tag.Value)); + break; case bool b: - return this.TransformBooleanTag(tag.Key, b); + result = this.TransformBooleanTag(tag.Key, b); + break; case byte: case sbyte: case short: @@ -42,22 +46,26 @@ public T TransformTag(KeyValuePair tag) case int: case uint: case long: - return this.TransformIntegralTag(tag.Key, Convert.ToInt64(tag.Value)); + result = this.TransformIntegralTag(tag.Key, Convert.ToInt64(tag.Value)); + break; case float: case double: - return this.TransformFloatingPointTag(tag.Key, Convert.ToDouble(tag.Value)); + result = this.TransformFloatingPointTag(tag.Key, Convert.ToDouble(tag.Value)); + break; case Array array: try { - return this.TransformArrayTagInternal(tag.Key, array); + result = this.TransformArrayTagInternal(tag.Key, array); } catch { // If ToString throws an exception then the tag is ignored. OpenTelemetrySdkEventSource.Log.UnsupportedAttributeType(tag.Value.GetType().ToString(), tag.Key); - return default(T); + return false; } + break; + // All other types are converted to strings including the following // built-in value types: // case nint: Pointer type. @@ -67,15 +75,19 @@ public T TransformTag(KeyValuePair tag) default: try { - return this.TransformStringTag(tag.Key, tag.Value.ToString()); + result = this.TransformStringTag(tag.Key, tag.Value.ToString()); } catch { // If ToString throws an exception then the tag is ignored. OpenTelemetrySdkEventSource.Log.UnsupportedAttributeType(tag.Value.GetType().ToString(), tag.Key); - return default(T); + return false; } + + break; } + + return true; } protected abstract T TransformIntegralTag(string key, long value); From 1f09f2c5f501a5985892780c224a2c631982decb Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 10:47:40 -0700 Subject: [PATCH 14/30] CodeAnalysis recommendations --- .../Implementation/JaegerActivityExtensions.cs | 4 ++-- .../Implementation/OtlpCommonExtensions.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs index fbfcaf99a1a..b94dc345481 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs @@ -45,7 +45,7 @@ internal static class JaegerActivityExtensions private const long TicksPerMicrosecond = TimeSpan.TicksPerMillisecond / 1000; private const long UnixEpochMicroseconds = UnixEpochTicks / TicksPerMicrosecond; // 62,135,596,800,000,000 - private static JaegerTagTransformer tagTransformer = new JaegerTagTransformer(); + private static readonly JaegerTagTransformer TagTransformer = new(); public static JaegerSpan ToJaegerSpan(this Activity activity) { @@ -235,7 +235,7 @@ public static JaegerSpanRef ToJaegerSpanRef(this in ActivityLink link) public static JaegerTag ToJaegerTag(this KeyValuePair attribute) { // TODO: Check status of try - tagTransformer.TryTransformTag(attribute, out var result); + TagTransformer.TryTransformTag(attribute, out var result); return result; } diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs index be12f0ec24a..a7c8d5e66f7 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs @@ -22,13 +22,13 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation { internal static class OtlpCommonExtensions { - private static OtlpKeyValueTransformer tagTransformer = new OtlpKeyValueTransformer(); + private static readonly OtlpKeyValueTransformer TagTransformer = new(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OtlpCommon.KeyValue ToOtlpAttribute(this KeyValuePair kvp) { // TODO: Check status of try - tagTransformer.TryTransformTag(kvp, out var result); + TagTransformer.TryTransformTag(kvp, out var result); return result; } } From bdd17b291a4534b7bc66707d04433a0642413395 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 11:11:43 -0700 Subject: [PATCH 15/30] Change OTLP exporter to use TryTransformTag --- .../Implementation/ActivityExtensions.cs | 4 +- .../Implementation/LogRecordExtensions.cs | 14 +++++-- .../Implementation/MetricItemExtensions.cs | 6 ++- .../Implementation/OtlpCommonExtensions.cs | 35 ---------------- .../Implementation/ResourceExtensions.cs | 7 ++-- .../OtlpAttributeTests.cs | 41 +++++++------------ 6 files changed, 36 insertions(+), 71 deletions(-) delete mode 100644 src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpCommonExtensions.cs diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs index 6ec0710b17d..6f624fc4eed 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs @@ -37,6 +37,7 @@ internal static class ActivityExtensions { private static readonly ConcurrentBag SpanListPool = new(); private static readonly Action, int> RepeatedFieldOfSpanSetCountAction = CreateRepeatedFieldOfSpanSetCountAction(); + private static readonly OtlpKeyValueTransformer TagTransformer = new(); internal static void AddBatch( this OtlpCollector.ExportTraceServiceRequest request, @@ -355,8 +356,7 @@ public bool ForEach(KeyValuePair activityTag) this.Created = true; } - var attribute = activityTag.ToOtlpAttribute(); - if (attribute != null) + if (TagTransformer.TryTransformTag(activityTag, out var attribute)) { PooledList.Add(ref this.Tags, attribute); diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs index 5cb08330049..3bb8145afc1 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs @@ -32,6 +32,8 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation { internal static class LogRecordExtensions { + private static readonly OtlpKeyValueTransformer TagTransformer = new(); + private static readonly string[] LogLevels = new string[7] { "Trace", "Debug", "Information", "Warning", "Error", "Critical", "None", @@ -105,8 +107,10 @@ internal static OtlpLogs.LogRecord ToOtlpLog(this LogRecord logRecord) } else { - var otlpAttribute = stateValue.ToOtlpAttribute(); - otlpLogRecord.Attributes.Add(otlpAttribute); + if (TagTransformer.TryTransformTag(stateValue, out var result)) + { + otlpLogRecord.Attributes.Add(result); + } } } } @@ -150,8 +154,10 @@ void ProcessScope(LogRecordScope scope, OtlpLogs.LogRecord otlpLog) foreach (var scopeItem in scope) { var scopeItemWithDepthInfo = new KeyValuePair($"[Scope.{scopeDepth}]:{scopeItem.Key}", scopeItem.Value); - var otlpAttribute = scopeItemWithDepthInfo.ToOtlpAttribute(); - otlpLog.Attributes.Add(otlpAttribute); + if (TagTransformer.TryTransformTag(scopeItemWithDepthInfo, out var result)) + { + otlpLog.Attributes.Add(result); + } } } } diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index cc6305b0bc6..d6a25a73797 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -34,6 +34,7 @@ internal static class MetricItemExtensions { private static readonly ConcurrentBag MetricListPool = new(); private static readonly Action, int> RepeatedFieldOfMetricSetCountAction = CreateRepeatedFieldOfMetricSetCountAction(); + private static readonly OtlpKeyValueTransformer TagTransformer = new(); internal static void AddMetrics( this OtlpCollector.ExportMetricsServiceRequest request, @@ -279,7 +280,10 @@ private static void AddAttributes(ReadOnlyTagCollection tags, RepeatedField -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using OtlpCommon = Opentelemetry.Proto.Common.V1; - -namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation -{ - internal static class OtlpCommonExtensions - { - private static readonly OtlpKeyValueTransformer TagTransformer = new(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static OtlpCommon.KeyValue ToOtlpAttribute(this KeyValuePair kvp) - { - // TODO: Check status of try - TagTransformer.TryTransformTag(kvp, out var result); - return result; - } - } -} diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ResourceExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ResourceExtensions.cs index fd03cb6cf67..d59a262f3dc 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ResourceExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ResourceExtensions.cs @@ -24,16 +24,17 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation { internal static class ResourceExtensions { + private static readonly OtlpKeyValueTransformer TagTransformer = new(); + public static OtlpResource.Resource ToOtlpResource(this Resource resource) { var processResource = new OtlpResource.Resource(); foreach (KeyValuePair attribute in resource.Attributes) { - var otlpAttribute = attribute.ToOtlpAttribute(); - if (otlpAttribute != null) + if (TagTransformer.TryTransformTag(attribute, out var result)) { - processResource.Attributes.Add(otlpAttribute); + processResource.Attributes.Add(result); } } diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpAttributeTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpAttributeTests.cs index 60652ec0957..b379bf06171 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpAttributeTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpAttributeTests.cs @@ -25,26 +25,25 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests { public class OtlpAttributeTests { + private static readonly OtlpKeyValueTransformer TagTransformer = new(); + [Fact] public void NullValueAttribute() { var kvp = new KeyValuePair("key", null); - var attribute = kvp.ToOtlpAttribute(); - Assert.Null(attribute); + Assert.False(TagTransformer.TryTransformTag(kvp, out var _)); } [Fact] public void EmptyArrays() { var kvp = new KeyValuePair("key", new int[] { }); - var attribute = kvp.ToOtlpAttribute(); - Assert.NotNull(attribute); + Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase); Assert.Empty(attribute.Value.ArrayValue.Values); kvp = new KeyValuePair("key", new object[] { }); - attribute = kvp.ToOtlpAttribute(); - Assert.NotNull(attribute); + Assert.True(TagTransformer.TryTransformTag(kvp, out attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase); Assert.Empty(attribute.Value.ArrayValue.Values); } @@ -67,8 +66,7 @@ public void EmptyArrays() public void IntegralTypesSupported(object value) { var kvp = new KeyValuePair("key", value); - var attribute = kvp.ToOtlpAttribute(); - Assert.NotNull(attribute); + Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); switch (value) { @@ -97,8 +95,7 @@ public void IntegralTypesSupported(object value) public void FloatingPointTypesSupported(object value) { var kvp = new KeyValuePair("key", value); - var attribute = kvp.ToOtlpAttribute(); - Assert.NotNull(attribute); + Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); switch (value) { @@ -125,8 +122,7 @@ public void FloatingPointTypesSupported(object value) public void BooleanTypeSupported(object value) { var kvp = new KeyValuePair("key", value); - var attribute = kvp.ToOtlpAttribute(); - Assert.NotNull(attribute); + Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); switch (value) { @@ -153,8 +149,7 @@ public void BooleanTypeSupported(object value) public void StringTypesSupported(object value) { var kvp = new KeyValuePair("key", value); - var attribute = kvp.ToOtlpAttribute(); - Assert.NotNull(attribute); + Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.StringValue, attribute.Value.ValueCase); Assert.Equal(Convert.ToString(value), attribute.Value.StringValue); } @@ -166,14 +161,12 @@ public void StringArrayTypesSupported() var stringArray = new string[] { "a", "b", "c", string.Empty, null }; var kvp = new KeyValuePair("key", charArray); - var attribute = kvp.ToOtlpAttribute(); - Assert.NotNull(attribute); + Assert.True(TagTransformer.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("key", stringArray); - attribute = kvp.ToOtlpAttribute(); - Assert.NotNull(attribute); + Assert.True(TagTransformer.TryTransformTag(kvp, out attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase); for (var i = 0; i < stringArray.Length; ++i) @@ -213,8 +206,7 @@ public void ToStringIsCalledForAllOtherTypes() foreach (var value in testValues) { var kvp = new KeyValuePair("key", value); - var attribute = kvp.ToOtlpAttribute(); - Assert.NotNull(attribute); + Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.StringValue, attribute.Value.ValueCase); Assert.Equal(value.ToString(), attribute.Value.StringValue); } @@ -222,8 +214,7 @@ public void ToStringIsCalledForAllOtherTypes() foreach (var value in testArrayValues) { var kvp = new KeyValuePair("key", value); - var attribute = kvp.ToOtlpAttribute(); - Assert.NotNull(attribute); + Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase); var array = value as Array; @@ -247,12 +238,10 @@ public void ToStringIsCalledForAllOtherTypes() public void ExceptionInToStringIsCaught() { var kvp = new KeyValuePair("key", new MyToStringMethodThrowsAnException()); - var attribute = kvp.ToOtlpAttribute(); - Assert.Null(attribute); + Assert.False(TagTransformer.TryTransformTag(kvp, out var _)); kvp = new KeyValuePair("key", new object[] { 1, false, new MyToStringMethodThrowsAnException() }); - attribute = kvp.ToOtlpAttribute(); - Assert.Null(attribute); + Assert.False(TagTransformer.TryTransformTag(kvp, out var _)); } private class MyToStringMethodThrowsAnException From f3ee3e7d1faab40f88583266cc757153b1c5ce79 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 11:14:37 -0700 Subject: [PATCH 16/30] CodeAnalysis --- .../OtlpAttributeTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpAttributeTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpAttributeTests.cs index b379bf06171..48c1eba3d45 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpAttributeTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpAttributeTests.cs @@ -37,12 +37,12 @@ public void NullValueAttribute() [Fact] public void EmptyArrays() { - var kvp = new KeyValuePair("key", new int[] { }); + var kvp = new KeyValuePair("key", Array.Empty()); Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase); Assert.Empty(attribute.Value.ArrayValue.Values); - kvp = new KeyValuePair("key", new object[] { }); + kvp = new KeyValuePair("key", Array.Empty()); Assert.True(TagTransformer.TryTransformTag(kvp, out attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase); Assert.Empty(attribute.Value.ArrayValue.Values); From c3dd4ec738b8d6df072213986eebf205f6a6901f Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 11:16:19 -0700 Subject: [PATCH 17/30] CodeAnalysis --- src/OpenTelemetry/Internal/TagTransformer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry/Internal/TagTransformer.cs b/src/OpenTelemetry/Internal/TagTransformer.cs index 92938c09be6..b9debbdf529 100644 --- a/src/OpenTelemetry/Internal/TagTransformer.cs +++ b/src/OpenTelemetry/Internal/TagTransformer.cs @@ -23,7 +23,7 @@ internal abstract class TagTransformer { public bool TryTransformTag(KeyValuePair tag, out T result) { - result = default(T); + result = default; if (tag.Value == null) { @@ -140,7 +140,7 @@ private T ConvertToStringArrayThenTransformArrayTag(string key, Array array) // If an exception is thrown when calling ToString // on any element of the array, then the entire array value // is ignored. - return default(T); + return default; } } } From 76a2f3c2848cfc636292514ce4098fe0a025a33e Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 12:01:58 -0700 Subject: [PATCH 18/30] Change Jaeger exporter to use TryTransformTag --- .../JaegerActivityExtensions.cs | 64 ++----------------- .../Implementation/JaegerTagTransformer.cs | 2 + .../Implementation/Process.cs | 14 ---- .../JaegerExporter.cs | 11 ++-- src/OpenTelemetry/Internal/TagTransformer.cs | 24 +++---- .../JaegerActivityConversionTest.cs | 15 ++--- .../JaegerExporterTests.cs | 3 +- 7 files changed, 32 insertions(+), 101 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs index b94dc345481..99be25fdbc9 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs @@ -45,8 +45,6 @@ internal static class JaegerActivityExtensions private const long TicksPerMicrosecond = TimeSpan.TicksPerMillisecond / 1000; private const long UnixEpochMicroseconds = UnixEpochTicks / TicksPerMicrosecond; // 62,135,596,800,000,000 - private static readonly JaegerTagTransformer TagTransformer = new(); - public static JaegerSpan ToJaegerSpan(this Activity activity) { var jaegerTags = new TagEnumerationState @@ -232,13 +230,6 @@ public static JaegerSpanRef ToJaegerSpanRef(this in ActivityLink link) return new JaegerSpanRef(refType, traceId.Low, traceId.High, spanId.Low); } - public static JaegerTag ToJaegerTag(this KeyValuePair attribute) - { - // TODO: Check status of try - TagTransformer.TryTransformTag(attribute, out var result); - return result; - } - public static long ToEpochMicroseconds(this DateTime utcDateTime) { // Truncate sub-microsecond precision before offsetting by the Unix Epoch to avoid @@ -255,42 +246,6 @@ public static long ToEpochMicroseconds(this DateTimeOffset timestamp) return microseconds - UnixEpochMicroseconds; } - private static void ProcessJaegerTagArray(ref PooledList tags, KeyValuePair activityTag) - { - if (activityTag.Value is int[] intArray) - { - foreach (var item in intArray) - { - JaegerTag jaegerTag = new JaegerTag(activityTag.Key, JaegerTagType.LONG, vLong: Convert.ToInt64(item)); - PooledList.Add(ref tags, jaegerTag); - } - } - else if (activityTag.Value is string[] stringArray) - { - foreach (var item in stringArray) - { - JaegerTag jaegerTag = new JaegerTag(activityTag.Key, JaegerTagType.STRING, vStr: item); - PooledList.Add(ref tags, jaegerTag); - } - } - else if (activityTag.Value is bool[] boolArray) - { - foreach (var item in boolArray) - { - JaegerTag jaegerTag = new JaegerTag(activityTag.Key, JaegerTagType.BOOL, vBool: item); - PooledList.Add(ref tags, jaegerTag); - } - } - else if (activityTag.Value is double[] doubleArray) - { - foreach (var item in doubleArray) - { - JaegerTag jaegerTag = new JaegerTag(activityTag.Key, JaegerTagType.DOUBLE, vDouble: item); - PooledList.Add(ref tags, jaegerTag); - } - } - } - private struct TagEnumerationState : IActivityEnumerator>, PeerServiceResolver.IPeerServiceState { public PooledList Tags; @@ -314,9 +269,8 @@ public bool ForEach(KeyValuePair activityTag) if (activityTag.Value != null) { var key = activityTag.Key; - var jaegerTag = activityTag.ToJaegerTag(); - if (jaegerTag.Equals(default(JaegerTag))) + if (!JaegerTagTransformer.Instance.TryTransformTag(activityTag, out var jaegerTag)) { return true; } @@ -397,18 +351,14 @@ private struct EventTagsEnumerationState : IActivityEnumerator tag) { - if (tag.Value is Array) - { - ProcessJaegerTagArray(ref this.Tags, tag); - } - else if (tag.Value != null) + if (JaegerTagTransformer.Instance.TryTransformTag(tag, out var result)) { - PooledList.Add(ref this.Tags, tag.ToJaegerTag()); - } + PooledList.Add(ref this.Tags, result); - if (tag.Key == "event") - { - this.HasEvent = true; + if (tag.Key == "event") + { + this.HasEvent = true; + } } return true; diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs index 5434ed0200a..afed69e5983 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs @@ -20,6 +20,8 @@ namespace OpenTelemetry.Exporter.Jaeger.Implementation { internal class JaegerTagTransformer : TagTransformer { + public static JaegerTagTransformer Instance = new JaegerTagTransformer(); + protected override JaegerTag TransformIntegralTag(string key, long value) { return new JaegerTag(key, JaegerTagType.LONG, vLong: value); diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/Process.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/Process.cs index 95bb58587b1..6b110053fa0 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/Process.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/Process.cs @@ -29,20 +29,6 @@ public Process(string serviceName) this.ServiceName = serviceName; } - public Process(string serviceName, IEnumerable> processTags) - : this(serviceName, processTags?.Select(pt => pt.ToJaegerTag()).ToDictionary(pt => pt.Key, pt => pt)) - { - } - - internal Process(string serviceName, Dictionary processTags) - : this(serviceName) - { - if (processTags != null) - { - this.Tags = processTags; - } - } - public string ServiceName { get; internal set; } internal Dictionary Tags { get; set; } diff --git a/src/OpenTelemetry.Exporter.Jaeger/JaegerExporter.cs b/src/OpenTelemetry.Exporter.Jaeger/JaegerExporter.cs index 5d57747a57b..4a26ce813d4 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/JaegerExporter.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/JaegerExporter.cs @@ -145,12 +145,15 @@ internal void SetResourceAndInitializeBatch(Resource resource) } } - if (process.Tags == null) + if (JaegerTagTransformer.Instance.TryTransformTag(label, out var result)) { - process.Tags = new Dictionary(); - } + if (process.Tags == null) + { + process.Tags = new Dictionary(); + } - process.Tags[key] = label.ToJaegerTag(); + process.Tags[key] = result; + } } if (serviceName != null) diff --git a/src/OpenTelemetry/Internal/TagTransformer.cs b/src/OpenTelemetry/Internal/TagTransformer.cs index b9debbdf529..1527d9f383b 100644 --- a/src/OpenTelemetry/Internal/TagTransformer.cs +++ b/src/OpenTelemetry/Internal/TagTransformer.cs @@ -59,7 +59,9 @@ public bool TryTransformTag(KeyValuePair tag, out T result) } catch { - // If ToString throws an exception then the tag is ignored. + // If an exception is thrown when calling ToString + // on any element of the array, then the entire array value + // is ignored. OpenTelemetrySdkEventSource.Log.UnsupportedAttributeType(tag.Value.GetType().ToString(), tag.Key); return false; } @@ -124,23 +126,13 @@ private T TransformArrayTagInternal(string key, Array array) private T ConvertToStringArrayThenTransformArrayTag(string key, Array array) { - try - { - var stringArray = new string[array.Length]; - - for (var i = 0; i < array.Length; ++i) - { - stringArray[i] = array.GetValue(i)?.ToString(); - } + var stringArray = new string[array.Length]; - return this.TransformArrayTag(key, stringArray); - } - catch + for (var i = 0; i < array.Length; ++i) { - // If an exception is thrown when calling ToString - // on any element of the array, then the entire array value - // is ignored. - return default; + stringArray[i] = array.GetValue(i)?.ToString(); } + + return this.TransformArrayTag(key, stringArray); } } diff --git a/test/OpenTelemetry.Exporter.Jaeger.Tests/Implementation/JaegerActivityConversionTest.cs b/test/OpenTelemetry.Exporter.Jaeger.Tests/Implementation/JaegerActivityConversionTest.cs index 0b31b68c79c..ad4d6db9c01 100644 --- a/test/OpenTelemetry.Exporter.Jaeger.Tests/Implementation/JaegerActivityConversionTest.cs +++ b/test/OpenTelemetry.Exporter.Jaeger.Tests/Implementation/JaegerActivityConversionTest.cs @@ -103,18 +103,15 @@ public void JaegerActivityConverterTest_ConvertActivityToJaegerSpan_AllPropertie var logs = jaegerSpan.Logs.ToArray(); var jaegerLog = logs[0]; Assert.Equal(activity.Events.First().Timestamp.ToEpochMicroseconds(), jaegerLog.Timestamp); - Assert.Equal(4, jaegerLog.Fields.Count); + Assert.Equal(3, jaegerLog.Fields.Count); var eventFields = jaegerLog.Fields.ToArray(); var eventField = eventFields[0]; Assert.Equal("key", eventField.Key); Assert.Equal("value", eventField.VStr); eventField = eventFields[1]; Assert.Equal("string_array", eventField.Key); - Assert.Equal("a", eventField.VStr); + Assert.Equal(@"[""a"",""b""]", eventField.VStr); eventField = eventFields[2]; - Assert.Equal("string_array", eventField.Key); - Assert.Equal("b", eventField.VStr); - eventField = eventFields[3]; Assert.Equal("event", eventField.Key); Assert.Equal("Event1", eventField.VStr); @@ -168,12 +165,12 @@ public void JaegerActivityConverterTest_ConvertActivityToJaegerSpan_NoAttributes var logs = jaegerSpan.Logs.ToArray(); var jaegerLog = logs[0]; Assert.Equal(activity.Events.First().Timestamp.ToEpochMicroseconds(), jaegerLog.Timestamp); - Assert.Equal(4, jaegerLog.Fields.Count); + Assert.Equal(3, jaegerLog.Fields.Count); var eventFields = jaegerLog.Fields.ToArray(); var eventField = eventFields[0]; Assert.Equal("key", eventField.Key); Assert.Equal("value", eventField.VStr); - eventField = eventFields[3]; + eventField = eventFields[2]; Assert.Equal("event", eventField.Key); Assert.Equal("Event1", eventField.VStr); @@ -338,12 +335,12 @@ public void JaegerActivityConverterTest_ConvertActivityToJaegerSpan_NoLinks() var logs = jaegerSpan.Logs.ToArray(); var jaegerLog = logs[0]; Assert.Equal(activity.Events.First().Timestamp.ToEpochMicroseconds(), jaegerLog.Timestamp); - Assert.Equal(4, jaegerLog.Fields.Count); + Assert.Equal(3, jaegerLog.Fields.Count); var eventFields = jaegerLog.Fields.ToArray(); var eventField = eventFields[0]; Assert.Equal("key", eventField.Key); Assert.Equal("value", eventField.VStr); - eventField = eventFields[3]; + eventField = eventFields[2]; Assert.Equal("event", eventField.Key); Assert.Equal("Event1", eventField.VStr); Assert.Equal(activity.Events.First().Timestamp.ToEpochMicroseconds(), jaegerLog.Timestamp); diff --git a/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterTests.cs b/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterTests.cs index 82096ba587c..5d018bcf8c1 100644 --- a/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterTests.cs +++ b/test/OpenTelemetry.Exporter.Jaeger.Tests/JaegerExporterTests.cs @@ -201,7 +201,8 @@ public void JaegerTraceExporter_SetResource_CombinesTags() using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions()); var process = jaegerTraceExporter.Process; - process.Tags = new Dictionary { ["Tag1"] = new KeyValuePair("Tag1", "value1").ToJaegerTag() }; + JaegerTagTransformer.Instance.TryTransformTag(new KeyValuePair("Tag1", "value1"), out var result); + process.Tags = new Dictionary { ["Tag1"] = result }; jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddAttributes(new Dictionary { From 38fb5f0a686476075e38d40984dd2620e322df05 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 12:13:58 -0700 Subject: [PATCH 19/30] Make TagTransformers singletons --- .../Implementation/JaegerTagTransformer.cs | 6 +++- .../Implementation/ActivityExtensions.cs | 3 +- .../Implementation/LogRecordExtensions.cs | 6 ++-- .../Implementation/MetricItemExtensions.cs | 3 +- .../Implementation/OtlpKeyValueTransformer.cs | 6 ++++ .../Implementation/ResourceExtensions.cs | 4 +-- .../Implementation/ZipkinSpan.cs | 6 ++-- .../Implementation/ZipkinTagTransformer.cs | 6 ++++ .../ZipkinExporter.cs | 4 +-- .../OtlpAttributeTests.cs | 28 +++++++++---------- 10 files changed, 39 insertions(+), 33 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs index afed69e5983..ceb57c61f16 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs @@ -20,7 +20,11 @@ namespace OpenTelemetry.Exporter.Jaeger.Implementation { internal class JaegerTagTransformer : TagTransformer { - public static JaegerTagTransformer Instance = new JaegerTagTransformer(); + public static JaegerTagTransformer Instance = new(); + + private JaegerTagTransformer() + { + } protected override JaegerTag TransformIntegralTag(string key, long value) { diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs index 6f624fc4eed..6e62e19e805 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs @@ -37,7 +37,6 @@ internal static class ActivityExtensions { private static readonly ConcurrentBag SpanListPool = new(); private static readonly Action, int> RepeatedFieldOfSpanSetCountAction = CreateRepeatedFieldOfSpanSetCountAction(); - private static readonly OtlpKeyValueTransformer TagTransformer = new(); internal static void AddBatch( this OtlpCollector.ExportTraceServiceRequest request, @@ -356,7 +355,7 @@ public bool ForEach(KeyValuePair activityTag) this.Created = true; } - if (TagTransformer.TryTransformTag(activityTag, out var attribute)) + if (OtlpKeyValueTransformer.Instance.TryTransformTag(activityTag, out var attribute)) { PooledList.Add(ref this.Tags, attribute); diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs index 3bb8145afc1..dacee70c817 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs @@ -32,8 +32,6 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation { internal static class LogRecordExtensions { - private static readonly OtlpKeyValueTransformer TagTransformer = new(); - private static readonly string[] LogLevels = new string[7] { "Trace", "Debug", "Information", "Warning", "Error", "Critical", "None", @@ -107,7 +105,7 @@ internal static OtlpLogs.LogRecord ToOtlpLog(this LogRecord logRecord) } else { - if (TagTransformer.TryTransformTag(stateValue, out var result)) + if (OtlpKeyValueTransformer.Instance.TryTransformTag(stateValue, out var result)) { otlpLogRecord.Attributes.Add(result); } @@ -154,7 +152,7 @@ void ProcessScope(LogRecordScope scope, OtlpLogs.LogRecord otlpLog) foreach (var scopeItem in scope) { var scopeItemWithDepthInfo = new KeyValuePair($"[Scope.{scopeDepth}]:{scopeItem.Key}", scopeItem.Value); - if (TagTransformer.TryTransformTag(scopeItemWithDepthInfo, out var result)) + if (OtlpKeyValueTransformer.Instance.TryTransformTag(scopeItemWithDepthInfo, out var result)) { otlpLog.Attributes.Add(result); } diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index d6a25a73797..fe21b8d058e 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -34,7 +34,6 @@ internal static class MetricItemExtensions { private static readonly ConcurrentBag MetricListPool = new(); private static readonly Action, int> RepeatedFieldOfMetricSetCountAction = CreateRepeatedFieldOfMetricSetCountAction(); - private static readonly OtlpKeyValueTransformer TagTransformer = new(); internal static void AddMetrics( this OtlpCollector.ExportMetricsServiceRequest request, @@ -280,7 +279,7 @@ private static void AddAttributes(ReadOnlyTagCollection tags, RepeatedField { + public static OtlpKeyValueTransformer Instance = new(); + + private OtlpKeyValueTransformer() + { + } + protected override OtlpCommon.KeyValue TransformIntegralTag(string key, long value) { return new OtlpCommon.KeyValue { Key = key, Value = this.TransformIntegralValue(value) }; diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ResourceExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ResourceExtensions.cs index d59a262f3dc..5086b0cbc2c 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ResourceExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ResourceExtensions.cs @@ -24,15 +24,13 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation { internal static class ResourceExtensions { - private static readonly OtlpKeyValueTransformer TagTransformer = new(); - public static OtlpResource.Resource ToOtlpResource(this Resource resource) { var processResource = new OtlpResource.Resource(); foreach (KeyValuePair attribute in resource.Attributes) { - if (TagTransformer.TryTransformTag(attribute, out var result)) + if (OtlpKeyValueTransformer.Instance.TryTransformTag(attribute, out var result)) { processResource.Attributes.Add(result); } diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs index 228bf66df2b..ac75989f35a 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs @@ -90,7 +90,7 @@ public void Return() this.Tags.Return(); } - public void Write(Utf8JsonWriter writer, ZipkinTagTransformer tagTransformer) + public void Write(Utf8JsonWriter writer) { writer.WriteStartObject(); @@ -177,7 +177,7 @@ public void Write(Utf8JsonWriter writer, ZipkinTagTransformer tagTransformer) { foreach (var tag in this.LocalEndpoint.Tags ?? Enumerable.Empty>()) { - if (tagTransformer.TryTransformTag(tag, out var result)) + if (ZipkinTagTransformer.Instance.TryTransformTag(tag, out var result)) { writer.WriteString(tag.Key, result); } @@ -185,7 +185,7 @@ public void Write(Utf8JsonWriter writer, ZipkinTagTransformer tagTransformer) foreach (var tag in this.Tags) { - if (tagTransformer.TryTransformTag(tag, out var result)) + if (ZipkinTagTransformer.Instance.TryTransformTag(tag, out var result)) { writer.WriteString(tag.Key, result); } diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs index 6b8e8b16ff3..5c447ba9083 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs @@ -20,6 +20,12 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation { internal class ZipkinTagTransformer : TagTransformer { + public static ZipkinTagTransformer Instance = new(); + + private ZipkinTagTransformer() + { + } + protected override string TransformIntegralTag(string key, long value) => value.ToString(); protected override string TransformFloatingPointTag(string key, double value) => value.ToString(); diff --git a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs index b3fd9d2d642..1927a4f754e 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporter.cs @@ -197,7 +197,6 @@ private sealed class JsonContent : HttpContent private readonly ZipkinExporter exporter; private readonly Batch batch; private Utf8JsonWriter writer; - private ZipkinTagTransformer tagTransformer; public JsonContent(ZipkinExporter exporter, in Batch batch) { @@ -233,7 +232,6 @@ private void SerializeToStreamInternal(Stream stream) if (this.writer == null) { this.writer = new Utf8JsonWriter(stream); - this.tagTransformer = new ZipkinTagTransformer(); } else { @@ -246,7 +244,7 @@ private void SerializeToStreamInternal(Stream stream) { var zipkinSpan = activity.ToZipkinSpan(this.exporter.LocalEndpoint, this.exporter.options.UseShortTraceIds); - zipkinSpan.Write(this.writer, this.tagTransformer); + zipkinSpan.Write(this.writer); zipkinSpan.Return(); if (this.writer.BytesPending >= this.exporter.maxPayloadSizeInBytes) diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpAttributeTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpAttributeTests.cs index 48c1eba3d45..8b97444dee1 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpAttributeTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpAttributeTests.cs @@ -25,25 +25,23 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests { public class OtlpAttributeTests { - private static readonly OtlpKeyValueTransformer TagTransformer = new(); - [Fact] public void NullValueAttribute() { var kvp = new KeyValuePair("key", null); - Assert.False(TagTransformer.TryTransformTag(kvp, out var _)); + Assert.False(OtlpKeyValueTransformer.Instance.TryTransformTag(kvp, out var _)); } [Fact] public void EmptyArrays() { var kvp = new KeyValuePair("key", Array.Empty()); - Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); + Assert.True(OtlpKeyValueTransformer.Instance.TryTransformTag(kvp, out var attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase); Assert.Empty(attribute.Value.ArrayValue.Values); kvp = new KeyValuePair("key", Array.Empty()); - Assert.True(TagTransformer.TryTransformTag(kvp, out attribute)); + Assert.True(OtlpKeyValueTransformer.Instance.TryTransformTag(kvp, out attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase); Assert.Empty(attribute.Value.ArrayValue.Values); } @@ -66,7 +64,7 @@ public void EmptyArrays() public void IntegralTypesSupported(object value) { var kvp = new KeyValuePair("key", value); - Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); + Assert.True(OtlpKeyValueTransformer.Instance.TryTransformTag(kvp, out var attribute)); switch (value) { @@ -95,7 +93,7 @@ public void IntegralTypesSupported(object value) public void FloatingPointTypesSupported(object value) { var kvp = new KeyValuePair("key", value); - Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); + Assert.True(OtlpKeyValueTransformer.Instance.TryTransformTag(kvp, out var attribute)); switch (value) { @@ -122,7 +120,7 @@ public void FloatingPointTypesSupported(object value) public void BooleanTypeSupported(object value) { var kvp = new KeyValuePair("key", value); - Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); + Assert.True(OtlpKeyValueTransformer.Instance.TryTransformTag(kvp, out var attribute)); switch (value) { @@ -149,7 +147,7 @@ public void BooleanTypeSupported(object value) public void StringTypesSupported(object value) { var kvp = new KeyValuePair("key", value); - Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); + Assert.True(OtlpKeyValueTransformer.Instance.TryTransformTag(kvp, out var attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.StringValue, attribute.Value.ValueCase); Assert.Equal(Convert.ToString(value), attribute.Value.StringValue); } @@ -161,12 +159,12 @@ public void StringArrayTypesSupported() var stringArray = new string[] { "a", "b", "c", string.Empty, null }; var kvp = new KeyValuePair("key", charArray); - Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); + Assert.True(OtlpKeyValueTransformer.Instance.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("key", stringArray); - Assert.True(TagTransformer.TryTransformTag(kvp, out attribute)); + Assert.True(OtlpKeyValueTransformer.Instance.TryTransformTag(kvp, out attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase); for (var i = 0; i < stringArray.Length; ++i) @@ -206,7 +204,7 @@ public void ToStringIsCalledForAllOtherTypes() foreach (var value in testValues) { var kvp = new KeyValuePair("key", value); - Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); + Assert.True(OtlpKeyValueTransformer.Instance.TryTransformTag(kvp, out var attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.StringValue, attribute.Value.ValueCase); Assert.Equal(value.ToString(), attribute.Value.StringValue); } @@ -214,7 +212,7 @@ public void ToStringIsCalledForAllOtherTypes() foreach (var value in testArrayValues) { var kvp = new KeyValuePair("key", value); - Assert.True(TagTransformer.TryTransformTag(kvp, out var attribute)); + Assert.True(OtlpKeyValueTransformer.Instance.TryTransformTag(kvp, out var attribute)); Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase); var array = value as Array; @@ -238,10 +236,10 @@ public void ToStringIsCalledForAllOtherTypes() public void ExceptionInToStringIsCaught() { var kvp = new KeyValuePair("key", new MyToStringMethodThrowsAnException()); - Assert.False(TagTransformer.TryTransformTag(kvp, out var _)); + Assert.False(OtlpKeyValueTransformer.Instance.TryTransformTag(kvp, out var _)); kvp = new KeyValuePair("key", new object[] { 1, false, new MyToStringMethodThrowsAnException() }); - Assert.False(TagTransformer.TryTransformTag(kvp, out var _)); + Assert.False(OtlpKeyValueTransformer.Instance.TryTransformTag(kvp, out var _)); } private class MyToStringMethodThrowsAnException From efc21a431ba2cb5117c197f7cf13b832243b7558 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 12:20:16 -0700 Subject: [PATCH 20/30] Unused using --- src/OpenTelemetry.Exporter.Jaeger/Implementation/Process.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/Process.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/Process.cs index 6b110053fa0..1d76584748e 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/Process.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/Process.cs @@ -15,7 +15,6 @@ // using System.Collections.Generic; -using System.Linq; using System.Text; using Thrift.Protocol; using Thrift.Protocol.Entities; From a536bf07c8dee77c9cb91774d73f6d141aa3e1b3 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 15:43:42 -0700 Subject: [PATCH 21/30] else if --- .../Implementation/LogRecordExtensions.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs index dacee70c817..6139831d162 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/LogRecordExtensions.cs @@ -103,12 +103,9 @@ internal static OtlpLogs.LogRecord ToOtlpLog(this LogRecord logRecord) { otlpLogRecord.Body = new OtlpCommon.AnyValue { StringValue = stateValue.Value as string }; } - else + else if (OtlpKeyValueTransformer.Instance.TryTransformTag(stateValue, out var result)) { - if (OtlpKeyValueTransformer.Instance.TryTransformTag(stateValue, out var result)) - { - otlpLogRecord.Attributes.Add(result); - } + otlpLogRecord.Attributes.Add(result); } } } From b6cab43faa67285ff63653cfaa16112e39a212d2 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 15:47:26 -0700 Subject: [PATCH 22/30] Make singleton Instance a property --- .../Implementation/JaegerTagTransformer.cs | 4 ++-- .../Implementation/OtlpKeyValueTransformer.cs | 4 ++-- .../Implementation/ZipkinTagTransformer.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs index ceb57c61f16..ecc569a6308 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs @@ -20,12 +20,12 @@ namespace OpenTelemetry.Exporter.Jaeger.Implementation { internal class JaegerTagTransformer : TagTransformer { - public static JaegerTagTransformer Instance = new(); - private JaegerTagTransformer() { } + public static JaegerTagTransformer Instance { get; } = new(); + protected override JaegerTag TransformIntegralTag(string key, long value) { return new JaegerTag(key, JaegerTagType.LONG, vLong: value); diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs index 0117482f403..db36ed66230 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs @@ -22,12 +22,12 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation { internal class OtlpKeyValueTransformer : TagAndValueTransformer { - public static OtlpKeyValueTransformer Instance = new(); - private OtlpKeyValueTransformer() { } + public static OtlpKeyValueTransformer Instance { get; } = new(); + protected override OtlpCommon.KeyValue TransformIntegralTag(string key, long value) { return new OtlpCommon.KeyValue { Key = key, Value = this.TransformIntegralValue(value) }; diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs index 5c447ba9083..ceec69c2745 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs @@ -20,12 +20,12 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation { internal class ZipkinTagTransformer : TagTransformer { - public static ZipkinTagTransformer Instance = new(); - private ZipkinTagTransformer() { } + public static ZipkinTagTransformer Instance { get; } = new(); + protected override string TransformIntegralTag(string key, long value) => value.ToString(); protected override string TransformFloatingPointTag(string key, double value) => value.ToString(); From 5b236560dbd8ba8ca95f005c720153aab4204190 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 15:49:15 -0700 Subject: [PATCH 23/30] :seal: classes --- .../Implementation/JaegerTagTransformer.cs | 2 +- .../Implementation/OtlpKeyValueTransformer.cs | 2 +- .../Implementation/ZipkinTagTransformer.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs index ecc569a6308..825a6b0e6d7 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs @@ -18,7 +18,7 @@ namespace OpenTelemetry.Exporter.Jaeger.Implementation { - internal class JaegerTagTransformer : TagTransformer + internal sealed class JaegerTagTransformer : TagTransformer { private JaegerTagTransformer() { diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs index db36ed66230..818c07e1825 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs @@ -20,7 +20,7 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation { - internal class OtlpKeyValueTransformer : TagAndValueTransformer + internal sealed class OtlpKeyValueTransformer : TagAndValueTransformer { private OtlpKeyValueTransformer() { diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs index ceec69c2745..df0e7b29cab 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs @@ -18,7 +18,7 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation { - internal class ZipkinTagTransformer : TagTransformer + internal sealed class ZipkinTagTransformer : TagTransformer { private ZipkinTagTransformer() { From 040762c11855fd4746ce482b1d502cc4f169c2c4 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 15:54:24 -0700 Subject: [PATCH 24/30] Debug.Assert --- src/OpenTelemetry/Internal/TagAndValueTransformer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/OpenTelemetry/Internal/TagAndValueTransformer.cs b/src/OpenTelemetry/Internal/TagAndValueTransformer.cs index 2dfe9b1b413..19a8520eebf 100644 --- a/src/OpenTelemetry/Internal/TagAndValueTransformer.cs +++ b/src/OpenTelemetry/Internal/TagAndValueTransformer.cs @@ -15,6 +15,7 @@ // using System; +using System.Diagnostics; namespace OpenTelemetry.Internal; @@ -22,6 +23,8 @@ internal abstract class TagAndValueTransformer : TagTransformer { public TValue TransformValue(object value) { + Debug.Assert(value != null, $"{nameof(value)} was null"); + switch (value) { case char: From fd9f373a04e6bab933cc60baa85bf3dba675cb21 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 15:58:16 -0700 Subject: [PATCH 25/30] Do later --- src/OpenTelemetry/Internal/TagTransformer.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry/Internal/TagTransformer.cs b/src/OpenTelemetry/Internal/TagTransformer.cs index 1527d9f383b..5ad8a0ecf08 100644 --- a/src/OpenTelemetry/Internal/TagTransformer.cs +++ b/src/OpenTelemetry/Internal/TagTransformer.cs @@ -23,10 +23,9 @@ internal abstract class TagTransformer { public bool TryTransformTag(KeyValuePair tag, out T result) { - result = default; - if (tag.Value == null) { + result = default; return false; } @@ -63,6 +62,7 @@ public bool TryTransformTag(KeyValuePair tag, out T result) // on any element of the array, then the entire array value // is ignored. OpenTelemetrySdkEventSource.Log.UnsupportedAttributeType(tag.Value.GetType().ToString(), tag.Key); + result = default; return false; } @@ -83,6 +83,7 @@ public bool TryTransformTag(KeyValuePair tag, out T result) { // If ToString throws an exception then the tag is ignored. OpenTelemetrySdkEventSource.Log.UnsupportedAttributeType(tag.Value.GetType().ToString(), tag.Key); + result = default; return false; } From 0d31699d8c0bf8dd23980dd3388b101c535e13bf Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 16:02:52 -0700 Subject: [PATCH 26/30] Make TransformValue protected --- src/OpenTelemetry/Internal/TagAndValueTransformer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/Internal/TagAndValueTransformer.cs b/src/OpenTelemetry/Internal/TagAndValueTransformer.cs index 19a8520eebf..4438dfb9e31 100644 --- a/src/OpenTelemetry/Internal/TagAndValueTransformer.cs +++ b/src/OpenTelemetry/Internal/TagAndValueTransformer.cs @@ -21,7 +21,7 @@ namespace OpenTelemetry.Internal; internal abstract class TagAndValueTransformer : TagTransformer { - public TValue TransformValue(object value) + protected TValue TransformValue(object value) { Debug.Assert(value != null, $"{nameof(value)} was null"); From 673ade0df0e20183a69f1f95bd457ec01a5daef0 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 16:15:02 -0700 Subject: [PATCH 27/30] Exclude TagTransformer.cs from compilation of SDK project --- src/OpenTelemetry/OpenTelemetry.csproj | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/OpenTelemetry/OpenTelemetry.csproj b/src/OpenTelemetry/OpenTelemetry.csproj index f8e5910d7dc..ecef799dc05 100644 --- a/src/OpenTelemetry/OpenTelemetry.csproj +++ b/src/OpenTelemetry/OpenTelemetry.csproj @@ -16,10 +16,16 @@ false + + + + + + - From 74df0df2e40bed9ad83ae195cb6fe48d5024cbc0 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 16:41:32 -0700 Subject: [PATCH 28/30] Move JSON serialization to projects that need it --- .../Implementation/JaegerTagTransformer.cs | 4 ++++ .../Implementation/ZipkinTagTransformer.cs | 4 ++++ src/OpenTelemetry/Internal/TagTransformer.cs | 3 +-- src/OpenTelemetry/OpenTelemetry.csproj | 7 ------- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs index 825a6b0e6d7..3852a6be165 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs @@ -14,6 +14,7 @@ // limitations under the License. // +using System; using OpenTelemetry.Internal; namespace OpenTelemetry.Exporter.Jaeger.Implementation @@ -45,5 +46,8 @@ protected override JaegerTag TransformStringTag(string key, string value) { return new JaegerTag(key, JaegerTagType.STRING, vStr: value); } + + protected override JaegerTag TransformArrayTag(string key, Array array) + => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(array)); } } diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs index df0e7b29cab..4f960811761 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs @@ -14,6 +14,7 @@ // limitations under the License. // +using System; using OpenTelemetry.Internal; namespace OpenTelemetry.Exporter.Zipkin.Implementation @@ -33,5 +34,8 @@ private ZipkinTagTransformer() protected override string TransformBooleanTag(string key, bool value) => value ? "true" : "false"; protected override string TransformStringTag(string key, string value) => value; + + protected override string TransformArrayTag(string key, Array array) + => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(array)); } } diff --git a/src/OpenTelemetry/Internal/TagTransformer.cs b/src/OpenTelemetry/Internal/TagTransformer.cs index 5ad8a0ecf08..e63ccd623f9 100644 --- a/src/OpenTelemetry/Internal/TagTransformer.cs +++ b/src/OpenTelemetry/Internal/TagTransformer.cs @@ -101,8 +101,7 @@ public bool TryTransformTag(KeyValuePair tag, out T result) protected abstract T TransformStringTag(string key, string value); - protected virtual T TransformArrayTag(string key, Array array) => - this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(array)); + protected abstract T TransformArrayTag(string key, Array array); private T TransformArrayTagInternal(string key, Array array) { diff --git a/src/OpenTelemetry/OpenTelemetry.csproj b/src/OpenTelemetry/OpenTelemetry.csproj index ecef799dc05..a247eba4f37 100644 --- a/src/OpenTelemetry/OpenTelemetry.csproj +++ b/src/OpenTelemetry/OpenTelemetry.csproj @@ -16,13 +16,6 @@ false - - - - - - From d8821455efd0273174596cb30afe44a5358322ab Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 16:44:17 -0700 Subject: [PATCH 29/30] File-scoped namespaces --- .../Implementation/JaegerTagTransformer.cs | 59 +++++---- .../Implementation/OtlpKeyValueTransformer.cs | 113 +++++++++--------- .../Implementation/ZipkinTagTransformer.cs | 25 ++-- 3 files changed, 97 insertions(+), 100 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs index 3852a6be165..ccc38b2efe7 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerTagTransformer.cs @@ -17,37 +17,36 @@ using System; using OpenTelemetry.Internal; -namespace OpenTelemetry.Exporter.Jaeger.Implementation +namespace OpenTelemetry.Exporter.Jaeger.Implementation; + +internal sealed class JaegerTagTransformer : TagTransformer { - internal sealed class JaegerTagTransformer : TagTransformer + private JaegerTagTransformer() + { + } + + public static JaegerTagTransformer Instance { get; } = new(); + + protected override JaegerTag TransformIntegralTag(string key, long value) + { + return new JaegerTag(key, JaegerTagType.LONG, vLong: value); + } + + protected override JaegerTag TransformFloatingPointTag(string key, double value) { - private JaegerTagTransformer() - { - } - - public static JaegerTagTransformer Instance { get; } = new(); - - protected override JaegerTag TransformIntegralTag(string key, long value) - { - return new JaegerTag(key, JaegerTagType.LONG, vLong: value); - } - - protected override JaegerTag TransformFloatingPointTag(string key, double value) - { - return new JaegerTag(key, JaegerTagType.DOUBLE, vDouble: value); - } - - protected override JaegerTag TransformBooleanTag(string key, bool value) - { - return new JaegerTag(key, JaegerTagType.BOOL, vBool: value); - } - - protected override JaegerTag TransformStringTag(string key, string value) - { - return new JaegerTag(key, JaegerTagType.STRING, vStr: value); - } - - protected override JaegerTag TransformArrayTag(string key, Array array) - => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(array)); + return new JaegerTag(key, JaegerTagType.DOUBLE, vDouble: value); } + + protected override JaegerTag TransformBooleanTag(string key, bool value) + { + return new JaegerTag(key, JaegerTagType.BOOL, vBool: value); + } + + protected override JaegerTag TransformStringTag(string key, string value) + { + return new JaegerTag(key, JaegerTagType.STRING, vStr: value); + } + + protected override JaegerTag TransformArrayTag(string key, Array array) + => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(array)); } diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs index 818c07e1825..dc254a451ca 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpKeyValueTransformer.cs @@ -18,79 +18,78 @@ using OpenTelemetry.Internal; using OtlpCommon = Opentelemetry.Proto.Common.V1; -namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation +namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; + +internal sealed class OtlpKeyValueTransformer : TagAndValueTransformer { - internal sealed class OtlpKeyValueTransformer : TagAndValueTransformer + private OtlpKeyValueTransformer() { - private OtlpKeyValueTransformer() - { - } + } - public static OtlpKeyValueTransformer Instance { get; } = new(); + public static OtlpKeyValueTransformer Instance { get; } = new(); - protected override OtlpCommon.KeyValue TransformIntegralTag(string key, long value) - { - return new OtlpCommon.KeyValue { Key = key, Value = this.TransformIntegralValue(value) }; - } + protected override OtlpCommon.KeyValue TransformIntegralTag(string key, long value) + { + return new OtlpCommon.KeyValue { Key = key, Value = this.TransformIntegralValue(value) }; + } - protected override OtlpCommon.KeyValue TransformFloatingPointTag(string key, double value) - { - return new OtlpCommon.KeyValue { Key = key, Value = this.TransformFloatingPointValue(value) }; - } + protected override OtlpCommon.KeyValue TransformFloatingPointTag(string key, double value) + { + return new OtlpCommon.KeyValue { Key = key, Value = this.TransformFloatingPointValue(value) }; + } - protected override OtlpCommon.KeyValue TransformBooleanTag(string key, bool value) - { - return new OtlpCommon.KeyValue { Key = key, Value = this.TransformBooleanValue(value) }; - } + protected override OtlpCommon.KeyValue TransformBooleanTag(string key, bool value) + { + return new OtlpCommon.KeyValue { Key = key, Value = this.TransformBooleanValue(value) }; + } - protected override OtlpCommon.KeyValue TransformStringTag(string key, string value) - { - return new OtlpCommon.KeyValue { Key = key, Value = this.TransformStringValue(value) }; - } + protected override OtlpCommon.KeyValue TransformStringTag(string key, string value) + { + return new OtlpCommon.KeyValue { Key = key, Value = this.TransformStringValue(value) }; + } - protected override OtlpCommon.KeyValue TransformArrayTag(string key, Array array) - { - return new OtlpCommon.KeyValue { Key = key, Value = this.TransformArrayValue(array) }; - } + protected override OtlpCommon.KeyValue TransformArrayTag(string key, Array array) + { + return new OtlpCommon.KeyValue { Key = key, Value = this.TransformArrayValue(array) }; + } - protected override OtlpCommon.AnyValue TransformIntegralValue(long value) - { - return new OtlpCommon.AnyValue { IntValue = value }; - } + protected override OtlpCommon.AnyValue TransformIntegralValue(long value) + { + return new OtlpCommon.AnyValue { IntValue = value }; + } - protected override OtlpCommon.AnyValue TransformFloatingPointValue(double value) - { - return new OtlpCommon.AnyValue { DoubleValue = value }; - } + protected override OtlpCommon.AnyValue TransformFloatingPointValue(double value) + { + return new OtlpCommon.AnyValue { DoubleValue = value }; + } - protected override OtlpCommon.AnyValue TransformBooleanValue(bool value) - { - return new OtlpCommon.AnyValue { BoolValue = value }; - } + protected override OtlpCommon.AnyValue TransformBooleanValue(bool value) + { + return new OtlpCommon.AnyValue { BoolValue = value }; + } - protected override OtlpCommon.AnyValue TransformStringValue(string value) - { - return new OtlpCommon.AnyValue { StringValue = value }; - } + protected override OtlpCommon.AnyValue TransformStringValue(string value) + { + return new OtlpCommon.AnyValue { StringValue = value }; + } - protected override OtlpCommon.AnyValue TransformArrayValue(Array array) - { - var arrayValue = new OtlpCommon.ArrayValue(); + protected override OtlpCommon.AnyValue TransformArrayValue(Array array) + { + var arrayValue = new OtlpCommon.ArrayValue(); - foreach (var item in array) + foreach (var item in array) + { + try { - try - { - var value = item != null ? this.TransformValue(item) : new OtlpCommon.AnyValue(); - arrayValue.Values.Add(value); - } - catch - { - return null; - } + var value = item != null ? this.TransformValue(item) : new OtlpCommon.AnyValue(); + arrayValue.Values.Add(value); + } + catch + { + return null; } - - return new OtlpCommon.AnyValue { ArrayValue = arrayValue }; } + + return new OtlpCommon.AnyValue { ArrayValue = arrayValue }; } } diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs index 4f960811761..0a7a0d85b2e 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinTagTransformer.cs @@ -17,25 +17,24 @@ using System; using OpenTelemetry.Internal; -namespace OpenTelemetry.Exporter.Zipkin.Implementation +namespace OpenTelemetry.Exporter.Zipkin.Implementation; + +internal sealed class ZipkinTagTransformer : TagTransformer { - internal sealed class ZipkinTagTransformer : TagTransformer + private ZipkinTagTransformer() { - private ZipkinTagTransformer() - { - } + } - public static ZipkinTagTransformer Instance { get; } = new(); + public static ZipkinTagTransformer Instance { get; } = new(); - protected override string TransformIntegralTag(string key, long value) => value.ToString(); + protected override string TransformIntegralTag(string key, long value) => value.ToString(); - protected override string TransformFloatingPointTag(string key, double value) => value.ToString(); + protected override string TransformFloatingPointTag(string key, double value) => value.ToString(); - protected override string TransformBooleanTag(string key, bool value) => value ? "true" : "false"; + protected override string TransformBooleanTag(string key, bool value) => value ? "true" : "false"; - protected override string TransformStringTag(string key, string value) => value; + protected override string TransformStringTag(string key, string value) => value; - protected override string TransformArrayTag(string key, Array array) - => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(array)); - } + protected override string TransformArrayTag(string key, Array array) + => this.TransformStringTag(key, System.Text.Json.JsonSerializer.Serialize(array)); } From 5fa42813f6e3800189f12796b243b585db51db48 Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Wed, 25 May 2022 17:18:54 -0700 Subject: [PATCH 30/30] Update changelogs --- .../CHANGELOG.md | 19 +++++++++++++++++++ .../CHANGELOG.md | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md index 4b0cab56f41..8278480772b 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md @@ -2,6 +2,25 @@ ## Unreleased +* Improve the conversion and formatting of attribute values. + The list of data types that must be supported per the + [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/common#attribute) + is more narrow than what the .NET OpenTelemetry SDK supports. Numeric + [built-in value types](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/built-in-types) + are supported by converting to a `long` or `double` as appropriate except for + numeric types that could cause overflow (`ulong`) or rounding (`decimal`) + which are converted to strings. Non-numeric built-in types - `string`, + `char`, `bool` are supported. All other types are converted to a `string`. + Array values are also supported. + ([#3281](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3281)) +* Fix conversion of array-valued resource attributes. They were previously + converted to a string like "System.String[]". + ([#3281](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3281)) +* Fix exporting of array-valued attributes on an `Activity`. Previously, each + item in the array would result in a new tag on an exported `Activity`. Now, + array-valued attributes are serialzed to a JSON-array representation. + ([#3281](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3281)) + ## 1.3.0-beta.2 Released 2022-May-16 diff --git a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md index 5585eaf7770..9b7b23f4f76 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md @@ -2,6 +2,25 @@ ## Unreleased +* Improve the conversion and formatting of attribute values. + The list of data types that must be supported per the + [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/common#attribute) + is more narrow than what the .NET OpenTelemetry SDK supports. Numeric + [built-in value types](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/built-in-types) + are supported by converting to a `long` or `double` as appropriate except for + numeric types that could cause overflow (`ulong`) or rounding (`decimal`) + which are converted to strings. Non-numeric built-in types - `string`, + `char`, `bool` are supported. All other types are converted to a `string`. + Array values are also supported. + ([#3281](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3281)) +* Fix conversion of array-valued resource attributes. They were previously + converted to a string like "System.String[]". + ([#3281](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3281)) +* Fix exporting of array-valued attributes on an `Activity`. Previously, each + item in the array would result in a new tag on an exported `Activity`. Now, + array-valued attributes are serialzed to a JSON-array representation. + ([#3281](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3281)) + ## 1.3.0-beta.2 Released 2022-May-16