Skip to content

Commit

Permalink
OTLP exporter: Standardize handling of attributes (#3262)
Browse files Browse the repository at this point in the history
  • Loading branch information
alanwest authored May 11, 2022
1 parent a53900f commit e7f06af
Show file tree
Hide file tree
Showing 5 changed files with 394 additions and 35 deletions.
13 changes: 13 additions & 0 deletions src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ option
* Fix handling of array-valued attributes for the OTLP trace exporter.
([#3238](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3238))

* Improve the conversion and formatting of attribute values to the OTLP format
for resources, metrics, and logs. 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.
([#3262](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3262))

## 1.3.0-beta.1

Released 2022-Apr-15
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,41 +201,6 @@ internal static OtlpTrace.Span ToOtlpSpan(this Activity activity)
return otlpSpan;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static OtlpCommon.KeyValue ToOtlpAttribute(this KeyValuePair<string, object> kvp)
{
if (kvp.Value == null)
{
return null;
}

var attrib = new OtlpCommon.KeyValue { Key = kvp.Key, Value = new OtlpCommon.AnyValue { } };

switch (kvp.Value)
{
case string s:
attrib.Value.StringValue = s;
break;
case bool b:
attrib.Value.BoolValue = b;
break;
case int i:
attrib.Value.IntValue = i;
break;
case long l:
attrib.Value.IntValue = l;
break;
case double d:
attrib.Value.DoubleValue = d;
break;
default:
attrib.Value.StringValue = kvp.Value.ToString();
break;
}

return attrib;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static OtlpTrace.Status ToOtlpStatus(this Activity activity, ref TagEnumerationState otlpTags)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,11 @@ 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);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// <copyright file="OtlpCommonExtensions.cs" company="OpenTelemetry Authors">
// 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.
// </copyright>

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using OtlpCommon = Opentelemetry.Proto.Common.V1;

namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation
{
internal static class OtlpCommonExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static OtlpCommon.KeyValue ToOtlpAttribute(this KeyValuePair<string, object> 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 };
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static OtlpCommon.AnyValue ToOtlpValue(object value)
{
switch (value)
{
case char:
case string:
return new OtlpCommon.AnyValue { StringValue = Convert.ToString(value) };
case bool b:
return new OtlpCommon.AnyValue { BoolValue = b };
case byte:
case sbyte:
case short:
case ushort:
case int:
case uint:
case long:
return new OtlpCommon.AnyValue { IntValue = Convert.ToInt64(value) };
case float:
case double:
return new OtlpCommon.AnyValue { DoubleValue = Convert.ToDouble(value) };
case Array array:
return ToOtlpArrayValue(array);

// 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
{
return new OtlpCommon.AnyValue { StringValue = value.ToString() };
}
catch
{
return null;
}
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static OtlpCommon.AnyValue ToOtlpArrayValue(Array array)
{
#pragma warning disable SA1011 // Closing square brackets should be spaced correctly
var arrayValue = new OtlpCommon.ArrayValue();
switch (array)
{
case char[]:
case string[]:
case bool[]:
case byte[]:
case sbyte[]:
case short[]:
case ushort[]:
case int[]:
case uint[]:
case long[]:
case float[]:
case double[]:
foreach (var item in array)
{
arrayValue.Values.Add(ToOtlpValue(item));
}

return new OtlpCommon.AnyValue { ArrayValue = arrayValue };
default:
foreach (var item in array)
{
try
{
arrayValue.Values.Add(ToOtlpValue(item.ToString()));
}
catch
{
return null;
}
}

return new OtlpCommon.AnyValue { ArrayValue = arrayValue };
}
#pragma warning restore SA1011 // Closing square brackets should be spaced correctly
}
}
}
Loading

0 comments on commit e7f06af

Please sign in to comment.