diff --git a/src/Microsoft.AspNet.Hosting/Internal/FastHttpRequestIdentifierFeature.cs b/src/Microsoft.AspNet.Hosting/Internal/FastHttpRequestIdentifierFeature.cs new file mode 100644 index 0000000000..74f7b36d6e --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/Internal/FastHttpRequestIdentifierFeature.cs @@ -0,0 +1,60 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading; +using Microsoft.AspNet.Http.Features; + +namespace Microsoft.AspNet.Hosting.Internal +{ + public class FastHttpRequestIdentifierFeature : IHttpRequestIdentifierFeature + { + private static readonly string _hexChars = "0123456789ABCDEF"; + // Seed the _requestId for this application instance with a random int + private static long _requestId = new Random().Next(); + + private string _id = null; + + public string TraceIdentifier + { + get + { + // Don't incur the cost of generating the request ID until it's asked for + if (_id == null) + { + _id = GenerateRequestId(Interlocked.Increment(ref _requestId)); + } + return _id; + } + set + { + _id = value; + } + } + + private static string GenerateRequestId(long id) + { + // The following routine is ~33% faster than calling long.ToString() when testing in tight loops of + // 1 million iterations. + var charBuffer = new char[sizeof(long) * 2]; + charBuffer[0] = _hexChars[(int)(id >> 60) & 0x0f]; + charBuffer[1] = _hexChars[(int)(id >> 56) & 0x0f]; + charBuffer[2] = _hexChars[(int)(id >> 52) & 0x0f]; + charBuffer[3] = _hexChars[(int)(id >> 48) & 0x0f]; + charBuffer[4] = _hexChars[(int)(id >> 44) & 0x0f]; + charBuffer[5] = _hexChars[(int)(id >> 40) & 0x0f]; + charBuffer[6] = _hexChars[(int)(id >> 36) & 0x0f]; + charBuffer[7] = _hexChars[(int)(id >> 32) & 0x0f]; + charBuffer[8] = _hexChars[(int)(id >> 28) & 0x0f]; + charBuffer[9] = _hexChars[(int)(id >> 24) & 0x0f]; + charBuffer[10] = _hexChars[(int)(id >> 20) & 0x0f]; + charBuffer[11] = _hexChars[(int)(id >> 16) & 0x0f]; + charBuffer[12] = _hexChars[(int)(id >> 12) & 0x0f]; + charBuffer[13] = _hexChars[(int)(id >> 8) & 0x0f]; + charBuffer[14] = _hexChars[(int)(id >> 4) & 0x0f]; + charBuffer[15] = _hexChars[(int)(id >> 0) & 0x0f]; + + return new string(charBuffer); + } + } +} diff --git a/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs b/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs index 786ba49eff..55b4170469 100644 --- a/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs +++ b/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs @@ -12,7 +12,6 @@ using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Hosting.Startup; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Features.Internal; using Microsoft.AspNet.Server.Features; using Microsoft.Dnx.Runtime; using Microsoft.Extensions.Configuration; @@ -278,10 +277,7 @@ namespace Microsoft.AspNet.Hosting.Internal var requestIdentifierFeature = httpContext.Features.Get(); if (requestIdentifierFeature == null) { - requestIdentifierFeature = new HttpRequestIdentifierFeature() - { - TraceIdentifier = Guid.NewGuid().ToString() - }; + requestIdentifierFeature = new FastHttpRequestIdentifierFeature(); httpContext.Features.Set(requestIdentifierFeature); } diff --git a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs b/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs index 9594e06f26..e3bd3759a7 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs @@ -305,7 +305,7 @@ namespace Microsoft.AspNet.Hosting // Assert Assert.NotNull(httpContext); - Assert.IsType(httpContext.Features.Get()); + Assert.IsType(httpContext.Features.Get()); } [Fact] @@ -328,7 +328,7 @@ namespace Microsoft.AspNet.Hosting // Assert Assert.NotNull(httpContext); - Assert.IsType(httpContext.Features.Get()); + Assert.IsType(httpContext.Features.Get()); } [Fact] diff --git a/test/Microsoft.AspNet.Hosting.Tests/Internal/FastHttpRequestIdentifierFeatureTests.cs b/test/Microsoft.AspNet.Hosting.Tests/Internal/FastHttpRequestIdentifierFeatureTests.cs new file mode 100644 index 0000000000..fff0fb603a --- /dev/null +++ b/test/Microsoft.AspNet.Hosting.Tests/Internal/FastHttpRequestIdentifierFeatureTests.cs @@ -0,0 +1,44 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNet.Hosting.Internal; +using Xunit; + +namespace Microsoft.AspNet.Hosting.Tests.Internal +{ + public class FastHttpRequestIdentifierFeatureTests + { + [Fact] + public void TraceIdentifier_ReturnsId() + { + var feature = new FastHttpRequestIdentifierFeature(); + + var id = feature.TraceIdentifier; + + Assert.NotNull(id); + } + + [Fact] + public void TraceIdentifier_ReturnsStableId() + { + var feature = new FastHttpRequestIdentifierFeature(); + + var id1 = feature.TraceIdentifier; + var id2 = feature.TraceIdentifier; + + Assert.Equal(id1, id2); + } + + [Fact] + public void TraceIdentifier_ReturnsUniqueIdForDifferentInstances() + { + var feature1 = new FastHttpRequestIdentifierFeature(); + var feature2 = new FastHttpRequestIdentifierFeature(); + + var id1 = feature1.TraceIdentifier; + var id2 = feature2.TraceIdentifier; + + Assert.NotEqual(id1, id2); + } + } +}