Updating exporters to use TagObjects instead of Tags (#1000)

* Update ZipkinExporter to use TagObjects instead of Tags

* Updating JaegerExporter to use TagObjects

* Updating OtlpExporter to use TagObjects

* removing unused using

* Removing duplicated logic

Co-authored-by: Cijo Thomas <cithomas@microsoft.com>
This commit is contained in:
Eddy Nakamura 2020-08-04 21:10:29 -03:00 committed by GitHub
parent 4f8c351420
commit 53a579f507
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 85 deletions

View File

@ -48,11 +48,11 @@ namespace OpenTelemetry.Exporter.Jaeger.Implementation
[SemanticConventions.AttributeNetPeerIp] = 2,
["peer.hostname"] = 2,
["peer.address"] = 2,
["http.host"] = 3, // peer.service for Http.
["db.instance"] = 3, // peer.service for Redis.
[SemanticConventions.AttributeHttpHost] = 3, // peer.service for Http.
[SemanticConventions.AttributeDbInstance] = 3, // peer.service for Redis.
};
private static readonly DictionaryEnumerator<string, string, TagState>.ForEachDelegate ProcessActivityTagRef = ProcessActivityTag;
private static readonly DictionaryEnumerator<string, object, TagState>.ForEachDelegate ProcessActivityTagRef = ProcessActivityTag;
private static readonly ListEnumerator<ActivityLink, PooledListState<JaegerSpanRef>>.ForEachDelegate ProcessActivityLinkRef = ProcessActivityLink;
private static readonly ListEnumerator<ActivityEvent, PooledListState<JaegerLog>>.ForEachDelegate ProcessActivityEventRef = ProcessActivityEvent;
private static readonly DictionaryEnumerator<string, object, PooledListState<JaegerTag>>.ForEachDelegate ProcessTagRef = ProcessTag;
@ -64,8 +64,8 @@ namespace OpenTelemetry.Exporter.Jaeger.Implementation
Tags = PooledList<JaegerTag>.Create(),
};
DictionaryEnumerator<string, string, TagState>.AllocationFreeForEach(
activity.Tags,
DictionaryEnumerator<string, object, TagState>.AllocationFreeForEach(
activity.TagObjects,
ref jaegerTags,
ProcessActivityTagRef);
@ -217,23 +217,16 @@ namespace OpenTelemetry.Exporter.Jaeger.Implementation
public static JaegerTag ToJaegerTag(this KeyValuePair<string, object> attribute)
{
switch (attribute.Value)
return attribute.Value switch
{
case string s:
return new JaegerTag(attribute.Key, JaegerTagType.STRING, vStr: s);
case int i:
return new JaegerTag(attribute.Key, JaegerTagType.LONG, vLong: Convert.ToInt64(i));
case long l:
return new JaegerTag(attribute.Key, JaegerTagType.LONG, vLong: l);
case float f:
return new JaegerTag(attribute.Key, JaegerTagType.DOUBLE, vDouble: Convert.ToDouble(f));
case double d:
return new JaegerTag(attribute.Key, JaegerTagType.DOUBLE, vDouble: d);
case bool b:
return new JaegerTag(attribute.Key, JaegerTagType.BOOL, vBool: b);
}
return new JaegerTag(attribute.Key, JaegerTagType.STRING, vStr: attribute.Value.ToString());
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()),
};
}
public static long ToEpochMicroseconds(this DateTime utcDateTime)
@ -256,9 +249,9 @@ namespace OpenTelemetry.Exporter.Jaeger.Implementation
return microseconds - UnixEpochMicroseconds;
}
private static bool ProcessActivityTag(ref TagState state, KeyValuePair<string, string> activityTag)
private static bool ProcessActivityTag(ref TagState state, KeyValuePair<string, object> activityTag)
{
var jaegerTag = new JaegerTag(activityTag.Key, JaegerTagType.STRING, activityTag.Value);
JaegerTag jaegerTag = activityTag.ToJaegerTag();
if (jaegerTag.VStr != null
&& PeerServiceKeyResolutionDictionary.TryGetValue(activityTag.Key, out int priority)

View File

@ -112,7 +112,7 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation
EndTimeUnixNano = (ulong)(startTimeUnixNano + activity.Duration.ToNanoseconds()),
};
foreach (var kvp in activity.Tags)
foreach (var kvp in activity.TagObjects)
{
var attribute = ToOtlpAttribute(kvp);
if (attribute != null && attribute.Key != SpanAttributeConstants.StatusCodeKey && attribute.Key != SpanAttributeConstants.StatusDescriptionKey)
@ -219,39 +219,6 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation
return otlpEvent;
}
private static OtlpCommon.KeyValue ToOtlpAttribute(KeyValuePair<string, string> kvp)
{
// TODO: enforce no duplicate keys?
// TODO: reverse?
// To maintain full fidelity to downstream receivers convert to the proper attribute types
if (kvp.Value == null)
{
return null;
}
var attrib = new OtlpCommon.KeyValue { Key = kvp.Key, Value = new OtlpCommon.AnyValue { } };
if (long.TryParse(kvp.Value, out var longValue))
{
attrib.Value.IntValue = longValue;
}
else if (double.TryParse(kvp.Value, out var doubleValue))
{
attrib.Value.DoubleValue = doubleValue;
}
else if (bool.TryParse(kvp.Value, out var boolValue))
{
attrib.Value.BoolValue = boolValue;
}
else
{
attrib.Value.StringValue = kvp.Value;
}
return attrib;
}
private static OtlpCommon.KeyValue ToOtlpAttribute(KeyValuePair<string, object> kvp)
{
if (kvp.Value == null)

View File

@ -37,8 +37,8 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation
[SemanticConventions.AttributeNetPeerIp] = 2,
["peer.hostname"] = 2,
["peer.address"] = 2,
["http.host"] = 3, // RemoteEndpoint.ServiceName for Http.
["db.instance"] = 3, // RemoteEndpoint.ServiceName for Redis.
[SemanticConventions.AttributeHttpHost] = 3, // RemoteEndpoint.ServiceName for Http.
[SemanticConventions.AttributeDbInstance] = 3, // RemoteEndpoint.ServiceName for Redis.
};
private static readonly string InvalidSpanId = default(ActivitySpanId).ToHexString();
@ -46,7 +46,7 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation
private static readonly ConcurrentDictionary<string, ZipkinEndpoint> LocalEndpointCache = new ConcurrentDictionary<string, ZipkinEndpoint>();
private static readonly ConcurrentDictionary<string, ZipkinEndpoint> RemoteEndpointCache = new ConcurrentDictionary<string, ZipkinEndpoint>();
private static readonly DictionaryEnumerator<string, string, AttributeEnumerationState>.ForEachDelegate ProcessTagsRef = ProcessTags;
private static readonly DictionaryEnumerator<string, object, AttributeEnumerationState>.ForEachDelegate ProcessTagsRef = ProcessTags;
private static readonly ListEnumerator<ActivityEvent, PooledList<ZipkinAnnotation>>.ForEachDelegate ProcessActivityEventsRef = ProcessActivityEvents;
internal static ZipkinSpan ToZipkinSpan(this Activity activity, ZipkinEndpoint defaultLocalEndpoint, bool useShortTraceIds = false)
@ -62,18 +62,18 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation
var attributeEnumerationState = new AttributeEnumerationState
{
Tags = PooledList<KeyValuePair<string, string>>.Create(),
Tags = PooledList<KeyValuePair<string, object>>.Create(),
};
DictionaryEnumerator<string, string, AttributeEnumerationState>.AllocationFreeForEach(activity.Tags, ref attributeEnumerationState, ProcessTagsRef);
DictionaryEnumerator<string, object, AttributeEnumerationState>.AllocationFreeForEach(activity.TagObjects, ref attributeEnumerationState, ProcessTagsRef);
var activitySource = activity.Source;
if (!string.IsNullOrEmpty(activitySource.Name))
{
PooledList<KeyValuePair<string, string>>.Add(ref attributeEnumerationState.Tags, new KeyValuePair<string, string>("library.name", activitySource.Name));
PooledList<KeyValuePair<string, object>>.Add(ref attributeEnumerationState.Tags, new KeyValuePair<string, object>("library.name", activitySource.Name));
if (!string.IsNullOrEmpty(activitySource.Version))
{
PooledList<KeyValuePair<string, string>>.Add(ref attributeEnumerationState.Tags, new KeyValuePair<string, string>("library.version", activitySource.Version));
PooledList<KeyValuePair<string, object>>.Add(ref attributeEnumerationState.Tags, new KeyValuePair<string, object>("library.version", activitySource.Version));
}
}
@ -161,19 +161,14 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation
private static string ToActivityKind(Activity activity)
{
switch (activity.Kind)
return activity.Kind switch
{
case ActivityKind.Server:
return "SERVER";
case ActivityKind.Producer:
return "PRODUCER";
case ActivityKind.Consumer:
return "CONSUMER";
case ActivityKind.Client:
return "CLIENT";
}
return null;
ActivityKind.Server => "SERVER",
ActivityKind.Producer => "PRODUCER",
ActivityKind.Consumer => "CONSUMER",
ActivityKind.Client => "CLIENT",
_ => null,
};
}
private static bool ProcessActivityEvents(ref PooledList<ZipkinAnnotation> annotations, ActivityEvent @event)
@ -182,10 +177,10 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation
return true;
}
private static bool ProcessTags(ref AttributeEnumerationState state, KeyValuePair<string, string> attribute)
private static bool ProcessTags(ref AttributeEnumerationState state, KeyValuePair<string, object> attribute)
{
string key = attribute.Key;
string strVal = attribute.Value;
string strVal = attribute.Value as string;
if (strVal != null)
{
@ -205,12 +200,12 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation
}
else
{
PooledList<KeyValuePair<string, string>>.Add(ref state.Tags, new KeyValuePair<string, string>(key, strVal));
PooledList<KeyValuePair<string, object>>.Add(ref state.Tags, new KeyValuePair<string, object>(key, strVal));
}
}
else
{
PooledList<KeyValuePair<string, string>>.Add(ref state.Tags, new KeyValuePair<string, string>(key, strVal));
PooledList<KeyValuePair<string, object>>.Add(ref state.Tags, new KeyValuePair<string, object>(key, strVal));
}
return true;
@ -218,7 +213,7 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation
private struct AttributeEnumerationState
{
public PooledList<KeyValuePair<string, string>> Tags;
public PooledList<KeyValuePair<string, object>> Tags;
public string RemoteEndpointServiceName;

View File

@ -37,7 +37,7 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation
ZipkinEndpoint localEndpoint,
ZipkinEndpoint remoteEndpoint,
in PooledList<ZipkinAnnotation>? annotations,
in PooledList<KeyValuePair<string, string>>? tags,
in PooledList<KeyValuePair<string, object>>? tags,
bool? debug,
bool? shared)
{
@ -86,7 +86,7 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation
public PooledList<ZipkinAnnotation>? Annotations { get; }
public PooledList<KeyValuePair<string, string>>? Tags { get; }
public PooledList<KeyValuePair<string, object>>? Tags { get; }
public bool? Debug { get; }
@ -282,7 +282,28 @@ namespace OpenTelemetry.Exporter.Zipkin.Implementation
foreach (var tag in this.Tags.Value)
{
writer.WriteString(tag.Key, tag.Value);
if (tag.Value is int intValue)
{
writer.WriteNumber(tag.Key, intValue);
}
else if (tag.Value is bool boolVal)
{
writer.WriteBoolean(tag.Key, boolVal);
}
else if (tag.Value is double doubleVal)
{
writer.WriteNumber(tag.Key, doubleVal);
}
else if (tag.Value is string stringVal)
{
writer.WriteString(tag.Key, stringVal);
}
else
{
// Should we try to convert to string? Or
// just drop it?
writer.WriteString(tag.Key, tag.Value.ToString());
}
}
writer.WriteEndObject();

View File

@ -152,7 +152,7 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests
foreach (var kvp in attributes)
{
rootActivity.SetTag(kvp.Key, kvp.Value.ToString());
rootActivity.SetTag(kvp.Key, kvp.Value);
}
var startTime = new DateTime(2020, 02, 20, 20, 20, 20, DateTimeKind.Utc);