Merge pull request #440 from benaadams/move-request-identifier
Expose TraceIdentifier on Httpcontext
This commit is contained in:
commit
7d62a188e1
|
|
@ -34,6 +34,8 @@ namespace Microsoft.AspNet.Http
|
||||||
|
|
||||||
public abstract CancellationToken RequestAborted { get; set; }
|
public abstract CancellationToken RequestAborted { get; set; }
|
||||||
|
|
||||||
|
public abstract string TraceIdentifier { get; set; }
|
||||||
|
|
||||||
public abstract ISession Session { get; set; }
|
public abstract ISession Session { get; set; }
|
||||||
|
|
||||||
public abstract void Abort();
|
public abstract void Abort();
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,15 @@ namespace Microsoft.AspNet.Http.Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IHttpRequestIdentifierFeature RequestIdentifierFeature
|
||||||
|
{
|
||||||
|
get {
|
||||||
|
return FeatureHelpers.GetOrCreate<IHttpRequestIdentifierFeature>(
|
||||||
|
_features,
|
||||||
|
() => new HttpRequestIdentifierFeature());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override IFeatureCollection Features { get { return _features; } }
|
public override IFeatureCollection Features { get { return _features; } }
|
||||||
|
|
||||||
public override HttpRequest Request { get { return _request; } }
|
public override HttpRequest Request { get { return _request; } }
|
||||||
|
|
@ -167,6 +176,12 @@ namespace Microsoft.AspNet.Http.Internal
|
||||||
set { LifetimeFeature.RequestAborted = value; }
|
set { LifetimeFeature.RequestAborted = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string TraceIdentifier
|
||||||
|
{
|
||||||
|
get { return RequestIdentifierFeature.TraceIdentifier; }
|
||||||
|
set { RequestIdentifierFeature.TraceIdentifier = value; }
|
||||||
|
}
|
||||||
|
|
||||||
public override ISession Session
|
public override ISession Session
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,21 @@ namespace Microsoft.AspNet.Http.Features
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static T GetOrCreate<T>(
|
||||||
|
IFeatureCollection features,
|
||||||
|
Func<T> factory)
|
||||||
|
{
|
||||||
|
T obj = features.Get<T>();
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
obj = factory();
|
||||||
|
features.Set(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static T GetOrCreateAndCache<T>(
|
public static T GetOrCreateAndCache<T>(
|
||||||
IFeatureCache cache,
|
IFeatureCache cache,
|
||||||
IFeatureCollection features,
|
IFeatureCollection features,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,64 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Http.Features.Internal
|
namespace Microsoft.AspNet.Http.Features.Internal
|
||||||
{
|
{
|
||||||
public class HttpRequestIdentifierFeature : IHttpRequestIdentifierFeature
|
public class HttpRequestIdentifierFeature : IHttpRequestIdentifierFeature
|
||||||
{
|
{
|
||||||
public string TraceIdentifier { get; set; }
|
// Base64 encoding - but in ascii sort order for easy text based sorting
|
||||||
|
private static readonly string _encode32Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
|
||||||
|
// Seed the _requestId for this application instance with
|
||||||
|
// the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001
|
||||||
|
// for a roughly increasing _requestId over restarts
|
||||||
|
private static long _requestId = DateTime.UtcNow.Ticks;
|
||||||
|
|
||||||
|
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 unsafe string GenerateRequestId(long id)
|
||||||
|
{
|
||||||
|
// The following routine is ~310% faster than calling long.ToString() on x64
|
||||||
|
// and ~600% faster than calling long.ToString() on x86 in tight loops of 1 million+ iterations
|
||||||
|
// See: https://github.com/aspnet/Hosting/pull/385
|
||||||
|
|
||||||
|
// stackalloc to allocate array on stack rather than heap
|
||||||
|
char* charBuffer = stackalloc char[13];
|
||||||
|
|
||||||
|
charBuffer[0] = _encode32Chars[(int)(id >> 60) & 31];
|
||||||
|
charBuffer[1] = _encode32Chars[(int)(id >> 55) & 31];
|
||||||
|
charBuffer[2] = _encode32Chars[(int)(id >> 50) & 31];
|
||||||
|
charBuffer[3] = _encode32Chars[(int)(id >> 45) & 31];
|
||||||
|
charBuffer[4] = _encode32Chars[(int)(id >> 40) & 31];
|
||||||
|
charBuffer[5] = _encode32Chars[(int)(id >> 35) & 31];
|
||||||
|
charBuffer[6] = _encode32Chars[(int)(id >> 30) & 31];
|
||||||
|
charBuffer[7] = _encode32Chars[(int)(id >> 25) & 31];
|
||||||
|
charBuffer[8] = _encode32Chars[(int)(id >> 20) & 31];
|
||||||
|
charBuffer[9] = _encode32Chars[(int)(id >> 15) & 31];
|
||||||
|
charBuffer[10] = _encode32Chars[(int)(id >> 10) & 31];
|
||||||
|
charBuffer[11] = _encode32Chars[(int)(id >> 5) & 31];
|
||||||
|
charBuffer[12] = _encode32Chars[(int)id & 31];
|
||||||
|
|
||||||
|
// string ctor overload that takes char*
|
||||||
|
return new string(charBuffer, 0, 13);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,7 +6,8 @@
|
||||||
"url": "git://github.com/aspnet/httpabstractions"
|
"url": "git://github.com/aspnet/httpabstractions"
|
||||||
},
|
},
|
||||||
"compilationOptions": {
|
"compilationOptions": {
|
||||||
"warningsAsErrors": true
|
"warningsAsErrors": true,
|
||||||
|
"allowUnsafe": true
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNet.Http.Abstractions": "1.0.0-*",
|
"Microsoft.AspNet.Http.Abstractions": "1.0.0-*",
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,20 @@ namespace Microsoft.AspNet.Http.Internal
|
||||||
Assert.Same(item, context.Items["foo"]);
|
Assert.Same(item, context.Items["foo"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetItems_DefaultRequestIdentifierAvailable()
|
||||||
|
{
|
||||||
|
var context = new DefaultHttpContext(new FeatureCollection());
|
||||||
|
Assert.Null(context.Features.Get<IHttpRequestIdentifierFeature>());
|
||||||
|
var traceIdentifier = context.TraceIdentifier;
|
||||||
|
Assert.NotNull(context.Features.Get<IHttpRequestIdentifierFeature>());
|
||||||
|
Assert.NotNull(traceIdentifier);
|
||||||
|
Assert.Same(traceIdentifier, context.TraceIdentifier);
|
||||||
|
|
||||||
|
context.TraceIdentifier = "Hello";
|
||||||
|
Assert.Same("Hello", context.TraceIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void SetItems_NewCollectionUsed()
|
public void SetItems_NewCollectionUsed()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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.Http.Features.Internal;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Http.Tests
|
||||||
|
{
|
||||||
|
public class HttpRequestIdentifierFeatureTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void TraceIdentifier_ReturnsId()
|
||||||
|
{
|
||||||
|
var feature = new HttpRequestIdentifierFeature();
|
||||||
|
|
||||||
|
var id = feature.TraceIdentifier;
|
||||||
|
|
||||||
|
Assert.NotNull(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TraceIdentifier_ReturnsStableId()
|
||||||
|
{
|
||||||
|
var feature = new HttpRequestIdentifierFeature();
|
||||||
|
|
||||||
|
var id1 = feature.TraceIdentifier;
|
||||||
|
var id2 = feature.TraceIdentifier;
|
||||||
|
|
||||||
|
Assert.Equal(id1, id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TraceIdentifier_ReturnsUniqueIdForDifferentInstances()
|
||||||
|
{
|
||||||
|
var feature1 = new HttpRequestIdentifierFeature();
|
||||||
|
var feature2 = new HttpRequestIdentifierFeature();
|
||||||
|
|
||||||
|
var id1 = feature1.TraceIdentifier;
|
||||||
|
var id2 = feature2.TraceIdentifier;
|
||||||
|
|
||||||
|
Assert.NotEqual(id1, id2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue