Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to ActivityTraceId and ActivitySpanId (from .NET) #136

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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