249 lines
9.0 KiB
C#
249 lines
9.0 KiB
C#
// 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;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using Microsoft.AspNetCore.Mvc.ViewComponents;
|
|
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
|
{
|
|
internal static class MvcViewFeaturesLoggerExtensions
|
|
{
|
|
private static readonly double TimestampToTicks = TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency;
|
|
private static readonly string[] EmptyArguments = new string[0];
|
|
|
|
private static readonly Action<ILogger, string, string[], Exception> _viewComponentExecuting;
|
|
private static readonly Action<ILogger, string, double, string, Exception> _viewComponentExecuted;
|
|
|
|
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;
|
|
|
|
private static readonly Action<ILogger, string, Exception> _antiforgeryTokenInvalid;
|
|
|
|
private static readonly Action<ILogger, string, Exception> _viewComponentResultExecuting;
|
|
|
|
private static readonly Action<ILogger, string, Exception> _viewResultExecuting;
|
|
private static readonly Action<ILogger, string, Exception> _viewFound;
|
|
private static readonly Action<ILogger, string, IEnumerable<string>, Exception> _viewNotFound;
|
|
|
|
static MvcViewFeaturesLoggerExtensions()
|
|
{
|
|
_viewComponentExecuting = LoggerMessage.Define<string, string[]>(
|
|
LogLevel.Debug,
|
|
1,
|
|
"Executing view component {ViewComponentName} with arguments ({Arguments}).");
|
|
|
|
_viewComponentExecuted = LoggerMessage.Define<string, double, string>(
|
|
LogLevel.Debug,
|
|
2,
|
|
"Executed view component {ViewComponentName} in {ElapsedMilliseconds}ms and returned " +
|
|
"{ViewComponentResult}");
|
|
|
|
_partialViewResultExecuting = LoggerMessage.Define<string>(
|
|
LogLevel.Information,
|
|
1,
|
|
"Executing PartialViewResult, running view at path {Path}.");
|
|
|
|
_partialViewFound = LoggerMessage.Define<string>(
|
|
LogLevel.Debug,
|
|
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}");
|
|
|
|
_antiforgeryTokenInvalid = LoggerMessage.Define<string>(
|
|
LogLevel.Information,
|
|
1,
|
|
"Antiforgery token validation failed. {Message}");
|
|
|
|
_viewComponentResultExecuting = LoggerMessage.Define<string>(
|
|
LogLevel.Information,
|
|
1,
|
|
"Executing ViewComponentResult, running {ViewComponentName}.");
|
|
|
|
_viewResultExecuting = LoggerMessage.Define<string>(
|
|
LogLevel.Information,
|
|
1,
|
|
"Executing ViewResult, running view at path {Path}.");
|
|
|
|
_viewFound = LoggerMessage.Define<string>(
|
|
LogLevel.Debug,
|
|
2,
|
|
"The view '{ViewName}' was found.");
|
|
|
|
_viewNotFound = LoggerMessage.Define<string, IEnumerable<string>>(
|
|
LogLevel.Error,
|
|
3,
|
|
"The view '{ViewName}' was not found. Searched locations: {SearchedViewLocations}");
|
|
}
|
|
|
|
public static IDisposable ViewComponentScope(this ILogger logger, ViewComponentContext context)
|
|
{
|
|
return logger.BeginScope(new ViewComponentLogScope(context.ViewComponentDescriptor));
|
|
}
|
|
|
|
public static void ViewComponentExecuting(
|
|
this ILogger logger,
|
|
ViewComponentContext context,
|
|
object[] arguments)
|
|
{
|
|
var formattedArguments = GetFormattedArguments(arguments);
|
|
_viewComponentExecuting(logger, context.ViewComponentDescriptor.DisplayName, formattedArguments, null);
|
|
}
|
|
|
|
private static string[] GetFormattedArguments(object[] arguments)
|
|
{
|
|
if (arguments == null || arguments.Length == 0)
|
|
{
|
|
return EmptyArguments;
|
|
}
|
|
|
|
var formattedArguments = new string[arguments.Length];
|
|
for (var i = 0; i < formattedArguments.Length; i++)
|
|
{
|
|
formattedArguments[i] = Convert.ToString(arguments[i]);
|
|
}
|
|
|
|
return formattedArguments;
|
|
}
|
|
|
|
public static void ViewComponentExecuted(
|
|
this ILogger logger,
|
|
ViewComponentContext context,
|
|
long startTimestamp,
|
|
object result)
|
|
{
|
|
// Don't log if logging wasn't enabled at start of request as time will be wildly wrong.
|
|
if (startTimestamp != 0)
|
|
{
|
|
var currentTimestamp = Stopwatch.GetTimestamp();
|
|
var elapsed = new TimeSpan((long)(TimestampToTicks * (currentTimestamp - startTimestamp)));
|
|
|
|
_viewComponentExecuted(
|
|
logger,
|
|
context.ViewComponentDescriptor.DisplayName,
|
|
elapsed.TotalMilliseconds,
|
|
Convert.ToString(result),
|
|
null);
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
_partialViewResultExecuting(logger, view.Path, null);
|
|
}
|
|
|
|
public static void AntiforgeryTokenInvalid(this ILogger logger, string message, Exception exception)
|
|
{
|
|
_antiforgeryTokenInvalid(logger, message, exception);
|
|
}
|
|
|
|
public static void ViewComponentResultExecuting(this ILogger logger, string viewComponentName)
|
|
{
|
|
if (logger.IsEnabled(LogLevel.Information))
|
|
{
|
|
_viewComponentResultExecuting(logger, viewComponentName, null);
|
|
}
|
|
}
|
|
|
|
public static void ViewComponentResultExecuting(this ILogger logger, Type viewComponentType)
|
|
{
|
|
if (logger.IsEnabled(LogLevel.Information))
|
|
{
|
|
_viewComponentResultExecuting(logger, viewComponentType.Name, null);
|
|
}
|
|
}
|
|
|
|
public static void ViewResultExecuting(this ILogger logger, IView view)
|
|
{
|
|
_viewResultExecuting(logger, view.Path, null);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
private class ViewComponentLogScope : IReadOnlyList<KeyValuePair<string, object>>
|
|
{
|
|
private readonly ViewComponentDescriptor _descriptor;
|
|
|
|
public ViewComponentLogScope(ViewComponentDescriptor descriptor)
|
|
{
|
|
_descriptor = descriptor;
|
|
}
|
|
|
|
public KeyValuePair<string, object> this[int index]
|
|
{
|
|
get
|
|
{
|
|
if (index == 0)
|
|
{
|
|
return new KeyValuePair<string, object>("ViewComponentName", _descriptor.DisplayName);
|
|
}
|
|
else if (index == 1)
|
|
{
|
|
return new KeyValuePair<string, object>("ViewComponentId", _descriptor.Id);
|
|
}
|
|
throw new IndexOutOfRangeException(nameof(index));
|
|
}
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get
|
|
{
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
|
|
{
|
|
for (int i = 0; i < Count; ++i)
|
|
{
|
|
yield return this[i];
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return _descriptor.DisplayName;
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
}
|
|
}
|
|
}
|