Skip to content
This repository was archived by the owner on Apr 11, 2019. It is now read-only.

[MCC-261721] Don't break on 128bit X-B3-TraceId by tossing high bits #100

Merged
merged 8 commits into from
Nov 17, 2016
17 changes: 14 additions & 3 deletions src/Medidata.ZipkinTracer.Core/TraceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ internal TraceProvider(IZipkinConfig config, IOwinContext context = null)
}

// zipkin use the following X-Headers to propagate the trace information
headerTraceId = context.Request.Headers[TraceIdHeaderName];
headerTraceId = GetLower16Characters(context.Request.Headers[TraceIdHeaderName]);
headerSpanId = context.Request.Headers[SpanIdHeaderName];
headerParentSpanId = context.Request.Headers[ParentSpanIdHeaderName];
headerSampled = context.Request.Headers[SampledHeaderName];
Expand Down Expand Up @@ -120,8 +120,19 @@ public ITraceProvider GetNext()
/// <returns>true: parsed</returns>
private bool Parse(string value)
{
long result;
return !string.IsNullOrWhiteSpace(value) && Int64.TryParse(value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out result);
ulong result;
return !string.IsNullOrWhiteSpace(value) && UInt64.TryParse(value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out result);
}

/// <summary>
/// Get Lower 16 Characters of an id
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private string GetLower16Characters(string value)
{
if (string.IsNullOrWhiteSpace(value)) return value;
return value.Length > 16 ? value.Substring(value.Length - 16) : value;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question, is this trying to return the first or the last 16 characters?
E.g., if value = "abcdefghijklmnopq", what should be returned?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will return the last 16 🎆


/// <summary>
Expand Down
81 changes: 81 additions & 0 deletions tests/Medidata.ZipkinTracer.Core.Test/TraceProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,5 +218,86 @@ public void GetNext()
Assert.AreEqual(sut.SpanId, nextTraceProvider.ParentSpanId);
Assert.AreEqual(sut.IsSampled, nextTraceProvider.IsSampled);
}

[TestMethod]
public void TraceIdWithLessThan16Characters()
{
// Arrange
var fixture = new Fixture();
var traceId = "48485a3953bb612";

var context = GenerateContext(
traceId,
Convert.ToString(fixture.Create<long>(), 16),
Convert.ToString(fixture.Create<long>(), 16),
fixture.Create<bool>());

// Act
var sut = new TraceProvider(new ZipkinConfig(), context);

// Assert
Assert.AreEqual(traceId, sut.TraceId);
}

[TestMethod]
public void TraceIdWith16Characters()
{
// Arrange
var fixture = new Fixture();
var traceId = "48485a3953bb6124";

var context = GenerateContext(
traceId,
Convert.ToString(fixture.Create<long>(), 16),
Convert.ToString(fixture.Create<long>(), 16),
fixture.Create<bool>());

// Act
var sut = new TraceProvider(new ZipkinConfig(), context);

// Assert
Assert.AreEqual(traceId, sut.TraceId);
}

[TestMethod]
public void TraceIdWith32Characters()
{
// Arrange
var fixture = new Fixture();
var traceIdLower16Chars = "48485a3953bb6124";
var traceId = "18485a3953bb6124" + traceIdLower16Chars;

var context = GenerateContext(
traceId,
Convert.ToString(fixture.Create<long>(), 16),
Convert.ToString(fixture.Create<long>(), 16),
fixture.Create<bool>());

// Act
var sut = new TraceProvider(new ZipkinConfig(), context);

// Assert
Assert.AreEqual(traceIdLower16Chars, sut.TraceId);
}

private IOwinContext GenerateContext(string traceId, string spanId, string parentSpanId, bool isSampled)
{
var context = MockRepository.GenerateStub<IOwinContext>();
var request = MockRepository.GenerateStub<IOwinRequest>();
var headers = new HeaderDictionary(new Dictionary<string, string[]>
{
{ TraceProvider.TraceIdHeaderName, new [] { traceId } },
{ TraceProvider.SpanIdHeaderName, new [] { spanId } },
{ TraceProvider.ParentSpanIdHeaderName, new [] { parentSpanId } },
{ TraceProvider.SampledHeaderName, new [] { isSampled.ToString() } }
});
var environment = new Dictionary<string, object>();

request.Stub(x => x.Headers).Return(headers);
context.Stub(x => x.Request).Return(request);
context.Stub(x => x.Environment).Return(environment);

return context;
}
}
}