Skip to content

Commit

Permalink
Updating exporters to use TagObjects instead of Tags (open-telemetry#…
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
eddynaka and cijothomas authored Aug 5, 2020
1 parent 4f8c351 commit 53a579f
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ internal static class JaegerActivityExtensions
[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;
Expand All @@ -64,8 +64,8 @@ public static JaegerSpan ToJaegerSpan(this Activity activity)
Tags = PooledList<JaegerTag>.Create(),
};

DictionaryEnumerator<string, string, TagState>.AllocationFreeForEach(
activity.Tags,
DictionaryEnumerator<string, object, TagState>.AllocationFreeForEach(
activity.TagObjects,
ref jaegerTags,
ProcessActivityTagRef);

Expand Down Expand Up @@ -217,23 +217,16 @@ public static JaegerSpanRef ToJaegerSpanRef(this in ActivityLink link)

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)
Expand All @@ -256,9 +249,9 @@ public static long ToEpochMicroseconds(this DateTimeOffset timestamp)
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ internal static OtlpTrace.Span ToOtlpSpan(this Activity activity)
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)
Expand Down Expand Up @@ -219,39 +219,6 @@ private static OtlpTrace.Span.Types.Event ToOtlpEvent(ActivityEvent activityEven
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@ internal static class ZipkinActivityConversionExtensions
[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();

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)
Expand All @@ -62,18 +62,18 @@ internal static ZipkinSpan ToZipkinSpan(this Activity activity, ZipkinEndpoint d

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));
}
}

Expand Down Expand Up @@ -161,19 +161,14 @@ private static string EncodeTraceId(ActivityTraceId traceId, bool useShortTraceI

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)
Expand All @@ -182,10 +177,10 @@ private static bool ProcessActivityEvents(ref PooledList<ZipkinAnnotation> annot
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)
{
Expand All @@ -205,20 +200,20 @@ private static bool ProcessTags(ref AttributeEnumerationState state, KeyValuePai
}
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;
}

private struct AttributeEnumerationState
{
public PooledList<KeyValuePair<string, string>> Tags;
public PooledList<KeyValuePair<string, object>> Tags;

public string RemoteEndpointServiceName;

Expand Down
27 changes: 24 additions & 3 deletions src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinSpan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public ZipkinSpan(
ZipkinEndpoint localEndpoint,
ZipkinEndpoint remoteEndpoint,
in PooledList<ZipkinAnnotation>? annotations,
in PooledList<KeyValuePair<string, string>>? tags,
in PooledList<KeyValuePair<string, object>>? tags,
bool? debug,
bool? shared)
{
Expand Down Expand Up @@ -86,7 +86,7 @@ public ZipkinSpan(

public PooledList<ZipkinAnnotation>? Annotations { get; }

public PooledList<KeyValuePair<string, string>>? Tags { get; }
public PooledList<KeyValuePair<string, object>>? Tags { get; }

public bool? Debug { get; }

Expand Down Expand Up @@ -282,7 +282,28 @@ public void Write(Utf8JsonWriter writer)

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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public void ToOtlpSpanTest()

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);
Expand Down

0 comments on commit 53a579f

Please sign in to comment.