Add logging of elapsed time for the action.
This commit is contained in:
parent
cea8d019f1
commit
ec2abc8ae0
|
|
@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
var actionDescriptor = await _actionSelector.SelectAsync(context);
|
var actionDescriptor = await _actionSelector.SelectAsync(context);
|
||||||
if (actionDescriptor == null)
|
if (actionDescriptor == null)
|
||||||
{
|
{
|
||||||
_logger.LogVerbose("No actions matched the current request.");
|
_logger.NoActionsMatched();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,10 +90,13 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
|
|
||||||
using (_logger.ActionScope(actionDescriptor))
|
using (_logger.ActionScope(actionDescriptor))
|
||||||
{
|
{
|
||||||
_logger.LogVerbose("Executing action {ActionDisplayName}", actionDescriptor.DisplayName);
|
_logger.ExecutingAction(actionDescriptor);
|
||||||
|
|
||||||
|
var startTime = Environment.TickCount;
|
||||||
await InvokeActionAsync(context, actionDescriptor);
|
await InvokeActionAsync(context, actionDescriptor);
|
||||||
context.IsHandled = true;
|
context.IsHandled = true;
|
||||||
|
|
||||||
|
_logger.ExecutedAction(actionDescriptor, startTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,43 @@ namespace Microsoft.AspNet.Mvc.Logging
|
||||||
{
|
{
|
||||||
internal static class MvcRouteHandlerLoggerExtensions
|
internal static class MvcRouteHandlerLoggerExtensions
|
||||||
{
|
{
|
||||||
|
private static Action<ILogger, string, Exception> _actionExecuting;
|
||||||
|
private static Action<ILogger, string, double, Exception> _actionExecuted;
|
||||||
|
|
||||||
|
static MvcRouteHandlerLoggerExtensions()
|
||||||
|
{
|
||||||
|
_actionExecuting = LoggerMessage.Define<string>(
|
||||||
|
LogLevel.Verbose,
|
||||||
|
1,
|
||||||
|
"Executing action {ActionName}");
|
||||||
|
|
||||||
|
_actionExecuted = LoggerMessage.Define<string, double>(
|
||||||
|
LogLevel.Information,
|
||||||
|
2,
|
||||||
|
"Executed action {ActionName} in {ElapsedMilliseconds}ms");
|
||||||
|
}
|
||||||
|
|
||||||
public static IDisposable ActionScope(this ILogger logger, ActionDescriptor action)
|
public static IDisposable ActionScope(this ILogger logger, ActionDescriptor action)
|
||||||
{
|
{
|
||||||
return logger.BeginScopeImpl(new ActionLogScope(action));
|
return logger.BeginScopeImpl(new ActionLogScope(action));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ExecutingAction(this ILogger logger, ActionDescriptor action)
|
||||||
|
{
|
||||||
|
_actionExecuting(logger, action.DisplayName, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ExecutedAction(this ILogger logger, ActionDescriptor action, int startTicks)
|
||||||
|
{
|
||||||
|
var elapsed = new TimeSpan(Environment.TickCount - startTicks);
|
||||||
|
_actionExecuted(logger, action.DisplayName, elapsed.TotalMilliseconds, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void NoActionsMatched(this ILogger logger)
|
||||||
|
{
|
||||||
|
logger.LogVerbose(3, "No actions matched the current request");
|
||||||
|
}
|
||||||
|
|
||||||
private class ActionLogScope : ILogValues
|
private class ActionLogScope : ILogValues
|
||||||
{
|
{
|
||||||
private readonly ActionDescriptor _action;
|
private readonly ActionDescriptor _action;
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,16 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
// Arrange
|
// Arrange
|
||||||
var sink = new TestSink();
|
var sink = new TestSink();
|
||||||
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
var displayName = "A.B.C";
|
var displayName = "A.B.C";
|
||||||
var actionDescriptor = new Mock<ActionDescriptor>();
|
var actionDescriptor = new Mock<ActionDescriptor>();
|
||||||
actionDescriptor.SetupGet(ad => ad.DisplayName)
|
actionDescriptor
|
||||||
.Returns(displayName);
|
.SetupGet(ad => ad.DisplayName)
|
||||||
|
.Returns(displayName);
|
||||||
|
|
||||||
var context = CreateRouteContext(actionDescriptor: actionDescriptor.Object, loggerFactory: loggerFactory);
|
var context = CreateRouteContext(actionDescriptor: actionDescriptor.Object, loggerFactory: loggerFactory);
|
||||||
|
|
||||||
var handler = new MvcRouteHandler();
|
var handler = new MvcRouteHandler();
|
||||||
var expectedMessage = $"Executing action {displayName}";
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await handler.RouteAsync(context);
|
await handler.RouteAsync(context);
|
||||||
|
|
@ -39,8 +42,11 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Single(sink.Scopes);
|
Assert.Single(sink.Scopes);
|
||||||
Assert.Equal(displayName, sink.Scopes[0].Scope?.ToString());
|
Assert.Equal(displayName, sink.Scopes[0].Scope?.ToString());
|
||||||
Assert.Single(sink.Writes);
|
|
||||||
Assert.Equal(expectedMessage, sink.Writes[0].State?.ToString());
|
Assert.Equal(2, sink.Writes.Count);
|
||||||
|
Assert.Equal($"Executing action {displayName}", sink.Writes[0].State?.ToString());
|
||||||
|
// This message has the execution time embedded, which we don't want to verify.
|
||||||
|
Assert.StartsWith($"Executed action {displayName} ", sink.Writes[1].State?.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -59,7 +65,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
loggerFactory: loggerFactory);
|
loggerFactory: loggerFactory);
|
||||||
|
|
||||||
var handler = new MvcRouteHandler();
|
var handler = new MvcRouteHandler();
|
||||||
var expectedMessage = "No actions matched the current request.";
|
var expectedMessage = "No actions matched the current request";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await handler.RouteAsync(context);
|
await handler.RouteAsync(context);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue