* Move logging to new style

This commit is contained in:
ryanbrandenburg 2015-10-21 16:06:56 -07:00
parent 3c46662d91
commit 5763eb580a
27 changed files with 422 additions and 166 deletions

View File

@ -13,6 +13,7 @@ using Microsoft.AspNet.Mvc.Filters;
using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Logging;
@ -48,17 +49,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
private ResultExecutingContext _resultExecutingContext;
private ResultExecutedContext _resultExecutedContext;
private const string AuthorizationFailureLogMessage =
"Authorization failed for the request at filter '{AuthorizationFilter}'.";
private const string ResourceFilterShortCircuitLogMessage =
"Request was short circuited at resource filter '{ResourceFilter}'.";
private const string ActionFilterShortCircuitLogMessage =
"Request was short circuited at action filter '{ActionFilter}'.";
private const string ExceptionFilterShortCircuitLogMessage =
"Request was short circuited at exception filter '{ExceptionFilter}'.";
private const string ResultFilterShortCircuitLogMessage =
"Request was short circuited at result filter '{ResultFilter}'.";
public FilterActionInvoker(
ActionContext actionContext,
@ -306,7 +296,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
}
else
{
Logger.LogWarning(AuthorizationFailureLogMessage, current.FilterAsync.GetType().FullName);
Logger.AuthorizationFailure(current.FilterAsync);
}
}
else if (current.Filter != null)
@ -328,7 +318,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
}
else
{
Logger.LogWarning(AuthorizationFailureLogMessage, current.Filter.GetType().FullName);
Logger.AuthorizationFailure(current.Filter);
}
}
else
@ -393,9 +383,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
// If we get here then the filter didn't call 'next' indicating a short circuit
if (_resourceExecutingContext.Result != null)
{
Logger.LogVerbose(
ResourceFilterShortCircuitLogMessage,
item.FilterAsync.GetType().FullName);
Logger.ResourceFilterShortCircuited(item.FilterAsync);
await InvokeResultAsync(_resourceExecutingContext.Result);
}
@ -422,8 +410,8 @@ namespace Microsoft.AspNet.Mvc.Controllers
if (_resourceExecutingContext.Result != null)
{
// Short-circuited by setting a result.
Logger.LogVerbose(ResourceFilterShortCircuitLogMessage, item.Filter.GetType().FullName);
Logger.ResourceFilterShortCircuited(item.Filter);
await InvokeResultAsync(_resourceExecutingContext.Result);
_resourceExecutedContext = new ResourceExecutedContext(_resourceExecutingContext, _filters)
@ -558,9 +546,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
if (_exceptionContext.Exception == null)
{
Logger.LogVerbose(
ExceptionFilterShortCircuitLogMessage,
current.FilterAsync.GetType().FullName);
Logger.ExceptionFilterShortCircuited(current.FilterAsync);
}
}
}
@ -587,9 +573,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
if (_exceptionContext.Exception == null)
{
Logger.LogVerbose(
ExceptionFilterShortCircuitLogMessage,
current.Filter.GetType().FullName);
Logger.ExceptionFilterShortCircuited(current.Filter);
}
}
}
@ -676,8 +660,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
if (_actionExecutedContext == null)
{
// If we get here then the filter didn't call 'next' indicating a short circuit
Logger.LogVerbose(ActionFilterShortCircuitLogMessage, item.FilterAsync.GetType().FullName);
Logger.ActionFilterShortCircuited(item.FilterAsync);
_actionExecutedContext = new ActionExecutedContext(
_actionExecutingContext,
@ -704,8 +687,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
if (_actionExecutingContext.Result != null)
{
// Short-circuited by setting a result.
Logger.LogVerbose(ActionFilterShortCircuitLogMessage, item.Filter.GetType().FullName);
Logger.ActionFilterShortCircuited(item.Filter);
_actionExecutedContext = new ActionExecutedContext(
_actionExecutingContext,
@ -834,7 +816,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
if (_resultExecutedContext == null || _resultExecutingContext.Cancel == true)
{
// Short-circuited by not calling next || Short-circuited by setting Cancel == true
Logger.LogVerbose(ResourceFilterShortCircuitLogMessage, item.FilterAsync.GetType().FullName);
Logger.ResourceFilterShortCircuited(item.FilterAsync);
_resultExecutedContext = new ResultExecutedContext(
_resultExecutingContext,
@ -861,7 +843,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
if (_resultExecutingContext.Cancel == true)
{
// Short-circuited by setting Cancel == true
Logger.LogVerbose(ResourceFilterShortCircuitLogMessage, item.Filter.GetType().FullName);
Logger.ResourceFilterShortCircuited(item.Filter);
_resultExecutedContext = new ResultExecutedContext(
_resultExecutingContext,

View File

@ -9,6 +9,7 @@ using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.ActionConstraints;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.Logging;
@ -87,8 +88,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
Environment.NewLine,
finalMatches.Select(a => a.DisplayName));
_logger.LogError("Request matched multiple actions resulting in ambiguity. " +
"Matching actions: {AmbiguousActions}", actionNames);
_logger.AmbiguousActions(actionNames);
var message = Resources.FormatDefaultActionSelector_AmbiguousActions(
Environment.NewLine,
@ -170,14 +170,10 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
if (!constraint.Accept(constraintContext))
{
isMatch = false;
_logger.LogVerbose(
"Action '{ActionDisplayName}' with id '{ActionId}' did not match the " +
"constraint '{ActionConstraint}'",
_logger.ConstraintMismatch(
candidate.Action.DisplayName,
candidate.Action.Id,
constraint);
break;
}
}

View File

@ -128,18 +128,13 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
if (selectedFormatter == null)
{
// No formatter supports this.
Logger.LogWarning("No output formatter was found to write the response.");
Logger.NoFormatter(formatterContext);
context.HttpContext.Response.StatusCode = StatusCodes.Status406NotAcceptable;
return TaskCache.CompletedTask;
}
Logger.LogVerbose(
"Selected output formatter '{OutputFormatter}' and content type " +
"'{ContentType}' to write the response.",
selectedFormatter.GetType().FullName,
formatterContext.ContentType);
Logger.FormatterSelected(selectedFormatter, formatterContext);
Logger.ObjectResultExecuting(context);
result.OnFormatting(context);
@ -183,9 +178,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
// or URL path extension mapping). If yes, then ignore content-negotiation and use this content-type.
if (contentTypes.Count == 1)
{
Logger.LogVerbose(
"Skipped content negotiation as content type '{ContentType}' is explicitly set for the response.",
contentTypes[0]);
Logger.SkippedContentNegotiation(contentTypes[0]);
return SelectFormatterUsingAnyAcceptableContentType(formatterContext, formatters, contentTypes);
}
@ -200,7 +193,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
// which can write the type. Let the formatter choose the Content-Type.
if (acceptValues == null || acceptValues.Count == 0)
{
Logger.LogVerbose("No information found on request to perform content negotiation.");
Logger.NoAcceptForNegotiation();
return SelectFormatterNotUsingAcceptHeaders(formatterContext, formatters);
}
@ -219,7 +212,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
// the type. Let the formatter choose the Content-Type.
if (selectedFormatter == null)
{
Logger.LogVerbose("Could not find an output formatter based on content negotiation.");
Logger.NoFormatterFromNegotiation(acceptValues);
// Set this flag to indicate that content-negotiation has failed to let formatters decide
// if they want to write the response or not.

View File

@ -8,9 +8,9 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
public static class ChallengeResultLoggerExtenstions
internal static class ChallengeResultLoggerExtenstions
{
private static Action<ILogger, string[], Exception> _challengeResultExecuting;
private static readonly Action<ILogger, string[], Exception> _challengeResultExecuting;
static ChallengeResultLoggerExtenstions()
{

View File

@ -7,9 +7,9 @@ using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNet.Mvc.Logging
{
public static class ContentResultLoggerExtensions
internal static class ContentResultLoggerExtensions
{
private static Action<ILogger, string, Exception> _contentResultExecuting;
private static readonly Action<ILogger, string, Exception> _contentResultExecuting;
static ContentResultLoggerExtensions()
{

View File

@ -8,10 +8,10 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
public static class ControllerActionInvokerLoggerExtensions
internal static class ControllerActionInvokerLoggerExtensions
{
private static Action<ILogger, string, string[], ModelValidationState, Exception> _actionMethodExecuting;
private static Action<ILogger, string, string, Exception> _actionMethodExecuted;
private static readonly Action<ILogger, string, string[], ModelValidationState, Exception> _actionMethodExecuting;
private static readonly Action<ILogger, string, string, Exception> _actionMethodExecuted;
static ControllerActionInvokerLoggerExtensions()
{

View File

@ -0,0 +1,41 @@
// 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 Microsoft.AspNet.Mvc.ActionConstraints;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
internal static class DefaultActionSelectorLoggerExtensions
{
private static readonly Action<ILogger, string, Exception> _ambiguousActions;
private static readonly Action<ILogger, string, string, IActionConstraint, Exception> _constraintMismatch;
static DefaultActionSelectorLoggerExtensions()
{
_ambiguousActions = LoggerMessage.Define<string>(
LogLevel.Error,
1,
"Request matched multiple actions resulting in ambiguity. Matching actions: {AmbiguousActions}");
_constraintMismatch = LoggerMessage.Define<string, string, IActionConstraint>(
LogLevel.Verbose,
2,
"Action '{ActionName}' with id '{ActionId}' did not match the constraint '{ActionConstraint}'");
}
public static void AmbiguousActions(this ILogger logger, string actionNames)
{
_ambiguousActions(logger, actionNames, null);
}
public static void ConstraintMismatch(
this ILogger logger,
string actionName,
string actionId,
IActionConstraint actionConstraint)
{
_constraintMismatch(logger, actionName, actionId, actionConstraint, null);
}
}
}

View File

@ -6,9 +6,9 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
public static class FileResultLoggerExtensions
internal static class FileResultLoggerExtensions
{
private static Action<ILogger, string, Exception> _fileResultExecuting;
private static readonly Action<ILogger, string, Exception> _fileResultExecuting;
static FileResultLoggerExtensions()
{

View File

@ -0,0 +1,65 @@
// 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 Microsoft.AspNet.Mvc.Filters;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
internal static class FilterActionInvokerLoggerExtensions
{
private static readonly Action<ILogger, object, Exception> _authorizationFailure;
private static readonly Action<ILogger, object, Exception> _resourceFilterShortCircuit;
private static readonly Action<ILogger, object, Exception> _actionFilterShortCircuit;
private static readonly Action<ILogger, object, Exception> _exceptionFilterShortCircuit;
static FilterActionInvokerLoggerExtensions()
{
_authorizationFailure = LoggerMessage.Define<object>(
LogLevel.Warning,
1,
"Authorization failed for the request at filter '{AuthorizationFilter}'.");
_resourceFilterShortCircuit = LoggerMessage.Define<object>(
LogLevel.Verbose,
2,
"Request was short circuited at resource filter '{ResourceFilter}'.");
_actionFilterShortCircuit = LoggerMessage.Define<object>(
LogLevel.Verbose,
3,
"Request was short circuited at action filter '{ActionFilter}'.");
_exceptionFilterShortCircuit = LoggerMessage.Define<object>(
LogLevel.Verbose,
4,
"Request was short circuited at exception filter '{ExceptionFilter}'.");
}
public static void AuthorizationFailure(
this ILogger logger,
IFilterMetadata filter)
{
_authorizationFailure(logger, filter, null);
}
public static void ResourceFilterShortCircuited(
this ILogger logger,
IFilterMetadata filter)
{
_resourceFilterShortCircuit(logger, filter, null);
}
public static void ExceptionFilterShortCircuited(
this ILogger logger,
IFilterMetadata filter)
{
_exceptionFilterShortCircuit(logger, filter, null);
}
public static void ActionFilterShortCircuited(
this ILogger logger,
IFilterMetadata filter)
{
_actionFilterShortCircuit(logger, filter, null);
}
}
}

View File

@ -6,9 +6,9 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
public static class HttpStatusCodeLoggerExtensions
internal static class HttpStatusCodeLoggerExtensions
{
private static Action<ILogger, int, Exception> _httpStatusCodeResultExecuting;
private static readonly Action<ILogger, int, Exception> _httpStatusCodeResultExecuting;
static HttpStatusCodeLoggerExtensions()
{

View File

@ -0,0 +1,26 @@
using System;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
internal static class InnerAttributeRouteLoggerExtensions
{
private static readonly Action<ILogger, string, string, Exception> _matchedRouteName;
static InnerAttributeRouteLoggerExtensions()
{
_matchedRouteName = LoggerMessage.Define<string, string>(
LogLevel.Verbose,
1,
"Request successfully matched the route with name '{RouteName}' and template '{RouteTemplate}'.");
}
public static void MatchedRouteName(
this ILogger logger,
string routeName,
string routeTemplate)
{
_matchedRouteName(logger, routeName, routeTemplate, null);
}
}
}

View File

@ -6,9 +6,9 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
public static class LocalRedirectResultLoggerExtensions
internal static class LocalRedirectResultLoggerExtensions
{
private static Action<ILogger, string, Exception> _localRedirectResultExecuting;
private static readonly Action<ILogger, string, Exception> _localRedirectResultExecuting;
static LocalRedirectResultLoggerExtensions()
{

View File

@ -10,8 +10,8 @@ namespace Microsoft.AspNet.Mvc.Logging
{
internal static class MvcRouteHandlerLoggerExtensions
{
private static Action<ILogger, string, Exception> _actionExecuting;
private static Action<ILogger, string, double, Exception> _actionExecuted;
private static readonly Action<ILogger, string, Exception> _actionExecuting;
private static readonly Action<ILogger, string, double, Exception> _actionExecuted;
static MvcRouteHandlerLoggerExtensions()
{

View File

@ -1,26 +1,85 @@
// 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.
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNet.Mvc.Logging
{
public static class ObjectResultExecutorLoggerExtensions
internal static class ObjectResultExecutorLoggerExtensions
{
private static Action<ILogger, string, Exception> _objectResultExecuting;
private static readonly Action<ILogger, string, Exception> _objectResultExecuting;
private static readonly Action<ILogger, string, Exception> _noFormatter;
private static readonly Action<ILogger, IOutputFormatter, string, Exception> _formatterSelected;
private static readonly Action<ILogger, string, Exception> _skippedContentNegotiation;
private static readonly Action<ILogger, string, Exception> _noAcceptForNegotiation;
private static readonly Action<ILogger, IEnumerable<MediaTypeHeaderValue>, Exception> _noFormatterFromNegotiation;
static ObjectResultExecutorLoggerExtensions()
{
_noFormatter = LoggerMessage.Define<string>(
LogLevel.Warning,
1,
"No output formatter was found for content type '{ContentType}' to write the response.");
_objectResultExecuting = LoggerMessage.Define<string>(
LogLevel.Information,
1,
"Executing ObjectResult, writing value {Value}.");
_formatterSelected = LoggerMessage.Define<IOutputFormatter, string>(
LogLevel.Verbose,
2,
"Selected output formatter '{OutputFormatter}' and content type '{ContentType}' to write the response.");
_skippedContentNegotiation = LoggerMessage.Define<string>(
LogLevel.Verbose,
3,
"Skipped content negotiation as content type '{ContentType}' is explicitly set for the response.");
_noAcceptForNegotiation = LoggerMessage.Define<string>(
LogLevel.Verbose,
4,
"No information found on request to perform content negotiation.");
_noFormatterFromNegotiation = LoggerMessage.Define<IEnumerable<MediaTypeHeaderValue>>(
LogLevel.Verbose,
5,
"Could not find an output formatter based on content negotiation. Accepted types were ({AcceptTypes})");
}
public static void ObjectResultExecuting(this ILogger logger, object value)
{
_objectResultExecuting(logger, Convert.ToString(value), null);
}
public static void NoFormatter(
this ILogger logger,
OutputFormatterWriteContext formatterContext)
{
_noFormatter(logger, Convert.ToString(formatterContext.ContentType), null);
}
public static void FormatterSelected(
this ILogger logger,
IOutputFormatter outputFormatter,
OutputFormatterWriteContext context)
{
var contentType = Convert.ToString(context.ContentType);
_formatterSelected(logger, outputFormatter, contentType, null);
}
public static void SkippedContentNegotiation(this ILogger logger, MediaTypeHeaderValue contentType)
{
_skippedContentNegotiation(logger, Convert.ToString(contentType), null);
}
public static void NoAcceptForNegotiation(this ILogger logger)
{
_noAcceptForNegotiation(logger, null, null);
}
public static void NoFormatterFromNegotiation(this ILogger logger, IEnumerable<MediaTypeHeaderValue> acceptTypes)
{
_noFormatterFromNegotiation(logger, acceptTypes, null);
}
}
}

View File

@ -6,9 +6,9 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
public static class RedirectResultLoggerExtensions
internal static class RedirectResultLoggerExtensions
{
private static Action<ILogger, string, Exception> _redirectResultExecuting;
private static readonly Action<ILogger, string, Exception> _redirectResultExecuting;
static RedirectResultLoggerExtensions()
{

View File

@ -6,9 +6,9 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
public static class RedirectToActionResultLoggerExtensions
internal static class RedirectToActionResultLoggerExtensions
{
private static Action<ILogger, string, Exception> _redirectToActionResultExecuting;
private static readonly Action<ILogger, string, Exception> _redirectToActionResultExecuting;
static RedirectToActionResultLoggerExtensions()
{

View File

@ -6,9 +6,9 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
public static class RedirectToRouteResultLoggerExtensions
internal static class RedirectToRouteResultLoggerExtensions
{
private static Action<ILogger, string, string, Exception> _redirectToRouteResultExecuting;
private static readonly Action<ILogger, string, string, Exception> _redirectToRouteResultExecuting;
static RedirectToRouteResultLoggerExtensions()
{

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
internal static class ViewResultExecutorLoggerExtensions
{
private static readonly Action<ILogger, string, Exception> _viewFound;
private static readonly Action<ILogger, string, IEnumerable<string>, Exception> _viewNotFound;
static ViewResultExecutorLoggerExtensions()
{
_viewFound = LoggerMessage.Define<string>(
LogLevel.Verbose,
1,
"The view '{ViewName}' was found.");
_viewNotFound = LoggerMessage.Define<string, IEnumerable<string>>(
LogLevel.Error,
2,
"The view '{ViewName}' was not found. Searched locations: {SearchedViewLocations}");
}
public static void ViewFound(this ILogger logger, string viewName)
{
_viewFound(logger, viewName, null);
}
public static void ViewNotFound(
this ILogger logger,
string viewName,
IEnumerable<string> searchedLocations)
{
_viewNotFound(logger, viewName, searchedLocations, null);
}
}
}

View File

@ -7,6 +7,7 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Internal.Routing;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Routing.Template;
using Microsoft.Extensions.Logging;
@ -156,8 +157,7 @@ namespace Microsoft.AspNet.Mvc.Routing
continue;
}
_logger.LogVerbose(
"Request successfully matched the route with name '{RouteName}' and template '{RouteTemplate}'.",
_logger.MatchedRouteName(
matchingEntry.RouteName,
matchingEntry.RouteTemplate);

View File

@ -6,9 +6,9 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
public static class JsonResultLoggerExtensions
internal static class JsonResultLoggerExtensions
{
private static Action<ILogger, string, Exception> _jsonResultExecuting;
private static readonly Action<ILogger, string, Exception> _jsonResultExecuting;
static JsonResultLoggerExtensions()
{

View File

@ -4,7 +4,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.TagHelpers.Logging;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.Extensions.Logging;
@ -63,17 +64,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
match => match.PresentAttributes.Any(
attribute => PartiallyMatchedAttributes.Contains(
attribute, StringComparer.OrdinalIgnoreCase)));
logger.LogWarning(new PartialModeMatchLogValues<TMode>(uniqueId, viewPath, partialOnlyMatches));
logger.TagHelperPartialMatches<TMode>(uniqueId, viewPath, partialOnlyMatches);
}
if (logger.IsEnabled(LogLevel.Verbose) && !FullMatches.Any())
{
logger.LogVerbose(
"Skipping processing for tag helper '{TagHelper}' with id '{TagHelperId}'.",
tagHelper.GetType().GetTypeInfo().FullName,
logger.TagHelperSkippingProcessing(
tagHelper,
uniqueId);
}
}
}
}
}

View File

@ -1,63 +0,0 @@
// 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.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
{
/// <summary>
/// Log values for <see cref="AspNet.Razor.TagHelpers.ITagHelper"/> instances that opt out of
/// processing due to missing attributes for one of several possible modes.
/// </summary>
public class PartialModeMatchLogValues<TMode> : ILogValues
{
private readonly string _uniqueId;
private readonly string _viewPath;
private readonly IEnumerable<ModeMatchAttributes<TMode>> _partialMatches;
/// <summary>
/// Creates a new <see cref="PartialModeMatchLogValues{TMode}"/>.
/// </summary>
/// <param name="uniqueId">The unique ID of the HTML element this message applies to.</param>
/// <param name="viewPath">The path to the view.</param>
/// <param name="partialMatches">The set of modes with partial required attributes.</param>
public PartialModeMatchLogValues(
string uniqueId,
string viewPath,
IEnumerable<ModeMatchAttributes<TMode>> partialMatches)
{
if (partialMatches == null)
{
throw new ArgumentNullException(nameof(partialMatches));
}
_uniqueId = uniqueId;
_viewPath = viewPath;
_partialMatches = partialMatches;
}
public override string ToString()
{
var newLine = Environment.NewLine;
return string.Format(
$"Tag Helper with ID '{_uniqueId}' in view '{_viewPath}' had partial matches " +
$"while determining mode:{newLine}\t{{0}}",
string.Join($"{newLine}\t", _partialMatches.Select(partial =>
string.Format($"Mode '{partial.Mode}' missing attributes:{newLine}\t\t{{0}} ",
string.Join($"{newLine}\t\t", partial.MissingAttributes)))));
}
public IEnumerable<KeyValuePair<string, object>> GetValues()
{
yield return new KeyValuePair<string, object>(
"Message",
"Tag helper had partial matches while determining mode.");
yield return new KeyValuePair<string, object>("UniqueId", _uniqueId);
yield return new KeyValuePair<string, object>("ViewPath", _viewPath);
yield return new KeyValuePair<string, object>("PartialMatches", _partialMatches);
}
}
}

View File

@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Mvc.TagHelpers.Internal;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.TagHelpers.Logging
{
internal static class ModeMatchResultLoggerExtensions
{
private static readonly Action<ILogger, ITagHelper, string, Exception> _skippingProcessing;
static ModeMatchResultLoggerExtensions()
{
_skippingProcessing = LoggerMessage.Define<ITagHelper, string>(
LogLevel.Verbose,
1,
"Skipping processing for tag helper '{TagHelper}' with id '{TagHelperId}'.");
}
public static void TagHelperPartialMatches<TMode>(
this ILogger logger,
string uniqueId,
string viewPath,
IEnumerable<ModeMatchAttributes<TMode>> partialMatches)
{
var logValues = new PartialModeMatchLogValues<TMode>(
uniqueId,
viewPath,
partialMatches);
logger.LogWarning(logValues);
}
public static void TagHelperSkippingProcessing(
this ILogger logger,
ITagHelper tagHelper,
string uniqueId)
{
_skippingProcessing(
logger,
tagHelper,
uniqueId,
null);
}
/// <summary>
/// Log values for <see cref="AspNet.Razor.TagHelpers.ITagHelper"/> instances that opt out
/// of processing due to missing attributes for one of several possible modes.
/// </summary>
private class PartialModeMatchLogValues<TMode> : ILogValues
{
private readonly IEnumerable<ModeMatchAttributes<TMode>> _partialMatches;
private readonly string _uniqueId;
private readonly string _viewPath;
/// <summary>
/// Creates a new <see cref="PartialModeMatchLogValues{TMode}"/>.
/// </summary>
/// <param name="uniqueId">
/// The unique ID of the HTML element this message applies to.
/// </param>
/// <param name="viewPath">The path to the view.</param>
/// <param name="partialMatches">The set of modes with partial required attributes.</param>
public PartialModeMatchLogValues(
string uniqueId,
string viewPath,
IEnumerable<ModeMatchAttributes<TMode>> partialMatches)
{
if (partialMatches == null)
{
throw new ArgumentNullException(nameof(partialMatches));
}
_uniqueId = uniqueId;
_viewPath = viewPath;
_partialMatches = partialMatches;
}
public IEnumerable<KeyValuePair<string, object>> GetValues()
{
yield return new KeyValuePair<string, object>(
"Message",
"Tag helper had partial matches while determining mode.");
yield return new KeyValuePair<string, object>("UniqueId", _uniqueId);
yield return new KeyValuePair<string, object>("ViewPath", _viewPath);
yield return new KeyValuePair<string, object>("PartialMatches", _partialMatches);
}
public override string ToString()
{
var newLine = Environment.NewLine;
return string.Format(
$"Tag Helper with ID '{_uniqueId}' in view '{_viewPath}' had partial matches " +
$"while determining mode:{newLine}\t{{0}}",
string.Join($"{newLine}\t", _partialMatches.Select(partial =>
string.Format($"Mode '{partial.Mode}' missing attributes:{newLine}\t\t{{0}} ",
string.Join($"{newLine}\t\t", partial.MissingAttributes)))));
}
}
}
}

View File

@ -2,14 +2,17 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.Logging
namespace Microsoft.AspNet.Mvc.ViewFeatures.Logging
{
public static class PartialViewResultExecutorLoggerExtensions
internal static class PartialViewResultExecutorLoggerExtensions
{
private static Action<ILogger, string, Exception> _partialViewResultExecuting;
private static readonly Action<ILogger, string, Exception> _partialViewFound;
private static readonly Action<ILogger, string, IEnumerable<string>, Exception> _partialViewNotFound;
private static readonly Action<ILogger, string, Exception> _partialViewResultExecuting;
static PartialViewResultExecutorLoggerExtensions()
{
@ -17,6 +20,29 @@ namespace Microsoft.AspNet.Mvc.Logging
LogLevel.Information,
1,
"Executing PartialViewResult, running view at path {Path}.");
_partialViewFound = LoggerMessage.Define<string>(
LogLevel.Verbose,
2,
"The partial view '{PartialViewName}' was found.");
_partialViewNotFound = LoggerMessage.Define<string, IEnumerable<string>>(
LogLevel.Error,
3,
"The partial view '{PartialViewName}' was not found. Searched locations: {SearchedViewLocations}");
}
public static void PartialViewFound(
this ILogger logger,
string partialViewName)
{
_partialViewFound(logger, partialViewName, null);
}
public static void PartialViewNotFound(
this ILogger logger,
string partialViewName,
IEnumerable<string> searchedLocations)
{
_partialViewNotFound(logger, partialViewName, searchedLocations, null);
}
public static void PartialViewResultExecuting(this ILogger logger, IView view)

View File

@ -8,6 +8,7 @@ using Microsoft.AspNet.Mvc.Diagnostics;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.ViewFeatures.Logging;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.OptionsModel;
@ -73,16 +74,13 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
{
DiagnosticSource.ViewFound(actionContext, true, viewResult, viewName, result.View);
Logger.LogVerbose("The partial view '{PartialViewName}' was found.", viewName);
Logger.PartialViewFound(viewName);
}
else
{
DiagnosticSource.ViewNotFound(actionContext, true, viewResult, viewName, result.SearchedLocations);
Logger.LogError(
"The partial view '{PartialViewName}' was not found. Searched locations: {SearchedViewLocations}",
viewName,
result.SearchedLocations);
Logger.PartialViewNotFound(viewName, result.SearchedLocations);
}
return result;

View File

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.ViewFeatures.Logging;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.OptionsModel;
@ -84,7 +85,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
});
}
Logger.LogVerbose("The view '{ViewName}' was found.", viewName);
Logger.PartialViewFound(viewName);
}
else
{
@ -101,11 +102,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
searchedLocations = result.SearchedLocations
});
}
Logger.LogError(
"The view '{ViewName}' was not found. Searched locations: {SearchedViewLocations}",
viewName,
result.SearchedLocations);
Logger.PartialViewNotFound(viewName, result.SearchedLocations);
}
return result;
@ -135,7 +132,6 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
throw new ArgumentNullException(nameof(viewResult));
}
Logger.ViewResultExecuting(view);
return ExecuteAsync(

View File

@ -330,8 +330,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
// Arrange
var source = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new CommonTestEncoder());
var target = new StringWriter();
var expected = @"Hello world
abc";
var expected = "Hello world" + Environment.NewLine + "abc";
// Act
source.WriteLine("Hello world");
@ -390,8 +389,7 @@ abc";
// Arrange
var source = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new CommonTestEncoder());
var target = new StringWriter();
var expected = @"Hello world
";
var expected = "Hello world" + Environment.NewLine;
// Act
source.Write("Hello ");