Skip to content

Commit

Permalink
Use ActivityTraceId and ActivitySpanId (#136)
Browse files Browse the repository at this point in the history
  • Loading branch information
Liudmila Molkova authored Jul 11, 2019
1 parent e511e84 commit 9523c31
Show file tree
Hide file tree
Showing 68 changed files with 589 additions and 1,679 deletions.
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
<PropertyGroup>
<RepositoryType>git</RepositoryType>
<PackageProjectUrl>https://github.com/open-telemetry/opentelemetry-dotnet</PackageProjectUrl>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
</Project>
46 changes: 26 additions & 20 deletions src/OpenTelemetry.Abstractions/Context/Propagation/BinaryFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,29 @@
namespace OpenTelemetry.Context.Propagation
{
using System;
using System.Diagnostics;
using OpenTelemetry.Trace;

public class BinaryFormat : IBinaryFormat
{
private const byte VersionId = 0;
private const int VersionIdOffset = 0;
private const int TraceIdSize = 16;
private const int SpanIdSize = 8;
private const int TraceOptionsSize = 1;

// The version_id/field_id size in bytes.
private const byte IdSize = 1;
private const byte TraceIdFieldId = 0;
private const int TraceIdFieldIdOffset = VersionIdOffset + IdSize;
private const int TraceIdOffset = TraceIdFieldIdOffset + IdSize;
private const byte SpanIdFieldId = 1;
private const int SpaneIdFieldIdOffset = TraceIdOffset + TraceId.Size;
private const int SpaneIdFieldIdOffset = TraceIdOffset + TraceIdSize;
private const int SpanIdOffset = SpaneIdFieldIdOffset + IdSize;
private const byte TraceOptionsFieldId = 2;
private const int TraceOptionFieldIdOffset = SpanIdOffset + SpanId.Size;
private const int TraceOptionFieldIdOffset = SpanIdOffset + SpanIdSize;
private const int TraceOptionOffset = TraceOptionFieldIdOffset + IdSize;
private const int FormatLength = (4 * IdSize) + TraceId.Size + SpanId.Size + TraceOptions.Size;
private const int FormatLength = (4 * IdSize) + TraceIdSize + SpanIdSize + TraceOptionsSize;

public SpanContext FromByteArray(byte[] bytes)
{
Expand All @@ -49,28 +53,29 @@ public SpanContext FromByteArray(byte[] bytes)
throw new SpanContextParseException("Unsupported version.");
}

var traceId = TraceId.Invalid;
var spanId = SpanId.Invalid;
var traceOptions = TraceOptions.Default;
ActivityTraceId traceId = default;
ActivitySpanId spanId = default;
var traceOptions = ActivityTraceFlags.None;

var traceparentBytes = new ReadOnlySpan<byte>(bytes);
var pos = 1;
try
{
if (bytes.Length > pos && bytes[pos] == TraceIdFieldId)
{
traceId = TraceId.FromBytes(bytes, pos + IdSize);
pos += IdSize + TraceId.Size;
traceId = ActivityTraceId.CreateFromBytes(traceparentBytes.Slice(pos + IdSize, 16));
pos += IdSize + TraceIdSize;
}

if (bytes.Length > pos && bytes[pos] == SpanIdFieldId)
{
spanId = SpanId.FromBytes(bytes, pos + IdSize);
pos += IdSize + SpanId.Size;
spanId = ActivitySpanId.CreateFromBytes(traceparentBytes.Slice(pos + IdSize, 8));
pos += IdSize + SpanIdSize;
}

if (bytes.Length > pos && bytes[pos] == TraceOptionsFieldId)
{
traceOptions = TraceOptions.FromBytes(bytes, pos + IdSize);
traceOptions = (ActivityTraceFlags)traceparentBytes[pos + IdSize];
}

return SpanContext.Create(traceId, spanId, traceOptions, Tracestate.Empty);
Expand All @@ -88,15 +93,16 @@ public byte[] ToByteArray(SpanContext spanContext)
throw new ArgumentNullException(nameof(spanContext));
}

var bytes = new byte[FormatLength];
bytes[VersionIdOffset] = VersionId;
bytes[TraceIdFieldIdOffset] = TraceIdFieldId;
spanContext.TraceId.CopyBytesTo(bytes, TraceIdOffset);
bytes[SpaneIdFieldIdOffset] = SpanIdFieldId;
spanContext.SpanId.CopyBytesTo(bytes, SpanIdOffset);
bytes[TraceOptionFieldIdOffset] = TraceOptionsFieldId;
spanContext.TraceOptions.CopyBytesTo(bytes, TraceOptionOffset);
return bytes;
Span<byte> spanBytes = stackalloc byte[FormatLength];
spanBytes[VersionIdOffset] = VersionId;
spanBytes[TraceIdFieldIdOffset] = TraceIdFieldId;
spanBytes[SpaneIdFieldIdOffset] = SpanIdFieldId;
spanBytes[TraceOptionFieldIdOffset] = TraceOptionsFieldId;
spanBytes[TraceOptionOffset] = (byte)spanContext.TraceOptions;
spanContext.TraceId.CopyTo(spanBytes.Slice(TraceIdOffset));
spanContext.SpanId.CopyTo(spanBytes.Slice(SpanIdOffset));

return spanBytes.ToArray();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace OpenTelemetry.Context.Propagation
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using OpenTelemetry.Trace;
Expand All @@ -35,6 +36,7 @@ public class TraceContextFormat : ITextFormat
private static readonly int SpanIdLength = "00f067aa0ba902b7".Length;
private static readonly int VersionAndTraceIdAndSpanIdLength = "00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-".Length;
private static readonly int OptionsLength = "00".Length;
private static readonly int TraceparentLengthV0 = "00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-00".Length;

/// <inheritdoc/>
public ISet<string> Fields => new HashSet<string> { "tracestate", "traceparent" };
Expand All @@ -47,13 +49,13 @@ public SpanContext Extract<T>(T carrier, Func<T, string, IEnumerable<string>> ge
var traceparentCollection = getter(carrier, "traceparent");
var tracestateCollection = getter(carrier, "tracestate");

if (traceparentCollection.Count() > 1)
if (traceparentCollection != null && traceparentCollection.Count() > 1)
{
// multiple traceparent are not allowed
return SpanContext.Blank;
}

var traceparent = traceparentCollection?.FirstOrDefault();
var traceparent = traceparentCollection.First();
var traceparentParsed = this.TryExtractTraceparent(traceparent, out var traceId, out var spanId, out var traceoptions);

if (!traceparentParsed)
Expand Down Expand Up @@ -165,8 +167,8 @@ public SpanContext Extract<T>(T carrier, Func<T, string, IEnumerable<string>> ge
/// <inheritdoc/>
public void Inject<T>(SpanContext spanContext, T carrier, Action<T, string, string> setter)
{
var traceparent = string.Concat("00-", spanContext.TraceId.ToLowerBase16(), "-", spanContext.SpanId.ToLowerBase16());
traceparent = string.Concat(traceparent, spanContext.TraceOptions.IsSampled ? "-01" : "-00");
var traceparent = string.Concat("00-", spanContext.TraceId.ToHexString(), "-", spanContext.SpanId.ToHexString());
traceparent = string.Concat(traceparent, (spanContext.TraceOptions & ActivityTraceFlags.Recorded) != 0 ? "-01" : "-00");

setter(carrier, "traceparent", traceparent);

Expand All @@ -193,92 +195,90 @@ public void Inject<T>(SpanContext spanContext, T carrier, Action<T, string, stri
}
}

private bool TryExtractTraceparent(string traceparent, out TraceId traceId, out SpanId spanId, out TraceOptions traceoptions)
private bool TryExtractTraceparent(string traceparent, out ActivityTraceId traceId, out ActivitySpanId spanId, out ActivityTraceFlags traceoptions)
{
// from https://github.com/w3c/distributed-tracing/blob/master/trace_context/HTTP_HEADER_FORMAT.md
// traceparent: 00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01

traceId = TraceId.Invalid;
spanId = SpanId.Invalid;
traceoptions = TraceOptions.Default;
traceId = default;
spanId = default;
traceoptions = default;
var bestAttempt = false;

if (string.IsNullOrWhiteSpace(traceparent))
if (string.IsNullOrWhiteSpace(traceparent) || traceparent.Length < TraceparentLengthV0)
{
return false;
}

// if version does not end with delimeter
if (traceparent.Length < VersionPrefixIdLength || traceparent[VersionPrefixIdLength - 1] != '-')
if (traceparent[VersionPrefixIdLength - 1] != '-')
{
return false;
}

// or version is not a hex (will throw)
var versionArray = Arrays.StringToByteArray(traceparent, 0, VersionLength);
var version0 = this.HexCharToByte(traceparent[0]);
var version1 = this.HexCharToByte(traceparent[1]);

if (versionArray[0] == 255)
if (version0 == 0xf && version1 == 0xf)
{
return false;
}

if (versionArray[0] > 0)
if (version0 > 0)
{
// expected version is 00
// for higher versions - best attempt parsing of trace id, span id, etc.
bestAttempt = true;
}

if (traceparent.Length < VersionAndTraceIdLength || traceparent[VersionAndTraceIdLength - 1] != '-')
if (traceparent[VersionAndTraceIdLength - 1] != '-')
{
return false;
}

try
{
traceId = TraceId.FromBytes(Arrays.StringToByteArray(traceparent, VersionPrefixIdLength, TraceIdLength));
traceId = ActivityTraceId.CreateFromString(traceparent.AsSpan().Slice(VersionPrefixIdLength, TraceIdLength));
}
catch (ArgumentOutOfRangeException)
{
// it's ok to still parse tracestate
return false;
}

if (traceparent.Length < VersionAndTraceIdAndSpanIdLength || traceparent[VersionAndTraceIdAndSpanIdLength - 1] != '-')
if (traceparent[VersionAndTraceIdAndSpanIdLength - 1] != '-')
{
return false;
}

try
{
spanId = SpanId.FromBytes(Arrays.StringToByteArray(traceparent, VersionAndTraceIdLength, SpanIdLength));
spanId = ActivitySpanId.CreateFromString(traceparent.AsSpan().Slice(VersionAndTraceIdLength, SpanIdLength));
}
catch (ArgumentOutOfRangeException)
{
// it's ok to still parse tracestate
return false;
}

if (traceparent.Length < VersionAndTraceIdAndSpanIdLength + OptionsLength)
{
return false;
}

byte[] optionsArray;
byte options0;
byte options1;

try
{
optionsArray = Arrays.StringToByteArray(traceparent, VersionAndTraceIdAndSpanIdLength, OptionsLength);
options0 = this.HexCharToByte(traceparent[VersionAndTraceIdAndSpanIdLength]);
options1 = this.HexCharToByte(traceparent[VersionAndTraceIdAndSpanIdLength]);
}
catch (ArgumentOutOfRangeException)
{
// it's ok to still parse tracestate
return false;
}

if ((optionsArray[0] | 1) == 1)
if ((options0 | 1) == 1)
{
traceoptions = TraceOptions.Builder().SetIsSampled(true).Build();
traceoptions |= ActivityTraceFlags.Recorded;
}

if ((!bestAttempt) && (traceparent.Length != VersionAndTraceIdAndSpanIdLength + OptionsLength))
Expand All @@ -288,14 +288,33 @@ private bool TryExtractTraceparent(string traceparent, out TraceId traceId, out

if (bestAttempt)
{
if ((traceparent.Length > VersionAndTraceIdAndSpanIdLength + OptionsLength) &&
(traceparent[VersionAndTraceIdAndSpanIdLength + OptionsLength] != '-'))
if ((traceparent.Length > TraceparentLengthV0) && (traceparent[TraceparentLengthV0] != '-'))
{
return false;
}
}

return true;
}

private byte HexCharToByte(char c)
{
if ((c >= '0') && (c <= '9'))
{
return (byte)(c - '0');
}

if ((c >= 'a') && (c <= 'f'))
{
return (byte)(c - 'a' + 10);
}

if ((c >= 'A') && (c <= 'F'))
{
return (byte)(c - 'A' + 10);
}

throw new ArgumentOutOfRangeException("Invalid character: " + c);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@
<Description>OpenTelemetry .NET API abstractions</Description>
<RootNamespace>OpenTelemetry</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="4.6.0-preview6.19303.8" />
</ItemGroup>
</Project>
4 changes: 1 addition & 3 deletions src/OpenTelemetry.Abstractions/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

using System.Runtime.CompilerServices;

[assembly: System.CLSCompliant(true)]

[assembly: InternalsVisibleTo("OpenTelemetry.Tests" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2" + AssemblyInfo.MoqPublicKey)]

Expand All @@ -33,4 +31,4 @@ internal static class AssemblyInfo
public const string PublicKey = "";
public const string MoqPublicKey = "";
}
#endif
#endif
3 changes: 2 additions & 1 deletion src/OpenTelemetry.Abstractions/Trace/ISampler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
namespace OpenTelemetry.Trace
{
using System.Collections.Generic;
using System.Diagnostics;

/// <summary>
/// Sampler to reduce data volume. This sampler executes before Span object was created.
Expand All @@ -41,6 +42,6 @@ public interface ISampler
/// </param>
/// <param name="links">Links associated with the span.</param>
/// <returns>True of span needs to be created. False otherwise.</returns>
bool ShouldSample(SpanContext parentContext, TraceId traceId, SpanId spanId, string name, IEnumerable<ILink> links);
bool ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name, IEnumerable<ILink> links);
}
}
4 changes: 2 additions & 2 deletions src/OpenTelemetry.Abstractions/Trace/Link.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ public static ILink FromSpanContext(SpanContext context, IDictionary<string, IAt
public override string ToString()
{
return "Link{"
+ "traceId=" + this.Context.TraceId + ", "
+ "spanId=" + this.Context.SpanId + ", "
+ "traceId=" + this.Context.TraceId.ToHexString() + ", "
+ "spanId=" + this.Context.SpanId.ToHexString() + ", "
+ "tracestate=" + this.Context.Tracestate.ToString() + ", "
+ "attributes=" + Collections.ToString(this.Attributes)
+ "}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
namespace OpenTelemetry.Trace.Sampler.Internal
{
using System.Collections.Generic;
using System.Diagnostics;

internal sealed class AlwaysSampleSampler : ISampler
{
Expand All @@ -27,7 +28,7 @@ internal AlwaysSampleSampler()
public string Description => this.ToString();

/// <inheritdoc />
public bool ShouldSample(SpanContext parentContext, TraceId traceId, SpanId spanId, string name, IEnumerable<ILink> parentLinks)
public bool ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name, IEnumerable<ILink> parentLinks)
{
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
namespace OpenTelemetry.Trace.Sampler.Internal
{
using System.Collections.Generic;
using System.Diagnostics;

/// <inheritdoc />
internal sealed class NeverSampleSampler : ISampler
Expand All @@ -28,7 +29,7 @@ internal NeverSampleSampler()
public string Description => this.ToString();

/// <inheritdoc />
public bool ShouldSample(SpanContext parentContext, TraceId traceId, SpanId spanId, string name, IEnumerable<ILink> links)
public bool ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name, IEnumerable<ILink> links)
{
return false;
}
Expand Down
Loading

0 comments on commit 9523c31

Please sign in to comment.