Create a logging scope having request id

This commit is contained in:
Kiran Challa 2015-03-25 11:08:58 -07:00 committed by Kiran Challa
parent 5fac18b418
commit d270525fde
4 changed files with 182 additions and 8 deletions

View File

@ -0,0 +1,18 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Hosting
{
public class DefaultRequestIdentifierFeature : IRequestIdentifierFeature
{
public DefaultRequestIdentifierFeature()
{
TraceIdentifier = Guid.NewGuid();
}
public Guid TraceIdentifier { get; }
}
}

View File

@ -6,11 +6,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.FeatureModel;
using Microsoft.AspNet.Hosting.Builder;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Hosting.Startup;
using Microsoft.AspNet.Http;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Hosting
{
@ -24,7 +27,7 @@ namespace Microsoft.AspNet.Hosting
// Start/ApplicationServices block use methods
private bool _useDisabled;
private IApplicationBuilderFactory _builderFactory;
private IApplicationBuilder _builder;
private IServiceProvider _applicationServices;
@ -56,14 +59,20 @@ namespace Microsoft.AspNet.Hosting
var applicationDelegate = BuildApplicationDelegate();
var _contextFactory = _applicationServices.GetRequiredService<IHttpContextFactory>();
var _contextAccessor = _applicationServices.GetRequiredService<IHttpContextAccessor>();
var logger = _applicationServices.GetRequiredService<ILogger<HostingEngine>>();
var contextFactory = _applicationServices.GetRequiredService<IHttpContextFactory>();
var contextAccessor = _applicationServices.GetRequiredService<IHttpContextAccessor>();
var server = _serverFactory.Start(_serverInstance,
features =>
async features =>
{
var httpContext = _contextFactory.CreateHttpContext(features);
_contextAccessor.HttpContext = httpContext;
return applicationDelegate(httpContext);
var httpContext = contextFactory.CreateHttpContext(features);
var requestIdentifier = GetRequestIdentifier(httpContext);
using (logger.BeginScope("Request Id: {RequestId}", requestIdentifier))
{
contextAccessor.HttpContext = httpContext;
await applicationDelegate(httpContext);
}
});
return new Disposable(() =>
@ -163,6 +172,18 @@ namespace Microsoft.AspNet.Hosting
}
}
private Guid GetRequestIdentifier(HttpContext httpContext)
{
var requestIdentifierFeature = httpContext.GetFeature<IRequestIdentifierFeature>();
if (requestIdentifierFeature == null)
{
requestIdentifierFeature = new DefaultRequestIdentifierFeature();
httpContext.SetFeature<IRequestIdentifierFeature>(requestIdentifierFeature);
}
return requestIdentifierFeature.TraceIdentifier;
}
// Consider cutting
public IHostingEngine UseEnvironment(string environment)
{
@ -207,7 +228,7 @@ namespace Microsoft.AspNet.Hosting
public IHostingEngine UseStartup(Action<IApplicationBuilder> configureApp, Action<IServiceCollection> configureServices)
{
CheckUseAllowed();
_startup = new StartupMethods(configureApp,
_startup = new StartupMethods(configureApp,
services => {
if (configureServices != null)
{

View File

@ -7,12 +7,16 @@ using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.FeatureModel;
using Microsoft.AspNet.Hosting.Builder;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Hosting.Startup;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Testing.xunit;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Hosting
@ -150,6 +154,115 @@ namespace Microsoft.AspNet.Hosting
RunMapPath(virtualPath, expectedSuffix);
}
[Fact]
public void HostingEngine_CreatesDefaultRequestIdentifierFeature_IfNotPresent()
{
// Arrange
HttpContext httpContext = null;
var requestDelegate = new RequestDelegate(innerHttpContext =>
{
httpContext = innerHttpContext;
return Task.FromResult(0);
});
var featuresSupportedByHost = new FeatureCollection();
var hostingEngine = CreateHostingEngine(featuresSupportedByHost, requestDelegate);
// Act
var disposable = hostingEngine.Start();
// Assert
Assert.NotNull(httpContext);
Assert.IsType<DefaultRequestIdentifierFeature>(httpContext.GetFeature<IRequestIdentifierFeature>());
}
[Fact]
public void Hosting_CreatesDefaultRequestIdentifierFeature_IfNotPresent_ForImmutableFeatureCollection()
{
// Arrange
HttpContext httpContext = null;
var requestDelegate = new RequestDelegate(innerHttpContext =>
{
httpContext = innerHttpContext;
return Task.FromResult(0);
});
var featuresSupportedByHost = new Mock<IFeatureCollection>();
featuresSupportedByHost
.Setup(fc => fc.Add(It.IsAny<Type>(), It.IsAny<object>()))
.Throws(new NotImplementedException());
featuresSupportedByHost
.Setup(fc => fc.Add(new KeyValuePair<Type, object>(It.IsAny<Type>(), It.IsAny<object>())))
.Throws(new NotImplementedException());
var hostingEngine = CreateHostingEngine(featuresSupportedByHost.Object, requestDelegate);
// Act
var disposable = hostingEngine.Start();
// Assert
Assert.NotNull(httpContext);
Assert.IsType<DefaultRequestIdentifierFeature>(httpContext.GetFeature<IRequestIdentifierFeature>());
}
[Fact]
public void HostingEngine_DoesNot_CreateDefaultRequestIdentifierFeature_IfPresent()
{
// Arrange
HttpContext httpContext = null;
var requestDelegate = new RequestDelegate(innerHttpContext =>
{
httpContext = innerHttpContext;
return Task.FromResult(0);
});
var featuresSupportedByHost = new FeatureCollection();
var requestIdentifierFeature = new Mock<IRequestIdentifierFeature>().Object;
featuresSupportedByHost.Add(typeof(IRequestIdentifierFeature), requestIdentifierFeature);
var hostingEngine = CreateHostingEngine(featuresSupportedByHost, requestDelegate);
// Act
var disposable = hostingEngine.Start();
// Assert
Assert.NotNull(httpContext);
Assert.Same(requestIdentifierFeature, httpContext.GetFeature<IRequestIdentifierFeature>());
}
private IHostingEngine CreateHostingEngine(
IFeatureCollection featuresSupportedByHost,
RequestDelegate requestDelegate)
{
var applicationBuilder = new Mock<IApplicationBuilder>();
applicationBuilder.Setup(appBuilder => appBuilder.Build()).Returns(requestDelegate);
var applicationBuilderFactory = new Mock<IApplicationBuilderFactory>();
applicationBuilderFactory
.Setup(abf => abf.CreateBuilder(It.IsAny<object>()))
.Returns(applicationBuilder.Object);
var serviceCollection = new ServiceCollection();
serviceCollection.Add(
new ServiceDescriptor(typeof(IApplicationBuilderFactory), applicationBuilderFactory.Object));
serviceCollection.Add(
new ServiceDescriptor(typeof(ILogger<HostingEngine>), new Mock<ILogger<HostingEngine>>().Object));
serviceCollection.Add(
new ServiceDescriptor(typeof(IHttpContextFactory), new HttpContextFactory()));
serviceCollection.Add(
new ServiceDescriptor(typeof(IHttpContextAccessor), new Mock<IHttpContextAccessor>().Object));
var startupLoader = new Mock<IStartupLoader>();
var startupMethods = new StartupMethods(
(appBuilder) => { },
(configureServices) => configureServices.BuildServiceProvider());
startupLoader.Setup(sl => sl.Load(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<List<string>>()))
.Returns(startupMethods);
var hostingEngine = new HostingEngine(
serviceCollection,
startupLoader.Object,
new Mock<IConfiguration>().Object,
new Mock<IHostingEnvironment>().Object,
"TestAppName");
return hostingEngine.UseServer(new TestServerFactory(featuresSupportedByHost));
}
private void RunMapPath(string virtualPath, string expectedSuffix)
{
var engine = WebHost.CreateEngine().UseServer(this);
@ -207,5 +320,26 @@ namespace Microsoft.AspNet.Hosting
throw new NotImplementedException();
}
}
private class TestServerFactory : IServerFactory
{
private readonly IFeatureCollection _featuresSupportedByThisHost;
public TestServerFactory(IFeatureCollection featuresSupportedByThisHost)
{
_featuresSupportedByThisHost = featuresSupportedByThisHost;
}
public IServerInformation Initialize(IConfiguration configuration)
{
return null;
}
public IDisposable Start(IServerInformation serverInformation, Func<IFeatureCollection, Task> application)
{
application(_featuresSupportedByThisHost).Wait();
return null;
}
}
}
}

View File

@ -5,6 +5,7 @@
"Microsoft.AspNet.Testing": "1.0.0-*",
"Microsoft.Framework.OptionsModel": "1.0.0-*",
"Microsoft.Framework.Runtime.Interfaces": "1.0.0-*",
"Moq": "4.2.1312.1622",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
},
"frameworks": {