From 49ea4164f4d67994b56ebc52f57804d90cc2c8dd Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sun, 10 May 2020 21:16:46 -0400 Subject: [PATCH 01/13] More work on ASP.NET Core timings This is a stab, may change a lot...getting it up for tweaking. Trying to repro the negative timing issue we see in Stack Overflow. --- .../Controllers/HomeController.cs | 5 +++ .../Helpers/ExampleActionFilter.cs | 25 +++++++++++ samples/Samples.AspNetCore3/Startup.cs | 1 + .../MvcDiagnosticListener.cs | 41 +++++++++++-------- .../MiniProfilerOptions.cs | 11 +++++ 5 files changed, 67 insertions(+), 16 deletions(-) create mode 100644 samples/Samples.AspNetCore3/Helpers/ExampleActionFilter.cs diff --git a/samples/Samples.AspNetCore3/Controllers/HomeController.cs b/samples/Samples.AspNetCore3/Controllers/HomeController.cs index 25e20c9ce..081c75e84 100644 --- a/samples/Samples.AspNetCore3/Controllers/HomeController.cs +++ b/samples/Samples.AspNetCore3/Controllers/HomeController.cs @@ -5,6 +5,11 @@ namespace Samples.AspNetCore.Controllers { public class HomeController : Controller { + [ExampleActionFilter] + [ExampleLongActionFilter] + [ExampleActionFilter] + [ExampleActionFilter] + [ExampleActionFilter] public IActionResult Index() { using (MiniProfiler.Current.Step("Example Step")) diff --git a/samples/Samples.AspNetCore3/Helpers/ExampleActionFilter.cs b/samples/Samples.AspNetCore3/Helpers/ExampleActionFilter.cs new file mode 100644 index 000000000..b8da546b3 --- /dev/null +++ b/samples/Samples.AspNetCore3/Helpers/ExampleActionFilter.cs @@ -0,0 +1,25 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace Samples.AspNetCore +{ + public class ExampleActionFilterAttribute : ActionFilterAttribute + { + public override void OnActionExecuting(ActionExecutingContext context) => Thread.Sleep(100); + } + + public class ExampleLongActionFilterAttribute : ActionFilterAttribute + { + public override void OnActionExecuting(ActionExecutingContext context) => Thread.Sleep(500); + } + + public class ExampleAsyncActionFilterAttribute : IAsyncActionFilter + { + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + await Task.Delay(100); + await next(); + } + } +} diff --git a/samples/Samples.AspNetCore3/Startup.cs b/samples/Samples.AspNetCore3/Startup.cs index 456bff246..6205ca10f 100644 --- a/samples/Samples.AspNetCore3/Startup.cs +++ b/samples/Samples.AspNetCore3/Startup.cs @@ -82,6 +82,7 @@ public void ConfigureServices(IServiceCollection services) // Enabled sending the Server-Timing header on responses options.EnableServerTimingHeader = true; + options.EnableMvcFilterProfiling = false; options.IgnoredPaths.Add("/lib"); options.IgnoredPaths.Add("/css"); diff --git a/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs b/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs index 5c65400a5..bc740698b 100644 --- a/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs +++ b/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs @@ -86,6 +86,15 @@ private string GetName(string label, ActionDescriptor descriptor) return null; } + private object StartFilter(T state, string stepName) where T : class + { + if (MiniProfiler.Current?.Options is MiniProfilerOptions opts && opts.EnableMvcFilterProfiling) + { + CurrentTiming.Value = (state, MiniProfiler.Current.StepIf(stepName, opts.MvcFilterMinimumSaveMs ?? 0, true)); + } + return null; + } + private object Complete(T state) where T : class { if (CurrentTiming.Value.State is T currentState && currentState == state) @@ -113,41 +122,41 @@ private string GetName(string label, ActionDescriptor descriptor) AfterActionResultEventData data => Complete(data.Result), // AuthorizationFilterOnAuthorization - BeforeAuthorizationFilterOnAuthorizationEventData data => Start(data.Filter, "Auth Filter: " + GetName(data.Filter)), + BeforeAuthorizationFilterOnAuthorizationEventData data => StartFilter(data.Filter, "Auth Filter: " + GetName(data.Filter)), AfterAuthorizationFilterOnAuthorizationEventData data => Complete(data.Filter), // ResourceFilterOnResourceExecution - BeforeResourceFilterOnResourceExecutionEventData data => Start(data.Filter, "Resource Filter (Exec): " + GetName(data.Filter)), + BeforeResourceFilterOnResourceExecutionEventData data => StartFilter(data.Filter, "Resource Filter (Exec): " + GetName(data.Filter)), AfterResourceFilterOnResourceExecutionEventData data => Complete(data.Filter), // ResourceFilterOnResourceExecuting - BeforeResourceFilterOnResourceExecutingEventData data => Start(data.Filter, "Resource Filter (Execing): " + GetName(data.Filter)), + BeforeResourceFilterOnResourceExecutingEventData data => StartFilter(data.Filter, "Resource Filter (Execing): " + GetName(data.Filter)), AfterResourceFilterOnResourceExecutingEventData data => Complete(data.Filter), // ResourceFilterOnResourceExecuted - BeforeResourceFilterOnResourceExecutedEventData data => Start(data.Filter, "Resource Filter (Execed): " + GetName(data.Filter)), + BeforeResourceFilterOnResourceExecutedEventData data => StartFilter(data.Filter, "Resource Filter (Execed): " + GetName(data.Filter)), AfterResourceFilterOnResourceExecutedEventData data => Complete(data.Filter), // ExceptionFilterOnException - BeforeExceptionFilterOnException data => Start(data.Filter, "Exception Filter: " + GetName(data.Filter)), + BeforeExceptionFilterOnException data => StartFilter(data.Filter, "Exception Filter: " + GetName(data.Filter)), AfterExceptionFilterOnExceptionEventData data => Complete(data.Filter), // ActionFilterOnActionExecution - BeforeActionFilterOnActionExecutionEventData data => Start(data.Filter, "Action Filter (Exec): " + GetName(data.Filter)), + BeforeActionFilterOnActionExecutionEventData data => StartFilter(data.Filter, "Action Filter (Exec): " + GetName(data.Filter)), AfterActionFilterOnActionExecutionEventData data => Complete(data.Filter), // ActionFilterOnActionExecuting - BeforeActionFilterOnActionExecutingEventData data => Start(data.Filter, "Action Filter (Execing): " + GetName(data.Filter)), + BeforeActionFilterOnActionExecutingEventData data => StartFilter(data.Filter, "Action Filter (Execing): " + GetName(data.Filter)), AfterActionFilterOnActionExecutingEventData data => Complete(data.Filter), // ActionFilterOnActionExecuted - BeforeActionFilterOnActionExecutedEventData data => Start(data.Filter, "Action Filter (Execed): " + GetName(data.Filter)), + BeforeActionFilterOnActionExecutedEventData data => StartFilter(data.Filter, "Action Filter (Execed): " + GetName(data.Filter)), AfterActionFilterOnActionExecutedEventData data => Complete(data.Filter), // ResultFilterOnResultExecution - BeforeResultFilterOnResultExecutionEventData data => Start(data.Filter, "Result Filter (Exec): " + GetName(data.Filter)), + BeforeResultFilterOnResultExecutionEventData data => StartFilter(data.Filter, "Result Filter (Exec): " + GetName(data.Filter)), AfterResultFilterOnResultExecutionEventData data => Complete(data.Filter), // ResultFilterOnResultExecuting - BeforeResultFilterOnResultExecutingEventData data => Start(data.Filter, "Result Filter (Execing): " + GetName(data.Filter)), + BeforeResultFilterOnResultExecutingEventData data => StartFilter(data.Filter, "Result Filter (Execing): " + GetName(data.Filter)), AfterResultFilterOnResultExecutingEventData data => Complete(data.Filter), // ResultFilterOnResultExecuted - BeforeResultFilterOnResultExecutedEventData data => Start(data.Filter, "Result Filter (Execed): " + GetName(data.Filter)), + BeforeResultFilterOnResultExecutedEventData data => StartFilter(data.Filter, "Result Filter (Execed): " + GetName(data.Filter)), AfterResultFilterOnResultExecutedEventData data => Complete(data.Filter), // Razor Bits: https://github.com/dotnet/aspnetcore/blob/v3.0.0/src/Mvc/Mvc.Razor/src/Diagnostics/MvcDiagnostics.cs @@ -161,20 +170,20 @@ private string GetName(string label, ActionDescriptor descriptor) AfterHandlerMethodEventData data => Complete(data.Instance), // PageFilterOnPageHandlerExecution - BeforePageFilterOnPageHandlerExecutionEventData data => Start(data.Filter, "Filter (Exec): " + GetName(data.Filter)), + BeforePageFilterOnPageHandlerExecutionEventData data => StartFilter(data.Filter, "Filter (Exec): " + GetName(data.Filter)), AfterPageFilterOnPageHandlerExecutionEventData data => Complete(data.Filter), // PageFilterOnPageHandlerExecuting - BeforePageFilterOnPageHandlerExecutingEventData data => Start(data.Filter, "Filter (Execing): " + GetName(data.Filter)), + BeforePageFilterOnPageHandlerExecutingEventData data => StartFilter(data.Filter, "Filter (Execing): " + GetName(data.Filter)), AfterPageFilterOnPageHandlerExecutingEventData data => Complete(data.Filter), // PageFilterOnPageHandlerExecuted - BeforePageFilterOnPageHandlerExecutedEventData data => Start(data.Filter, "Filter (Execed): " + GetName(data.Filter)), + BeforePageFilterOnPageHandlerExecutedEventData data => StartFilter(data.Filter, "Filter (Execed): " + GetName(data.Filter)), AfterPageFilterOnPageHandlerExecutedEventData data => Complete(data.Filter), // PageFilterOnPageHandlerSelection - BeforePageFilterOnPageHandlerSelectionEventData data => Start(data.Filter, "Filter (Selection): " + GetName(data.Filter)), + BeforePageFilterOnPageHandlerSelectionEventData data => StartFilter(data.Filter, "Filter (Selection): " + GetName(data.Filter)), AfterPageFilterOnPageHandlerSelectionEventData data => Complete(data.Filter), // PageFilterOnPageHandlerSelected - BeforePageFilterOnPageHandlerSelectedEventData data => Start(data.Filter, "Filter (Selected): " + GetName(data.Filter)), + BeforePageFilterOnPageHandlerSelectedEventData data => StartFilter(data.Filter, "Filter (Selected): " + GetName(data.Filter)), AfterPageFilterOnPageHandlerSelectedEventData data => Complete(data.Filter), _ => null }; diff --git a/src/MiniProfiler.AspNetCore/MiniProfilerOptions.cs b/src/MiniProfiler.AspNetCore/MiniProfilerOptions.cs index a0117ccbc..98b171fb8 100644 --- a/src/MiniProfiler.AspNetCore/MiniProfilerOptions.cs +++ b/src/MiniProfiler.AspNetCore/MiniProfilerOptions.cs @@ -60,6 +60,17 @@ public class MiniProfilerOptions : MiniProfilerBaseOptions /// Whether to add a Server-Timing header after profiling a request. Only supported in .NET Core 3.0 and higher. /// public bool EnableServerTimingHeader { get; set; } + + /// + /// Whether to profile MVC filters as individual steps. + /// + public bool EnableMvcFilterProfiling { get; set; } = true; + + /// + /// The minimum duration to record for MVC filter timings, anything below this will be discarded as noise. + /// Defaults to 0.01 ms + /// + public decimal? MvcFilterMinimumSaveMs { get; set; } = -1000.01m; #endif } } From c3961208a02dc69ec2655f39b4c27de18a97b6fa Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sat, 23 May 2020 22:23:36 -0400 Subject: [PATCH 02/13] DEBUG MODE OF DOOM Gotta figure out stack slicing off the top here yet...but some progress in an uber debug mode for things. --- .../Controllers/HomeController.cs | 3 + .../Helpers/ExampleActionFilter.cs | 10 +- samples/Samples.AspNetCore3/Startup.cs | 5 +- samples/Samples.AspNetCore3/web.config | 2 +- .../Helpers/StackTraceSnippet.cs | 485 +++++++++++++++++- .../Internal/MiniProfilerBaseOptions.cs | 5 + src/MiniProfiler.Shared/Timing.cs | 11 + src/MiniProfiler.Shared/TimingDebugInfo.cs | 59 +++ src/MiniProfiler.Shared/ui/includes.css | 85 ++- src/MiniProfiler.Shared/ui/includes.less | 106 +++- src/MiniProfiler.Shared/ui/includes.min.css | 2 +- .../ui/lib/MiniProfiler.ts | 27 +- 12 files changed, 775 insertions(+), 25 deletions(-) create mode 100644 src/MiniProfiler.Shared/TimingDebugInfo.cs diff --git a/samples/Samples.AspNetCore3/Controllers/HomeController.cs b/samples/Samples.AspNetCore3/Controllers/HomeController.cs index 081c75e84..7df90852e 100644 --- a/samples/Samples.AspNetCore3/Controllers/HomeController.cs +++ b/samples/Samples.AspNetCore3/Controllers/HomeController.cs @@ -10,6 +10,9 @@ public class HomeController : Controller [ExampleActionFilter] [ExampleActionFilter] [ExampleActionFilter] + [ExampleAsyncActionFilter] + [ExampleAsyncActionFilter] + [ExampleActionFilter] public IActionResult Index() { using (MiniProfiler.Current.Step("Example Step")) diff --git a/samples/Samples.AspNetCore3/Helpers/ExampleActionFilter.cs b/samples/Samples.AspNetCore3/Helpers/ExampleActionFilter.cs index b8da546b3..0c08a6b8d 100644 --- a/samples/Samples.AspNetCore3/Helpers/ExampleActionFilter.cs +++ b/samples/Samples.AspNetCore3/Helpers/ExampleActionFilter.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Filters; @@ -11,14 +12,15 @@ public class ExampleActionFilterAttribute : ActionFilterAttribute public class ExampleLongActionFilterAttribute : ActionFilterAttribute { - public override void OnActionExecuting(ActionExecutingContext context) => Thread.Sleep(500); + public override void OnActionExecuting(ActionExecutingContext context) => Thread.Sleep(200); } - public class ExampleAsyncActionFilterAttribute : IAsyncActionFilter + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)] + public class ExampleAsyncActionFilterAttribute : Attribute, IAsyncActionFilter { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { - await Task.Delay(100); + await Task.Delay(300); await next(); } } diff --git a/samples/Samples.AspNetCore3/Startup.cs b/samples/Samples.AspNetCore3/Startup.cs index 6205ca10f..4bd1a8255 100644 --- a/samples/Samples.AspNetCore3/Startup.cs +++ b/samples/Samples.AspNetCore3/Startup.cs @@ -82,7 +82,10 @@ public void ConfigureServices(IServiceCollection services) // Enabled sending the Server-Timing header on responses options.EnableServerTimingHeader = true; - options.EnableMvcFilterProfiling = false; + options.EnableMvcFilterProfiling = true; + + // Alrighty, I'm done screwing around - TIME TO LOG EVERYTHING! ALLOCATIONS BE DAMNED! + options.EnableDebugMode = true; options.IgnoredPaths.Add("/lib"); options.IgnoredPaths.Add("/css"); diff --git a/samples/Samples.AspNetCore3/web.config b/samples/Samples.AspNetCore3/web.config index ccdd0e200..d195283ab 100644 --- a/samples/Samples.AspNetCore3/web.config +++ b/samples/Samples.AspNetCore3/web.config @@ -7,7 +7,7 @@ - + diff --git a/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs b/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs index eaa1a794d..b93c67796 100644 --- a/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs +++ b/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs @@ -1,6 +1,11 @@ using StackExchange.Profiling.Internal; +using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Net; using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; namespace StackExchange.Profiling.Helpers { @@ -44,14 +49,13 @@ bool ShouldExcludeType(MethodBase method) var sb = StringBuilderCache.Get(); int stackLength = 0, startFrame = frames.Length - 1; - for (int i = 0; i < frames.Length; i++) { var method = frames[i].GetMethod(); if (stackLength >= options.StackMaxLength - // ASP.NET: no need to continue up the chain - || method.Name == "System.Web.HttpApplication.IExecutionStep.Execute" - || (method.Module.Name == "Microsoft.AspNetCore.Mvc.Core.dll" && method.DeclaringType.Name == "ObjectMethodExecutor")) + // ASP.NET: no need to continue up the chain + || method.Name == "System.Web.HttpApplication.IExecutionStep.Execute" + || (method.Module.Name == "Microsoft.AspNetCore.Mvc.Core.dll" && method.DeclaringType.Name == "ObjectMethodExecutor")) { frames[i] = null; startFrame = i < 0 ? 0 : i - 1; @@ -69,6 +73,7 @@ bool ShouldExcludeType(MethodBase method) } } + //string nextSuffix = null; for (var i = startFrame; i >= 0; i--) { var f = frames[i]; @@ -80,10 +85,482 @@ bool ShouldExcludeType(MethodBase method) sb.Append(" > "); } sb.Append(method.Name); + sb.Append(" (").Append(f.ToString()).Append(")"); } } return sb.ToStringRecycle(); } } + + /// + /// StackTrace utilities, from Exceptional + /// + /// + /// ...need to make this a source package... + /// + internal static class StackTraceUtils + { + // Inspired by StackTraceParser by Atif Aziz, project home: https://github.com/atifaziz/StackTraceParser + internal const string Space = @"[\x20\t]", + NoSpace = @"[^\x20\t]"; + private static class Groups + { + public const string LeadIn = nameof(LeadIn); + public const string Frame = nameof(Frame); + public const string Type = nameof(Type); + public const string AsyncMethod = nameof(AsyncMethod); + public const string Method = nameof(Method); + public const string Params = nameof(Params); + public const string ParamType = nameof(ParamType); + public const string ParamName = nameof(ParamName); + public const string SourceInfo = nameof(SourceInfo); + public const string Path = nameof(Path); + public const string LinePrefix = nameof(LinePrefix); + public const string Line = nameof(Line); + } + + private static readonly char[] NewLine_CarriageReturn = { '\n', '\r' }; + + private const string EndStack = "--- End of stack trace from previous location where exception was thrown ---"; + + // TODO: Patterns, or a bunch of these... + private static readonly HashSet _asyncFrames = new HashSet() + { + // 3.1 Stacks + "System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(Exception exception)", + "System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder`1.SetException(Exception exception)", + "System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining)", + "System.Threading.Tasks.Task.FinishSlow(Boolean userDelegateExecute)", + "System.Threading.Tasks.Task.TrySetException(Object exceptionObject)", + + // 3.0 Stacks + "System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)", + "System.Threading.Tasks.Task.RunContinuations(Object continuationObject)", + "System.Threading.Tasks.Task`1.TrySetResult(TResult result)", + "System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(Action action, Boolean allowInlining)", + "System.Threading.Tasks.Task.CancellationCleanupLogic()", + "System.Threading.Tasks.Task.TrySetCanceled(CancellationToken tokenToRecord, Object cancellationException)", + "System.Threading.Tasks.Task.FinishContinuations()", + + "System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()", + "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(TResult result)", + "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s)", + "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread)", + "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext()", + "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetException(Exception exception)", + "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetResult(TResult result)", + "System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()", + "System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder`1.SetResult(TResult result)", + "System.Runtime.CompilerServices.TaskAwaiter.<>c.b__12_0(Action innerContinuation, Task innerTask)", + + // < .NET Core 3.0 stacks + "System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()", + "System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)", + "System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)", + "System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)", + "System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()", + "System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()", + "System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()", + "System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)", + "System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()", + "Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()", + EndStack + }; + + // TODO: Adjust for URLs instead of files + private static readonly Regex _regex = new Regex($@" + ^(?<{Groups.LeadIn}>{Space}*\w+{Space}+) + (?<{Groups.Frame}> + (?<{Groups.Type}>({NoSpace}+(<(?<{Groups.AsyncMethod}>\w+)>d__[0-9]+))|{NoSpace}+)\. + (?<{Groups.Method}>{NoSpace}+?){Space}* + (?<{Groups.Params}>\(({Space}*\) + |(?<{Groups.ParamType}>.+?){Space}+(?<{Groups.ParamName}>.+?) + (,{Space}*(?<{Groups.ParamType}>.+?){Space}+(?<{Groups.ParamName}>.+?))*\)) + ) + ({Space}+ + (\w+{Space}+ + (?<{Groups.SourceInfo}> + (?<{Groups.Path}>([a-z]\:.+?|(\b(https?|ftp|file)://)?[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])) + (?<{Groups.LinePrefix}>\:\w+{Space}+) + (?<{Groups.Line}>[0-9]+)\p{{P}}? + |\[0x[0-9a-f]+\]{Space}+\w+{Space}+<(?<{Groups.Path}>[^>]+)>(?<{Groups.LinePrefix}>:)(?<{Groups.Line}>[0-9]+)) + ) + )? + )\s*$", + RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Multiline + | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace, + TimeSpan.FromSeconds(2)); + + /// + /// Converts a stack trace to formatted HTML with styling and linkifiation. + /// + /// The stack trace to HTMLify. + /// An HTML-pretty version of the stack trace. + public static string HtmlPrettify(string stackTrace, int? commonStart = null) + { + string GetBetween(Capture prev, Capture next) => + stackTrace.Substring(prev.Index + prev.Length, next.Index - (prev.Index + prev.Length)); + + int pos = 0; + var sb = StringBuilderCache.Get(); + var matches = _regex.Matches(stackTrace); + for (var mi = 0; mi < matches.Count; mi++) + { + Match m = matches[mi]; + Group leadIn = m.Groups[Groups.LeadIn], + frame = m.Groups[Groups.Frame], + type = m.Groups[Groups.Type], + asyncMethod = m.Groups[Groups.AsyncMethod], + method = m.Groups[Groups.Method], + allParams = m.Groups[Groups.Params], + sourceInfo = m.Groups[Groups.SourceInfo], + path = m.Groups[Groups.Path], + linePrefix = m.Groups[Groups.LinePrefix], + line = m.Groups[Groups.Line]; + CaptureCollection paramTypes = m.Groups[Groups.ParamType].Captures, + paramNames = m.Groups[Groups.ParamName].Captures; + bool nextIsAsync = false; + if (mi < matches.Count - 1) + { + Group nextFrame = matches[mi + 1].Groups[Groups.Frame]; + nextIsAsync = _asyncFrames.Contains(nextFrame.Value); + } + + var isAsync = _asyncFrames.Contains(frame.Value); + + // The initial message may be above an async frame + if (sb.Length == 0 && isAsync && leadIn.Index > pos) + { + sb.Append("") + .Append("") + .AppendHtmlEncode(stackTrace.Substring(pos, leadIn.Index - pos).Trim(NewLine_CarriageReturn)) + .Append("") + .Append(""); + pos += sb.Length; + } + + sb.Append("= commonStart) + { + sb.Append(" common"); + } + sb.Append("\">"); + + if (leadIn.Index > pos) + { + var miscContent = stackTrace.Substring(pos, leadIn.Index - pos); + if (miscContent.Contains(EndStack)) + { + // Handle end-of-stack removals and redundant multilines remaining + miscContent = miscContent.Replace(EndStack, "") + .Replace("\r\n\r\n", "\r\n") + .Replace("\n\n", "\n\n"); + } + + sb.Append("") + .AppendHtmlEncode(miscContent) + .Append(""); + } + sb.Append("") + .AppendHtmlEncode(leadIn.Value) + .Append(""); + + // Check if the next line is the end of an async hand-off + var nextEndStack = stackTrace.IndexOf(EndStack, m.Index + m.Length); + if ((nextEndStack > -1 && nextEndStack < m.Index + m.Length + 3) || (!isAsync && nextIsAsync)) + { + sb.Append("async "); + } + + if (asyncMethod.Success) + { + sb.Append("") + .AppendGenericsHtml(GetBetween(leadIn, asyncMethod)) + .Append("") + .Append("") + .AppendHtmlEncode(asyncMethod.Value) + .Append("") + .Append("") + .AppendGenericsHtml(GetBetween(asyncMethod, method)); + sb.Append(""); + } + else + { + sb.Append("") + .AppendGenericsHtml(type.Value) + .Append("") + .AppendHtmlEncode(GetBetween(type, method)) // "." + .Append("") + .Append(""); + } + sb.Append("") + .Append("") + .AppendHtmlEncode(NormalizeMethodName(method.Value)) + .Append(""); + + if (paramTypes.Count > 0) + { + sb.Append("") + .Append(GetBetween(method, paramTypes[0])) + .Append(""); + for (var i = 0; i < paramTypes.Count; i++) + { + if (i > 0) + { + sb.Append("") + .AppendHtmlEncode(GetBetween(paramNames[i - 1], paramTypes[i])) // ", " + .Append(""); + } + sb.Append("") + .AppendGenericsHtml(paramTypes[i].Value) + .Append("") + .AppendHtmlEncode(GetBetween(paramTypes[i], paramNames[i])) // " " + .Append("") + .AppendHtmlEncode(paramNames[i].Value) + .Append(""); + } + var last = paramNames[paramTypes.Count - 1]; + sb.Append("") + .AppendHtmlEncode(allParams.Value.Substring(last.Index + last.Length - allParams.Index)) + .Append(""); + } + else + { + sb.Append("") + .AppendHtmlEncode(allParams.Value) // "()" + .Append(""); + } + sb.Append(""); // method-section for table layout + + if (sourceInfo.Value.HasValue()) + { + sb.Append(""); + + var curPath = sourceInfo.Value; + if (curPath != sourceInfo.Value) + { + sb.Append("") + .AppendHtmlEncode(GetBetween(allParams, sourceInfo)) + .Append("") + .Append(curPath); + } + else if (path.Value.HasValue()) + { + var subPath = GetSubPath(path.Value, type.Value); + + sb.Append("") + .AppendHtmlEncode(GetBetween(allParams, path)) + .Append("") + .Append("") + .AppendHtmlEncode(subPath) + .Append("") + .AppendHtmlEncode(GetBetween(path, linePrefix)) + .Append("") + .AppendHtmlEncode(linePrefix.Value) + .Append("") + .Append("") + .AppendHtmlEncode(line.Value) + .Append(""); + } + sb.Append(""); + } + + sb.Append(""); + + pos = frame.Index + frame.Length; + } + + // append anything left + sb.Append(""); + var tailLength = stackTrace.Length - pos; + if (tailLength > 0) + { + sb.AppendHtmlEncode(stackTrace.Substring(pos, tailLength)); + } + sb.Append(""); + + return sb.ToStringRecycle(); + } + + private static char[] Backslash { get; } = new[] { '\\' }; + + private static string GetSubPath(string sourcePath, string type) + { + //C:\git\NickCraver\StackExchange.Exceptional\src\StackExchange.Exceptional.Shared\Utils.Test.cs + int pathPos = 0; + foreach (var path in sourcePath.Split(Backslash)) + { + pathPos += (path.Length + 1); + if (type.StartsWith(path)) + { + return sourcePath.Substring(pathPos); + } + } + return sourcePath; + } + + /// + /// .NET Core changes methods so generics render as as Method[T], this normalizes it. + /// + private static string NormalizeMethodName(string method) + { + return method?.Replace("[", "<").Replace("]", ">"); + } + } + + internal static class StackTraceExtensions + { + private static readonly char[] _dot = new char[] { '.' }; + private static readonly Regex _genericTypeRegex = new Regex($@"(?{StackTraceUtils.NoSpace}+)`(?\d+)"); + private static readonly string[] _singleT = new[] { "T" }; + + private static readonly Dictionary _commonGenerics = new Dictionary + { + ["Microsoft.CodeAnalysis.SymbolVisitor`1"] = new[] { "TResult" }, + ["Microsoft.CodeAnalysis.Diagnostics.CodeBlockStartAnalysisContext`1"] = new[] { "TLanguageKindEnum" }, + ["Microsoft.CodeAnalysis.Diagnostics.SourceTextValueProvider`1"] = new[] { "TValue" }, + ["Microsoft.CodeAnalysis.Diagnostics.SyntaxTreeValueProvider`1"] = new[] { "TValue" }, + ["Microsoft.CodeAnalysis.Semantics.OperationVisitor`2"] = new[] { "TArgument", "TResult" }, + ["System.Converter`2"] = new[] { "TInput", "TOutput" }, + ["System.EventHandler`1"] = new[] { "TEventArgs" }, + ["System.Func`1"] = new[] { "TResult" }, + ["System.Func`2"] = new[] { "T", "TResult" }, + ["System.Func`3"] = new[] { "T1", "T2", "TResult" }, + ["System.Func`4"] = new[] { "T1", "T2", "T3", "TResult" }, + ["System.Func`5"] = new[] { "T1", "T2", "T3", "T4", "TResult" }, + ["System.Func`6"] = new[] { "T1", "T2", "T3", "T4", "T5", "TResult" }, + ["System.Func`7"] = new[] { "T1", "T2", "T3", "T4", "T5", "T6", "TResult" }, + ["System.Func`8"] = new[] { "T1", "T2", "T3", "T4", "T5", "T6", "T7", "TResult" }, + ["System.Func`9"] = new[] { "T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "TResult" }, + ["System.Func`10"] = new[] { "T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "T9", "TResult" }, + ["System.Func`11"] = new[] { "T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "T9", "T10", "TResult" }, + ["System.Func`12"] = new[] { "T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "T9", "T10", "T11", "TResult" }, + ["System.Func`13"] = new[] { "T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "T9", "T10", "T11", "T12", "TResult" }, + ["System.Func`14"] = new[] { "T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "T9", "T10", "T11", "T12", "T13", "TResult" }, + ["System.Func`15"] = new[] { "T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "T9", "T10", "T11", "T12", "T13", "T14", "TResult" }, + ["System.Func`16"] = new[] { "T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "T9", "T10", "T11", "T12", "T13", "T14", "T15", "TResult" }, + ["System.Func`17"] = new[] { "T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "T9", "T10", "T11", "T12", "T13", "T14", "T15", "T16", "TWhatTheHellAreYouDoing" }, + ["System.Tuple`8"] = new[] { "T1", "T2", "T3", "T4", "T5", "T6", "T7", "TRest" }, + ["System.Collections.Concurrent.ConcurrentDictionary`2"] = new[] { "TKey", "TValue" }, + ["System.Collections.Concurrent.OrderablePartitioner`1"] = new[] { "TSource" }, + ["System.Collections.Concurrent.Partitioner`1"] = new[] { "TSource" }, + ["System.Collections.Generic.Dictionary`2"] = new[] { "TKey", "TValue" }, + ["System.Collections.Generic.SortedDictionary`2"] = new[] { "TKey", "TValue" }, + ["System.Collections.Generic.SortedList`2"] = new[] { "TKey", "TValue" }, + ["System.Collections.Immutable.ImmutableDictionary`2"] = new[] { "TKey", "TValue" }, + ["System.Collections.Immutable.ImmutableSortedDictionary`2"] = new[] { "TKey", "TValue" }, + ["System.Collections.ObjectModel.KeyedCollection`2"] = new[] { "TKey", "TItem" }, + ["System.Collections.ObjectModel.ReadOnlyDictionary`2"] = new[] { "TKey", "TValue" }, + ["System.Data.Common.CommandTrees.DbExpressionVisitor`1"] = new[] { "TResultType" }, + ["System.Data.Linq.EntitySet`1"] = new[] { "TEntity" }, + ["System.Data.Linq.Table`1"] = new[] { "TEntity" }, + ["System.Data.Linq.Mapping.MetaAccessor`2"] = new[] { "TEntity", "TMember" }, + ["System.Data.Linq.SqlClient.Implementation.ObjectMaterializer`1"] = new[] { "TDataReader" }, + ["System.Data.Objects.ObjectSet`1"] = new[] { "TEntity" }, + ["System.Data.Objects.DataClasses.EntityCollection`1"] = new[] { "TEntity" }, + ["System.Data.Objects.DataClasses.EntityReference`1"] = new[] { "TEntity" }, + ["System.Linq.Lookup`2"] = new[] { "TKey", "TElement" }, + ["System.Linq.OrderedParallelQuery`1"] = new[] { "TSource" }, + ["System.Linq.ParallelQuery`1"] = new[] { "TSource" }, + ["System.Linq.Expressions.Expression`1"] = new[] { "TDelegate" }, + ["System.Runtime.CompilerServices.ConditionalWeakTable`2"] = new[] { "TKey", "TValue" }, + ["System.Threading.Tasks.Task`1"] = new[] { "TResult" }, + ["System.Threading.Tasks.TaskCompletionSource`1"] = new[] { "TResult" }, + ["System.Threading.Tasks.TaskFactory`1"] = new[] { "TResult" }, + ["System.Web.ModelBinding.ArrayModelBinder`1"] = new[] { "TElement" }, + ["System.Web.ModelBinding.CollectionModelBinder`1"] = new[] { "TElement" }, + ["System.Web.ModelBinding.DataAnnotationsModelValidator`1"] = new[] { "TAttribute" }, + ["System.Web.ModelBinding.DictionaryModelBinder`2"] = new[] { "TKey", "TValue" }, + ["System.Web.ModelBinding.DictionaryValueProvider`1"] = new[] { "TValue" }, + ["System.Web.ModelBinding.KeyValuePairModelBinder`2"] = new[] { "TKey", "TValue" }, + ["System.Windows.WeakEventManager`2"] = new[] { "TEventSource", "TEventArgs" }, + ["System.Windows.Documents.TextElementCollection`1"] = new[] { "TextElementType" }, + ["System.Windows.Threading.DispatcherOperation`1"] = new[] { "TResult" }, + ["System.Xaml.Schema.XamlValueConverter`1"] = new[] { "TConverterBase" }, + }; + + internal static StringBuilder AppendHtmlEncode(this StringBuilder sb, string s) => sb.Append(WebUtility.HtmlEncode(s)); + + internal static StringBuilder AppendGenericsHtml(this StringBuilder sb, string typeOrMethod) + { + const string _dotSpan = "."; + // Check the common framework list above + _commonGenerics.TryGetValue(typeOrMethod, out string[] args); + + // Break each type down by namespace and class (remember, we *could* have nested generic classes) + var classes = typeOrMethod.Split(_dot); + // Loop through each dot component of the type, e.g. "System", "Collections", "Generics" + for (var i = 0; i < classes.Length; i++) + { + if (i > 0) + { + sb.Append(_dotSpan); + } + var match = _genericTypeRegex.Match(classes[i]); + if (match.Success) + { + // If arguments aren't known, get the defaults + if (args == null && int.TryParse(match.Groups["ArgCount"].Value, out int count)) + { + if (count == 1) + { + args = _singleT; + } + else + { + args = new string[count]; + for (var j = 0; j < count; j++) + { + args[j] = "T" + (j + 1).ToString(); // , or + } + } + } + // In the known case, BaseClass is "System.Collections.Generic.Dictionary" + // In the unknown case, we're hitting here at "Class" only + sb.AppendHtmlEncode(match.Groups["BaseClass"].Value); + AppendArgs(args); + } + else + { + sb.AppendHtmlEncode(classes[i]); + } + } + return sb; + + void AppendArgs(string[] tArgs) + { + sb.Append("<"); + // Don't put crazy amounts of arguments in here + if (tArgs.Length > 5) + { + sb.Append("").Append(tArgs[0]).Append("") + .Append(",") + .Append("").Append(tArgs[1]).Append("") + .Append(",") + .Append("").Append(tArgs[2]).Append("") + .Append("…") + .Append("").Append(tArgs[tArgs.Length - 1]).Append(""); + } + else + { + for (int i = 0; i < tArgs.Length; i++) + { + if (i > 0) + { + sb.Append(","); + } + sb.Append(""); + sb.Append(tArgs[i]) + .Append(""); + } + } + sb.Append(">"); + } + } + } } diff --git a/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs b/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs index b3566c8fb..9bc2200bf 100644 --- a/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs +++ b/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs @@ -23,6 +23,11 @@ public class MiniProfilerBaseOptions /// public virtual string VersionHash { get; set; } = typeof(MiniProfilerBaseOptions).GetTypeInfo().Assembly.GetCustomAttribute()?.InformationalVersion ?? Version.ToString(); + /// + /// Whether to enable verbose diagnostics mode in MiniProfiler. + /// + public bool EnableDebugMode { get; set; } + /// /// Assemblies to exclude from the stack trace report. /// diff --git a/src/MiniProfiler.Shared/Timing.cs b/src/MiniProfiler.Shared/Timing.cs index 793018242..8e22f107d 100644 --- a/src/MiniProfiler.Shared/Timing.cs +++ b/src/MiniProfiler.Shared/Timing.cs @@ -50,6 +50,11 @@ public Timing(MiniProfiler profiler, Timing parent, string name, decimal? minSav _minSaveMs = minSaveMs; _includeChildrenWithMinSave = includeChildrenWithMinSave == true; StartMilliseconds = profiler.GetRoundedMilliseconds(_startTicks); + + if (profiler.Options.EnableDebugMode) + { + DebugInfo = new TimingDebugInfo(this); + } } /// @@ -107,6 +112,12 @@ public List Children [DataMember(Order = 6)] public Dictionary> CustomTimings { get; set; } + /// + /// Present only when EnableDebugMode is true, additional step info in-memory only. + /// + [DataMember(Order = 7)] + public TimingDebugInfo DebugInfo { get; set; } + /// /// JSON representing the Custom Timings associated with this timing. /// diff --git a/src/MiniProfiler.Shared/TimingDebugInfo.cs b/src/MiniProfiler.Shared/TimingDebugInfo.cs new file mode 100644 index 000000000..cf68e6509 --- /dev/null +++ b/src/MiniProfiler.Shared/TimingDebugInfo.cs @@ -0,0 +1,59 @@ +using System.Diagnostics; +using System.Runtime.Serialization; +using StackExchange.Profiling.Helpers; + +namespace StackExchange.Profiling +{ + /// + /// Debug info for a timing, only present when EnableDebugMode is set in options + /// + [DataContract] + public class TimingDebugInfo + { + /// + /// An (already-encoded) HTML representation of the call stack. + /// + /// + /// Repetitive, but pays the prettification cost on fetch. + /// We'll want to do diff with the parent timing here in highlight or something. + /// + [DataMember(Order = 1)] + public string RichHtmlStack => StackTraceUtils.HtmlPrettify(RawStack.ToString(), CommonStackStart); + + /// + /// The index of the stack frame that common frames with parent start at (e.g. happened in the parent timing, before this). + /// + [DataMember(Order = 2)] + public int? CommonStackStart { get; } + + private Timing ParentTiming { get; } + private StackTrace RawStack { get; } + + internal TimingDebugInfo(Timing parent) + { + ParentTiming = parent; + RawStack = new StackTrace(4, true); + + if (parent.ParentTiming?.DebugInfo?.RawStack is StackTrace parentStack) + { + // Seek a common end in frames + int myIndex, parentIndex; + for (myIndex = RawStack.FrameCount - 1, parentIndex = parentStack.FrameCount - 1; + myIndex >= 0 && parentIndex >= 0; + myIndex--, parentIndex--) + { + StackFrame myFrame = RawStack.GetFrame(myIndex), + parentFrame = parentStack.GetFrame(parentIndex); + if (myFrame.GetILOffset() == parentFrame.GetILOffset() && myFrame.GetMethod() == parentFrame.GetMethod()) + { + CommonStackStart = myIndex; + } + else + { + break; + } + } + } + } + } +} diff --git a/src/MiniProfiler.Shared/ui/includes.css b/src/MiniProfiler.Shared/ui/includes.css index baa36e955..1d0c53549 100644 --- a/src/MiniProfiler.Shared/ui/includes.css +++ b/src/MiniProfiler.Shared/ui/includes.css @@ -218,6 +218,86 @@ .mp-result table.mp-client-timings .t-paint div { background: var(--mp-timing-paint-color); } +.mp-result .mp-debug { + position: relative; + cursor: pointer; +} +.mp-result .mp-debug .mp-debug-tooltip { + display: none; + position: fixed; + background-color: var(--mp-main-bg-color); + box-shadow: var(--mp-popup-shadow); + right: 100px; + max-width: 90%; + border-radius: 10px; + padding: 12px; + opacity: 0.95; + backdrop-filter: blur(4px); +} +.mp-result .mp-debug:hover .mp-label { + text-decoration: underline; +} +.mp-result .mp-debug td:first-child:hover .mp-debug-tooltip { + display: block; +} +.mp-result .mp-debug td:first-child > span { + color: var(--mp-link-color); +} +.mp-result .mp-stack-trace { + color: var(--mp-muted-color); + margin-bottom: 5px; + font-family: Consolas, Monaco, monospace; + overflow-x: hidden; + overflow-y: auto; + white-space: pre-line; + max-height: 200px; +} +.mp-result .mp-stack-trace .stack-row { + white-space: nowrap; +} +.mp-result .mp-stack-trace .stack-row.common { + filter: grayscale(80%); +} +.mp-result .mp-stack-trace .stack.async { + opacity: 0.6; + display: none; +} +.mp-result .mp-stack-trace .stack.leadin, +.mp-result .mp-stack-trace .stack.file, +.mp-result .mp-stack-trace .stack.line-prefix, +.mp-result .mp-stack-trace .stack.path, +.mp-result .mp-stack-trace .stack.dot { + color: var(--mp-muted-color); +} +.mp-result .mp-stack-trace .stack.async-tag { + color: var(--mp-highlight-attribute-color); + font-weight: bold; +} +.mp-result .mp-stack-trace .stack.async-tag:before { + content: "("; +} +.mp-result .mp-stack-trace .stack.async-tag:after { + content: ")"; +} +.mp-result .mp-stack-trace .stack.type { + color: var(--mp-highlight-keyword-color); +} +.mp-result .mp-stack-trace .stack.generic-type { + color: var(--mp-highlight-fade-color); +} +.mp-result .mp-stack-trace .stack.misc, +.mp-result .mp-stack-trace .stack.parens { + color: var(--mp-highlight-comment-color); +} +.mp-result .mp-stack-trace .stack.method { + color: var(--mp-highlight-string-color); +} +.mp-result .mp-stack-trace .stack.paramType { + color: var(--mp-highlight-attribute-color); +} +.mp-result .mp-stack-trace .stack.paramName { + color: var(--mp-highlight-variable-color); +} .mp-result .mp-label { color: var(--mp-label-color); overflow: hidden; @@ -400,11 +480,6 @@ .mp-queries .mp-odd { background-color: var(--mp-alt-row-color); } -.mp-queries .mp-stack-trace { - padding-bottom: 1px; - color: var(--mp-muted-color); - margin-bottom: 5px; -} .mp-queries .mp-since-start, .mp-queries .mp-duration { text-align: right; diff --git a/src/MiniProfiler.Shared/ui/includes.less b/src/MiniProfiler.Shared/ui/includes.less index 0c62e9bf1..0661f1921 100644 --- a/src/MiniProfiler.Shared/ui/includes.less +++ b/src/MiniProfiler.Shared/ui/includes.less @@ -206,6 +206,106 @@ } } + .mp-debug { + position: relative; + cursor: pointer; + + .mp-debug-tooltip { + display: none; + position: fixed; + background-color: var(--mp-main-bg-color); + box-shadow: var(--mp-popup-shadow); + right: 100px; + max-width: 90%; + border-radius: 10px; + padding: 12px; + //margin-top: 22px; + opacity: 0.95; + backdrop-filter: blur(4px); + } + + &:hover { + .mp-label { + text-decoration: underline; + } + } + + td:first-child { + &:hover .mp-debug-tooltip { + display: block; + } + & > span { + color: var(--mp-link-color); + } + } + } + + .mp-stack-trace { + color: var(--mp-muted-color); + margin-bottom: 5px; + font-family: Consolas, Monaco, monospace; + overflow-x: hidden; + overflow-y: auto; + white-space: pre-line; + max-height: 200px; + + .stack-row { + white-space: nowrap; + + &.common { + filter: grayscale(80%); + } + } + + .stack { + &.async { + opacity: 0.6; + display: none; + } + + &.leadin, &.file, &.line-prefix, &.path, &.dot { + color: var(--mp-muted-color); + } + + &.async-tag { + color: var(--mp-highlight-attribute-color); + font-weight: bold; + + &:before { + content: "("; + } + + &:after { + content: ")"; + } + } + + &.type { + color: var(--mp-highlight-keyword-color); + } + + &.generic-type { + color: var(--mp-highlight-fade-color); + } + + &.misc, &.parens { + color: var(--mp-highlight-comment-color); + } + + &.method { + color: var(--mp-highlight-string-color); + } + + &.paramType { + color: var(--mp-highlight-attribute-color); + } + + &.paramName { + color: var(--mp-highlight-variable-color); + } + } + } + .mp-label { color: var(--mp-label-color); overflow: hidden; @@ -425,12 +525,6 @@ background-color: var(--mp-alt-row-color); } - .mp-stack-trace { - padding-bottom: 1px; - color: var(--mp-muted-color); - margin-bottom: 5px; - } - .mp-since-start, .mp-duration { text-align: right; } diff --git a/src/MiniProfiler.Shared/ui/includes.min.css b/src/MiniProfiler.Shared/ui/includes.min.css index ad74a0d91..491b77017 100644 --- a/src/MiniProfiler.Shared/ui/includes.min.css +++ b/src/MiniProfiler.Shared/ui/includes.min.css @@ -1 +1 @@ -:root{--mp-main-bg-color:#fff;--mp-button-active-bg-color:#207ab7;--mp-button-active-text-color:#fff;--mp-button-warning-bg-color:#c91d2e;--mp-button-warning-text-color:#fff;--mp-duration-color:#111;--mp-warning-color:#c91d2e;--mp-critical-color:#f00;--mp-alt-row-color:#f5f5f5;--mp-muted-color:#aaa;--mp-link-color:#07c;--mp-label-color:#555;--mp-gap-font-color:#444;--mp-gap-bg-color:#e1e5ed;--mp-overlay-bg-color:#000;--mp-info-border-color:#ddd;--mp-query-border-color:#efefef;--mp-timing-unknown-color:#80ccda;--mp-timing-dns-color:#8baad1;--mp-timing-connect-color:#8cbb4e;--mp-timing-ssl-color:#795892;--mp-timing-request-color:#0099b2;--mp-timing-response-color:#d99d35;--mp-timing-dom-color:#bd4d32;--mp-timing-domcontent-color:#dd4678;--mp-timing-load-color:#1d72aa;--mp-timing-paint-color:#bc41e3;--mp-highlight-fade-color:#ffb;--mp-highlight-default-color:#000;--mp-highlight-string-color:#756bb1;--mp-highlight-comment-color:#636363;--mp-highlight-literal-color:#31a354;--mp-highlight-variable-color:#88f;--mp-highlight-keyword-color:#3182bd;--mp-highlight-attribute-color:#e6550d;--mp-result-border:solid .5px #ababab;--mp-result-border-radius:10px;--mp-popup-shadow:0 1px 5px #55555555;}@media(prefers-color-scheme:dark){.mp-scheme-auto{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-auto body{background-color:var(--mp-main-bg-color);}}.mp-scheme-dark{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-dark body{background-color:var(--mp-main-bg-color);}.mp-result,.mp-queries{color:var(--mp-label-color);line-height:1;font-size:12px;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code,.mp-result label,.mp-queries label,.mp-result table,.mp-queries table,.mp-result tbody,.mp-queries tbody,.mp-result thead,.mp-queries thead,.mp-result tfoot,.mp-queries tfoot,.mp-result tr,.mp-queries tr,.mp-result th,.mp-queries th,.mp-result td,.mp-queries td{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;background-color:transparent;overflow:visible;max-height:none;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code{font-family:Fira Code,Consolas,monospace,serif;font-variant-ligatures:none;}.mp-result table,.mp-queries table{color:var(--mp-label-color);border-collapse:collapse;border-spacing:0;width:100%;}.mp-result a,.mp-queries a{cursor:pointer;color:var(--mp-link-color);text-decoration:none;}.mp-result a:hover,.mp-queries a:hover{text-decoration:underline;}.mp-result{font-family:sans-serif;}.mp-result.show-columns th.mp-more-columns,.mp-result.show-columns td.mp-more-columns{display:table-cell !important;}.mp-result.show-columns a.mp-more-columns{display:inline-block;}.mp-result.show-columns .mp-links span a:nth-child(1){display:none;}.mp-result.show-trivial tr.mp-trivial{display:table-row !important;}.mp-result.show-trivial a.mp-trivial{display:inline-block;}.mp-result.show-trivial .mp-links span a:nth-child(3){display:none;}.mp-result table.mp-client-timings{margin-top:10px;}.mp-result table.mp-client-timings td:nth-child(2){width:100%;padding:0;}.mp-result table.mp-client-timings td div{height:13px;min-width:1px;}.mp-result table.mp-client-timings .t-point div{height:4px;border-radius:8px;margin-bottom:4px;box-shadow:0 0 2px;}.mp-result table.mp-client-timings .t-unknown div{background:var(--mp-timing-unknown-color);}.mp-result table.mp-client-timings .t-dns div{background:var(--mp-timing-dns-color);}.mp-result table.mp-client-timings .t-connect div{background:var(--mp-timing-connect-color);}.mp-result table.mp-client-timings .t-ssl div{background:var(--mp-timing-ssl-color);}.mp-result table.mp-client-timings .t-request div{background:var(--mp-timing-request-color);}.mp-result table.mp-client-timings .t-response div{background:var(--mp-timing-response-color);}.mp-result table.mp-client-timings .t-dom div{background:var(--mp-timing-dom-color);}.mp-result table.mp-client-timings .t-domcontent div{background:var(--mp-timing-domcontent-color);}.mp-result table.mp-client-timings .t-load div{background:var(--mp-timing-load-color);}.mp-result table.mp-client-timings .t-paint div{background:var(--mp-timing-paint-color);}.mp-result .mp-label{color:var(--mp-label-color);overflow:hidden;text-overflow:ellipsis;}.mp-result .mp-unit{color:var(--mp-muted-color);}.mp-result .mp-more-columns{display:none;}.mp-result .mp-trivial{display:none;}.mp-result .mp-trivial td,.mp-result .mp-trivial td *{color:var(--mp-muted-color) !important;}.mp-result .mp-number{color:var(--mp-duration-color);}.mp-result .mp-info>div{white-space:nowrap;overflow:hidden;}.mp-result .mp-info>div>div{display:inline-block;}.mp-result .mp-info .mp-name{display:inline-block;font-weight:bold;float:left;}.mp-result .mp-info .mp-machine-name,.mp-result .mp-info .mp-started{text-align:right;float:right;}.mp-result .mp-info .mp-server-time{white-space:nowrap;}.mp-result .mp-timings th{background-color:var(--mp-main-bg-color);color:var(--mp-muted-color);text-align:right;}.mp-result .mp-timings th,.mp-result .mp-timings td{white-space:nowrap;}.mp-result .mp-timings .mp-show-more{display:none;}.mp-result .mp-timings .mp-duration{font-family:Consolas,monospace,serif;color:var(--mp-duration-color);text-align:right;}.mp-result .mp-timings .mp-indent{letter-spacing:4px;}.mp-result .mp-timings .mp-queries-show .mp-number,.mp-result .mp-timings .mp-queries-show .mp-unit{color:var(--mp-link-color);}.mp-result .mp-timings .mp-queries-show.mp-queries-warning{color:var(--mp-warning-color);font-weight:bold;}.mp-result .mp-timings .mp-queries-duration{padding-left:6px;}.mp-result .mp-timings:not(.mp-client-timings) .mp-trivial:first-child{display:table-row;}.mp-result .mp-custom-timing-overview{float:right;margin:10px 0;width:auto;}.mp-result .mp-custom-timing-overview td{white-space:nowrap;text-align:right;}.mp-result .mp-custom-timing-overview td:last-child{padding-left:8px;}.mp-result .mp-links{margin-top:10px;clear:both;}.mp-result .mp-links span{float:right;}.mp-result .mp-links a{font-size:95%;margin-left:12px;}.mp-result .mp-links a:first-child{margin-left:0;}.mp-warning{color:var(--mp-critical-color);}@keyframes mp-fadeIn{from{background-color:var(--mp-highlight-fade-color);}to{background-color:none;}}.mp-overlay{z-index:2147483642;}.mp-overlay .mp-overlay-bg{z-index:2147483643;background:var(--mp-overlay-bg-color);opacity:.5;top:0;left:0;min-width:100%;position:fixed;height:calc(100%);}.mp-overlay .mp-queries{display:block;z-index:2147483644;top:25px;left:25px;right:25px;position:fixed;max-height:calc(100vh - 50px);background-color:var(--mp-main-bg-color);border-radius:2px;overflow-y:auto;overflow-x:auto;}.mp-queries{font-family:sans-serif;}.mp-queries pre{white-space:pre-wrap;}.mp-queries div{text-align:left;}.mp-queries table{table-layout:fixed;}.mp-queries td,.mp-queries th{padding:8px;border-bottom:solid 1px var(--mp-query-border-color);}.mp-queries td:first-child,.mp-queries th:first-child{width:250px;text-align:right;}.mp-queries td:first-child div,.mp-queries th:first-child div{text-align:right;margin-bottom:5px;word-break:break-word;}.mp-queries td:last-child,.mp-queries th:last-child{text-align:left;padding-right:15px;}.mp-queries .highlight{animation:mp-fadeIn 2s 1;}.mp-queries .mp-odd{background-color:var(--mp-alt-row-color);}.mp-queries .mp-stack-trace{padding-bottom:1px;color:var(--mp-muted-color);margin-bottom:5px;}.mp-queries .mp-since-start,.mp-queries .mp-duration{text-align:right;}.mp-queries.show-trivial .mp-gap-info.mp-trivial-gap{display:table-row;}.mp-queries .mp-gap-info{background-color:var(--mp-gap-bg-color);opacity:.8;color:var(--mp-gap-font-color);}.mp-queries .mp-gap-info .query{word-break:break-all;}.mp-queries .mp-gap-info .mp-unit{color:var(--mp-muted-color);}.mp-queries .mp-gap-info.mp-trivial-gap{display:none;}.mp-queries .mp-trivial-gap-container{text-align:center;margin:8px 0;}.mp-queries .mp-call-type{font-weight:bold;}.mp-queries .hljs{display:block;overflow-x:auto;padding:.5em;}.mp-queries .hljs,.mp-queries .hljs-subst{color:var(--mp-highlight-default-color);}.mp-queries .hljs-string,.mp-queries .hljs-meta,.mp-queries .hljs-symbol,.mp-queries .hljs-template-tag,.mp-queries .hljs-template-variable,.mp-queries .hljs-addition{color:var(--mp-highlight-string-color);}.mp-queries .hljs-comment,.mp-queries .hljs-quote{color:var(--mp-highlight-comment-color);}.mp-queries .hljs-number,.mp-queries .hljs-regexp,.mp-queries .hljs-literal,.mp-queries .hljs-bullet,.mp-queries .hljs-link{color:var(--mp-highlight-literal-color);}.mp-queries .hljs-deletion,.mp-queries .hljs-variable{color:var(--mp-highlight-variable-color);}.mp-queries .hljs-keyword,.mp-queries .hljs-selector-tag,.mp-queries .hljs-title,.mp-queries .hljs-section,.mp-queries .hljs-built_in,.mp-queries .hljs-doctag,.mp-queries .hljs-type,.mp-queries .hljs-tag,.mp-queries .hljs-name,.mp-queries .hljs-selector-id,.mp-queries .hljs-selector-class,.mp-queries .hljs-strong{color:var(--mp-highlight-keyword-color);}.mp-queries .hljs-emphasis{font-style:italic;}.mp-queries .hljs-attribute{color:var(--mp-highlight-attribute-color);}.mp-results{z-index:2147483641;position:fixed;top:0;}.mp-results.mp-left,.mp-results.mp-bottomleft{left:0;}.mp-results.mp-left .mp-controls,.mp-results.mp-left.mp-no-controls .mp-result:last-child .mp-button{border-bottom-right-radius:var(--mp-result-border-radius);}.mp-results.mp-left .mp-button,.mp-results.mp-left .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-right{right:0;}.mp-results.mp-right .mp-controls,.mp-results.mp-right.mp-no-controls .mp-result:last-child .mp-button{border-bottom-left-radius:var(--mp-result-border-radius);}.mp-results.mp-right .mp-button,.mp-results.mp-right .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomleft{top:inherit;bottom:0;}.mp-results.mp-bottomleft .mp-result:first-child .mp-button{border-top-right-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomleft .mp-button,.mp-results.mp-bottomleft .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-bottomleft .mp-result .mp-button,.mp-results.mp-bottomleft .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results.mp-bottomright{top:inherit;bottom:0;right:0;}.mp-results.mp-bottomright .mp-result:first-child .mp-button{border-top-left-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomright .mp-button,.mp-results.mp-bottomright .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomright .mp-result .mp-button,.mp-results.mp-bottomright .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results .mp-button{user-select:none;}.mp-results .mp-button.mp-button-warning{font-weight:bold;background-color:var(--mp-button-warning-bg-color);color:var(--mp-button-warning-text-color);}.mp-results .mp-button.mp-button-warning .mp-number,.mp-results .mp-button.mp-button-warning .mp-unit,.mp-results .mp-button.mp-button-warning .mp-warning{color:var(--mp-button-warning-text-color);}.mp-results .mp-button .mp-warning{font-weight:bold;}.mp-results .mp-button>.mp-number{font-family:Consolas,monospace,serif;}.mp-results .mp-controls{display:none;}.mp-results .mp-button,.mp-results .mp-controls{z-index:2147483640;border-bottom:var(--mp-result-border);background-color:var(--mp-main-bg-color);padding:4px 8px;text-align:right;cursor:pointer;}.mp-results .mp-result{position:relative;}.mp-results .mp-result.active .mp-button{background-color:var(--mp-button-active-bg-color);animation:none;border-radius:0 !important;}.mp-results .mp-result.active .mp-button.mp-button-warning{background-color:var(--mp-button-warning-bg-color);}.mp-results .mp-result.active .mp-button .mp-number,.mp-results .mp-result.active .mp-button .mp-warning{color:var(--mp-button-active-text-color);font-weight:bold;}.mp-results .mp-result.active .mp-button .mp-unit{color:var(--mp-button-active-text-color);font-weight:normal;}.mp-results .mp-result.active .mp-popup{display:block;}.mp-results.new .mp-button{animation:mp-fadeIn 2s 1;}.mp-results .mp-controls{display:block;font-size:12px;font-family:Consolas,monospace,serif;cursor:default;text-align:center;}.mp-results .mp-controls span{color:var(--mp-muted-color);border-right:1px solid var(--mp-muted-color);padding-right:5px;margin-right:5px;cursor:pointer;}.mp-results .mp-controls span:last-child{border-right:none;}.mp-results .mp-popup{display:none;z-index:2147483641;position:absolute;background-color:var(--mp-main-bg-color);padding:5px 10px;text-align:left;line-height:18px;overflow:auto;box-shadow:var(--mp-popup-shadow);border-radius:2px;}.mp-results .mp-popup .mp-info{margin-bottom:3px;padding-bottom:2px;border-bottom:1px solid var(--mp-info-border-color);}.mp-results .mp-popup .mp-info .mp-name{font-size:1.1em;}.mp-results .mp-popup .mp-info .mp-overall-duration{color:var(--mp-muted-color);}.mp-results .mp-popup .mp-timings th,.mp-results .mp-popup .mp-timings td{padding:0 6px;}.mp-results .mp-popup .mp-timings th{font-size:95%;padding-bottom:3px;}.mp-results .mp-popup .mp-timings .mp-label{max-width:350px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;}.mp-results .mp-queries{display:none;}.mp-results.mp-min .mp-result{display:none;}.mp-results.mp-min .mp-controls span{display:none;}.mp-results.mp-min .mp-controls .mp-min-max{border-right:none;padding:0;margin:0;}.mp-results.mp-min:hover .mp-controls .mp-min-max{display:inline;}.mp-result-full .mp-result{width:950px;margin:25px auto;}.mp-result-full .mp-result .mp-button{display:none;}.mp-result-full .mp-result .mp-popup .mp-info{font-size:18px;border-bottom:1px solid var(--mp-muted-color);padding-bottom:3px;margin-bottom:10px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-name{margin-bottom:5px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration,.mp-result-full .mp-result .mp-popup .mp-info .mp-started{font-size:80%;color:var(--mp-muted-color);}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration{padding-right:20px;}.mp-result-full .mp-result .mp-popup .mp-timings td,.mp-result-full .mp-result .mp-popup .mp-timings th{font-size:13px;padding-left:8px;padding-right:8px;}.mp-result-full .mp-result .mp-popup .mp-timings th{padding-bottom:7px;}.mp-result-full .mp-result .mp-popup .mp-timings td{padding-bottom:4px;}.mp-result-full .mp-result .mp-popup .mp-timings td:first-child{padding-left:10px;}.mp-result-full .mp-result .mp-popup .mp-timings .mp-label{max-width:550px;}.mp-result-full .mp-result .mp-queries{margin:20px 0;}.mp-result-full .mp-result .mp-queries th{font-size:16px;}.mp-result-full .mp-share-mp-results{display:none;}table.mp-results-index{border:0;border-spacing:0;font-size:12px;font-family:Arial;}table.mp-results-index a{color:var(--mp-link-color);text-decoration:none;}table.mp-results-index tbody{color:var(--mp-label-color);}table.mp-results-index tbody tr:nth-child(odd){background-color:var(--mp-alt-row-color);}table.mp-results-index tbody tr:nth-child(even){background-color:var(--mp-main-bg-color);}table.mp-results-index tbody td{text-align:center;}table.mp-results-index tbody td:first-child{text-align:left;}table.mp-results-index tbody td[colspan="3"]{color:var(--mp-muted-color);}table.mp-results-index thead tr{color:var(--mp-label-color);}table.mp-results-index thead tr th{padding:5px 15px;}table.mp-results-index td{padding:8px;} \ No newline at end of file +:root{--mp-main-bg-color:#fff;--mp-button-active-bg-color:#207ab7;--mp-button-active-text-color:#fff;--mp-button-warning-bg-color:#c91d2e;--mp-button-warning-text-color:#fff;--mp-duration-color:#111;--mp-warning-color:#c91d2e;--mp-critical-color:#f00;--mp-alt-row-color:#f5f5f5;--mp-muted-color:#aaa;--mp-link-color:#07c;--mp-label-color:#555;--mp-gap-font-color:#444;--mp-gap-bg-color:#e1e5ed;--mp-overlay-bg-color:#000;--mp-info-border-color:#ddd;--mp-query-border-color:#efefef;--mp-timing-unknown-color:#80ccda;--mp-timing-dns-color:#8baad1;--mp-timing-connect-color:#8cbb4e;--mp-timing-ssl-color:#795892;--mp-timing-request-color:#0099b2;--mp-timing-response-color:#d99d35;--mp-timing-dom-color:#bd4d32;--mp-timing-domcontent-color:#dd4678;--mp-timing-load-color:#1d72aa;--mp-timing-paint-color:#bc41e3;--mp-highlight-fade-color:#ffb;--mp-highlight-default-color:#000;--mp-highlight-string-color:#756bb1;--mp-highlight-comment-color:#636363;--mp-highlight-literal-color:#31a354;--mp-highlight-variable-color:#88f;--mp-highlight-keyword-color:#3182bd;--mp-highlight-attribute-color:#e6550d;--mp-result-border:solid .5px #ababab;--mp-result-border-radius:10px;--mp-popup-shadow:0 1px 5px #55555555;}@media(prefers-color-scheme:dark){.mp-scheme-auto{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-auto body{background-color:var(--mp-main-bg-color);}}.mp-scheme-dark{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-dark body{background-color:var(--mp-main-bg-color);}.mp-result,.mp-queries{color:var(--mp-label-color);line-height:1;font-size:12px;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code,.mp-result label,.mp-queries label,.mp-result table,.mp-queries table,.mp-result tbody,.mp-queries tbody,.mp-result thead,.mp-queries thead,.mp-result tfoot,.mp-queries tfoot,.mp-result tr,.mp-queries tr,.mp-result th,.mp-queries th,.mp-result td,.mp-queries td{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;background-color:transparent;overflow:visible;max-height:none;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code{font-family:Fira Code,Consolas,monospace,serif;font-variant-ligatures:none;}.mp-result table,.mp-queries table{color:var(--mp-label-color);border-collapse:collapse;border-spacing:0;width:100%;}.mp-result a,.mp-queries a{cursor:pointer;color:var(--mp-link-color);text-decoration:none;}.mp-result a:hover,.mp-queries a:hover{text-decoration:underline;}.mp-result{font-family:sans-serif;}.mp-result.show-columns th.mp-more-columns,.mp-result.show-columns td.mp-more-columns{display:table-cell !important;}.mp-result.show-columns a.mp-more-columns{display:inline-block;}.mp-result.show-columns .mp-links span a:nth-child(1){display:none;}.mp-result.show-trivial tr.mp-trivial{display:table-row !important;}.mp-result.show-trivial a.mp-trivial{display:inline-block;}.mp-result.show-trivial .mp-links span a:nth-child(3){display:none;}.mp-result table.mp-client-timings{margin-top:10px;}.mp-result table.mp-client-timings td:nth-child(2){width:100%;padding:0;}.mp-result table.mp-client-timings td div{height:13px;min-width:1px;}.mp-result table.mp-client-timings .t-point div{height:4px;border-radius:8px;margin-bottom:4px;box-shadow:0 0 2px;}.mp-result table.mp-client-timings .t-unknown div{background:var(--mp-timing-unknown-color);}.mp-result table.mp-client-timings .t-dns div{background:var(--mp-timing-dns-color);}.mp-result table.mp-client-timings .t-connect div{background:var(--mp-timing-connect-color);}.mp-result table.mp-client-timings .t-ssl div{background:var(--mp-timing-ssl-color);}.mp-result table.mp-client-timings .t-request div{background:var(--mp-timing-request-color);}.mp-result table.mp-client-timings .t-response div{background:var(--mp-timing-response-color);}.mp-result table.mp-client-timings .t-dom div{background:var(--mp-timing-dom-color);}.mp-result table.mp-client-timings .t-domcontent div{background:var(--mp-timing-domcontent-color);}.mp-result table.mp-client-timings .t-load div{background:var(--mp-timing-load-color);}.mp-result table.mp-client-timings .t-paint div{background:var(--mp-timing-paint-color);}.mp-result .mp-debug{position:relative;cursor:pointer;}.mp-result .mp-debug .mp-debug-tooltip{display:none;position:fixed;background-color:var(--mp-main-bg-color);box-shadow:var(--mp-popup-shadow);right:100px;max-width:90%;border-radius:10px;padding:12px;opacity:.95;backdrop-filter:blur(4px);}.mp-result .mp-debug:hover .mp-label{text-decoration:underline;}.mp-result .mp-debug td:first-child:hover .mp-debug-tooltip{display:block;}.mp-result .mp-debug td:first-child>span{color:var(--mp-link-color);}.mp-result .mp-stack-trace{color:var(--mp-muted-color);margin-bottom:5px;font-family:Consolas,Monaco,monospace;overflow-x:hidden;overflow-y:auto;white-space:pre-line;max-height:200px;}.mp-result .mp-stack-trace .stack-row{white-space:nowrap;}.mp-result .mp-stack-trace .stack-row.common{filter:grayscale(80%);}.mp-result .mp-stack-trace .stack.async{opacity:.6;display:none;}.mp-result .mp-stack-trace .stack.leadin,.mp-result .mp-stack-trace .stack.file,.mp-result .mp-stack-trace .stack.line-prefix,.mp-result .mp-stack-trace .stack.path,.mp-result .mp-stack-trace .stack.dot{color:var(--mp-muted-color);}.mp-result .mp-stack-trace .stack.async-tag{color:var(--mp-highlight-attribute-color);font-weight:bold;}.mp-result .mp-stack-trace .stack.async-tag:before{content:"(";}.mp-result .mp-stack-trace .stack.async-tag:after{content:")";}.mp-result .mp-stack-trace .stack.type{color:var(--mp-highlight-keyword-color);}.mp-result .mp-stack-trace .stack.generic-type{color:var(--mp-highlight-fade-color);}.mp-result .mp-stack-trace .stack.misc,.mp-result .mp-stack-trace .stack.parens{color:var(--mp-highlight-comment-color);}.mp-result .mp-stack-trace .stack.method{color:var(--mp-highlight-string-color);}.mp-result .mp-stack-trace .stack.paramType{color:var(--mp-highlight-attribute-color);}.mp-result .mp-stack-trace .stack.paramName{color:var(--mp-highlight-variable-color);}.mp-result .mp-label{color:var(--mp-label-color);overflow:hidden;text-overflow:ellipsis;}.mp-result .mp-unit{color:var(--mp-muted-color);}.mp-result .mp-more-columns{display:none;}.mp-result .mp-trivial{display:none;}.mp-result .mp-trivial td,.mp-result .mp-trivial td *{color:var(--mp-muted-color) !important;}.mp-result .mp-number{color:var(--mp-duration-color);}.mp-result .mp-info>div{white-space:nowrap;overflow:hidden;}.mp-result .mp-info>div>div{display:inline-block;}.mp-result .mp-info .mp-name{display:inline-block;font-weight:bold;float:left;}.mp-result .mp-info .mp-machine-name,.mp-result .mp-info .mp-started{text-align:right;float:right;}.mp-result .mp-info .mp-server-time{white-space:nowrap;}.mp-result .mp-timings th{background-color:var(--mp-main-bg-color);color:var(--mp-muted-color);text-align:right;}.mp-result .mp-timings th,.mp-result .mp-timings td{white-space:nowrap;}.mp-result .mp-timings .mp-show-more{display:none;}.mp-result .mp-timings .mp-duration{font-family:Consolas,monospace,serif;color:var(--mp-duration-color);text-align:right;}.mp-result .mp-timings .mp-indent{letter-spacing:4px;}.mp-result .mp-timings .mp-queries-show .mp-number,.mp-result .mp-timings .mp-queries-show .mp-unit{color:var(--mp-link-color);}.mp-result .mp-timings .mp-queries-show.mp-queries-warning{color:var(--mp-warning-color);font-weight:bold;}.mp-result .mp-timings .mp-queries-duration{padding-left:6px;}.mp-result .mp-timings:not(.mp-client-timings) .mp-trivial:first-child{display:table-row;}.mp-result .mp-custom-timing-overview{float:right;margin:10px 0;width:auto;}.mp-result .mp-custom-timing-overview td{white-space:nowrap;text-align:right;}.mp-result .mp-custom-timing-overview td:last-child{padding-left:8px;}.mp-result .mp-links{margin-top:10px;clear:both;}.mp-result .mp-links span{float:right;}.mp-result .mp-links a{font-size:95%;margin-left:12px;}.mp-result .mp-links a:first-child{margin-left:0;}.mp-warning{color:var(--mp-critical-color);}@keyframes mp-fadeIn{from{background-color:var(--mp-highlight-fade-color);}to{background-color:none;}}.mp-overlay{z-index:2147483642;}.mp-overlay .mp-overlay-bg{z-index:2147483643;background:var(--mp-overlay-bg-color);opacity:.5;top:0;left:0;min-width:100%;position:fixed;height:calc(100%);}.mp-overlay .mp-queries{display:block;z-index:2147483644;top:25px;left:25px;right:25px;position:fixed;max-height:calc(100vh - 50px);background-color:var(--mp-main-bg-color);border-radius:2px;overflow-y:auto;overflow-x:auto;}.mp-queries{font-family:sans-serif;}.mp-queries pre{white-space:pre-wrap;}.mp-queries div{text-align:left;}.mp-queries table{table-layout:fixed;}.mp-queries td,.mp-queries th{padding:8px;border-bottom:solid 1px var(--mp-query-border-color);}.mp-queries td:first-child,.mp-queries th:first-child{width:250px;text-align:right;}.mp-queries td:first-child div,.mp-queries th:first-child div{text-align:right;margin-bottom:5px;word-break:break-word;}.mp-queries td:last-child,.mp-queries th:last-child{text-align:left;padding-right:15px;}.mp-queries .highlight{animation:mp-fadeIn 2s 1;}.mp-queries .mp-odd{background-color:var(--mp-alt-row-color);}.mp-queries .mp-since-start,.mp-queries .mp-duration{text-align:right;}.mp-queries.show-trivial .mp-gap-info.mp-trivial-gap{display:table-row;}.mp-queries .mp-gap-info{background-color:var(--mp-gap-bg-color);opacity:.8;color:var(--mp-gap-font-color);}.mp-queries .mp-gap-info .query{word-break:break-all;}.mp-queries .mp-gap-info .mp-unit{color:var(--mp-muted-color);}.mp-queries .mp-gap-info.mp-trivial-gap{display:none;}.mp-queries .mp-trivial-gap-container{text-align:center;margin:8px 0;}.mp-queries .mp-call-type{font-weight:bold;}.mp-queries .hljs{display:block;overflow-x:auto;padding:.5em;}.mp-queries .hljs,.mp-queries .hljs-subst{color:var(--mp-highlight-default-color);}.mp-queries .hljs-string,.mp-queries .hljs-meta,.mp-queries .hljs-symbol,.mp-queries .hljs-template-tag,.mp-queries .hljs-template-variable,.mp-queries .hljs-addition{color:var(--mp-highlight-string-color);}.mp-queries .hljs-comment,.mp-queries .hljs-quote{color:var(--mp-highlight-comment-color);}.mp-queries .hljs-number,.mp-queries .hljs-regexp,.mp-queries .hljs-literal,.mp-queries .hljs-bullet,.mp-queries .hljs-link{color:var(--mp-highlight-literal-color);}.mp-queries .hljs-deletion,.mp-queries .hljs-variable{color:var(--mp-highlight-variable-color);}.mp-queries .hljs-keyword,.mp-queries .hljs-selector-tag,.mp-queries .hljs-title,.mp-queries .hljs-section,.mp-queries .hljs-built_in,.mp-queries .hljs-doctag,.mp-queries .hljs-type,.mp-queries .hljs-tag,.mp-queries .hljs-name,.mp-queries .hljs-selector-id,.mp-queries .hljs-selector-class,.mp-queries .hljs-strong{color:var(--mp-highlight-keyword-color);}.mp-queries .hljs-emphasis{font-style:italic;}.mp-queries .hljs-attribute{color:var(--mp-highlight-attribute-color);}.mp-results{z-index:2147483641;position:fixed;top:0;}.mp-results.mp-left,.mp-results.mp-bottomleft{left:0;}.mp-results.mp-left .mp-controls,.mp-results.mp-left.mp-no-controls .mp-result:last-child .mp-button{border-bottom-right-radius:var(--mp-result-border-radius);}.mp-results.mp-left .mp-button,.mp-results.mp-left .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-right{right:0;}.mp-results.mp-right .mp-controls,.mp-results.mp-right.mp-no-controls .mp-result:last-child .mp-button{border-bottom-left-radius:var(--mp-result-border-radius);}.mp-results.mp-right .mp-button,.mp-results.mp-right .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomleft{top:inherit;bottom:0;}.mp-results.mp-bottomleft .mp-result:first-child .mp-button{border-top-right-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomleft .mp-button,.mp-results.mp-bottomleft .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-bottomleft .mp-result .mp-button,.mp-results.mp-bottomleft .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results.mp-bottomright{top:inherit;bottom:0;right:0;}.mp-results.mp-bottomright .mp-result:first-child .mp-button{border-top-left-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomright .mp-button,.mp-results.mp-bottomright .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomright .mp-result .mp-button,.mp-results.mp-bottomright .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results .mp-button{user-select:none;}.mp-results .mp-button.mp-button-warning{font-weight:bold;background-color:var(--mp-button-warning-bg-color);color:var(--mp-button-warning-text-color);}.mp-results .mp-button.mp-button-warning .mp-number,.mp-results .mp-button.mp-button-warning .mp-unit,.mp-results .mp-button.mp-button-warning .mp-warning{color:var(--mp-button-warning-text-color);}.mp-results .mp-button .mp-warning{font-weight:bold;}.mp-results .mp-button>.mp-number{font-family:Consolas,monospace,serif;}.mp-results .mp-controls{display:none;}.mp-results .mp-button,.mp-results .mp-controls{z-index:2147483640;border-bottom:var(--mp-result-border);background-color:var(--mp-main-bg-color);padding:4px 8px;text-align:right;cursor:pointer;}.mp-results .mp-result{position:relative;}.mp-results .mp-result.active .mp-button{background-color:var(--mp-button-active-bg-color);animation:none;border-radius:0 !important;}.mp-results .mp-result.active .mp-button.mp-button-warning{background-color:var(--mp-button-warning-bg-color);}.mp-results .mp-result.active .mp-button .mp-number,.mp-results .mp-result.active .mp-button .mp-warning{color:var(--mp-button-active-text-color);font-weight:bold;}.mp-results .mp-result.active .mp-button .mp-unit{color:var(--mp-button-active-text-color);font-weight:normal;}.mp-results .mp-result.active .mp-popup{display:block;}.mp-results.new .mp-button{animation:mp-fadeIn 2s 1;}.mp-results .mp-controls{display:block;font-size:12px;font-family:Consolas,monospace,serif;cursor:default;text-align:center;}.mp-results .mp-controls span{color:var(--mp-muted-color);border-right:1px solid var(--mp-muted-color);padding-right:5px;margin-right:5px;cursor:pointer;}.mp-results .mp-controls span:last-child{border-right:none;}.mp-results .mp-popup{display:none;z-index:2147483641;position:absolute;background-color:var(--mp-main-bg-color);padding:5px 10px;text-align:left;line-height:18px;overflow:auto;box-shadow:var(--mp-popup-shadow);border-radius:2px;}.mp-results .mp-popup .mp-info{margin-bottom:3px;padding-bottom:2px;border-bottom:1px solid var(--mp-info-border-color);}.mp-results .mp-popup .mp-info .mp-name{font-size:1.1em;}.mp-results .mp-popup .mp-info .mp-overall-duration{color:var(--mp-muted-color);}.mp-results .mp-popup .mp-timings th,.mp-results .mp-popup .mp-timings td{padding:0 6px;}.mp-results .mp-popup .mp-timings th{font-size:95%;padding-bottom:3px;}.mp-results .mp-popup .mp-timings .mp-label{max-width:350px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;}.mp-results .mp-queries{display:none;}.mp-results.mp-min .mp-result{display:none;}.mp-results.mp-min .mp-controls span{display:none;}.mp-results.mp-min .mp-controls .mp-min-max{border-right:none;padding:0;margin:0;}.mp-results.mp-min:hover .mp-controls .mp-min-max{display:inline;}.mp-result-full .mp-result{width:950px;margin:25px auto;}.mp-result-full .mp-result .mp-button{display:none;}.mp-result-full .mp-result .mp-popup .mp-info{font-size:18px;border-bottom:1px solid var(--mp-muted-color);padding-bottom:3px;margin-bottom:10px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-name{margin-bottom:5px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration,.mp-result-full .mp-result .mp-popup .mp-info .mp-started{font-size:80%;color:var(--mp-muted-color);}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration{padding-right:20px;}.mp-result-full .mp-result .mp-popup .mp-timings td,.mp-result-full .mp-result .mp-popup .mp-timings th{font-size:13px;padding-left:8px;padding-right:8px;}.mp-result-full .mp-result .mp-popup .mp-timings th{padding-bottom:7px;}.mp-result-full .mp-result .mp-popup .mp-timings td{padding-bottom:4px;}.mp-result-full .mp-result .mp-popup .mp-timings td:first-child{padding-left:10px;}.mp-result-full .mp-result .mp-popup .mp-timings .mp-label{max-width:550px;}.mp-result-full .mp-result .mp-queries{margin:20px 0;}.mp-result-full .mp-result .mp-queries th{font-size:16px;}.mp-result-full .mp-share-mp-results{display:none;}table.mp-results-index{border:0;border-spacing:0;font-size:12px;font-family:Arial;}table.mp-results-index a{color:var(--mp-link-color);text-decoration:none;}table.mp-results-index tbody{color:var(--mp-label-color);}table.mp-results-index tbody tr:nth-child(odd){background-color:var(--mp-alt-row-color);}table.mp-results-index tbody tr:nth-child(even){background-color:var(--mp-main-bg-color);}table.mp-results-index tbody td{text-align:center;}table.mp-results-index tbody td:first-child{text-align:left;}table.mp-results-index tbody td[colspan="3"]{color:var(--mp-muted-color);}table.mp-results-index thead tr{color:var(--mp-label-color);}table.mp-results-index thead tr th{padding:5px 15px;}table.mp-results-index td{padding:8px;} \ No newline at end of file diff --git a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts index 7fe57b155..9b8874e04 100644 --- a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts +++ b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts @@ -64,6 +64,12 @@ namespace StackExchange.Profiling { Parent: ITiming; // added for gaps (TODO: change all this) richTiming: IGapTiming[]; + // In debug mode only + DebugInfo: ITimingDebugInfo; + } + + interface ITimingDebugInfo { + RichHtmlStack: string; } interface ICustomTiming { @@ -673,11 +679,26 @@ namespace StackExchange.Profiling { } return (milliseconds || 0).toFixed(decimalPlaces === undefined ? 1 : decimalPlaces); }; + const renderDebugInfo = (timing: ITiming) => { + if (timing.DebugInfo) { + return ` +
+
Detailed info for ${encode(timing.Name)}
+
Starts at: ${duration(timing.StartMilliseconds)} ms
+
Self duration: ${duration(timing.DurationWithoutChildrenMilliseconds)} ms
+
Overall duration (with children): ${duration(timing.DurationMilliseconds)} ms
+
Stack:
+
${timing.DebugInfo.RichHtmlStack}
+
+ `; + } + }; const renderTiming = (timing: ITiming) => { const customTimingTypes = p.CustomTimingStats ? Object.keys(p.CustomTimingStats) : []; let str = ` - + + ${renderDebugInfo(timing)} 0 ? ` style="padding-left:${timing.Depth * 11}px;"` : ''}> ${encode(timing.Name)} @@ -709,7 +730,7 @@ namespace StackExchange.Profiling { - + @@ -721,7 +742,7 @@ namespace StackExchange.Profiling { - + From 35c945122e4166b925f23d92ae23bab57c15a86f Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sun, 24 May 2020 08:51:57 -0400 Subject: [PATCH 03/13] More style and tooltip refinement --- .../Helpers/StackTraceSnippet.cs | 3 ++- src/MiniProfiler.Shared/ui/includes.css | 11 +++++---- src/MiniProfiler.Shared/ui/includes.less | 17 +++++++------- src/MiniProfiler.Shared/ui/includes.min.css | 2 +- .../ui/lib/MiniProfiler.ts | 23 ++++++++++++++++--- 5 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs b/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs index b93c67796..7fa0af6ca 100644 --- a/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs +++ b/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs @@ -196,8 +196,9 @@ private static class Groups /// Converts a stack trace to formatted HTML with styling and linkifiation. /// /// The stack trace to HTMLify. + /// The frame index to start marking as common (e.g. to grey out beneath). /// An HTML-pretty version of the stack trace. - public static string HtmlPrettify(string stackTrace, int? commonStart = null) + internal static string HtmlPrettify(string stackTrace, int? commonStart = null) { string GetBetween(Capture prev, Capture next) => stackTrace.Substring(prev.Index + prev.Length, next.Index - (prev.Index + prev.Length)); diff --git a/src/MiniProfiler.Shared/ui/includes.css b/src/MiniProfiler.Shared/ui/includes.css index 1d0c53549..65c653c10 100644 --- a/src/MiniProfiler.Shared/ui/includes.css +++ b/src/MiniProfiler.Shared/ui/includes.css @@ -229,19 +229,20 @@ box-shadow: var(--mp-popup-shadow); right: 100px; max-width: 90%; - border-radius: 10px; + border-radius: 9px; padding: 12px; + margin-top: 18px; opacity: 0.95; backdrop-filter: blur(4px); } -.mp-result .mp-debug:hover .mp-label { - text-decoration: underline; +.mp-result .mp-debug .mp-nested-timing { + margin-left: 16px; } .mp-result .mp-debug td:first-child:hover .mp-debug-tooltip { display: block; } -.mp-result .mp-debug td:first-child > span { - color: var(--mp-link-color); +.mp-result .mp-debug td:first-child:hover > span { + text-shadow: var(--mp-button-active-text-color) 0 0 4px; } .mp-result .mp-stack-trace { color: var(--mp-muted-color); diff --git a/src/MiniProfiler.Shared/ui/includes.less b/src/MiniProfiler.Shared/ui/includes.less index 0661f1921..a910ac9d2 100644 --- a/src/MiniProfiler.Shared/ui/includes.less +++ b/src/MiniProfiler.Shared/ui/includes.less @@ -217,25 +217,24 @@ box-shadow: var(--mp-popup-shadow); right: 100px; max-width: 90%; - border-radius: 10px; + border-radius: 9px; padding: 12px; - //margin-top: 22px; + margin-top: 18px; opacity: 0.95; backdrop-filter: blur(4px); } - &:hover { - .mp-label { - text-decoration: underline; - } + .mp-nested-timing { + margin-left: 16px; } - td:first-child { - &:hover .mp-debug-tooltip { + td:first-child:hover { + .mp-debug-tooltip { display: block; } + & > span { - color: var(--mp-link-color); + text-shadow: var(--mp-button-active-text-color) 0 0 4px; } } } diff --git a/src/MiniProfiler.Shared/ui/includes.min.css b/src/MiniProfiler.Shared/ui/includes.min.css index 491b77017..72430d951 100644 --- a/src/MiniProfiler.Shared/ui/includes.min.css +++ b/src/MiniProfiler.Shared/ui/includes.min.css @@ -1 +1 @@ -:root{--mp-main-bg-color:#fff;--mp-button-active-bg-color:#207ab7;--mp-button-active-text-color:#fff;--mp-button-warning-bg-color:#c91d2e;--mp-button-warning-text-color:#fff;--mp-duration-color:#111;--mp-warning-color:#c91d2e;--mp-critical-color:#f00;--mp-alt-row-color:#f5f5f5;--mp-muted-color:#aaa;--mp-link-color:#07c;--mp-label-color:#555;--mp-gap-font-color:#444;--mp-gap-bg-color:#e1e5ed;--mp-overlay-bg-color:#000;--mp-info-border-color:#ddd;--mp-query-border-color:#efefef;--mp-timing-unknown-color:#80ccda;--mp-timing-dns-color:#8baad1;--mp-timing-connect-color:#8cbb4e;--mp-timing-ssl-color:#795892;--mp-timing-request-color:#0099b2;--mp-timing-response-color:#d99d35;--mp-timing-dom-color:#bd4d32;--mp-timing-domcontent-color:#dd4678;--mp-timing-load-color:#1d72aa;--mp-timing-paint-color:#bc41e3;--mp-highlight-fade-color:#ffb;--mp-highlight-default-color:#000;--mp-highlight-string-color:#756bb1;--mp-highlight-comment-color:#636363;--mp-highlight-literal-color:#31a354;--mp-highlight-variable-color:#88f;--mp-highlight-keyword-color:#3182bd;--mp-highlight-attribute-color:#e6550d;--mp-result-border:solid .5px #ababab;--mp-result-border-radius:10px;--mp-popup-shadow:0 1px 5px #55555555;}@media(prefers-color-scheme:dark){.mp-scheme-auto{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-auto body{background-color:var(--mp-main-bg-color);}}.mp-scheme-dark{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-dark body{background-color:var(--mp-main-bg-color);}.mp-result,.mp-queries{color:var(--mp-label-color);line-height:1;font-size:12px;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code,.mp-result label,.mp-queries label,.mp-result table,.mp-queries table,.mp-result tbody,.mp-queries tbody,.mp-result thead,.mp-queries thead,.mp-result tfoot,.mp-queries tfoot,.mp-result tr,.mp-queries tr,.mp-result th,.mp-queries th,.mp-result td,.mp-queries td{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;background-color:transparent;overflow:visible;max-height:none;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code{font-family:Fira Code,Consolas,monospace,serif;font-variant-ligatures:none;}.mp-result table,.mp-queries table{color:var(--mp-label-color);border-collapse:collapse;border-spacing:0;width:100%;}.mp-result a,.mp-queries a{cursor:pointer;color:var(--mp-link-color);text-decoration:none;}.mp-result a:hover,.mp-queries a:hover{text-decoration:underline;}.mp-result{font-family:sans-serif;}.mp-result.show-columns th.mp-more-columns,.mp-result.show-columns td.mp-more-columns{display:table-cell !important;}.mp-result.show-columns a.mp-more-columns{display:inline-block;}.mp-result.show-columns .mp-links span a:nth-child(1){display:none;}.mp-result.show-trivial tr.mp-trivial{display:table-row !important;}.mp-result.show-trivial a.mp-trivial{display:inline-block;}.mp-result.show-trivial .mp-links span a:nth-child(3){display:none;}.mp-result table.mp-client-timings{margin-top:10px;}.mp-result table.mp-client-timings td:nth-child(2){width:100%;padding:0;}.mp-result table.mp-client-timings td div{height:13px;min-width:1px;}.mp-result table.mp-client-timings .t-point div{height:4px;border-radius:8px;margin-bottom:4px;box-shadow:0 0 2px;}.mp-result table.mp-client-timings .t-unknown div{background:var(--mp-timing-unknown-color);}.mp-result table.mp-client-timings .t-dns div{background:var(--mp-timing-dns-color);}.mp-result table.mp-client-timings .t-connect div{background:var(--mp-timing-connect-color);}.mp-result table.mp-client-timings .t-ssl div{background:var(--mp-timing-ssl-color);}.mp-result table.mp-client-timings .t-request div{background:var(--mp-timing-request-color);}.mp-result table.mp-client-timings .t-response div{background:var(--mp-timing-response-color);}.mp-result table.mp-client-timings .t-dom div{background:var(--mp-timing-dom-color);}.mp-result table.mp-client-timings .t-domcontent div{background:var(--mp-timing-domcontent-color);}.mp-result table.mp-client-timings .t-load div{background:var(--mp-timing-load-color);}.mp-result table.mp-client-timings .t-paint div{background:var(--mp-timing-paint-color);}.mp-result .mp-debug{position:relative;cursor:pointer;}.mp-result .mp-debug .mp-debug-tooltip{display:none;position:fixed;background-color:var(--mp-main-bg-color);box-shadow:var(--mp-popup-shadow);right:100px;max-width:90%;border-radius:10px;padding:12px;opacity:.95;backdrop-filter:blur(4px);}.mp-result .mp-debug:hover .mp-label{text-decoration:underline;}.mp-result .mp-debug td:first-child:hover .mp-debug-tooltip{display:block;}.mp-result .mp-debug td:first-child>span{color:var(--mp-link-color);}.mp-result .mp-stack-trace{color:var(--mp-muted-color);margin-bottom:5px;font-family:Consolas,Monaco,monospace;overflow-x:hidden;overflow-y:auto;white-space:pre-line;max-height:200px;}.mp-result .mp-stack-trace .stack-row{white-space:nowrap;}.mp-result .mp-stack-trace .stack-row.common{filter:grayscale(80%);}.mp-result .mp-stack-trace .stack.async{opacity:.6;display:none;}.mp-result .mp-stack-trace .stack.leadin,.mp-result .mp-stack-trace .stack.file,.mp-result .mp-stack-trace .stack.line-prefix,.mp-result .mp-stack-trace .stack.path,.mp-result .mp-stack-trace .stack.dot{color:var(--mp-muted-color);}.mp-result .mp-stack-trace .stack.async-tag{color:var(--mp-highlight-attribute-color);font-weight:bold;}.mp-result .mp-stack-trace .stack.async-tag:before{content:"(";}.mp-result .mp-stack-trace .stack.async-tag:after{content:")";}.mp-result .mp-stack-trace .stack.type{color:var(--mp-highlight-keyword-color);}.mp-result .mp-stack-trace .stack.generic-type{color:var(--mp-highlight-fade-color);}.mp-result .mp-stack-trace .stack.misc,.mp-result .mp-stack-trace .stack.parens{color:var(--mp-highlight-comment-color);}.mp-result .mp-stack-trace .stack.method{color:var(--mp-highlight-string-color);}.mp-result .mp-stack-trace .stack.paramType{color:var(--mp-highlight-attribute-color);}.mp-result .mp-stack-trace .stack.paramName{color:var(--mp-highlight-variable-color);}.mp-result .mp-label{color:var(--mp-label-color);overflow:hidden;text-overflow:ellipsis;}.mp-result .mp-unit{color:var(--mp-muted-color);}.mp-result .mp-more-columns{display:none;}.mp-result .mp-trivial{display:none;}.mp-result .mp-trivial td,.mp-result .mp-trivial td *{color:var(--mp-muted-color) !important;}.mp-result .mp-number{color:var(--mp-duration-color);}.mp-result .mp-info>div{white-space:nowrap;overflow:hidden;}.mp-result .mp-info>div>div{display:inline-block;}.mp-result .mp-info .mp-name{display:inline-block;font-weight:bold;float:left;}.mp-result .mp-info .mp-machine-name,.mp-result .mp-info .mp-started{text-align:right;float:right;}.mp-result .mp-info .mp-server-time{white-space:nowrap;}.mp-result .mp-timings th{background-color:var(--mp-main-bg-color);color:var(--mp-muted-color);text-align:right;}.mp-result .mp-timings th,.mp-result .mp-timings td{white-space:nowrap;}.mp-result .mp-timings .mp-show-more{display:none;}.mp-result .mp-timings .mp-duration{font-family:Consolas,monospace,serif;color:var(--mp-duration-color);text-align:right;}.mp-result .mp-timings .mp-indent{letter-spacing:4px;}.mp-result .mp-timings .mp-queries-show .mp-number,.mp-result .mp-timings .mp-queries-show .mp-unit{color:var(--mp-link-color);}.mp-result .mp-timings .mp-queries-show.mp-queries-warning{color:var(--mp-warning-color);font-weight:bold;}.mp-result .mp-timings .mp-queries-duration{padding-left:6px;}.mp-result .mp-timings:not(.mp-client-timings) .mp-trivial:first-child{display:table-row;}.mp-result .mp-custom-timing-overview{float:right;margin:10px 0;width:auto;}.mp-result .mp-custom-timing-overview td{white-space:nowrap;text-align:right;}.mp-result .mp-custom-timing-overview td:last-child{padding-left:8px;}.mp-result .mp-links{margin-top:10px;clear:both;}.mp-result .mp-links span{float:right;}.mp-result .mp-links a{font-size:95%;margin-left:12px;}.mp-result .mp-links a:first-child{margin-left:0;}.mp-warning{color:var(--mp-critical-color);}@keyframes mp-fadeIn{from{background-color:var(--mp-highlight-fade-color);}to{background-color:none;}}.mp-overlay{z-index:2147483642;}.mp-overlay .mp-overlay-bg{z-index:2147483643;background:var(--mp-overlay-bg-color);opacity:.5;top:0;left:0;min-width:100%;position:fixed;height:calc(100%);}.mp-overlay .mp-queries{display:block;z-index:2147483644;top:25px;left:25px;right:25px;position:fixed;max-height:calc(100vh - 50px);background-color:var(--mp-main-bg-color);border-radius:2px;overflow-y:auto;overflow-x:auto;}.mp-queries{font-family:sans-serif;}.mp-queries pre{white-space:pre-wrap;}.mp-queries div{text-align:left;}.mp-queries table{table-layout:fixed;}.mp-queries td,.mp-queries th{padding:8px;border-bottom:solid 1px var(--mp-query-border-color);}.mp-queries td:first-child,.mp-queries th:first-child{width:250px;text-align:right;}.mp-queries td:first-child div,.mp-queries th:first-child div{text-align:right;margin-bottom:5px;word-break:break-word;}.mp-queries td:last-child,.mp-queries th:last-child{text-align:left;padding-right:15px;}.mp-queries .highlight{animation:mp-fadeIn 2s 1;}.mp-queries .mp-odd{background-color:var(--mp-alt-row-color);}.mp-queries .mp-since-start,.mp-queries .mp-duration{text-align:right;}.mp-queries.show-trivial .mp-gap-info.mp-trivial-gap{display:table-row;}.mp-queries .mp-gap-info{background-color:var(--mp-gap-bg-color);opacity:.8;color:var(--mp-gap-font-color);}.mp-queries .mp-gap-info .query{word-break:break-all;}.mp-queries .mp-gap-info .mp-unit{color:var(--mp-muted-color);}.mp-queries .mp-gap-info.mp-trivial-gap{display:none;}.mp-queries .mp-trivial-gap-container{text-align:center;margin:8px 0;}.mp-queries .mp-call-type{font-weight:bold;}.mp-queries .hljs{display:block;overflow-x:auto;padding:.5em;}.mp-queries .hljs,.mp-queries .hljs-subst{color:var(--mp-highlight-default-color);}.mp-queries .hljs-string,.mp-queries .hljs-meta,.mp-queries .hljs-symbol,.mp-queries .hljs-template-tag,.mp-queries .hljs-template-variable,.mp-queries .hljs-addition{color:var(--mp-highlight-string-color);}.mp-queries .hljs-comment,.mp-queries .hljs-quote{color:var(--mp-highlight-comment-color);}.mp-queries .hljs-number,.mp-queries .hljs-regexp,.mp-queries .hljs-literal,.mp-queries .hljs-bullet,.mp-queries .hljs-link{color:var(--mp-highlight-literal-color);}.mp-queries .hljs-deletion,.mp-queries .hljs-variable{color:var(--mp-highlight-variable-color);}.mp-queries .hljs-keyword,.mp-queries .hljs-selector-tag,.mp-queries .hljs-title,.mp-queries .hljs-section,.mp-queries .hljs-built_in,.mp-queries .hljs-doctag,.mp-queries .hljs-type,.mp-queries .hljs-tag,.mp-queries .hljs-name,.mp-queries .hljs-selector-id,.mp-queries .hljs-selector-class,.mp-queries .hljs-strong{color:var(--mp-highlight-keyword-color);}.mp-queries .hljs-emphasis{font-style:italic;}.mp-queries .hljs-attribute{color:var(--mp-highlight-attribute-color);}.mp-results{z-index:2147483641;position:fixed;top:0;}.mp-results.mp-left,.mp-results.mp-bottomleft{left:0;}.mp-results.mp-left .mp-controls,.mp-results.mp-left.mp-no-controls .mp-result:last-child .mp-button{border-bottom-right-radius:var(--mp-result-border-radius);}.mp-results.mp-left .mp-button,.mp-results.mp-left .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-right{right:0;}.mp-results.mp-right .mp-controls,.mp-results.mp-right.mp-no-controls .mp-result:last-child .mp-button{border-bottom-left-radius:var(--mp-result-border-radius);}.mp-results.mp-right .mp-button,.mp-results.mp-right .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomleft{top:inherit;bottom:0;}.mp-results.mp-bottomleft .mp-result:first-child .mp-button{border-top-right-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomleft .mp-button,.mp-results.mp-bottomleft .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-bottomleft .mp-result .mp-button,.mp-results.mp-bottomleft .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results.mp-bottomright{top:inherit;bottom:0;right:0;}.mp-results.mp-bottomright .mp-result:first-child .mp-button{border-top-left-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomright .mp-button,.mp-results.mp-bottomright .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomright .mp-result .mp-button,.mp-results.mp-bottomright .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results .mp-button{user-select:none;}.mp-results .mp-button.mp-button-warning{font-weight:bold;background-color:var(--mp-button-warning-bg-color);color:var(--mp-button-warning-text-color);}.mp-results .mp-button.mp-button-warning .mp-number,.mp-results .mp-button.mp-button-warning .mp-unit,.mp-results .mp-button.mp-button-warning .mp-warning{color:var(--mp-button-warning-text-color);}.mp-results .mp-button .mp-warning{font-weight:bold;}.mp-results .mp-button>.mp-number{font-family:Consolas,monospace,serif;}.mp-results .mp-controls{display:none;}.mp-results .mp-button,.mp-results .mp-controls{z-index:2147483640;border-bottom:var(--mp-result-border);background-color:var(--mp-main-bg-color);padding:4px 8px;text-align:right;cursor:pointer;}.mp-results .mp-result{position:relative;}.mp-results .mp-result.active .mp-button{background-color:var(--mp-button-active-bg-color);animation:none;border-radius:0 !important;}.mp-results .mp-result.active .mp-button.mp-button-warning{background-color:var(--mp-button-warning-bg-color);}.mp-results .mp-result.active .mp-button .mp-number,.mp-results .mp-result.active .mp-button .mp-warning{color:var(--mp-button-active-text-color);font-weight:bold;}.mp-results .mp-result.active .mp-button .mp-unit{color:var(--mp-button-active-text-color);font-weight:normal;}.mp-results .mp-result.active .mp-popup{display:block;}.mp-results.new .mp-button{animation:mp-fadeIn 2s 1;}.mp-results .mp-controls{display:block;font-size:12px;font-family:Consolas,monospace,serif;cursor:default;text-align:center;}.mp-results .mp-controls span{color:var(--mp-muted-color);border-right:1px solid var(--mp-muted-color);padding-right:5px;margin-right:5px;cursor:pointer;}.mp-results .mp-controls span:last-child{border-right:none;}.mp-results .mp-popup{display:none;z-index:2147483641;position:absolute;background-color:var(--mp-main-bg-color);padding:5px 10px;text-align:left;line-height:18px;overflow:auto;box-shadow:var(--mp-popup-shadow);border-radius:2px;}.mp-results .mp-popup .mp-info{margin-bottom:3px;padding-bottom:2px;border-bottom:1px solid var(--mp-info-border-color);}.mp-results .mp-popup .mp-info .mp-name{font-size:1.1em;}.mp-results .mp-popup .mp-info .mp-overall-duration{color:var(--mp-muted-color);}.mp-results .mp-popup .mp-timings th,.mp-results .mp-popup .mp-timings td{padding:0 6px;}.mp-results .mp-popup .mp-timings th{font-size:95%;padding-bottom:3px;}.mp-results .mp-popup .mp-timings .mp-label{max-width:350px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;}.mp-results .mp-queries{display:none;}.mp-results.mp-min .mp-result{display:none;}.mp-results.mp-min .mp-controls span{display:none;}.mp-results.mp-min .mp-controls .mp-min-max{border-right:none;padding:0;margin:0;}.mp-results.mp-min:hover .mp-controls .mp-min-max{display:inline;}.mp-result-full .mp-result{width:950px;margin:25px auto;}.mp-result-full .mp-result .mp-button{display:none;}.mp-result-full .mp-result .mp-popup .mp-info{font-size:18px;border-bottom:1px solid var(--mp-muted-color);padding-bottom:3px;margin-bottom:10px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-name{margin-bottom:5px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration,.mp-result-full .mp-result .mp-popup .mp-info .mp-started{font-size:80%;color:var(--mp-muted-color);}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration{padding-right:20px;}.mp-result-full .mp-result .mp-popup .mp-timings td,.mp-result-full .mp-result .mp-popup .mp-timings th{font-size:13px;padding-left:8px;padding-right:8px;}.mp-result-full .mp-result .mp-popup .mp-timings th{padding-bottom:7px;}.mp-result-full .mp-result .mp-popup .mp-timings td{padding-bottom:4px;}.mp-result-full .mp-result .mp-popup .mp-timings td:first-child{padding-left:10px;}.mp-result-full .mp-result .mp-popup .mp-timings .mp-label{max-width:550px;}.mp-result-full .mp-result .mp-queries{margin:20px 0;}.mp-result-full .mp-result .mp-queries th{font-size:16px;}.mp-result-full .mp-share-mp-results{display:none;}table.mp-results-index{border:0;border-spacing:0;font-size:12px;font-family:Arial;}table.mp-results-index a{color:var(--mp-link-color);text-decoration:none;}table.mp-results-index tbody{color:var(--mp-label-color);}table.mp-results-index tbody tr:nth-child(odd){background-color:var(--mp-alt-row-color);}table.mp-results-index tbody tr:nth-child(even){background-color:var(--mp-main-bg-color);}table.mp-results-index tbody td{text-align:center;}table.mp-results-index tbody td:first-child{text-align:left;}table.mp-results-index tbody td[colspan="3"]{color:var(--mp-muted-color);}table.mp-results-index thead tr{color:var(--mp-label-color);}table.mp-results-index thead tr th{padding:5px 15px;}table.mp-results-index td{padding:8px;} \ No newline at end of file +:root{--mp-main-bg-color:#fff;--mp-button-active-bg-color:#207ab7;--mp-button-active-text-color:#fff;--mp-button-warning-bg-color:#c91d2e;--mp-button-warning-text-color:#fff;--mp-duration-color:#111;--mp-warning-color:#c91d2e;--mp-critical-color:#f00;--mp-alt-row-color:#f5f5f5;--mp-muted-color:#aaa;--mp-link-color:#07c;--mp-label-color:#555;--mp-gap-font-color:#444;--mp-gap-bg-color:#e1e5ed;--mp-overlay-bg-color:#000;--mp-info-border-color:#ddd;--mp-query-border-color:#efefef;--mp-timing-unknown-color:#80ccda;--mp-timing-dns-color:#8baad1;--mp-timing-connect-color:#8cbb4e;--mp-timing-ssl-color:#795892;--mp-timing-request-color:#0099b2;--mp-timing-response-color:#d99d35;--mp-timing-dom-color:#bd4d32;--mp-timing-domcontent-color:#dd4678;--mp-timing-load-color:#1d72aa;--mp-timing-paint-color:#bc41e3;--mp-highlight-fade-color:#ffb;--mp-highlight-default-color:#000;--mp-highlight-string-color:#756bb1;--mp-highlight-comment-color:#636363;--mp-highlight-literal-color:#31a354;--mp-highlight-variable-color:#88f;--mp-highlight-keyword-color:#3182bd;--mp-highlight-attribute-color:#e6550d;--mp-result-border:solid .5px #ababab;--mp-result-border-radius:10px;--mp-popup-shadow:0 1px 5px #55555555;}@media(prefers-color-scheme:dark){.mp-scheme-auto{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-auto body{background-color:var(--mp-main-bg-color);}}.mp-scheme-dark{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-dark body{background-color:var(--mp-main-bg-color);}.mp-result,.mp-queries{color:var(--mp-label-color);line-height:1;font-size:12px;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code,.mp-result label,.mp-queries label,.mp-result table,.mp-queries table,.mp-result tbody,.mp-queries tbody,.mp-result thead,.mp-queries thead,.mp-result tfoot,.mp-queries tfoot,.mp-result tr,.mp-queries tr,.mp-result th,.mp-queries th,.mp-result td,.mp-queries td{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;background-color:transparent;overflow:visible;max-height:none;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code{font-family:Fira Code,Consolas,monospace,serif;font-variant-ligatures:none;}.mp-result table,.mp-queries table{color:var(--mp-label-color);border-collapse:collapse;border-spacing:0;width:100%;}.mp-result a,.mp-queries a{cursor:pointer;color:var(--mp-link-color);text-decoration:none;}.mp-result a:hover,.mp-queries a:hover{text-decoration:underline;}.mp-result{font-family:sans-serif;}.mp-result.show-columns th.mp-more-columns,.mp-result.show-columns td.mp-more-columns{display:table-cell !important;}.mp-result.show-columns a.mp-more-columns{display:inline-block;}.mp-result.show-columns .mp-links span a:nth-child(1){display:none;}.mp-result.show-trivial tr.mp-trivial{display:table-row !important;}.mp-result.show-trivial a.mp-trivial{display:inline-block;}.mp-result.show-trivial .mp-links span a:nth-child(3){display:none;}.mp-result table.mp-client-timings{margin-top:10px;}.mp-result table.mp-client-timings td:nth-child(2){width:100%;padding:0;}.mp-result table.mp-client-timings td div{height:13px;min-width:1px;}.mp-result table.mp-client-timings .t-point div{height:4px;border-radius:8px;margin-bottom:4px;box-shadow:0 0 2px;}.mp-result table.mp-client-timings .t-unknown div{background:var(--mp-timing-unknown-color);}.mp-result table.mp-client-timings .t-dns div{background:var(--mp-timing-dns-color);}.mp-result table.mp-client-timings .t-connect div{background:var(--mp-timing-connect-color);}.mp-result table.mp-client-timings .t-ssl div{background:var(--mp-timing-ssl-color);}.mp-result table.mp-client-timings .t-request div{background:var(--mp-timing-request-color);}.mp-result table.mp-client-timings .t-response div{background:var(--mp-timing-response-color);}.mp-result table.mp-client-timings .t-dom div{background:var(--mp-timing-dom-color);}.mp-result table.mp-client-timings .t-domcontent div{background:var(--mp-timing-domcontent-color);}.mp-result table.mp-client-timings .t-load div{background:var(--mp-timing-load-color);}.mp-result table.mp-client-timings .t-paint div{background:var(--mp-timing-paint-color);}.mp-result .mp-debug{position:relative;cursor:pointer;}.mp-result .mp-debug .mp-debug-tooltip{display:none;position:fixed;background-color:var(--mp-main-bg-color);box-shadow:var(--mp-popup-shadow);right:100px;max-width:90%;border-radius:9px;padding:12px;margin-top:18px;opacity:.95;backdrop-filter:blur(4px);}.mp-result .mp-debug .mp-nested-timing{margin-left:16px;}.mp-result .mp-debug td:first-child:hover .mp-debug-tooltip{display:block;}.mp-result .mp-debug td:first-child:hover>span{text-shadow:var(--mp-button-active-text-color) 0 0 4px;}.mp-result .mp-stack-trace{color:var(--mp-muted-color);margin-bottom:5px;font-family:Consolas,Monaco,monospace;overflow-x:hidden;overflow-y:auto;white-space:pre-line;max-height:200px;}.mp-result .mp-stack-trace .stack-row{white-space:nowrap;}.mp-result .mp-stack-trace .stack-row.common{filter:grayscale(80%);}.mp-result .mp-stack-trace .stack.async{opacity:.6;display:none;}.mp-result .mp-stack-trace .stack.leadin,.mp-result .mp-stack-trace .stack.file,.mp-result .mp-stack-trace .stack.line-prefix,.mp-result .mp-stack-trace .stack.path,.mp-result .mp-stack-trace .stack.dot{color:var(--mp-muted-color);}.mp-result .mp-stack-trace .stack.async-tag{color:var(--mp-highlight-attribute-color);font-weight:bold;}.mp-result .mp-stack-trace .stack.async-tag:before{content:"(";}.mp-result .mp-stack-trace .stack.async-tag:after{content:")";}.mp-result .mp-stack-trace .stack.type{color:var(--mp-highlight-keyword-color);}.mp-result .mp-stack-trace .stack.generic-type{color:var(--mp-highlight-fade-color);}.mp-result .mp-stack-trace .stack.misc,.mp-result .mp-stack-trace .stack.parens{color:var(--mp-highlight-comment-color);}.mp-result .mp-stack-trace .stack.method{color:var(--mp-highlight-string-color);}.mp-result .mp-stack-trace .stack.paramType{color:var(--mp-highlight-attribute-color);}.mp-result .mp-stack-trace .stack.paramName{color:var(--mp-highlight-variable-color);}.mp-result .mp-label{color:var(--mp-label-color);overflow:hidden;text-overflow:ellipsis;}.mp-result .mp-unit{color:var(--mp-muted-color);}.mp-result .mp-more-columns{display:none;}.mp-result .mp-trivial{display:none;}.mp-result .mp-trivial td,.mp-result .mp-trivial td *{color:var(--mp-muted-color) !important;}.mp-result .mp-number{color:var(--mp-duration-color);}.mp-result .mp-info>div{white-space:nowrap;overflow:hidden;}.mp-result .mp-info>div>div{display:inline-block;}.mp-result .mp-info .mp-name{display:inline-block;font-weight:bold;float:left;}.mp-result .mp-info .mp-machine-name,.mp-result .mp-info .mp-started{text-align:right;float:right;}.mp-result .mp-info .mp-server-time{white-space:nowrap;}.mp-result .mp-timings th{background-color:var(--mp-main-bg-color);color:var(--mp-muted-color);text-align:right;}.mp-result .mp-timings th,.mp-result .mp-timings td{white-space:nowrap;}.mp-result .mp-timings .mp-show-more{display:none;}.mp-result .mp-timings .mp-duration{font-family:Consolas,monospace,serif;color:var(--mp-duration-color);text-align:right;}.mp-result .mp-timings .mp-indent{letter-spacing:4px;}.mp-result .mp-timings .mp-queries-show .mp-number,.mp-result .mp-timings .mp-queries-show .mp-unit{color:var(--mp-link-color);}.mp-result .mp-timings .mp-queries-show.mp-queries-warning{color:var(--mp-warning-color);font-weight:bold;}.mp-result .mp-timings .mp-queries-duration{padding-left:6px;}.mp-result .mp-timings:not(.mp-client-timings) .mp-trivial:first-child{display:table-row;}.mp-result .mp-custom-timing-overview{float:right;margin:10px 0;width:auto;}.mp-result .mp-custom-timing-overview td{white-space:nowrap;text-align:right;}.mp-result .mp-custom-timing-overview td:last-child{padding-left:8px;}.mp-result .mp-links{margin-top:10px;clear:both;}.mp-result .mp-links span{float:right;}.mp-result .mp-links a{font-size:95%;margin-left:12px;}.mp-result .mp-links a:first-child{margin-left:0;}.mp-warning{color:var(--mp-critical-color);}@keyframes mp-fadeIn{from{background-color:var(--mp-highlight-fade-color);}to{background-color:none;}}.mp-overlay{z-index:2147483642;}.mp-overlay .mp-overlay-bg{z-index:2147483643;background:var(--mp-overlay-bg-color);opacity:.5;top:0;left:0;min-width:100%;position:fixed;height:calc(100%);}.mp-overlay .mp-queries{display:block;z-index:2147483644;top:25px;left:25px;right:25px;position:fixed;max-height:calc(100vh - 50px);background-color:var(--mp-main-bg-color);border-radius:2px;overflow-y:auto;overflow-x:auto;}.mp-queries{font-family:sans-serif;}.mp-queries pre{white-space:pre-wrap;}.mp-queries div{text-align:left;}.mp-queries table{table-layout:fixed;}.mp-queries td,.mp-queries th{padding:8px;border-bottom:solid 1px var(--mp-query-border-color);}.mp-queries td:first-child,.mp-queries th:first-child{width:250px;text-align:right;}.mp-queries td:first-child div,.mp-queries th:first-child div{text-align:right;margin-bottom:5px;word-break:break-word;}.mp-queries td:last-child,.mp-queries th:last-child{text-align:left;padding-right:15px;}.mp-queries .highlight{animation:mp-fadeIn 2s 1;}.mp-queries .mp-odd{background-color:var(--mp-alt-row-color);}.mp-queries .mp-since-start,.mp-queries .mp-duration{text-align:right;}.mp-queries.show-trivial .mp-gap-info.mp-trivial-gap{display:table-row;}.mp-queries .mp-gap-info{background-color:var(--mp-gap-bg-color);opacity:.8;color:var(--mp-gap-font-color);}.mp-queries .mp-gap-info .query{word-break:break-all;}.mp-queries .mp-gap-info .mp-unit{color:var(--mp-muted-color);}.mp-queries .mp-gap-info.mp-trivial-gap{display:none;}.mp-queries .mp-trivial-gap-container{text-align:center;margin:8px 0;}.mp-queries .mp-call-type{font-weight:bold;}.mp-queries .hljs{display:block;overflow-x:auto;padding:.5em;}.mp-queries .hljs,.mp-queries .hljs-subst{color:var(--mp-highlight-default-color);}.mp-queries .hljs-string,.mp-queries .hljs-meta,.mp-queries .hljs-symbol,.mp-queries .hljs-template-tag,.mp-queries .hljs-template-variable,.mp-queries .hljs-addition{color:var(--mp-highlight-string-color);}.mp-queries .hljs-comment,.mp-queries .hljs-quote{color:var(--mp-highlight-comment-color);}.mp-queries .hljs-number,.mp-queries .hljs-regexp,.mp-queries .hljs-literal,.mp-queries .hljs-bullet,.mp-queries .hljs-link{color:var(--mp-highlight-literal-color);}.mp-queries .hljs-deletion,.mp-queries .hljs-variable{color:var(--mp-highlight-variable-color);}.mp-queries .hljs-keyword,.mp-queries .hljs-selector-tag,.mp-queries .hljs-title,.mp-queries .hljs-section,.mp-queries .hljs-built_in,.mp-queries .hljs-doctag,.mp-queries .hljs-type,.mp-queries .hljs-tag,.mp-queries .hljs-name,.mp-queries .hljs-selector-id,.mp-queries .hljs-selector-class,.mp-queries .hljs-strong{color:var(--mp-highlight-keyword-color);}.mp-queries .hljs-emphasis{font-style:italic;}.mp-queries .hljs-attribute{color:var(--mp-highlight-attribute-color);}.mp-results{z-index:2147483641;position:fixed;top:0;}.mp-results.mp-left,.mp-results.mp-bottomleft{left:0;}.mp-results.mp-left .mp-controls,.mp-results.mp-left.mp-no-controls .mp-result:last-child .mp-button{border-bottom-right-radius:var(--mp-result-border-radius);}.mp-results.mp-left .mp-button,.mp-results.mp-left .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-right{right:0;}.mp-results.mp-right .mp-controls,.mp-results.mp-right.mp-no-controls .mp-result:last-child .mp-button{border-bottom-left-radius:var(--mp-result-border-radius);}.mp-results.mp-right .mp-button,.mp-results.mp-right .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomleft{top:inherit;bottom:0;}.mp-results.mp-bottomleft .mp-result:first-child .mp-button{border-top-right-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomleft .mp-button,.mp-results.mp-bottomleft .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-bottomleft .mp-result .mp-button,.mp-results.mp-bottomleft .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results.mp-bottomright{top:inherit;bottom:0;right:0;}.mp-results.mp-bottomright .mp-result:first-child .mp-button{border-top-left-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomright .mp-button,.mp-results.mp-bottomright .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomright .mp-result .mp-button,.mp-results.mp-bottomright .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results .mp-button{user-select:none;}.mp-results .mp-button.mp-button-warning{font-weight:bold;background-color:var(--mp-button-warning-bg-color);color:var(--mp-button-warning-text-color);}.mp-results .mp-button.mp-button-warning .mp-number,.mp-results .mp-button.mp-button-warning .mp-unit,.mp-results .mp-button.mp-button-warning .mp-warning{color:var(--mp-button-warning-text-color);}.mp-results .mp-button .mp-warning{font-weight:bold;}.mp-results .mp-button>.mp-number{font-family:Consolas,monospace,serif;}.mp-results .mp-controls{display:none;}.mp-results .mp-button,.mp-results .mp-controls{z-index:2147483640;border-bottom:var(--mp-result-border);background-color:var(--mp-main-bg-color);padding:4px 8px;text-align:right;cursor:pointer;}.mp-results .mp-result{position:relative;}.mp-results .mp-result.active .mp-button{background-color:var(--mp-button-active-bg-color);animation:none;border-radius:0 !important;}.mp-results .mp-result.active .mp-button.mp-button-warning{background-color:var(--mp-button-warning-bg-color);}.mp-results .mp-result.active .mp-button .mp-number,.mp-results .mp-result.active .mp-button .mp-warning{color:var(--mp-button-active-text-color);font-weight:bold;}.mp-results .mp-result.active .mp-button .mp-unit{color:var(--mp-button-active-text-color);font-weight:normal;}.mp-results .mp-result.active .mp-popup{display:block;}.mp-results.new .mp-button{animation:mp-fadeIn 2s 1;}.mp-results .mp-controls{display:block;font-size:12px;font-family:Consolas,monospace,serif;cursor:default;text-align:center;}.mp-results .mp-controls span{color:var(--mp-muted-color);border-right:1px solid var(--mp-muted-color);padding-right:5px;margin-right:5px;cursor:pointer;}.mp-results .mp-controls span:last-child{border-right:none;}.mp-results .mp-popup{display:none;z-index:2147483641;position:absolute;background-color:var(--mp-main-bg-color);padding:5px 10px;text-align:left;line-height:18px;overflow:auto;box-shadow:var(--mp-popup-shadow);border-radius:2px;}.mp-results .mp-popup .mp-info{margin-bottom:3px;padding-bottom:2px;border-bottom:1px solid var(--mp-info-border-color);}.mp-results .mp-popup .mp-info .mp-name{font-size:1.1em;}.mp-results .mp-popup .mp-info .mp-overall-duration{color:var(--mp-muted-color);}.mp-results .mp-popup .mp-timings th,.mp-results .mp-popup .mp-timings td{padding:0 6px;}.mp-results .mp-popup .mp-timings th{font-size:95%;padding-bottom:3px;}.mp-results .mp-popup .mp-timings .mp-label{max-width:350px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;}.mp-results .mp-queries{display:none;}.mp-results.mp-min .mp-result{display:none;}.mp-results.mp-min .mp-controls span{display:none;}.mp-results.mp-min .mp-controls .mp-min-max{border-right:none;padding:0;margin:0;}.mp-results.mp-min:hover .mp-controls .mp-min-max{display:inline;}.mp-result-full .mp-result{width:950px;margin:25px auto;}.mp-result-full .mp-result .mp-button{display:none;}.mp-result-full .mp-result .mp-popup .mp-info{font-size:18px;border-bottom:1px solid var(--mp-muted-color);padding-bottom:3px;margin-bottom:10px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-name{margin-bottom:5px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration,.mp-result-full .mp-result .mp-popup .mp-info .mp-started{font-size:80%;color:var(--mp-muted-color);}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration{padding-right:20px;}.mp-result-full .mp-result .mp-popup .mp-timings td,.mp-result-full .mp-result .mp-popup .mp-timings th{font-size:13px;padding-left:8px;padding-right:8px;}.mp-result-full .mp-result .mp-popup .mp-timings th{padding-bottom:7px;}.mp-result-full .mp-result .mp-popup .mp-timings td{padding-bottom:4px;}.mp-result-full .mp-result .mp-popup .mp-timings td:first-child{padding-left:10px;}.mp-result-full .mp-result .mp-popup .mp-timings .mp-label{max-width:550px;}.mp-result-full .mp-result .mp-queries{margin:20px 0;}.mp-result-full .mp-result .mp-queries th{font-size:16px;}.mp-result-full .mp-share-mp-results{display:none;}table.mp-results-index{border:0;border-spacing:0;font-size:12px;font-family:Arial;}table.mp-results-index a{color:var(--mp-link-color);text-decoration:none;}table.mp-results-index tbody{color:var(--mp-label-color);}table.mp-results-index tbody tr:nth-child(odd){background-color:var(--mp-alt-row-color);}table.mp-results-index tbody tr:nth-child(even){background-color:var(--mp-main-bg-color);}table.mp-results-index tbody td{text-align:center;}table.mp-results-index tbody td:first-child{text-align:left;}table.mp-results-index tbody td[colspan="3"]{color:var(--mp-muted-color);}table.mp-results-index thead tr{color:var(--mp-label-color);}table.mp-results-index thead tr th{padding:5px 15px;}table.mp-results-index td{padding:8px;} \ No newline at end of file diff --git a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts index 9b8874e04..5a9ffce56 100644 --- a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts +++ b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts @@ -56,6 +56,7 @@ namespace StackExchange.Profiling { // additive on client side CustomTimingStats: { [id: string]: ICustomTimingStat }; DurationWithoutChildrenMilliseconds: number; + DurationOfChildrenMilliseconds: number; Depth: number; HasCustomTimings: boolean; HasDuplicateCustomTimings: { [id: string]: boolean }; @@ -484,6 +485,7 @@ namespace StackExchange.Profiling { function processTiming(timing: ITiming, parent: ITiming, depth: number) { timing.DurationWithoutChildrenMilliseconds = timing.DurationMilliseconds; + timing.DurationOfChildrenMilliseconds = 0; timing.Parent = parent; timing.Depth = depth; timing.HasDuplicateCustomTimings = {}; @@ -492,6 +494,7 @@ namespace StackExchange.Profiling { for (const child of timing.Children || []) { processTiming(child, timing, depth + 1); timing.DurationWithoutChildrenMilliseconds -= child.DurationMilliseconds; + timing.DurationOfChildrenMilliseconds += child.DurationMilliseconds; } // do this after subtracting child durations @@ -681,16 +684,30 @@ namespace StackExchange.Profiling { }; const renderDebugInfo = (timing: ITiming) => { if (timing.DebugInfo) { + const customTimings = (p.CustomTimingStats ? Object.keys(p.CustomTimingStats) : []).map((tk) => timing.CustomTimings[tk] ? ` +
+ ${timing.CustomTimingStats[tk].Count} ${encode(tk)} call${timing.CustomTimingStats[tk].Count == 1 ? '' : 's'} + totalling ${duration(timing.CustomTimingStats[tk].Duration)} ms + ${((timing.HasDuplicateCustomTimings[tk] || timing.HasWarnings[tk]) ? '(duplicates deletected)' : '')} +
` : '').join(''); return `
Detailed info for ${encode(timing.Name)}
Starts at: ${duration(timing.StartMilliseconds)} ms
-
Self duration: ${duration(timing.DurationWithoutChildrenMilliseconds)} ms
-
Overall duration (with children): ${duration(timing.DurationMilliseconds)} ms
+
+ Overall duration (with children): ${duration(timing.DurationMilliseconds)} ms +
+ Self duration: ${duration(timing.DurationWithoutChildrenMilliseconds)} ms + ${customTimings} +
+
+ Children (${timing.Children ? timing.Children.length : '0'}) duration: ${duration(timing.DurationOfChildrenMilliseconds)} ms +
+
Stack:
${timing.DebugInfo.RichHtmlStack}
- `; + 🔍`; } }; From 4e670409c776a632f6970811e04353e4a17d3a7b Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sun, 24 May 2020 10:23:05 -0400 Subject: [PATCH 04/13] Stack shaving and tooltip for trivials fixed --- .../MvcDiagnosticListener.cs | 8 +++++--- src/MiniProfiler.Shared/MiniProfiler.cs | 4 ++-- .../MiniProfilerExtensions.cs | 4 ++-- src/MiniProfiler.Shared/Timing.cs | 17 +++++++++++++++-- src/MiniProfiler.Shared/TimingDebugInfo.cs | 4 ++-- src/MiniProfiler.Shared/ui/includes.css | 4 ++-- src/MiniProfiler.Shared/ui/includes.less | 2 +- src/MiniProfiler.Shared/ui/includes.min.css | 2 +- 8 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs b/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs index bc740698b..e79c7acf6 100644 --- a/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs +++ b/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs @@ -82,15 +82,17 @@ private string GetName(string label, ActionDescriptor descriptor) private object Start(T state, string stepName) where T : class { - CurrentTiming.Value = (state, MiniProfiler.Current.Step(stepName)); + var profiler = MiniProfiler.Current; + CurrentTiming.Value = (state, profiler != null ? new Timing(profiler, profiler.Head, stepName, null, null, debugStackShave: 4) : null); return null; } private object StartFilter(T state, string stepName) where T : class { - if (MiniProfiler.Current?.Options is MiniProfilerOptions opts && opts.EnableMvcFilterProfiling) + var profiler = MiniProfiler.Current; + if (profiler?.Options is MiniProfilerOptions opts && opts.EnableMvcFilterProfiling) { - CurrentTiming.Value = (state, MiniProfiler.Current.StepIf(stepName, opts.MvcFilterMinimumSaveMs ?? 0, true)); + CurrentTiming.Value = (state, new Timing(profiler, profiler.Head, stepName, opts.MvcFilterMinimumSaveMs ?? 0, true, debugStackShave: 4)); } return null; } diff --git a/src/MiniProfiler.Shared/MiniProfiler.cs b/src/MiniProfiler.Shared/MiniProfiler.cs index 4f5495a82..b815f8c0b 100644 --- a/src/MiniProfiler.Shared/MiniProfiler.cs +++ b/src/MiniProfiler.Shared/MiniProfiler.cs @@ -333,9 +333,9 @@ public MiniProfiler Clone() } } - internal Timing StepImpl(string name, decimal? minSaveMs = null, bool? includeChildrenWithMinSave = false) + internal Timing StepImpl(string name, decimal? minSaveMs = null, bool? includeChildrenWithMinSave = false, int debugStackShave = 0) { - return new Timing(this, Head, name, minSaveMs, includeChildrenWithMinSave); + return new Timing(this, Head, name, minSaveMs, includeChildrenWithMinSave, debugStackShave); } /// diff --git a/src/MiniProfiler.Shared/MiniProfilerExtensions.cs b/src/MiniProfiler.Shared/MiniProfilerExtensions.cs index cd468f9ab..12d10f2dc 100644 --- a/src/MiniProfiler.Shared/MiniProfilerExtensions.cs +++ b/src/MiniProfiler.Shared/MiniProfilerExtensions.cs @@ -36,7 +36,7 @@ public static T Inline(this MiniProfiler profiler, Func selector, string n /// The current profiling session or null. /// A descriptive name for the code that is encapsulated by the resulting Timing's lifetime. /// the profile step - public static Timing Step(this MiniProfiler profiler, string name) => profiler?.StepImpl(name); + public static Timing Step(this MiniProfiler profiler, string name) => profiler?.StepImpl(name, debugStackShave: 1); /// /// Returns an () that will time the code between its creation and disposal. @@ -52,7 +52,7 @@ public static T Inline(this MiniProfiler profiler, Func selector, string n /// time spent in that time will also not count for the current StepIf calculation. public static Timing StepIf(this MiniProfiler profiler, string name, decimal minSaveMs, bool includeChildren = false) { - return profiler?.StepImpl(name, minSaveMs, includeChildren); + return profiler?.StepImpl(name, minSaveMs, includeChildren, debugStackShave: 1); } /// diff --git a/src/MiniProfiler.Shared/Timing.cs b/src/MiniProfiler.Shared/Timing.cs index 8e22f107d..3dc81aefa 100644 --- a/src/MiniProfiler.Shared/Timing.cs +++ b/src/MiniProfiler.Shared/Timing.cs @@ -35,7 +35,20 @@ public class Timing : IDisposable /// The name of this timing. /// (Optional) The minimum threshold (in milliseconds) for saving this timing. /// (Optional) Whether the children are included when comparing to the threshold. - public Timing(MiniProfiler profiler, Timing parent, string name, decimal? minSaveMs = null, bool? includeChildrenWithMinSave = false) + public Timing(MiniProfiler profiler, Timing parent, string name, decimal? minSaveMs = null, bool? includeChildrenWithMinSave = false) : + this(profiler, parent, name, minSaveMs, includeChildrenWithMinSave, 0) + { } + + /// + /// Creates a new Timing named 'name' in the 'profiler's session, with 'parent' as this Timing's immediate ancestor. + /// + /// The this belongs to. + /// The this is a child of. + /// The name of this timing. + /// (Optional) The minimum threshold (in milliseconds) for saving this timing. + /// (Optional) Whether the children are included when comparing to the threshold. + /// The number of frames to shave off the debug stack. + public Timing(MiniProfiler profiler, Timing parent, string name, decimal? minSaveMs, bool? includeChildrenWithMinSave, int debugStackShave) { Id = Guid.NewGuid(); Profiler = profiler; @@ -53,7 +66,7 @@ public Timing(MiniProfiler profiler, Timing parent, string name, decimal? minSav if (profiler.Options.EnableDebugMode) { - DebugInfo = new TimingDebugInfo(this); + DebugInfo = new TimingDebugInfo(this, debugStackShave); } } diff --git a/src/MiniProfiler.Shared/TimingDebugInfo.cs b/src/MiniProfiler.Shared/TimingDebugInfo.cs index cf68e6509..68dde9fd5 100644 --- a/src/MiniProfiler.Shared/TimingDebugInfo.cs +++ b/src/MiniProfiler.Shared/TimingDebugInfo.cs @@ -29,10 +29,10 @@ public class TimingDebugInfo private Timing ParentTiming { get; } private StackTrace RawStack { get; } - internal TimingDebugInfo(Timing parent) + internal TimingDebugInfo(Timing parent, int debugStackShave = 0) { ParentTiming = parent; - RawStack = new StackTrace(4, true); + RawStack = new StackTrace(4 + debugStackShave, true); if (parent.ParentTiming?.DebugInfo?.RawStack is StackTrace parentStack) { diff --git a/src/MiniProfiler.Shared/ui/includes.css b/src/MiniProfiler.Shared/ui/includes.css index 65c653c10..1f3e4f87c 100644 --- a/src/MiniProfiler.Shared/ui/includes.css +++ b/src/MiniProfiler.Shared/ui/includes.css @@ -313,8 +313,8 @@ .mp-result .mp-trivial { display: none; } -.mp-result .mp-trivial td, -.mp-result .mp-trivial td * { +.mp-result .mp-trivial td:not(:first-child), +.mp-result .mp-trivial td:not(:first-child) * { color: var(--mp-muted-color) !important; } .mp-result .mp-number { diff --git a/src/MiniProfiler.Shared/ui/includes.less b/src/MiniProfiler.Shared/ui/includes.less index a910ac9d2..b50efd0d9 100644 --- a/src/MiniProfiler.Shared/ui/includes.less +++ b/src/MiniProfiler.Shared/ui/includes.less @@ -322,7 +322,7 @@ .mp-trivial { display: none; - td, td * { + td:not(:first-child), td:not(:first-child) * { color: var(--mp-muted-color) !important; } } diff --git a/src/MiniProfiler.Shared/ui/includes.min.css b/src/MiniProfiler.Shared/ui/includes.min.css index 72430d951..7826085ad 100644 --- a/src/MiniProfiler.Shared/ui/includes.min.css +++ b/src/MiniProfiler.Shared/ui/includes.min.css @@ -1 +1 @@ -:root{--mp-main-bg-color:#fff;--mp-button-active-bg-color:#207ab7;--mp-button-active-text-color:#fff;--mp-button-warning-bg-color:#c91d2e;--mp-button-warning-text-color:#fff;--mp-duration-color:#111;--mp-warning-color:#c91d2e;--mp-critical-color:#f00;--mp-alt-row-color:#f5f5f5;--mp-muted-color:#aaa;--mp-link-color:#07c;--mp-label-color:#555;--mp-gap-font-color:#444;--mp-gap-bg-color:#e1e5ed;--mp-overlay-bg-color:#000;--mp-info-border-color:#ddd;--mp-query-border-color:#efefef;--mp-timing-unknown-color:#80ccda;--mp-timing-dns-color:#8baad1;--mp-timing-connect-color:#8cbb4e;--mp-timing-ssl-color:#795892;--mp-timing-request-color:#0099b2;--mp-timing-response-color:#d99d35;--mp-timing-dom-color:#bd4d32;--mp-timing-domcontent-color:#dd4678;--mp-timing-load-color:#1d72aa;--mp-timing-paint-color:#bc41e3;--mp-highlight-fade-color:#ffb;--mp-highlight-default-color:#000;--mp-highlight-string-color:#756bb1;--mp-highlight-comment-color:#636363;--mp-highlight-literal-color:#31a354;--mp-highlight-variable-color:#88f;--mp-highlight-keyword-color:#3182bd;--mp-highlight-attribute-color:#e6550d;--mp-result-border:solid .5px #ababab;--mp-result-border-radius:10px;--mp-popup-shadow:0 1px 5px #55555555;}@media(prefers-color-scheme:dark){.mp-scheme-auto{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-auto body{background-color:var(--mp-main-bg-color);}}.mp-scheme-dark{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-dark body{background-color:var(--mp-main-bg-color);}.mp-result,.mp-queries{color:var(--mp-label-color);line-height:1;font-size:12px;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code,.mp-result label,.mp-queries label,.mp-result table,.mp-queries table,.mp-result tbody,.mp-queries tbody,.mp-result thead,.mp-queries thead,.mp-result tfoot,.mp-queries tfoot,.mp-result tr,.mp-queries tr,.mp-result th,.mp-queries th,.mp-result td,.mp-queries td{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;background-color:transparent;overflow:visible;max-height:none;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code{font-family:Fira Code,Consolas,monospace,serif;font-variant-ligatures:none;}.mp-result table,.mp-queries table{color:var(--mp-label-color);border-collapse:collapse;border-spacing:0;width:100%;}.mp-result a,.mp-queries a{cursor:pointer;color:var(--mp-link-color);text-decoration:none;}.mp-result a:hover,.mp-queries a:hover{text-decoration:underline;}.mp-result{font-family:sans-serif;}.mp-result.show-columns th.mp-more-columns,.mp-result.show-columns td.mp-more-columns{display:table-cell !important;}.mp-result.show-columns a.mp-more-columns{display:inline-block;}.mp-result.show-columns .mp-links span a:nth-child(1){display:none;}.mp-result.show-trivial tr.mp-trivial{display:table-row !important;}.mp-result.show-trivial a.mp-trivial{display:inline-block;}.mp-result.show-trivial .mp-links span a:nth-child(3){display:none;}.mp-result table.mp-client-timings{margin-top:10px;}.mp-result table.mp-client-timings td:nth-child(2){width:100%;padding:0;}.mp-result table.mp-client-timings td div{height:13px;min-width:1px;}.mp-result table.mp-client-timings .t-point div{height:4px;border-radius:8px;margin-bottom:4px;box-shadow:0 0 2px;}.mp-result table.mp-client-timings .t-unknown div{background:var(--mp-timing-unknown-color);}.mp-result table.mp-client-timings .t-dns div{background:var(--mp-timing-dns-color);}.mp-result table.mp-client-timings .t-connect div{background:var(--mp-timing-connect-color);}.mp-result table.mp-client-timings .t-ssl div{background:var(--mp-timing-ssl-color);}.mp-result table.mp-client-timings .t-request div{background:var(--mp-timing-request-color);}.mp-result table.mp-client-timings .t-response div{background:var(--mp-timing-response-color);}.mp-result table.mp-client-timings .t-dom div{background:var(--mp-timing-dom-color);}.mp-result table.mp-client-timings .t-domcontent div{background:var(--mp-timing-domcontent-color);}.mp-result table.mp-client-timings .t-load div{background:var(--mp-timing-load-color);}.mp-result table.mp-client-timings .t-paint div{background:var(--mp-timing-paint-color);}.mp-result .mp-debug{position:relative;cursor:pointer;}.mp-result .mp-debug .mp-debug-tooltip{display:none;position:fixed;background-color:var(--mp-main-bg-color);box-shadow:var(--mp-popup-shadow);right:100px;max-width:90%;border-radius:9px;padding:12px;margin-top:18px;opacity:.95;backdrop-filter:blur(4px);}.mp-result .mp-debug .mp-nested-timing{margin-left:16px;}.mp-result .mp-debug td:first-child:hover .mp-debug-tooltip{display:block;}.mp-result .mp-debug td:first-child:hover>span{text-shadow:var(--mp-button-active-text-color) 0 0 4px;}.mp-result .mp-stack-trace{color:var(--mp-muted-color);margin-bottom:5px;font-family:Consolas,Monaco,monospace;overflow-x:hidden;overflow-y:auto;white-space:pre-line;max-height:200px;}.mp-result .mp-stack-trace .stack-row{white-space:nowrap;}.mp-result .mp-stack-trace .stack-row.common{filter:grayscale(80%);}.mp-result .mp-stack-trace .stack.async{opacity:.6;display:none;}.mp-result .mp-stack-trace .stack.leadin,.mp-result .mp-stack-trace .stack.file,.mp-result .mp-stack-trace .stack.line-prefix,.mp-result .mp-stack-trace .stack.path,.mp-result .mp-stack-trace .stack.dot{color:var(--mp-muted-color);}.mp-result .mp-stack-trace .stack.async-tag{color:var(--mp-highlight-attribute-color);font-weight:bold;}.mp-result .mp-stack-trace .stack.async-tag:before{content:"(";}.mp-result .mp-stack-trace .stack.async-tag:after{content:")";}.mp-result .mp-stack-trace .stack.type{color:var(--mp-highlight-keyword-color);}.mp-result .mp-stack-trace .stack.generic-type{color:var(--mp-highlight-fade-color);}.mp-result .mp-stack-trace .stack.misc,.mp-result .mp-stack-trace .stack.parens{color:var(--mp-highlight-comment-color);}.mp-result .mp-stack-trace .stack.method{color:var(--mp-highlight-string-color);}.mp-result .mp-stack-trace .stack.paramType{color:var(--mp-highlight-attribute-color);}.mp-result .mp-stack-trace .stack.paramName{color:var(--mp-highlight-variable-color);}.mp-result .mp-label{color:var(--mp-label-color);overflow:hidden;text-overflow:ellipsis;}.mp-result .mp-unit{color:var(--mp-muted-color);}.mp-result .mp-more-columns{display:none;}.mp-result .mp-trivial{display:none;}.mp-result .mp-trivial td,.mp-result .mp-trivial td *{color:var(--mp-muted-color) !important;}.mp-result .mp-number{color:var(--mp-duration-color);}.mp-result .mp-info>div{white-space:nowrap;overflow:hidden;}.mp-result .mp-info>div>div{display:inline-block;}.mp-result .mp-info .mp-name{display:inline-block;font-weight:bold;float:left;}.mp-result .mp-info .mp-machine-name,.mp-result .mp-info .mp-started{text-align:right;float:right;}.mp-result .mp-info .mp-server-time{white-space:nowrap;}.mp-result .mp-timings th{background-color:var(--mp-main-bg-color);color:var(--mp-muted-color);text-align:right;}.mp-result .mp-timings th,.mp-result .mp-timings td{white-space:nowrap;}.mp-result .mp-timings .mp-show-more{display:none;}.mp-result .mp-timings .mp-duration{font-family:Consolas,monospace,serif;color:var(--mp-duration-color);text-align:right;}.mp-result .mp-timings .mp-indent{letter-spacing:4px;}.mp-result .mp-timings .mp-queries-show .mp-number,.mp-result .mp-timings .mp-queries-show .mp-unit{color:var(--mp-link-color);}.mp-result .mp-timings .mp-queries-show.mp-queries-warning{color:var(--mp-warning-color);font-weight:bold;}.mp-result .mp-timings .mp-queries-duration{padding-left:6px;}.mp-result .mp-timings:not(.mp-client-timings) .mp-trivial:first-child{display:table-row;}.mp-result .mp-custom-timing-overview{float:right;margin:10px 0;width:auto;}.mp-result .mp-custom-timing-overview td{white-space:nowrap;text-align:right;}.mp-result .mp-custom-timing-overview td:last-child{padding-left:8px;}.mp-result .mp-links{margin-top:10px;clear:both;}.mp-result .mp-links span{float:right;}.mp-result .mp-links a{font-size:95%;margin-left:12px;}.mp-result .mp-links a:first-child{margin-left:0;}.mp-warning{color:var(--mp-critical-color);}@keyframes mp-fadeIn{from{background-color:var(--mp-highlight-fade-color);}to{background-color:none;}}.mp-overlay{z-index:2147483642;}.mp-overlay .mp-overlay-bg{z-index:2147483643;background:var(--mp-overlay-bg-color);opacity:.5;top:0;left:0;min-width:100%;position:fixed;height:calc(100%);}.mp-overlay .mp-queries{display:block;z-index:2147483644;top:25px;left:25px;right:25px;position:fixed;max-height:calc(100vh - 50px);background-color:var(--mp-main-bg-color);border-radius:2px;overflow-y:auto;overflow-x:auto;}.mp-queries{font-family:sans-serif;}.mp-queries pre{white-space:pre-wrap;}.mp-queries div{text-align:left;}.mp-queries table{table-layout:fixed;}.mp-queries td,.mp-queries th{padding:8px;border-bottom:solid 1px var(--mp-query-border-color);}.mp-queries td:first-child,.mp-queries th:first-child{width:250px;text-align:right;}.mp-queries td:first-child div,.mp-queries th:first-child div{text-align:right;margin-bottom:5px;word-break:break-word;}.mp-queries td:last-child,.mp-queries th:last-child{text-align:left;padding-right:15px;}.mp-queries .highlight{animation:mp-fadeIn 2s 1;}.mp-queries .mp-odd{background-color:var(--mp-alt-row-color);}.mp-queries .mp-since-start,.mp-queries .mp-duration{text-align:right;}.mp-queries.show-trivial .mp-gap-info.mp-trivial-gap{display:table-row;}.mp-queries .mp-gap-info{background-color:var(--mp-gap-bg-color);opacity:.8;color:var(--mp-gap-font-color);}.mp-queries .mp-gap-info .query{word-break:break-all;}.mp-queries .mp-gap-info .mp-unit{color:var(--mp-muted-color);}.mp-queries .mp-gap-info.mp-trivial-gap{display:none;}.mp-queries .mp-trivial-gap-container{text-align:center;margin:8px 0;}.mp-queries .mp-call-type{font-weight:bold;}.mp-queries .hljs{display:block;overflow-x:auto;padding:.5em;}.mp-queries .hljs,.mp-queries .hljs-subst{color:var(--mp-highlight-default-color);}.mp-queries .hljs-string,.mp-queries .hljs-meta,.mp-queries .hljs-symbol,.mp-queries .hljs-template-tag,.mp-queries .hljs-template-variable,.mp-queries .hljs-addition{color:var(--mp-highlight-string-color);}.mp-queries .hljs-comment,.mp-queries .hljs-quote{color:var(--mp-highlight-comment-color);}.mp-queries .hljs-number,.mp-queries .hljs-regexp,.mp-queries .hljs-literal,.mp-queries .hljs-bullet,.mp-queries .hljs-link{color:var(--mp-highlight-literal-color);}.mp-queries .hljs-deletion,.mp-queries .hljs-variable{color:var(--mp-highlight-variable-color);}.mp-queries .hljs-keyword,.mp-queries .hljs-selector-tag,.mp-queries .hljs-title,.mp-queries .hljs-section,.mp-queries .hljs-built_in,.mp-queries .hljs-doctag,.mp-queries .hljs-type,.mp-queries .hljs-tag,.mp-queries .hljs-name,.mp-queries .hljs-selector-id,.mp-queries .hljs-selector-class,.mp-queries .hljs-strong{color:var(--mp-highlight-keyword-color);}.mp-queries .hljs-emphasis{font-style:italic;}.mp-queries .hljs-attribute{color:var(--mp-highlight-attribute-color);}.mp-results{z-index:2147483641;position:fixed;top:0;}.mp-results.mp-left,.mp-results.mp-bottomleft{left:0;}.mp-results.mp-left .mp-controls,.mp-results.mp-left.mp-no-controls .mp-result:last-child .mp-button{border-bottom-right-radius:var(--mp-result-border-radius);}.mp-results.mp-left .mp-button,.mp-results.mp-left .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-right{right:0;}.mp-results.mp-right .mp-controls,.mp-results.mp-right.mp-no-controls .mp-result:last-child .mp-button{border-bottom-left-radius:var(--mp-result-border-radius);}.mp-results.mp-right .mp-button,.mp-results.mp-right .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomleft{top:inherit;bottom:0;}.mp-results.mp-bottomleft .mp-result:first-child .mp-button{border-top-right-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomleft .mp-button,.mp-results.mp-bottomleft .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-bottomleft .mp-result .mp-button,.mp-results.mp-bottomleft .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results.mp-bottomright{top:inherit;bottom:0;right:0;}.mp-results.mp-bottomright .mp-result:first-child .mp-button{border-top-left-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomright .mp-button,.mp-results.mp-bottomright .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomright .mp-result .mp-button,.mp-results.mp-bottomright .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results .mp-button{user-select:none;}.mp-results .mp-button.mp-button-warning{font-weight:bold;background-color:var(--mp-button-warning-bg-color);color:var(--mp-button-warning-text-color);}.mp-results .mp-button.mp-button-warning .mp-number,.mp-results .mp-button.mp-button-warning .mp-unit,.mp-results .mp-button.mp-button-warning .mp-warning{color:var(--mp-button-warning-text-color);}.mp-results .mp-button .mp-warning{font-weight:bold;}.mp-results .mp-button>.mp-number{font-family:Consolas,monospace,serif;}.mp-results .mp-controls{display:none;}.mp-results .mp-button,.mp-results .mp-controls{z-index:2147483640;border-bottom:var(--mp-result-border);background-color:var(--mp-main-bg-color);padding:4px 8px;text-align:right;cursor:pointer;}.mp-results .mp-result{position:relative;}.mp-results .mp-result.active .mp-button{background-color:var(--mp-button-active-bg-color);animation:none;border-radius:0 !important;}.mp-results .mp-result.active .mp-button.mp-button-warning{background-color:var(--mp-button-warning-bg-color);}.mp-results .mp-result.active .mp-button .mp-number,.mp-results .mp-result.active .mp-button .mp-warning{color:var(--mp-button-active-text-color);font-weight:bold;}.mp-results .mp-result.active .mp-button .mp-unit{color:var(--mp-button-active-text-color);font-weight:normal;}.mp-results .mp-result.active .mp-popup{display:block;}.mp-results.new .mp-button{animation:mp-fadeIn 2s 1;}.mp-results .mp-controls{display:block;font-size:12px;font-family:Consolas,monospace,serif;cursor:default;text-align:center;}.mp-results .mp-controls span{color:var(--mp-muted-color);border-right:1px solid var(--mp-muted-color);padding-right:5px;margin-right:5px;cursor:pointer;}.mp-results .mp-controls span:last-child{border-right:none;}.mp-results .mp-popup{display:none;z-index:2147483641;position:absolute;background-color:var(--mp-main-bg-color);padding:5px 10px;text-align:left;line-height:18px;overflow:auto;box-shadow:var(--mp-popup-shadow);border-radius:2px;}.mp-results .mp-popup .mp-info{margin-bottom:3px;padding-bottom:2px;border-bottom:1px solid var(--mp-info-border-color);}.mp-results .mp-popup .mp-info .mp-name{font-size:1.1em;}.mp-results .mp-popup .mp-info .mp-overall-duration{color:var(--mp-muted-color);}.mp-results .mp-popup .mp-timings th,.mp-results .mp-popup .mp-timings td{padding:0 6px;}.mp-results .mp-popup .mp-timings th{font-size:95%;padding-bottom:3px;}.mp-results .mp-popup .mp-timings .mp-label{max-width:350px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;}.mp-results .mp-queries{display:none;}.mp-results.mp-min .mp-result{display:none;}.mp-results.mp-min .mp-controls span{display:none;}.mp-results.mp-min .mp-controls .mp-min-max{border-right:none;padding:0;margin:0;}.mp-results.mp-min:hover .mp-controls .mp-min-max{display:inline;}.mp-result-full .mp-result{width:950px;margin:25px auto;}.mp-result-full .mp-result .mp-button{display:none;}.mp-result-full .mp-result .mp-popup .mp-info{font-size:18px;border-bottom:1px solid var(--mp-muted-color);padding-bottom:3px;margin-bottom:10px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-name{margin-bottom:5px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration,.mp-result-full .mp-result .mp-popup .mp-info .mp-started{font-size:80%;color:var(--mp-muted-color);}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration{padding-right:20px;}.mp-result-full .mp-result .mp-popup .mp-timings td,.mp-result-full .mp-result .mp-popup .mp-timings th{font-size:13px;padding-left:8px;padding-right:8px;}.mp-result-full .mp-result .mp-popup .mp-timings th{padding-bottom:7px;}.mp-result-full .mp-result .mp-popup .mp-timings td{padding-bottom:4px;}.mp-result-full .mp-result .mp-popup .mp-timings td:first-child{padding-left:10px;}.mp-result-full .mp-result .mp-popup .mp-timings .mp-label{max-width:550px;}.mp-result-full .mp-result .mp-queries{margin:20px 0;}.mp-result-full .mp-result .mp-queries th{font-size:16px;}.mp-result-full .mp-share-mp-results{display:none;}table.mp-results-index{border:0;border-spacing:0;font-size:12px;font-family:Arial;}table.mp-results-index a{color:var(--mp-link-color);text-decoration:none;}table.mp-results-index tbody{color:var(--mp-label-color);}table.mp-results-index tbody tr:nth-child(odd){background-color:var(--mp-alt-row-color);}table.mp-results-index tbody tr:nth-child(even){background-color:var(--mp-main-bg-color);}table.mp-results-index tbody td{text-align:center;}table.mp-results-index tbody td:first-child{text-align:left;}table.mp-results-index tbody td[colspan="3"]{color:var(--mp-muted-color);}table.mp-results-index thead tr{color:var(--mp-label-color);}table.mp-results-index thead tr th{padding:5px 15px;}table.mp-results-index td{padding:8px;} \ No newline at end of file +:root{--mp-main-bg-color:#fff;--mp-button-active-bg-color:#207ab7;--mp-button-active-text-color:#fff;--mp-button-warning-bg-color:#c91d2e;--mp-button-warning-text-color:#fff;--mp-duration-color:#111;--mp-warning-color:#c91d2e;--mp-critical-color:#f00;--mp-alt-row-color:#f5f5f5;--mp-muted-color:#aaa;--mp-link-color:#07c;--mp-label-color:#555;--mp-gap-font-color:#444;--mp-gap-bg-color:#e1e5ed;--mp-overlay-bg-color:#000;--mp-info-border-color:#ddd;--mp-query-border-color:#efefef;--mp-timing-unknown-color:#80ccda;--mp-timing-dns-color:#8baad1;--mp-timing-connect-color:#8cbb4e;--mp-timing-ssl-color:#795892;--mp-timing-request-color:#0099b2;--mp-timing-response-color:#d99d35;--mp-timing-dom-color:#bd4d32;--mp-timing-domcontent-color:#dd4678;--mp-timing-load-color:#1d72aa;--mp-timing-paint-color:#bc41e3;--mp-highlight-fade-color:#ffb;--mp-highlight-default-color:#000;--mp-highlight-string-color:#756bb1;--mp-highlight-comment-color:#636363;--mp-highlight-literal-color:#31a354;--mp-highlight-variable-color:#88f;--mp-highlight-keyword-color:#3182bd;--mp-highlight-attribute-color:#e6550d;--mp-result-border:solid .5px #ababab;--mp-result-border-radius:10px;--mp-popup-shadow:0 1px 5px #55555555;}@media(prefers-color-scheme:dark){.mp-scheme-auto{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-auto body{background-color:var(--mp-main-bg-color);}}.mp-scheme-dark{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-dark body{background-color:var(--mp-main-bg-color);}.mp-result,.mp-queries{color:var(--mp-label-color);line-height:1;font-size:12px;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code,.mp-result label,.mp-queries label,.mp-result table,.mp-queries table,.mp-result tbody,.mp-queries tbody,.mp-result thead,.mp-queries thead,.mp-result tfoot,.mp-queries tfoot,.mp-result tr,.mp-queries tr,.mp-result th,.mp-queries th,.mp-result td,.mp-queries td{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;background-color:transparent;overflow:visible;max-height:none;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code{font-family:Fira Code,Consolas,monospace,serif;font-variant-ligatures:none;}.mp-result table,.mp-queries table{color:var(--mp-label-color);border-collapse:collapse;border-spacing:0;width:100%;}.mp-result a,.mp-queries a{cursor:pointer;color:var(--mp-link-color);text-decoration:none;}.mp-result a:hover,.mp-queries a:hover{text-decoration:underline;}.mp-result{font-family:sans-serif;}.mp-result.show-columns th.mp-more-columns,.mp-result.show-columns td.mp-more-columns{display:table-cell !important;}.mp-result.show-columns a.mp-more-columns{display:inline-block;}.mp-result.show-columns .mp-links span a:nth-child(1){display:none;}.mp-result.show-trivial tr.mp-trivial{display:table-row !important;}.mp-result.show-trivial a.mp-trivial{display:inline-block;}.mp-result.show-trivial .mp-links span a:nth-child(3){display:none;}.mp-result table.mp-client-timings{margin-top:10px;}.mp-result table.mp-client-timings td:nth-child(2){width:100%;padding:0;}.mp-result table.mp-client-timings td div{height:13px;min-width:1px;}.mp-result table.mp-client-timings .t-point div{height:4px;border-radius:8px;margin-bottom:4px;box-shadow:0 0 2px;}.mp-result table.mp-client-timings .t-unknown div{background:var(--mp-timing-unknown-color);}.mp-result table.mp-client-timings .t-dns div{background:var(--mp-timing-dns-color);}.mp-result table.mp-client-timings .t-connect div{background:var(--mp-timing-connect-color);}.mp-result table.mp-client-timings .t-ssl div{background:var(--mp-timing-ssl-color);}.mp-result table.mp-client-timings .t-request div{background:var(--mp-timing-request-color);}.mp-result table.mp-client-timings .t-response div{background:var(--mp-timing-response-color);}.mp-result table.mp-client-timings .t-dom div{background:var(--mp-timing-dom-color);}.mp-result table.mp-client-timings .t-domcontent div{background:var(--mp-timing-domcontent-color);}.mp-result table.mp-client-timings .t-load div{background:var(--mp-timing-load-color);}.mp-result table.mp-client-timings .t-paint div{background:var(--mp-timing-paint-color);}.mp-result .mp-debug{position:relative;cursor:pointer;}.mp-result .mp-debug .mp-debug-tooltip{display:none;position:fixed;background-color:var(--mp-main-bg-color);box-shadow:var(--mp-popup-shadow);right:100px;max-width:90%;border-radius:9px;padding:12px;margin-top:18px;opacity:.95;backdrop-filter:blur(4px);}.mp-result .mp-debug .mp-nested-timing{margin-left:16px;}.mp-result .mp-debug td:first-child:hover .mp-debug-tooltip{display:block;}.mp-result .mp-debug td:first-child:hover>span{text-shadow:var(--mp-button-active-text-color) 0 0 4px;}.mp-result .mp-stack-trace{color:var(--mp-muted-color);margin-bottom:5px;font-family:Consolas,Monaco,monospace;overflow-x:hidden;overflow-y:auto;white-space:pre-line;max-height:200px;}.mp-result .mp-stack-trace .stack-row{white-space:nowrap;}.mp-result .mp-stack-trace .stack-row.common{filter:grayscale(80%);}.mp-result .mp-stack-trace .stack.async{opacity:.6;display:none;}.mp-result .mp-stack-trace .stack.leadin,.mp-result .mp-stack-trace .stack.file,.mp-result .mp-stack-trace .stack.line-prefix,.mp-result .mp-stack-trace .stack.path,.mp-result .mp-stack-trace .stack.dot{color:var(--mp-muted-color);}.mp-result .mp-stack-trace .stack.async-tag{color:var(--mp-highlight-attribute-color);font-weight:bold;}.mp-result .mp-stack-trace .stack.async-tag:before{content:"(";}.mp-result .mp-stack-trace .stack.async-tag:after{content:")";}.mp-result .mp-stack-trace .stack.type{color:var(--mp-highlight-keyword-color);}.mp-result .mp-stack-trace .stack.generic-type{color:var(--mp-highlight-fade-color);}.mp-result .mp-stack-trace .stack.misc,.mp-result .mp-stack-trace .stack.parens{color:var(--mp-highlight-comment-color);}.mp-result .mp-stack-trace .stack.method{color:var(--mp-highlight-string-color);}.mp-result .mp-stack-trace .stack.paramType{color:var(--mp-highlight-attribute-color);}.mp-result .mp-stack-trace .stack.paramName{color:var(--mp-highlight-variable-color);}.mp-result .mp-label{color:var(--mp-label-color);overflow:hidden;text-overflow:ellipsis;}.mp-result .mp-unit{color:var(--mp-muted-color);}.mp-result .mp-more-columns{display:none;}.mp-result .mp-trivial{display:none;}.mp-result .mp-trivial td:not(:first-child),.mp-result .mp-trivial td:not(:first-child) *{color:var(--mp-muted-color) !important;}.mp-result .mp-number{color:var(--mp-duration-color);}.mp-result .mp-info>div{white-space:nowrap;overflow:hidden;}.mp-result .mp-info>div>div{display:inline-block;}.mp-result .mp-info .mp-name{display:inline-block;font-weight:bold;float:left;}.mp-result .mp-info .mp-machine-name,.mp-result .mp-info .mp-started{text-align:right;float:right;}.mp-result .mp-info .mp-server-time{white-space:nowrap;}.mp-result .mp-timings th{background-color:var(--mp-main-bg-color);color:var(--mp-muted-color);text-align:right;}.mp-result .mp-timings th,.mp-result .mp-timings td{white-space:nowrap;}.mp-result .mp-timings .mp-show-more{display:none;}.mp-result .mp-timings .mp-duration{font-family:Consolas,monospace,serif;color:var(--mp-duration-color);text-align:right;}.mp-result .mp-timings .mp-indent{letter-spacing:4px;}.mp-result .mp-timings .mp-queries-show .mp-number,.mp-result .mp-timings .mp-queries-show .mp-unit{color:var(--mp-link-color);}.mp-result .mp-timings .mp-queries-show.mp-queries-warning{color:var(--mp-warning-color);font-weight:bold;}.mp-result .mp-timings .mp-queries-duration{padding-left:6px;}.mp-result .mp-timings:not(.mp-client-timings) .mp-trivial:first-child{display:table-row;}.mp-result .mp-custom-timing-overview{float:right;margin:10px 0;width:auto;}.mp-result .mp-custom-timing-overview td{white-space:nowrap;text-align:right;}.mp-result .mp-custom-timing-overview td:last-child{padding-left:8px;}.mp-result .mp-links{margin-top:10px;clear:both;}.mp-result .mp-links span{float:right;}.mp-result .mp-links a{font-size:95%;margin-left:12px;}.mp-result .mp-links a:first-child{margin-left:0;}.mp-warning{color:var(--mp-critical-color);}@keyframes mp-fadeIn{from{background-color:var(--mp-highlight-fade-color);}to{background-color:none;}}.mp-overlay{z-index:2147483642;}.mp-overlay .mp-overlay-bg{z-index:2147483643;background:var(--mp-overlay-bg-color);opacity:.5;top:0;left:0;min-width:100%;position:fixed;height:calc(100%);}.mp-overlay .mp-queries{display:block;z-index:2147483644;top:25px;left:25px;right:25px;position:fixed;max-height:calc(100vh - 50px);background-color:var(--mp-main-bg-color);border-radius:2px;overflow-y:auto;overflow-x:auto;}.mp-queries{font-family:sans-serif;}.mp-queries pre{white-space:pre-wrap;}.mp-queries div{text-align:left;}.mp-queries table{table-layout:fixed;}.mp-queries td,.mp-queries th{padding:8px;border-bottom:solid 1px var(--mp-query-border-color);}.mp-queries td:first-child,.mp-queries th:first-child{width:250px;text-align:right;}.mp-queries td:first-child div,.mp-queries th:first-child div{text-align:right;margin-bottom:5px;word-break:break-word;}.mp-queries td:last-child,.mp-queries th:last-child{text-align:left;padding-right:15px;}.mp-queries .highlight{animation:mp-fadeIn 2s 1;}.mp-queries .mp-odd{background-color:var(--mp-alt-row-color);}.mp-queries .mp-since-start,.mp-queries .mp-duration{text-align:right;}.mp-queries.show-trivial .mp-gap-info.mp-trivial-gap{display:table-row;}.mp-queries .mp-gap-info{background-color:var(--mp-gap-bg-color);opacity:.8;color:var(--mp-gap-font-color);}.mp-queries .mp-gap-info .query{word-break:break-all;}.mp-queries .mp-gap-info .mp-unit{color:var(--mp-muted-color);}.mp-queries .mp-gap-info.mp-trivial-gap{display:none;}.mp-queries .mp-trivial-gap-container{text-align:center;margin:8px 0;}.mp-queries .mp-call-type{font-weight:bold;}.mp-queries .hljs{display:block;overflow-x:auto;padding:.5em;}.mp-queries .hljs,.mp-queries .hljs-subst{color:var(--mp-highlight-default-color);}.mp-queries .hljs-string,.mp-queries .hljs-meta,.mp-queries .hljs-symbol,.mp-queries .hljs-template-tag,.mp-queries .hljs-template-variable,.mp-queries .hljs-addition{color:var(--mp-highlight-string-color);}.mp-queries .hljs-comment,.mp-queries .hljs-quote{color:var(--mp-highlight-comment-color);}.mp-queries .hljs-number,.mp-queries .hljs-regexp,.mp-queries .hljs-literal,.mp-queries .hljs-bullet,.mp-queries .hljs-link{color:var(--mp-highlight-literal-color);}.mp-queries .hljs-deletion,.mp-queries .hljs-variable{color:var(--mp-highlight-variable-color);}.mp-queries .hljs-keyword,.mp-queries .hljs-selector-tag,.mp-queries .hljs-title,.mp-queries .hljs-section,.mp-queries .hljs-built_in,.mp-queries .hljs-doctag,.mp-queries .hljs-type,.mp-queries .hljs-tag,.mp-queries .hljs-name,.mp-queries .hljs-selector-id,.mp-queries .hljs-selector-class,.mp-queries .hljs-strong{color:var(--mp-highlight-keyword-color);}.mp-queries .hljs-emphasis{font-style:italic;}.mp-queries .hljs-attribute{color:var(--mp-highlight-attribute-color);}.mp-results{z-index:2147483641;position:fixed;top:0;}.mp-results.mp-left,.mp-results.mp-bottomleft{left:0;}.mp-results.mp-left .mp-controls,.mp-results.mp-left.mp-no-controls .mp-result:last-child .mp-button{border-bottom-right-radius:var(--mp-result-border-radius);}.mp-results.mp-left .mp-button,.mp-results.mp-left .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-right{right:0;}.mp-results.mp-right .mp-controls,.mp-results.mp-right.mp-no-controls .mp-result:last-child .mp-button{border-bottom-left-radius:var(--mp-result-border-radius);}.mp-results.mp-right .mp-button,.mp-results.mp-right .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomleft{top:inherit;bottom:0;}.mp-results.mp-bottomleft .mp-result:first-child .mp-button{border-top-right-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomleft .mp-button,.mp-results.mp-bottomleft .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-bottomleft .mp-result .mp-button,.mp-results.mp-bottomleft .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results.mp-bottomright{top:inherit;bottom:0;right:0;}.mp-results.mp-bottomright .mp-result:first-child .mp-button{border-top-left-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomright .mp-button,.mp-results.mp-bottomright .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomright .mp-result .mp-button,.mp-results.mp-bottomright .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results .mp-button{user-select:none;}.mp-results .mp-button.mp-button-warning{font-weight:bold;background-color:var(--mp-button-warning-bg-color);color:var(--mp-button-warning-text-color);}.mp-results .mp-button.mp-button-warning .mp-number,.mp-results .mp-button.mp-button-warning .mp-unit,.mp-results .mp-button.mp-button-warning .mp-warning{color:var(--mp-button-warning-text-color);}.mp-results .mp-button .mp-warning{font-weight:bold;}.mp-results .mp-button>.mp-number{font-family:Consolas,monospace,serif;}.mp-results .mp-controls{display:none;}.mp-results .mp-button,.mp-results .mp-controls{z-index:2147483640;border-bottom:var(--mp-result-border);background-color:var(--mp-main-bg-color);padding:4px 8px;text-align:right;cursor:pointer;}.mp-results .mp-result{position:relative;}.mp-results .mp-result.active .mp-button{background-color:var(--mp-button-active-bg-color);animation:none;border-radius:0 !important;}.mp-results .mp-result.active .mp-button.mp-button-warning{background-color:var(--mp-button-warning-bg-color);}.mp-results .mp-result.active .mp-button .mp-number,.mp-results .mp-result.active .mp-button .mp-warning{color:var(--mp-button-active-text-color);font-weight:bold;}.mp-results .mp-result.active .mp-button .mp-unit{color:var(--mp-button-active-text-color);font-weight:normal;}.mp-results .mp-result.active .mp-popup{display:block;}.mp-results.new .mp-button{animation:mp-fadeIn 2s 1;}.mp-results .mp-controls{display:block;font-size:12px;font-family:Consolas,monospace,serif;cursor:default;text-align:center;}.mp-results .mp-controls span{color:var(--mp-muted-color);border-right:1px solid var(--mp-muted-color);padding-right:5px;margin-right:5px;cursor:pointer;}.mp-results .mp-controls span:last-child{border-right:none;}.mp-results .mp-popup{display:none;z-index:2147483641;position:absolute;background-color:var(--mp-main-bg-color);padding:5px 10px;text-align:left;line-height:18px;overflow:auto;box-shadow:var(--mp-popup-shadow);border-radius:2px;}.mp-results .mp-popup .mp-info{margin-bottom:3px;padding-bottom:2px;border-bottom:1px solid var(--mp-info-border-color);}.mp-results .mp-popup .mp-info .mp-name{font-size:1.1em;}.mp-results .mp-popup .mp-info .mp-overall-duration{color:var(--mp-muted-color);}.mp-results .mp-popup .mp-timings th,.mp-results .mp-popup .mp-timings td{padding:0 6px;}.mp-results .mp-popup .mp-timings th{font-size:95%;padding-bottom:3px;}.mp-results .mp-popup .mp-timings .mp-label{max-width:350px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;}.mp-results .mp-queries{display:none;}.mp-results.mp-min .mp-result{display:none;}.mp-results.mp-min .mp-controls span{display:none;}.mp-results.mp-min .mp-controls .mp-min-max{border-right:none;padding:0;margin:0;}.mp-results.mp-min:hover .mp-controls .mp-min-max{display:inline;}.mp-result-full .mp-result{width:950px;margin:25px auto;}.mp-result-full .mp-result .mp-button{display:none;}.mp-result-full .mp-result .mp-popup .mp-info{font-size:18px;border-bottom:1px solid var(--mp-muted-color);padding-bottom:3px;margin-bottom:10px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-name{margin-bottom:5px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration,.mp-result-full .mp-result .mp-popup .mp-info .mp-started{font-size:80%;color:var(--mp-muted-color);}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration{padding-right:20px;}.mp-result-full .mp-result .mp-popup .mp-timings td,.mp-result-full .mp-result .mp-popup .mp-timings th{font-size:13px;padding-left:8px;padding-right:8px;}.mp-result-full .mp-result .mp-popup .mp-timings th{padding-bottom:7px;}.mp-result-full .mp-result .mp-popup .mp-timings td{padding-bottom:4px;}.mp-result-full .mp-result .mp-popup .mp-timings td:first-child{padding-left:10px;}.mp-result-full .mp-result .mp-popup .mp-timings .mp-label{max-width:550px;}.mp-result-full .mp-result .mp-queries{margin:20px 0;}.mp-result-full .mp-result .mp-queries th{font-size:16px;}.mp-result-full .mp-share-mp-results{display:none;}table.mp-results-index{border:0;border-spacing:0;font-size:12px;font-family:Arial;}table.mp-results-index a{color:var(--mp-link-color);text-decoration:none;}table.mp-results-index tbody{color:var(--mp-label-color);}table.mp-results-index tbody tr:nth-child(odd){background-color:var(--mp-alt-row-color);}table.mp-results-index tbody tr:nth-child(even){background-color:var(--mp-main-bg-color);}table.mp-results-index tbody td{text-align:center;}table.mp-results-index tbody td:first-child{text-align:left;}table.mp-results-index tbody td[colspan="3"]{color:var(--mp-muted-color);}table.mp-results-index thead tr{color:var(--mp-label-color);}table.mp-results-index thead tr th{padding:5px 15px;}table.mp-results-index td{padding:8px;} \ No newline at end of file From 45b31cfcb73852bce982bba8506a9bada1239178 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sun, 24 May 2020 18:25:40 -0400 Subject: [PATCH 05/13] The the problem! This sets the parent profiler to where it should be when adding a new timing, even in the case of stack unwinds further up which hide our understanding of a previous head reset further down due to an AsyncLocal mismatch on the head. Now as a safety we roll up to the parent and get the right tree even with MVCs frame-saving shenanigans. Woohoo! Good god that was hard to figure out. --- .../Controllers/HomeController.cs | 8 +- .../MvcDiagnosticListener.cs | 154 ++++++++++++------ .../MiniProfilerOptions.cs | 13 +- src/MiniProfiler.Shared/Timing.cs | 6 + 4 files changed, 120 insertions(+), 61 deletions(-) diff --git a/samples/Samples.AspNetCore3/Controllers/HomeController.cs b/samples/Samples.AspNetCore3/Controllers/HomeController.cs index 7df90852e..ce49a9edc 100644 --- a/samples/Samples.AspNetCore3/Controllers/HomeController.cs +++ b/samples/Samples.AspNetCore3/Controllers/HomeController.cs @@ -3,16 +3,12 @@ namespace Samples.AspNetCore.Controllers { + [ExampleActionFilter] public class HomeController : Controller { - [ExampleActionFilter] [ExampleLongActionFilter] - [ExampleActionFilter] - [ExampleActionFilter] - [ExampleActionFilter] + //[ExampleActionFilter] [ExampleAsyncActionFilter] - [ExampleAsyncActionFilter] - [ExampleActionFilter] public IActionResult Index() { using (MiniProfiler.Current.Step("Example Step")) diff --git a/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs b/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs index e79c7acf6..d616d027b 100644 --- a/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs +++ b/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs @@ -1,4 +1,5 @@ #if NETCOREAPP3_0 +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Diagnostics; @@ -8,7 +9,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; -using System.Threading; +using System.Linq; namespace StackExchange.Profiling.Data { @@ -75,33 +76,80 @@ private string GetName(string label, ActionDescriptor descriptor) private static string GetName(IFilterMetadata filter) => filter.GetType().Name; + private const string ContextItemsKey = "MiniProfiler-DiagnosticStack"; /// - /// Stores the current timing in the tree, on each request. + /// Gets the timing stack for a given request. /// - private readonly AsyncLocal<(object State, Timing Timing)> CurrentTiming = new AsyncLocal<(object, Timing)>(); + private Stack<(object State, Timing Timing)> GetStack(HttpContext context) + { + if (context == null) + { + return null; + } + if (context?.Items[ContextItemsKey] is Stack<(object State, Timing Timing)> stack) + { + return stack; + } + stack = new Stack<(object State, Timing Timing)>(); + context.Items[ContextItemsKey] = stack; + return stack; + } - private object Start(T state, string stepName) where T : class + private object StartFilter(FilterContext context, T state, string stepName) where T : class { var profiler = MiniProfiler.Current; - CurrentTiming.Value = (state, profiler != null ? new Timing(profiler, profiler.Head, stepName, null, null, debugStackShave: 4) : null); + if (profiler?.Options is MiniProfilerOptions opts && opts.EnableMvcFilterProfiling) + { + var stack = GetStack(context.HttpContext); + Debug.WriteLine(new string(' ', stack.Count * 2) + "Start (" + state.GetType().Name + "): " + stepName); + stack.Push((state, new Timing(profiler, profiler.Head, stepName, opts.MvcFilterMinimumSaveMs, true, debugStackShave: 4))); + } return null; } - private object StartFilter(T state, string stepName) where T : class + private object StartView(HttpContext context, T state, string stepName) where T : class { var profiler = MiniProfiler.Current; - if (profiler?.Options is MiniProfilerOptions opts && opts.EnableMvcFilterProfiling) + if (profiler?.Options is MiniProfilerOptions opts && opts.EnableMvcViewProfiling) { - CurrentTiming.Value = (state, new Timing(profiler, profiler.Head, stepName, opts.MvcFilterMinimumSaveMs ?? 0, true, debugStackShave: 4)); + var stack = GetStack(context); + Debug.WriteLine(new string(' ', stack.Count * 2) + "Start (" + state.GetType().Name + "): " + stepName); + stack.Push((state, new Timing(profiler, profiler.Head, stepName, opts.MvcViewMinimumSaveMs, true, debugStackShave: 4))); } return null; } - private object Complete(T state) where T : class + private object Start(HttpContext context, T state, string stepName) where T : class { - if (CurrentTiming.Value.State is T currentState && currentState == state) + var profiler = MiniProfiler.Current; + var stack = GetStack(context); + Debug.WriteLine(new string(' ', stack.Count * 2) + "Start (" + state.GetType().Name + "): " + stepName); + stack.Push((state, profiler != null ? new Timing(profiler, profiler.Head, stepName, null, null, debugStackShave: 4) : null)); + return null; + } + + private object Complete(FilterContext context, T state) where T : class => Complete(context.HttpContext, state); + + private object Complete(HttpContext context, T state) where T : class + { + var stack = GetStack(context); + var top = stack.Pop(); + if (top.State is T currentState) + { + if (currentState == state) + { + Debug.WriteLine(new string(' ', stack.Count*2) + "End (" + state.GetType().Name + "): " + state.ToString()); + // Set the previous timing explicitly to the stack parent for this context + using (top.Timing) { } + } + else + { + Debug.WriteLine(new string(' ', stack.Count * 2) + "End mismatch on (" + currentState.GetType().ToString() + " vs. " + state.GetType().ToString() + "): " + state.ToString()); + } + } + else { - using (CurrentTiming.Value.Timing) { } + Debug.WriteLine(new string(' ', stack.Count * 2) + "End no current state: " + state.ToString()); } return null; } @@ -114,79 +162,79 @@ private string GetName(string label, ActionDescriptor descriptor) { // MVC Bits: https://github.com/dotnet/aspnetcore/blob/v3.0.0/src/Mvc/Mvc.Core/src/Diagnostics/MvcDiagnostics.cs // ActionEvent - BeforeActionEventData data => Start(data.ActionDescriptor, GetName("Action", data.ActionDescriptor)), - AfterActionEventData data => Complete(data.ActionDescriptor), + BeforeActionEventData data => Start(data.HttpContext, data.ActionDescriptor, GetName("Action", data.ActionDescriptor)), + AfterActionEventData data => Complete(data.HttpContext, data.ActionDescriptor), // ControllerActionMethod - BeforeControllerActionMethodEventData data => Start(data.ActionContext.ActionDescriptor, GetName("Controller Action", data.ActionContext.ActionDescriptor)), - AfterControllerActionMethodEventData data => Complete(data.ActionContext.ActionDescriptor), + BeforeControllerActionMethodEventData data => Start(data.ActionContext.HttpContext, data.ActionContext.ActionDescriptor, GetName("Controller Action", data.ActionContext.ActionDescriptor)), + AfterControllerActionMethodEventData data => Complete(data.ActionContext.HttpContext, data.ActionContext.ActionDescriptor), // ActionResultEvent - BeforeActionResultEventData data => Start(data.Result, GetName(data.Result)), - AfterActionResultEventData data => Complete(data.Result), + BeforeActionResultEventData data => Start(data.ActionContext.HttpContext, data.Result, GetName(data.Result)), + AfterActionResultEventData data => Complete(data.ActionContext.HttpContext, data.Result), // AuthorizationFilterOnAuthorization - BeforeAuthorizationFilterOnAuthorizationEventData data => StartFilter(data.Filter, "Auth Filter: " + GetName(data.Filter)), - AfterAuthorizationFilterOnAuthorizationEventData data => Complete(data.Filter), + BeforeAuthorizationFilterOnAuthorizationEventData data => StartFilter(data.AuthorizationContext, data.Filter, "Auth Filter: " + GetName(data.Filter)), + AfterAuthorizationFilterOnAuthorizationEventData data => Complete(data.AuthorizationContext.HttpContext, data.Filter), // ResourceFilterOnResourceExecution - BeforeResourceFilterOnResourceExecutionEventData data => StartFilter(data.Filter, "Resource Filter (Exec): " + GetName(data.Filter)), - AfterResourceFilterOnResourceExecutionEventData data => Complete(data.Filter), + BeforeResourceFilterOnResourceExecutionEventData data => StartFilter(data.ResourceExecutingContext, data.Filter, "Resource Filter (Exec): " + GetName(data.Filter)), + AfterResourceFilterOnResourceExecutionEventData data => Complete(data.ResourceExecutedContext.HttpContext, data.Filter), // ResourceFilterOnResourceExecuting - BeforeResourceFilterOnResourceExecutingEventData data => StartFilter(data.Filter, "Resource Filter (Execing): " + GetName(data.Filter)), - AfterResourceFilterOnResourceExecutingEventData data => Complete(data.Filter), + BeforeResourceFilterOnResourceExecutingEventData data => StartFilter(data.ResourceExecutingContext, data.Filter, "Resource Filter (Execing): " + GetName(data.Filter)), + AfterResourceFilterOnResourceExecutingEventData data => Complete(data.ResourceExecutingContext.HttpContext, data.Filter), // ResourceFilterOnResourceExecuted - BeforeResourceFilterOnResourceExecutedEventData data => StartFilter(data.Filter, "Resource Filter (Execed): " + GetName(data.Filter)), - AfterResourceFilterOnResourceExecutedEventData data => Complete(data.Filter), + BeforeResourceFilterOnResourceExecutedEventData data => StartFilter(data.ResourceExecutedContext, data.Filter, "Resource Filter (Execed): " + GetName(data.Filter)), + AfterResourceFilterOnResourceExecutedEventData data => Complete(data.ResourceExecutedContext, data.Filter), // ExceptionFilterOnException - BeforeExceptionFilterOnException data => StartFilter(data.Filter, "Exception Filter: " + GetName(data.Filter)), - AfterExceptionFilterOnExceptionEventData data => Complete(data.Filter), + BeforeExceptionFilterOnException data => StartFilter(data.ExceptionContext, data.Filter, "Exception Filter: " + GetName(data.Filter)), + AfterExceptionFilterOnExceptionEventData data => Complete(data.ExceptionContext, data.Filter), // ActionFilterOnActionExecution - BeforeActionFilterOnActionExecutionEventData data => StartFilter(data.Filter, "Action Filter (Exec): " + GetName(data.Filter)), - AfterActionFilterOnActionExecutionEventData data => Complete(data.Filter), + BeforeActionFilterOnActionExecutionEventData data => StartFilter(data.ActionExecutingContext, data.Filter, "Action Filter (Exec): " + GetName(data.Filter)), + AfterActionFilterOnActionExecutionEventData data => Complete(data.ActionExecutedContext, data.Filter), // ActionFilterOnActionExecuting - BeforeActionFilterOnActionExecutingEventData data => StartFilter(data.Filter, "Action Filter (Execing): " + GetName(data.Filter)), - AfterActionFilterOnActionExecutingEventData data => Complete(data.Filter), + BeforeActionFilterOnActionExecutingEventData data => StartFilter(data.ActionExecutingContext, data.Filter, "Action Filter (Execing): " + GetName(data.Filter)), + AfterActionFilterOnActionExecutingEventData data => Complete(data.ActionExecutingContext, data.Filter), // ActionFilterOnActionExecuted - BeforeActionFilterOnActionExecutedEventData data => StartFilter(data.Filter, "Action Filter (Execed): " + GetName(data.Filter)), - AfterActionFilterOnActionExecutedEventData data => Complete(data.Filter), + BeforeActionFilterOnActionExecutedEventData data => StartFilter(data.ActionExecutedContext, data.Filter, "Action Filter (Execed): " + GetName(data.Filter)), + AfterActionFilterOnActionExecutedEventData data => Complete(data.ActionExecutedContext, data.Filter), // ResultFilterOnResultExecution - BeforeResultFilterOnResultExecutionEventData data => StartFilter(data.Filter, "Result Filter (Exec): " + GetName(data.Filter)), - AfterResultFilterOnResultExecutionEventData data => Complete(data.Filter), + BeforeResultFilterOnResultExecutionEventData data => StartFilter(data.ResultExecutingContext, data.Filter, "Result Filter (Exec): " + GetName(data.Filter)), + AfterResultFilterOnResultExecutionEventData data => Complete(data.ResultExecutedContext, data.Filter), // ResultFilterOnResultExecuting - BeforeResultFilterOnResultExecutingEventData data => StartFilter(data.Filter, "Result Filter (Execing): " + GetName(data.Filter)), - AfterResultFilterOnResultExecutingEventData data => Complete(data.Filter), + BeforeResultFilterOnResultExecutingEventData data => StartFilter(data.ResultExecutingContext, data.Filter, "Result Filter (Execing): " + GetName(data.Filter)), + AfterResultFilterOnResultExecutingEventData data => Complete(data.ResultExecutingContext, data.Filter), // ResultFilterOnResultExecuted - BeforeResultFilterOnResultExecutedEventData data => StartFilter(data.Filter, "Result Filter (Execed): " + GetName(data.Filter)), - AfterResultFilterOnResultExecutedEventData data => Complete(data.Filter), + BeforeResultFilterOnResultExecutedEventData data => StartFilter(data.ResultExecutedContext, data.Filter, "Result Filter (Execed): " + GetName(data.Filter)), + AfterResultFilterOnResultExecutedEventData data => Complete(data.ResultExecutedContext, data.Filter), // Razor Bits: https://github.com/dotnet/aspnetcore/blob/v3.0.0/src/Mvc/Mvc.Razor/src/Diagnostics/MvcDiagnostics.cs // ViewPage - BeforeViewPageEventData data => Start(data.Page, "View: " + data.Page.Path), - AfterViewPageEventData data => Complete(data.Page), + BeforeViewPageEventData data => StartView(data.HttpContext, data.Page, "View: " + data.Page.Path), + AfterViewPageEventData data => Complete(data.HttpContext, data.Page), // RazorPage Bits: https://github.com/dotnet/aspnetcore/blob/v3.0.0/src/Mvc/Mvc.RazorPages/src/Diagnostics/MvcDiagnostics.cs // HandlerMethod - BeforeHandlerMethodEventData data => Start(data.Instance, "Handler: " + data.HandlerMethodDescriptor.Name), - AfterHandlerMethodEventData data => Complete(data.Instance), + BeforeHandlerMethodEventData data => Start(data.ActionContext.HttpContext, data.Instance, "Handler: " + data.HandlerMethodDescriptor.Name), + AfterHandlerMethodEventData data => Complete(data.ActionContext.HttpContext, data.Instance), // PageFilterOnPageHandlerExecution - BeforePageFilterOnPageHandlerExecutionEventData data => StartFilter(data.Filter, "Filter (Exec): " + GetName(data.Filter)), - AfterPageFilterOnPageHandlerExecutionEventData data => Complete(data.Filter), + BeforePageFilterOnPageHandlerExecutionEventData data => StartFilter(data.HandlerExecutionContext, data.Filter, "Filter (Exec): " + GetName(data.Filter)), + AfterPageFilterOnPageHandlerExecutionEventData data => Complete(data.HandlerExecutedContext, data.Filter), // PageFilterOnPageHandlerExecuting - BeforePageFilterOnPageHandlerExecutingEventData data => StartFilter(data.Filter, "Filter (Execing): " + GetName(data.Filter)), - AfterPageFilterOnPageHandlerExecutingEventData data => Complete(data.Filter), + BeforePageFilterOnPageHandlerExecutingEventData data => StartFilter(data.HandlerExecutingContext, data.Filter, "Filter (Execing): " + GetName(data.Filter)), + AfterPageFilterOnPageHandlerExecutingEventData data => Complete(data.HandlerExecutingContext, data.Filter), // PageFilterOnPageHandlerExecuted - BeforePageFilterOnPageHandlerExecutedEventData data => StartFilter(data.Filter, "Filter (Execed): " + GetName(data.Filter)), - AfterPageFilterOnPageHandlerExecutedEventData data => Complete(data.Filter), + BeforePageFilterOnPageHandlerExecutedEventData data => StartFilter(data.HandlerExecutedContext, data.Filter, "Filter (Execed): " + GetName(data.Filter)), + AfterPageFilterOnPageHandlerExecutedEventData data => Complete(data.HandlerExecutedContext, data.Filter), // PageFilterOnPageHandlerSelection - BeforePageFilterOnPageHandlerSelectionEventData data => StartFilter(data.Filter, "Filter (Selection): " + GetName(data.Filter)), - AfterPageFilterOnPageHandlerSelectionEventData data => Complete(data.Filter), + BeforePageFilterOnPageHandlerSelectionEventData data => StartFilter(data.HandlerSelectedContext, data.Filter, "Filter (Selection): " + GetName(data.Filter)), + AfterPageFilterOnPageHandlerSelectionEventData data => Complete(data.HandlerSelectedContext, data.Filter), // PageFilterOnPageHandlerSelected - BeforePageFilterOnPageHandlerSelectedEventData data => StartFilter(data.Filter, "Filter (Selected): " + GetName(data.Filter)), - AfterPageFilterOnPageHandlerSelectedEventData data => Complete(data.Filter), + BeforePageFilterOnPageHandlerSelectedEventData data => StartFilter(data.HandlerSelectedContext, data.Filter, "Filter (Selected): " + GetName(data.Filter)), + AfterPageFilterOnPageHandlerSelectedEventData data => Complete(data.HandlerSelectedContext, data.Filter), _ => null }; } diff --git a/src/MiniProfiler.AspNetCore/MiniProfilerOptions.cs b/src/MiniProfiler.AspNetCore/MiniProfilerOptions.cs index 98b171fb8..71dc1d2d3 100644 --- a/src/MiniProfiler.AspNetCore/MiniProfilerOptions.cs +++ b/src/MiniProfiler.AspNetCore/MiniProfilerOptions.cs @@ -68,9 +68,18 @@ public class MiniProfilerOptions : MiniProfilerBaseOptions /// /// The minimum duration to record for MVC filter timings, anything below this will be discarded as noise. - /// Defaults to 0.01 ms /// - public decimal? MvcFilterMinimumSaveMs { get; set; } = -1000.01m; + public decimal? MvcFilterMinimumSaveMs { get; set; } + + /// + /// Whether to profile MVC views as individual steps. + /// + public bool EnableMvcViewProfiling { get; set; } = true; + + /// + /// The minimum duration to record for MVC view timings, anything below this will be discarded as noise. + /// + public decimal? MvcViewMinimumSaveMs { get; set; } #endif } } diff --git a/src/MiniProfiler.Shared/Timing.cs b/src/MiniProfiler.Shared/Timing.cs index 3dc81aefa..eeaae9192 100644 --- a/src/MiniProfiler.Shared/Timing.cs +++ b/src/MiniProfiler.Shared/Timing.cs @@ -55,6 +55,12 @@ public Timing(MiniProfiler profiler, Timing parent, string name, decimal? minSav Profiler.Head = this; // root will have no parent + // Also, due to stack unwinding for minimal frame depth in MVC and such, we may need to traverse up when the + // AsyncLocal head is not reset properly in the context we expect (it was reset lower down) + while (parent?.DurationMilliseconds.HasValue == true) + { + parent = parent.ParentTiming; + } parent?.AddChild(this); Name = name; From 5ab1bf9342d0e3186224985e325e71b8987c0262 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sun, 24 May 2020 18:35:54 -0400 Subject: [PATCH 06/13] Remove Debug overhead shenanigans. --- .../MvcDiagnosticListener.cs | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs b/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs index d616d027b..77c092307 100644 --- a/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs +++ b/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs @@ -9,7 +9,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; namespace StackExchange.Profiling.Data { @@ -100,9 +99,7 @@ private Stack<(object State, Timing Timing)> GetStack(HttpContext context) var profiler = MiniProfiler.Current; if (profiler?.Options is MiniProfilerOptions opts && opts.EnableMvcFilterProfiling) { - var stack = GetStack(context.HttpContext); - Debug.WriteLine(new string(' ', stack.Count * 2) + "Start (" + state.GetType().Name + "): " + stepName); - stack.Push((state, new Timing(profiler, profiler.Head, stepName, opts.MvcFilterMinimumSaveMs, true, debugStackShave: 4))); + GetStack(context.HttpContext).Push((state, new Timing(profiler, profiler.Head, stepName, opts.MvcFilterMinimumSaveMs, true, debugStackShave: 4))); } return null; } @@ -112,9 +109,7 @@ private Stack<(object State, Timing Timing)> GetStack(HttpContext context) var profiler = MiniProfiler.Current; if (profiler?.Options is MiniProfilerOptions opts && opts.EnableMvcViewProfiling) { - var stack = GetStack(context); - Debug.WriteLine(new string(' ', stack.Count * 2) + "Start (" + state.GetType().Name + "): " + stepName); - stack.Push((state, new Timing(profiler, profiler.Head, stepName, opts.MvcViewMinimumSaveMs, true, debugStackShave: 4))); + GetStack(context).Push((state, new Timing(profiler, profiler.Head, stepName, opts.MvcViewMinimumSaveMs, true, debugStackShave: 4))); } return null; } @@ -122,9 +117,7 @@ private Stack<(object State, Timing Timing)> GetStack(HttpContext context) private object Start(HttpContext context, T state, string stepName) where T : class { var profiler = MiniProfiler.Current; - var stack = GetStack(context); - Debug.WriteLine(new string(' ', stack.Count * 2) + "Start (" + state.GetType().Name + "): " + stepName); - stack.Push((state, profiler != null ? new Timing(profiler, profiler.Head, stepName, null, null, debugStackShave: 4) : null)); + GetStack(context).Push((state, profiler != null ? new Timing(profiler, profiler.Head, stepName, null, null, debugStackShave: 4) : null)); return null; } @@ -134,22 +127,10 @@ private Stack<(object State, Timing Timing)> GetStack(HttpContext context) { var stack = GetStack(context); var top = stack.Pop(); - if (top.State is T currentState) - { - if (currentState == state) - { - Debug.WriteLine(new string(' ', stack.Count*2) + "End (" + state.GetType().Name + "): " + state.ToString()); - // Set the previous timing explicitly to the stack parent for this context - using (top.Timing) { } - } - else - { - Debug.WriteLine(new string(' ', stack.Count * 2) + "End mismatch on (" + currentState.GetType().ToString() + " vs. " + state.GetType().ToString() + "): " + state.ToString()); - } - } - else + if (top.State is T currentState && currentState == state) { - Debug.WriteLine(new string(' ', stack.Count * 2) + "End no current state: " + state.ToString()); + // Set the previous timing explicitly to the stack parent for this context + using (top.Timing) { } } return null; } From 6715ee6bc60f950e6f51d0fcfbd7666c7baa3e68 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sun, 24 May 2020 19:25:12 -0400 Subject: [PATCH 07/13] Fix debug off TypeScript --- src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts index 5a9ffce56..bec8e43fe 100644 --- a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts +++ b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts @@ -709,6 +709,7 @@ namespace StackExchange.Profiling { 🔍`; } + return ''; }; const renderTiming = (timing: ITiming) => { From 23a8f95eefc00e0c4a542ce0b91f818354447f57 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sun, 24 May 2020 19:25:18 -0400 Subject: [PATCH 08/13] Doc updates --- docs/AspDotNetCore.md | 21 +++++++++++++++++++++ samples/Samples.AspNetCore3/Startup.cs | 16 +++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/docs/AspDotNetCore.md b/docs/AspDotNetCore.md index e3b3d964a..334f3b9b0 100644 --- a/docs/AspDotNetCore.md +++ b/docs/AspDotNetCore.md @@ -64,6 +64,27 @@ public void ConfigureServices(IServiceCollection services) // (Optional) Use something other than the "light" color scheme. // (defaults to "light") options.ColorScheme = StackExchange.Profiling.ColorScheme.Auto; + + // The below are newer options, available in .NET Core 3.0 and above: + + // (Optional) You can disable MVC filter profiling + // (defaults to true, and filters are profiled) + options.EnableMvcFilterProfiling = true; + // ...or only save filters that take over a certain millisecond duration (including their children) + // (defaults to null, and all filters are profiled) + // options.MvcFilterMinimumSaveMs = 1.0m; + + // (Optional) You can disable MVC view profiling + // (defaults to true, and views are profiled) + options.EnableMvcFilterProfiling = true; + // ...or only save views that take over a certain millisecond duration (including their children) + // (defaults to null, and all views are profiled) + // options.MvcViewMinimumSaveMs = 1.0m; + + // (Optional - not recommended) You can enable a heavy debug mode with stacks and tooltips when using memory storage + // It has a lot of overhead vs. normal profiling and should only be used with that in mind + // (defaults to false, debug/heavy mode is off) + //options.EnableDebugMode = true; }); } ``` diff --git a/samples/Samples.AspNetCore3/Startup.cs b/samples/Samples.AspNetCore3/Startup.cs index 4bd1a8255..78d5956bc 100644 --- a/samples/Samples.AspNetCore3/Startup.cs +++ b/samples/Samples.AspNetCore3/Startup.cs @@ -82,10 +82,20 @@ public void ConfigureServices(IServiceCollection services) // Enabled sending the Server-Timing header on responses options.EnableServerTimingHeader = true; - options.EnableMvcFilterProfiling = true; - // Alrighty, I'm done screwing around - TIME TO LOG EVERYTHING! ALLOCATIONS BE DAMNED! - options.EnableDebugMode = true; + // Optionally disable MVC filter profiling + // options.EnableMvcFilterProfiling = false; + // Or only save filters that take over a certain millisecond duration (including their children) + // options.MvcFilterMinimumSaveMs = 1.0m; + + // Optionally disable MVC view profiling + // options.EnableMvcFilterProfiling = false; + // Or only save views that take over a certain millisecond duration (including their children) + // options.MvcViewMinimumSaveMs = 1.0m; + + // This enables debug mode with stacks and tooltips when using memory storage + // It has a lot of overhead vs. normal profiling and should only be used with that in mind + //options.EnableDebugMode = true; options.IgnoredPaths.Add("/lib"); options.IgnoredPaths.Add("/css"); From 26eed1cf7882f9adb18a10f86cccc29503bb34b0 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sun, 24 May 2020 19:33:57 -0400 Subject: [PATCH 09/13] Undo some diff, add inlining hints --- src/MiniProfiler.Shared/MiniProfiler.cs | 6 ++++-- src/MiniProfiler.Shared/MiniProfilerExtensions.cs | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/MiniProfiler.Shared/MiniProfiler.cs b/src/MiniProfiler.Shared/MiniProfiler.cs index b815f8c0b..e3f9997d6 100644 --- a/src/MiniProfiler.Shared/MiniProfiler.cs +++ b/src/MiniProfiler.Shared/MiniProfiler.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; @@ -333,9 +334,10 @@ public MiniProfiler Clone() } } - internal Timing StepImpl(string name, decimal? minSaveMs = null, bool? includeChildrenWithMinSave = false, int debugStackShave = 0) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Timing StepImpl(string name, decimal? minSaveMs = null, bool? includeChildrenWithMinSave = false) { - return new Timing(this, Head, name, minSaveMs, includeChildrenWithMinSave, debugStackShave); + return new Timing(this, Head, name, minSaveMs, includeChildrenWithMinSave); } /// diff --git a/src/MiniProfiler.Shared/MiniProfilerExtensions.cs b/src/MiniProfiler.Shared/MiniProfilerExtensions.cs index 12d10f2dc..3cd25d17b 100644 --- a/src/MiniProfiler.Shared/MiniProfilerExtensions.cs +++ b/src/MiniProfiler.Shared/MiniProfilerExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Runtime.CompilerServices; namespace StackExchange.Profiling { @@ -36,7 +37,8 @@ public static T Inline(this MiniProfiler profiler, Func selector, string n /// The current profiling session or null. /// A descriptive name for the code that is encapsulated by the resulting Timing's lifetime. /// the profile step - public static Timing Step(this MiniProfiler profiler, string name) => profiler?.StepImpl(name, debugStackShave: 1); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Timing Step(this MiniProfiler profiler, string name) => profiler?.StepImpl(name); /// /// Returns an () that will time the code between its creation and disposal. @@ -50,9 +52,10 @@ public static T Inline(this MiniProfiler profiler, Func selector, string n /// /// If is set to true and a child is removed due to its use of StepIf, then the /// time spent in that time will also not count for the current StepIf calculation. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Timing StepIf(this MiniProfiler profiler, string name, decimal minSaveMs, bool includeChildren = false) { - return profiler?.StepImpl(name, minSaveMs, includeChildren, debugStackShave: 1); + return profiler?.StepImpl(name, minSaveMs, includeChildren); } /// @@ -67,6 +70,7 @@ public static Timing StepIf(this MiniProfiler profiler, string name, decimal min /// /// Should be used like the extension method /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CustomTiming CustomTiming(this MiniProfiler profiler, string category, string commandString, string executeType = null, bool includeStackTrace = true) { return CustomTimingIf(profiler, category, commandString, 0, executeType: executeType, includeStackTrace: includeStackTrace); From d39dec06cf81698846524310fc2e80ef2bba58fc Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sun, 24 May 2020 19:35:48 -0400 Subject: [PATCH 10/13] Doc tidy --- samples/Samples.AspNetCore3/Startup.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/Samples.AspNetCore3/Startup.cs b/samples/Samples.AspNetCore3/Startup.cs index 78d5956bc..02272ffbb 100644 --- a/samples/Samples.AspNetCore3/Startup.cs +++ b/samples/Samples.AspNetCore3/Startup.cs @@ -84,14 +84,14 @@ public void ConfigureServices(IServiceCollection services) options.EnableServerTimingHeader = true; // Optionally disable MVC filter profiling - // options.EnableMvcFilterProfiling = false; + //options.EnableMvcFilterProfiling = false; // Or only save filters that take over a certain millisecond duration (including their children) - // options.MvcFilterMinimumSaveMs = 1.0m; + //options.MvcFilterMinimumSaveMs = 1.0m; // Optionally disable MVC view profiling - // options.EnableMvcFilterProfiling = false; + //options.EnableMvcFilterProfiling = false; // Or only save views that take over a certain millisecond duration (including their children) - // options.MvcViewMinimumSaveMs = 1.0m; + //options.MvcViewMinimumSaveMs = 1.0m; // This enables debug mode with stacks and tooltips when using memory storage // It has a lot of overhead vs. normal profiling and should only be used with that in mind From f98f39134a8043f18623ee34922bd4f839013392 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sun, 24 May 2020 19:39:51 -0400 Subject: [PATCH 11/13] Fix stack styling (undo removal here) --- src/MiniProfiler.Shared/ui/includes.css | 5 +++++ src/MiniProfiler.Shared/ui/includes.less | 6 ++++++ src/MiniProfiler.Shared/ui/includes.min.css | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/MiniProfiler.Shared/ui/includes.css b/src/MiniProfiler.Shared/ui/includes.css index 1f3e4f87c..3a87fe480 100644 --- a/src/MiniProfiler.Shared/ui/includes.css +++ b/src/MiniProfiler.Shared/ui/includes.css @@ -481,6 +481,11 @@ .mp-queries .mp-odd { background-color: var(--mp-alt-row-color); } +.mp-queries .mp-stack-trace { + padding-bottom: 1px; + color: var(--mp-muted-color); + margin-bottom: 5px; +} .mp-queries .mp-since-start, .mp-queries .mp-duration { text-align: right; diff --git a/src/MiniProfiler.Shared/ui/includes.less b/src/MiniProfiler.Shared/ui/includes.less index b50efd0d9..243aa1f2e 100644 --- a/src/MiniProfiler.Shared/ui/includes.less +++ b/src/MiniProfiler.Shared/ui/includes.less @@ -524,6 +524,12 @@ background-color: var(--mp-alt-row-color); } + .mp-stack-trace { + padding-bottom: 1px; + color: var(--mp-muted-color); + margin-bottom: 5px; + } + .mp-since-start, .mp-duration { text-align: right; } diff --git a/src/MiniProfiler.Shared/ui/includes.min.css b/src/MiniProfiler.Shared/ui/includes.min.css index 7826085ad..5f9e1663c 100644 --- a/src/MiniProfiler.Shared/ui/includes.min.css +++ b/src/MiniProfiler.Shared/ui/includes.min.css @@ -1 +1 @@ -:root{--mp-main-bg-color:#fff;--mp-button-active-bg-color:#207ab7;--mp-button-active-text-color:#fff;--mp-button-warning-bg-color:#c91d2e;--mp-button-warning-text-color:#fff;--mp-duration-color:#111;--mp-warning-color:#c91d2e;--mp-critical-color:#f00;--mp-alt-row-color:#f5f5f5;--mp-muted-color:#aaa;--mp-link-color:#07c;--mp-label-color:#555;--mp-gap-font-color:#444;--mp-gap-bg-color:#e1e5ed;--mp-overlay-bg-color:#000;--mp-info-border-color:#ddd;--mp-query-border-color:#efefef;--mp-timing-unknown-color:#80ccda;--mp-timing-dns-color:#8baad1;--mp-timing-connect-color:#8cbb4e;--mp-timing-ssl-color:#795892;--mp-timing-request-color:#0099b2;--mp-timing-response-color:#d99d35;--mp-timing-dom-color:#bd4d32;--mp-timing-domcontent-color:#dd4678;--mp-timing-load-color:#1d72aa;--mp-timing-paint-color:#bc41e3;--mp-highlight-fade-color:#ffb;--mp-highlight-default-color:#000;--mp-highlight-string-color:#756bb1;--mp-highlight-comment-color:#636363;--mp-highlight-literal-color:#31a354;--mp-highlight-variable-color:#88f;--mp-highlight-keyword-color:#3182bd;--mp-highlight-attribute-color:#e6550d;--mp-result-border:solid .5px #ababab;--mp-result-border-radius:10px;--mp-popup-shadow:0 1px 5px #55555555;}@media(prefers-color-scheme:dark){.mp-scheme-auto{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-auto body{background-color:var(--mp-main-bg-color);}}.mp-scheme-dark{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-dark body{background-color:var(--mp-main-bg-color);}.mp-result,.mp-queries{color:var(--mp-label-color);line-height:1;font-size:12px;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code,.mp-result label,.mp-queries label,.mp-result table,.mp-queries table,.mp-result tbody,.mp-queries tbody,.mp-result thead,.mp-queries thead,.mp-result tfoot,.mp-queries tfoot,.mp-result tr,.mp-queries tr,.mp-result th,.mp-queries th,.mp-result td,.mp-queries td{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;background-color:transparent;overflow:visible;max-height:none;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code{font-family:Fira Code,Consolas,monospace,serif;font-variant-ligatures:none;}.mp-result table,.mp-queries table{color:var(--mp-label-color);border-collapse:collapse;border-spacing:0;width:100%;}.mp-result a,.mp-queries a{cursor:pointer;color:var(--mp-link-color);text-decoration:none;}.mp-result a:hover,.mp-queries a:hover{text-decoration:underline;}.mp-result{font-family:sans-serif;}.mp-result.show-columns th.mp-more-columns,.mp-result.show-columns td.mp-more-columns{display:table-cell !important;}.mp-result.show-columns a.mp-more-columns{display:inline-block;}.mp-result.show-columns .mp-links span a:nth-child(1){display:none;}.mp-result.show-trivial tr.mp-trivial{display:table-row !important;}.mp-result.show-trivial a.mp-trivial{display:inline-block;}.mp-result.show-trivial .mp-links span a:nth-child(3){display:none;}.mp-result table.mp-client-timings{margin-top:10px;}.mp-result table.mp-client-timings td:nth-child(2){width:100%;padding:0;}.mp-result table.mp-client-timings td div{height:13px;min-width:1px;}.mp-result table.mp-client-timings .t-point div{height:4px;border-radius:8px;margin-bottom:4px;box-shadow:0 0 2px;}.mp-result table.mp-client-timings .t-unknown div{background:var(--mp-timing-unknown-color);}.mp-result table.mp-client-timings .t-dns div{background:var(--mp-timing-dns-color);}.mp-result table.mp-client-timings .t-connect div{background:var(--mp-timing-connect-color);}.mp-result table.mp-client-timings .t-ssl div{background:var(--mp-timing-ssl-color);}.mp-result table.mp-client-timings .t-request div{background:var(--mp-timing-request-color);}.mp-result table.mp-client-timings .t-response div{background:var(--mp-timing-response-color);}.mp-result table.mp-client-timings .t-dom div{background:var(--mp-timing-dom-color);}.mp-result table.mp-client-timings .t-domcontent div{background:var(--mp-timing-domcontent-color);}.mp-result table.mp-client-timings .t-load div{background:var(--mp-timing-load-color);}.mp-result table.mp-client-timings .t-paint div{background:var(--mp-timing-paint-color);}.mp-result .mp-debug{position:relative;cursor:pointer;}.mp-result .mp-debug .mp-debug-tooltip{display:none;position:fixed;background-color:var(--mp-main-bg-color);box-shadow:var(--mp-popup-shadow);right:100px;max-width:90%;border-radius:9px;padding:12px;margin-top:18px;opacity:.95;backdrop-filter:blur(4px);}.mp-result .mp-debug .mp-nested-timing{margin-left:16px;}.mp-result .mp-debug td:first-child:hover .mp-debug-tooltip{display:block;}.mp-result .mp-debug td:first-child:hover>span{text-shadow:var(--mp-button-active-text-color) 0 0 4px;}.mp-result .mp-stack-trace{color:var(--mp-muted-color);margin-bottom:5px;font-family:Consolas,Monaco,monospace;overflow-x:hidden;overflow-y:auto;white-space:pre-line;max-height:200px;}.mp-result .mp-stack-trace .stack-row{white-space:nowrap;}.mp-result .mp-stack-trace .stack-row.common{filter:grayscale(80%);}.mp-result .mp-stack-trace .stack.async{opacity:.6;display:none;}.mp-result .mp-stack-trace .stack.leadin,.mp-result .mp-stack-trace .stack.file,.mp-result .mp-stack-trace .stack.line-prefix,.mp-result .mp-stack-trace .stack.path,.mp-result .mp-stack-trace .stack.dot{color:var(--mp-muted-color);}.mp-result .mp-stack-trace .stack.async-tag{color:var(--mp-highlight-attribute-color);font-weight:bold;}.mp-result .mp-stack-trace .stack.async-tag:before{content:"(";}.mp-result .mp-stack-trace .stack.async-tag:after{content:")";}.mp-result .mp-stack-trace .stack.type{color:var(--mp-highlight-keyword-color);}.mp-result .mp-stack-trace .stack.generic-type{color:var(--mp-highlight-fade-color);}.mp-result .mp-stack-trace .stack.misc,.mp-result .mp-stack-trace .stack.parens{color:var(--mp-highlight-comment-color);}.mp-result .mp-stack-trace .stack.method{color:var(--mp-highlight-string-color);}.mp-result .mp-stack-trace .stack.paramType{color:var(--mp-highlight-attribute-color);}.mp-result .mp-stack-trace .stack.paramName{color:var(--mp-highlight-variable-color);}.mp-result .mp-label{color:var(--mp-label-color);overflow:hidden;text-overflow:ellipsis;}.mp-result .mp-unit{color:var(--mp-muted-color);}.mp-result .mp-more-columns{display:none;}.mp-result .mp-trivial{display:none;}.mp-result .mp-trivial td:not(:first-child),.mp-result .mp-trivial td:not(:first-child) *{color:var(--mp-muted-color) !important;}.mp-result .mp-number{color:var(--mp-duration-color);}.mp-result .mp-info>div{white-space:nowrap;overflow:hidden;}.mp-result .mp-info>div>div{display:inline-block;}.mp-result .mp-info .mp-name{display:inline-block;font-weight:bold;float:left;}.mp-result .mp-info .mp-machine-name,.mp-result .mp-info .mp-started{text-align:right;float:right;}.mp-result .mp-info .mp-server-time{white-space:nowrap;}.mp-result .mp-timings th{background-color:var(--mp-main-bg-color);color:var(--mp-muted-color);text-align:right;}.mp-result .mp-timings th,.mp-result .mp-timings td{white-space:nowrap;}.mp-result .mp-timings .mp-show-more{display:none;}.mp-result .mp-timings .mp-duration{font-family:Consolas,monospace,serif;color:var(--mp-duration-color);text-align:right;}.mp-result .mp-timings .mp-indent{letter-spacing:4px;}.mp-result .mp-timings .mp-queries-show .mp-number,.mp-result .mp-timings .mp-queries-show .mp-unit{color:var(--mp-link-color);}.mp-result .mp-timings .mp-queries-show.mp-queries-warning{color:var(--mp-warning-color);font-weight:bold;}.mp-result .mp-timings .mp-queries-duration{padding-left:6px;}.mp-result .mp-timings:not(.mp-client-timings) .mp-trivial:first-child{display:table-row;}.mp-result .mp-custom-timing-overview{float:right;margin:10px 0;width:auto;}.mp-result .mp-custom-timing-overview td{white-space:nowrap;text-align:right;}.mp-result .mp-custom-timing-overview td:last-child{padding-left:8px;}.mp-result .mp-links{margin-top:10px;clear:both;}.mp-result .mp-links span{float:right;}.mp-result .mp-links a{font-size:95%;margin-left:12px;}.mp-result .mp-links a:first-child{margin-left:0;}.mp-warning{color:var(--mp-critical-color);}@keyframes mp-fadeIn{from{background-color:var(--mp-highlight-fade-color);}to{background-color:none;}}.mp-overlay{z-index:2147483642;}.mp-overlay .mp-overlay-bg{z-index:2147483643;background:var(--mp-overlay-bg-color);opacity:.5;top:0;left:0;min-width:100%;position:fixed;height:calc(100%);}.mp-overlay .mp-queries{display:block;z-index:2147483644;top:25px;left:25px;right:25px;position:fixed;max-height:calc(100vh - 50px);background-color:var(--mp-main-bg-color);border-radius:2px;overflow-y:auto;overflow-x:auto;}.mp-queries{font-family:sans-serif;}.mp-queries pre{white-space:pre-wrap;}.mp-queries div{text-align:left;}.mp-queries table{table-layout:fixed;}.mp-queries td,.mp-queries th{padding:8px;border-bottom:solid 1px var(--mp-query-border-color);}.mp-queries td:first-child,.mp-queries th:first-child{width:250px;text-align:right;}.mp-queries td:first-child div,.mp-queries th:first-child div{text-align:right;margin-bottom:5px;word-break:break-word;}.mp-queries td:last-child,.mp-queries th:last-child{text-align:left;padding-right:15px;}.mp-queries .highlight{animation:mp-fadeIn 2s 1;}.mp-queries .mp-odd{background-color:var(--mp-alt-row-color);}.mp-queries .mp-since-start,.mp-queries .mp-duration{text-align:right;}.mp-queries.show-trivial .mp-gap-info.mp-trivial-gap{display:table-row;}.mp-queries .mp-gap-info{background-color:var(--mp-gap-bg-color);opacity:.8;color:var(--mp-gap-font-color);}.mp-queries .mp-gap-info .query{word-break:break-all;}.mp-queries .mp-gap-info .mp-unit{color:var(--mp-muted-color);}.mp-queries .mp-gap-info.mp-trivial-gap{display:none;}.mp-queries .mp-trivial-gap-container{text-align:center;margin:8px 0;}.mp-queries .mp-call-type{font-weight:bold;}.mp-queries .hljs{display:block;overflow-x:auto;padding:.5em;}.mp-queries .hljs,.mp-queries .hljs-subst{color:var(--mp-highlight-default-color);}.mp-queries .hljs-string,.mp-queries .hljs-meta,.mp-queries .hljs-symbol,.mp-queries .hljs-template-tag,.mp-queries .hljs-template-variable,.mp-queries .hljs-addition{color:var(--mp-highlight-string-color);}.mp-queries .hljs-comment,.mp-queries .hljs-quote{color:var(--mp-highlight-comment-color);}.mp-queries .hljs-number,.mp-queries .hljs-regexp,.mp-queries .hljs-literal,.mp-queries .hljs-bullet,.mp-queries .hljs-link{color:var(--mp-highlight-literal-color);}.mp-queries .hljs-deletion,.mp-queries .hljs-variable{color:var(--mp-highlight-variable-color);}.mp-queries .hljs-keyword,.mp-queries .hljs-selector-tag,.mp-queries .hljs-title,.mp-queries .hljs-section,.mp-queries .hljs-built_in,.mp-queries .hljs-doctag,.mp-queries .hljs-type,.mp-queries .hljs-tag,.mp-queries .hljs-name,.mp-queries .hljs-selector-id,.mp-queries .hljs-selector-class,.mp-queries .hljs-strong{color:var(--mp-highlight-keyword-color);}.mp-queries .hljs-emphasis{font-style:italic;}.mp-queries .hljs-attribute{color:var(--mp-highlight-attribute-color);}.mp-results{z-index:2147483641;position:fixed;top:0;}.mp-results.mp-left,.mp-results.mp-bottomleft{left:0;}.mp-results.mp-left .mp-controls,.mp-results.mp-left.mp-no-controls .mp-result:last-child .mp-button{border-bottom-right-radius:var(--mp-result-border-radius);}.mp-results.mp-left .mp-button,.mp-results.mp-left .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-right{right:0;}.mp-results.mp-right .mp-controls,.mp-results.mp-right.mp-no-controls .mp-result:last-child .mp-button{border-bottom-left-radius:var(--mp-result-border-radius);}.mp-results.mp-right .mp-button,.mp-results.mp-right .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomleft{top:inherit;bottom:0;}.mp-results.mp-bottomleft .mp-result:first-child .mp-button{border-top-right-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomleft .mp-button,.mp-results.mp-bottomleft .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-bottomleft .mp-result .mp-button,.mp-results.mp-bottomleft .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results.mp-bottomright{top:inherit;bottom:0;right:0;}.mp-results.mp-bottomright .mp-result:first-child .mp-button{border-top-left-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomright .mp-button,.mp-results.mp-bottomright .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomright .mp-result .mp-button,.mp-results.mp-bottomright .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results .mp-button{user-select:none;}.mp-results .mp-button.mp-button-warning{font-weight:bold;background-color:var(--mp-button-warning-bg-color);color:var(--mp-button-warning-text-color);}.mp-results .mp-button.mp-button-warning .mp-number,.mp-results .mp-button.mp-button-warning .mp-unit,.mp-results .mp-button.mp-button-warning .mp-warning{color:var(--mp-button-warning-text-color);}.mp-results .mp-button .mp-warning{font-weight:bold;}.mp-results .mp-button>.mp-number{font-family:Consolas,monospace,serif;}.mp-results .mp-controls{display:none;}.mp-results .mp-button,.mp-results .mp-controls{z-index:2147483640;border-bottom:var(--mp-result-border);background-color:var(--mp-main-bg-color);padding:4px 8px;text-align:right;cursor:pointer;}.mp-results .mp-result{position:relative;}.mp-results .mp-result.active .mp-button{background-color:var(--mp-button-active-bg-color);animation:none;border-radius:0 !important;}.mp-results .mp-result.active .mp-button.mp-button-warning{background-color:var(--mp-button-warning-bg-color);}.mp-results .mp-result.active .mp-button .mp-number,.mp-results .mp-result.active .mp-button .mp-warning{color:var(--mp-button-active-text-color);font-weight:bold;}.mp-results .mp-result.active .mp-button .mp-unit{color:var(--mp-button-active-text-color);font-weight:normal;}.mp-results .mp-result.active .mp-popup{display:block;}.mp-results.new .mp-button{animation:mp-fadeIn 2s 1;}.mp-results .mp-controls{display:block;font-size:12px;font-family:Consolas,monospace,serif;cursor:default;text-align:center;}.mp-results .mp-controls span{color:var(--mp-muted-color);border-right:1px solid var(--mp-muted-color);padding-right:5px;margin-right:5px;cursor:pointer;}.mp-results .mp-controls span:last-child{border-right:none;}.mp-results .mp-popup{display:none;z-index:2147483641;position:absolute;background-color:var(--mp-main-bg-color);padding:5px 10px;text-align:left;line-height:18px;overflow:auto;box-shadow:var(--mp-popup-shadow);border-radius:2px;}.mp-results .mp-popup .mp-info{margin-bottom:3px;padding-bottom:2px;border-bottom:1px solid var(--mp-info-border-color);}.mp-results .mp-popup .mp-info .mp-name{font-size:1.1em;}.mp-results .mp-popup .mp-info .mp-overall-duration{color:var(--mp-muted-color);}.mp-results .mp-popup .mp-timings th,.mp-results .mp-popup .mp-timings td{padding:0 6px;}.mp-results .mp-popup .mp-timings th{font-size:95%;padding-bottom:3px;}.mp-results .mp-popup .mp-timings .mp-label{max-width:350px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;}.mp-results .mp-queries{display:none;}.mp-results.mp-min .mp-result{display:none;}.mp-results.mp-min .mp-controls span{display:none;}.mp-results.mp-min .mp-controls .mp-min-max{border-right:none;padding:0;margin:0;}.mp-results.mp-min:hover .mp-controls .mp-min-max{display:inline;}.mp-result-full .mp-result{width:950px;margin:25px auto;}.mp-result-full .mp-result .mp-button{display:none;}.mp-result-full .mp-result .mp-popup .mp-info{font-size:18px;border-bottom:1px solid var(--mp-muted-color);padding-bottom:3px;margin-bottom:10px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-name{margin-bottom:5px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration,.mp-result-full .mp-result .mp-popup .mp-info .mp-started{font-size:80%;color:var(--mp-muted-color);}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration{padding-right:20px;}.mp-result-full .mp-result .mp-popup .mp-timings td,.mp-result-full .mp-result .mp-popup .mp-timings th{font-size:13px;padding-left:8px;padding-right:8px;}.mp-result-full .mp-result .mp-popup .mp-timings th{padding-bottom:7px;}.mp-result-full .mp-result .mp-popup .mp-timings td{padding-bottom:4px;}.mp-result-full .mp-result .mp-popup .mp-timings td:first-child{padding-left:10px;}.mp-result-full .mp-result .mp-popup .mp-timings .mp-label{max-width:550px;}.mp-result-full .mp-result .mp-queries{margin:20px 0;}.mp-result-full .mp-result .mp-queries th{font-size:16px;}.mp-result-full .mp-share-mp-results{display:none;}table.mp-results-index{border:0;border-spacing:0;font-size:12px;font-family:Arial;}table.mp-results-index a{color:var(--mp-link-color);text-decoration:none;}table.mp-results-index tbody{color:var(--mp-label-color);}table.mp-results-index tbody tr:nth-child(odd){background-color:var(--mp-alt-row-color);}table.mp-results-index tbody tr:nth-child(even){background-color:var(--mp-main-bg-color);}table.mp-results-index tbody td{text-align:center;}table.mp-results-index tbody td:first-child{text-align:left;}table.mp-results-index tbody td[colspan="3"]{color:var(--mp-muted-color);}table.mp-results-index thead tr{color:var(--mp-label-color);}table.mp-results-index thead tr th{padding:5px 15px;}table.mp-results-index td{padding:8px;} \ No newline at end of file +:root{--mp-main-bg-color:#fff;--mp-button-active-bg-color:#207ab7;--mp-button-active-text-color:#fff;--mp-button-warning-bg-color:#c91d2e;--mp-button-warning-text-color:#fff;--mp-duration-color:#111;--mp-warning-color:#c91d2e;--mp-critical-color:#f00;--mp-alt-row-color:#f5f5f5;--mp-muted-color:#aaa;--mp-link-color:#07c;--mp-label-color:#555;--mp-gap-font-color:#444;--mp-gap-bg-color:#e1e5ed;--mp-overlay-bg-color:#000;--mp-info-border-color:#ddd;--mp-query-border-color:#efefef;--mp-timing-unknown-color:#80ccda;--mp-timing-dns-color:#8baad1;--mp-timing-connect-color:#8cbb4e;--mp-timing-ssl-color:#795892;--mp-timing-request-color:#0099b2;--mp-timing-response-color:#d99d35;--mp-timing-dom-color:#bd4d32;--mp-timing-domcontent-color:#dd4678;--mp-timing-load-color:#1d72aa;--mp-timing-paint-color:#bc41e3;--mp-highlight-fade-color:#ffb;--mp-highlight-default-color:#000;--mp-highlight-string-color:#756bb1;--mp-highlight-comment-color:#636363;--mp-highlight-literal-color:#31a354;--mp-highlight-variable-color:#88f;--mp-highlight-keyword-color:#3182bd;--mp-highlight-attribute-color:#e6550d;--mp-result-border:solid .5px #ababab;--mp-result-border-radius:10px;--mp-popup-shadow:0 1px 5px #55555555;}@media(prefers-color-scheme:dark){.mp-scheme-auto{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-auto body{background-color:var(--mp-main-bg-color);}}.mp-scheme-dark{--mp-main-bg-color:#222;--mp-duration-color:#eee;--mp-alt-row-color:#333;--mp-muted-color:#888;--mp-label-color:#ccc;--mp-gap-font-color:#d6d6d6;--mp-gap-bg-color:#424448;--mp-link-color:#4db5ff;--mp-query-border-color:#575757;--mp-highlight-fade-color:#884;--mp-highlight-default-color:#eee;--mp-highlight-literal-color:#3fca6a;--mp-highlight-keyword-color:#36a1ef;--mp-result-border:solid .5px #575757;}.mp-scheme-dark body{background-color:var(--mp-main-bg-color);}.mp-result,.mp-queries{color:var(--mp-label-color);line-height:1;font-size:12px;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code,.mp-result label,.mp-queries label,.mp-result table,.mp-queries table,.mp-result tbody,.mp-queries tbody,.mp-result thead,.mp-queries thead,.mp-result tfoot,.mp-queries tfoot,.mp-result tr,.mp-queries tr,.mp-result th,.mp-queries th,.mp-result td,.mp-queries td{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;background-color:transparent;overflow:visible;max-height:none;}.mp-result pre,.mp-queries pre,.mp-result code,.mp-queries code{font-family:Fira Code,Consolas,monospace,serif;font-variant-ligatures:none;}.mp-result table,.mp-queries table{color:var(--mp-label-color);border-collapse:collapse;border-spacing:0;width:100%;}.mp-result a,.mp-queries a{cursor:pointer;color:var(--mp-link-color);text-decoration:none;}.mp-result a:hover,.mp-queries a:hover{text-decoration:underline;}.mp-result{font-family:sans-serif;}.mp-result.show-columns th.mp-more-columns,.mp-result.show-columns td.mp-more-columns{display:table-cell !important;}.mp-result.show-columns a.mp-more-columns{display:inline-block;}.mp-result.show-columns .mp-links span a:nth-child(1){display:none;}.mp-result.show-trivial tr.mp-trivial{display:table-row !important;}.mp-result.show-trivial a.mp-trivial{display:inline-block;}.mp-result.show-trivial .mp-links span a:nth-child(3){display:none;}.mp-result table.mp-client-timings{margin-top:10px;}.mp-result table.mp-client-timings td:nth-child(2){width:100%;padding:0;}.mp-result table.mp-client-timings td div{height:13px;min-width:1px;}.mp-result table.mp-client-timings .t-point div{height:4px;border-radius:8px;margin-bottom:4px;box-shadow:0 0 2px;}.mp-result table.mp-client-timings .t-unknown div{background:var(--mp-timing-unknown-color);}.mp-result table.mp-client-timings .t-dns div{background:var(--mp-timing-dns-color);}.mp-result table.mp-client-timings .t-connect div{background:var(--mp-timing-connect-color);}.mp-result table.mp-client-timings .t-ssl div{background:var(--mp-timing-ssl-color);}.mp-result table.mp-client-timings .t-request div{background:var(--mp-timing-request-color);}.mp-result table.mp-client-timings .t-response div{background:var(--mp-timing-response-color);}.mp-result table.mp-client-timings .t-dom div{background:var(--mp-timing-dom-color);}.mp-result table.mp-client-timings .t-domcontent div{background:var(--mp-timing-domcontent-color);}.mp-result table.mp-client-timings .t-load div{background:var(--mp-timing-load-color);}.mp-result table.mp-client-timings .t-paint div{background:var(--mp-timing-paint-color);}.mp-result .mp-debug{position:relative;cursor:pointer;}.mp-result .mp-debug .mp-debug-tooltip{display:none;position:fixed;background-color:var(--mp-main-bg-color);box-shadow:var(--mp-popup-shadow);right:100px;max-width:90%;border-radius:9px;padding:12px;margin-top:18px;opacity:.95;backdrop-filter:blur(4px);}.mp-result .mp-debug .mp-nested-timing{margin-left:16px;}.mp-result .mp-debug td:first-child:hover .mp-debug-tooltip{display:block;}.mp-result .mp-debug td:first-child:hover>span{text-shadow:var(--mp-button-active-text-color) 0 0 4px;}.mp-result .mp-stack-trace{color:var(--mp-muted-color);margin-bottom:5px;font-family:Consolas,Monaco,monospace;overflow-x:hidden;overflow-y:auto;white-space:pre-line;max-height:200px;}.mp-result .mp-stack-trace .stack-row{white-space:nowrap;}.mp-result .mp-stack-trace .stack-row.common{filter:grayscale(80%);}.mp-result .mp-stack-trace .stack.async{opacity:.6;display:none;}.mp-result .mp-stack-trace .stack.leadin,.mp-result .mp-stack-trace .stack.file,.mp-result .mp-stack-trace .stack.line-prefix,.mp-result .mp-stack-trace .stack.path,.mp-result .mp-stack-trace .stack.dot{color:var(--mp-muted-color);}.mp-result .mp-stack-trace .stack.async-tag{color:var(--mp-highlight-attribute-color);font-weight:bold;}.mp-result .mp-stack-trace .stack.async-tag:before{content:"(";}.mp-result .mp-stack-trace .stack.async-tag:after{content:")";}.mp-result .mp-stack-trace .stack.type{color:var(--mp-highlight-keyword-color);}.mp-result .mp-stack-trace .stack.generic-type{color:var(--mp-highlight-fade-color);}.mp-result .mp-stack-trace .stack.misc,.mp-result .mp-stack-trace .stack.parens{color:var(--mp-highlight-comment-color);}.mp-result .mp-stack-trace .stack.method{color:var(--mp-highlight-string-color);}.mp-result .mp-stack-trace .stack.paramType{color:var(--mp-highlight-attribute-color);}.mp-result .mp-stack-trace .stack.paramName{color:var(--mp-highlight-variable-color);}.mp-result .mp-label{color:var(--mp-label-color);overflow:hidden;text-overflow:ellipsis;}.mp-result .mp-unit{color:var(--mp-muted-color);}.mp-result .mp-more-columns{display:none;}.mp-result .mp-trivial{display:none;}.mp-result .mp-trivial td:not(:first-child),.mp-result .mp-trivial td:not(:first-child) *{color:var(--mp-muted-color) !important;}.mp-result .mp-number{color:var(--mp-duration-color);}.mp-result .mp-info>div{white-space:nowrap;overflow:hidden;}.mp-result .mp-info>div>div{display:inline-block;}.mp-result .mp-info .mp-name{display:inline-block;font-weight:bold;float:left;}.mp-result .mp-info .mp-machine-name,.mp-result .mp-info .mp-started{text-align:right;float:right;}.mp-result .mp-info .mp-server-time{white-space:nowrap;}.mp-result .mp-timings th{background-color:var(--mp-main-bg-color);color:var(--mp-muted-color);text-align:right;}.mp-result .mp-timings th,.mp-result .mp-timings td{white-space:nowrap;}.mp-result .mp-timings .mp-show-more{display:none;}.mp-result .mp-timings .mp-duration{font-family:Consolas,monospace,serif;color:var(--mp-duration-color);text-align:right;}.mp-result .mp-timings .mp-indent{letter-spacing:4px;}.mp-result .mp-timings .mp-queries-show .mp-number,.mp-result .mp-timings .mp-queries-show .mp-unit{color:var(--mp-link-color);}.mp-result .mp-timings .mp-queries-show.mp-queries-warning{color:var(--mp-warning-color);font-weight:bold;}.mp-result .mp-timings .mp-queries-duration{padding-left:6px;}.mp-result .mp-timings:not(.mp-client-timings) .mp-trivial:first-child{display:table-row;}.mp-result .mp-custom-timing-overview{float:right;margin:10px 0;width:auto;}.mp-result .mp-custom-timing-overview td{white-space:nowrap;text-align:right;}.mp-result .mp-custom-timing-overview td:last-child{padding-left:8px;}.mp-result .mp-links{margin-top:10px;clear:both;}.mp-result .mp-links span{float:right;}.mp-result .mp-links a{font-size:95%;margin-left:12px;}.mp-result .mp-links a:first-child{margin-left:0;}.mp-warning{color:var(--mp-critical-color);}@keyframes mp-fadeIn{from{background-color:var(--mp-highlight-fade-color);}to{background-color:none;}}.mp-overlay{z-index:2147483642;}.mp-overlay .mp-overlay-bg{z-index:2147483643;background:var(--mp-overlay-bg-color);opacity:.5;top:0;left:0;min-width:100%;position:fixed;height:calc(100%);}.mp-overlay .mp-queries{display:block;z-index:2147483644;top:25px;left:25px;right:25px;position:fixed;max-height:calc(100vh - 50px);background-color:var(--mp-main-bg-color);border-radius:2px;overflow-y:auto;overflow-x:auto;}.mp-queries{font-family:sans-serif;}.mp-queries pre{white-space:pre-wrap;}.mp-queries div{text-align:left;}.mp-queries table{table-layout:fixed;}.mp-queries td,.mp-queries th{padding:8px;border-bottom:solid 1px var(--mp-query-border-color);}.mp-queries td:first-child,.mp-queries th:first-child{width:250px;text-align:right;}.mp-queries td:first-child div,.mp-queries th:first-child div{text-align:right;margin-bottom:5px;word-break:break-word;}.mp-queries td:last-child,.mp-queries th:last-child{text-align:left;padding-right:15px;}.mp-queries .highlight{animation:mp-fadeIn 2s 1;}.mp-queries .mp-odd{background-color:var(--mp-alt-row-color);}.mp-queries .mp-stack-trace{padding-bottom:1px;color:var(--mp-muted-color);margin-bottom:5px;}.mp-queries .mp-since-start,.mp-queries .mp-duration{text-align:right;}.mp-queries.show-trivial .mp-gap-info.mp-trivial-gap{display:table-row;}.mp-queries .mp-gap-info{background-color:var(--mp-gap-bg-color);opacity:.8;color:var(--mp-gap-font-color);}.mp-queries .mp-gap-info .query{word-break:break-all;}.mp-queries .mp-gap-info .mp-unit{color:var(--mp-muted-color);}.mp-queries .mp-gap-info.mp-trivial-gap{display:none;}.mp-queries .mp-trivial-gap-container{text-align:center;margin:8px 0;}.mp-queries .mp-call-type{font-weight:bold;}.mp-queries .hljs{display:block;overflow-x:auto;padding:.5em;}.mp-queries .hljs,.mp-queries .hljs-subst{color:var(--mp-highlight-default-color);}.mp-queries .hljs-string,.mp-queries .hljs-meta,.mp-queries .hljs-symbol,.mp-queries .hljs-template-tag,.mp-queries .hljs-template-variable,.mp-queries .hljs-addition{color:var(--mp-highlight-string-color);}.mp-queries .hljs-comment,.mp-queries .hljs-quote{color:var(--mp-highlight-comment-color);}.mp-queries .hljs-number,.mp-queries .hljs-regexp,.mp-queries .hljs-literal,.mp-queries .hljs-bullet,.mp-queries .hljs-link{color:var(--mp-highlight-literal-color);}.mp-queries .hljs-deletion,.mp-queries .hljs-variable{color:var(--mp-highlight-variable-color);}.mp-queries .hljs-keyword,.mp-queries .hljs-selector-tag,.mp-queries .hljs-title,.mp-queries .hljs-section,.mp-queries .hljs-built_in,.mp-queries .hljs-doctag,.mp-queries .hljs-type,.mp-queries .hljs-tag,.mp-queries .hljs-name,.mp-queries .hljs-selector-id,.mp-queries .hljs-selector-class,.mp-queries .hljs-strong{color:var(--mp-highlight-keyword-color);}.mp-queries .hljs-emphasis{font-style:italic;}.mp-queries .hljs-attribute{color:var(--mp-highlight-attribute-color);}.mp-results{z-index:2147483641;position:fixed;top:0;}.mp-results.mp-left,.mp-results.mp-bottomleft{left:0;}.mp-results.mp-left .mp-controls,.mp-results.mp-left.mp-no-controls .mp-result:last-child .mp-button{border-bottom-right-radius:var(--mp-result-border-radius);}.mp-results.mp-left .mp-button,.mp-results.mp-left .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-right{right:0;}.mp-results.mp-right .mp-controls,.mp-results.mp-right.mp-no-controls .mp-result:last-child .mp-button{border-bottom-left-radius:var(--mp-result-border-radius);}.mp-results.mp-right .mp-button,.mp-results.mp-right .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomleft{top:inherit;bottom:0;}.mp-results.mp-bottomleft .mp-result:first-child .mp-button{border-top-right-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomleft .mp-button,.mp-results.mp-bottomleft .mp-controls{border-right:var(--mp-result-border);}.mp-results.mp-bottomleft .mp-result .mp-button,.mp-results.mp-bottomleft .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results.mp-bottomright{top:inherit;bottom:0;right:0;}.mp-results.mp-bottomright .mp-result:first-child .mp-button{border-top-left-radius:var(--mp-result-border-radius);}.mp-results.mp-bottomright .mp-button,.mp-results.mp-bottomright .mp-controls{border-left:var(--mp-result-border);}.mp-results.mp-bottomright .mp-result .mp-button,.mp-results.mp-bottomright .mp-controls{border-bottom:0;border-top:var(--mp-result-border);}.mp-results .mp-button{user-select:none;}.mp-results .mp-button.mp-button-warning{font-weight:bold;background-color:var(--mp-button-warning-bg-color);color:var(--mp-button-warning-text-color);}.mp-results .mp-button.mp-button-warning .mp-number,.mp-results .mp-button.mp-button-warning .mp-unit,.mp-results .mp-button.mp-button-warning .mp-warning{color:var(--mp-button-warning-text-color);}.mp-results .mp-button .mp-warning{font-weight:bold;}.mp-results .mp-button>.mp-number{font-family:Consolas,monospace,serif;}.mp-results .mp-controls{display:none;}.mp-results .mp-button,.mp-results .mp-controls{z-index:2147483640;border-bottom:var(--mp-result-border);background-color:var(--mp-main-bg-color);padding:4px 8px;text-align:right;cursor:pointer;}.mp-results .mp-result{position:relative;}.mp-results .mp-result.active .mp-button{background-color:var(--mp-button-active-bg-color);animation:none;border-radius:0 !important;}.mp-results .mp-result.active .mp-button.mp-button-warning{background-color:var(--mp-button-warning-bg-color);}.mp-results .mp-result.active .mp-button .mp-number,.mp-results .mp-result.active .mp-button .mp-warning{color:var(--mp-button-active-text-color);font-weight:bold;}.mp-results .mp-result.active .mp-button .mp-unit{color:var(--mp-button-active-text-color);font-weight:normal;}.mp-results .mp-result.active .mp-popup{display:block;}.mp-results.new .mp-button{animation:mp-fadeIn 2s 1;}.mp-results .mp-controls{display:block;font-size:12px;font-family:Consolas,monospace,serif;cursor:default;text-align:center;}.mp-results .mp-controls span{color:var(--mp-muted-color);border-right:1px solid var(--mp-muted-color);padding-right:5px;margin-right:5px;cursor:pointer;}.mp-results .mp-controls span:last-child{border-right:none;}.mp-results .mp-popup{display:none;z-index:2147483641;position:absolute;background-color:var(--mp-main-bg-color);padding:5px 10px;text-align:left;line-height:18px;overflow:auto;box-shadow:var(--mp-popup-shadow);border-radius:2px;}.mp-results .mp-popup .mp-info{margin-bottom:3px;padding-bottom:2px;border-bottom:1px solid var(--mp-info-border-color);}.mp-results .mp-popup .mp-info .mp-name{font-size:1.1em;}.mp-results .mp-popup .mp-info .mp-overall-duration{color:var(--mp-muted-color);}.mp-results .mp-popup .mp-timings th,.mp-results .mp-popup .mp-timings td{padding:0 6px;}.mp-results .mp-popup .mp-timings th{font-size:95%;padding-bottom:3px;}.mp-results .mp-popup .mp-timings .mp-label{max-width:350px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;}.mp-results .mp-queries{display:none;}.mp-results.mp-min .mp-result{display:none;}.mp-results.mp-min .mp-controls span{display:none;}.mp-results.mp-min .mp-controls .mp-min-max{border-right:none;padding:0;margin:0;}.mp-results.mp-min:hover .mp-controls .mp-min-max{display:inline;}.mp-result-full .mp-result{width:950px;margin:25px auto;}.mp-result-full .mp-result .mp-button{display:none;}.mp-result-full .mp-result .mp-popup .mp-info{font-size:18px;border-bottom:1px solid var(--mp-muted-color);padding-bottom:3px;margin-bottom:10px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-name{margin-bottom:5px;}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration,.mp-result-full .mp-result .mp-popup .mp-info .mp-started{font-size:80%;color:var(--mp-muted-color);}.mp-result-full .mp-result .mp-popup .mp-info .mp-overall-duration{padding-right:20px;}.mp-result-full .mp-result .mp-popup .mp-timings td,.mp-result-full .mp-result .mp-popup .mp-timings th{font-size:13px;padding-left:8px;padding-right:8px;}.mp-result-full .mp-result .mp-popup .mp-timings th{padding-bottom:7px;}.mp-result-full .mp-result .mp-popup .mp-timings td{padding-bottom:4px;}.mp-result-full .mp-result .mp-popup .mp-timings td:first-child{padding-left:10px;}.mp-result-full .mp-result .mp-popup .mp-timings .mp-label{max-width:550px;}.mp-result-full .mp-result .mp-queries{margin:20px 0;}.mp-result-full .mp-result .mp-queries th{font-size:16px;}.mp-result-full .mp-share-mp-results{display:none;}table.mp-results-index{border:0;border-spacing:0;font-size:12px;font-family:Arial;}table.mp-results-index a{color:var(--mp-link-color);text-decoration:none;}table.mp-results-index tbody{color:var(--mp-label-color);}table.mp-results-index tbody tr:nth-child(odd){background-color:var(--mp-alt-row-color);}table.mp-results-index tbody tr:nth-child(even){background-color:var(--mp-main-bg-color);}table.mp-results-index tbody td{text-align:center;}table.mp-results-index tbody td:first-child{text-align:left;}table.mp-results-index tbody td[colspan="3"]{color:var(--mp-muted-color);}table.mp-results-index thead tr{color:var(--mp-label-color);}table.mp-results-index thead tr th{padding:5px 15px;}table.mp-results-index td{padding:8px;} \ No newline at end of file From 3ce56e7dc60a271ad38057a02d714b2e25fd4f47 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sun, 24 May 2020 19:44:31 -0400 Subject: [PATCH 12/13] Undo more diff --- src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs b/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs index 7fa0af6ca..4a7ad29be 100644 --- a/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs +++ b/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs @@ -49,13 +49,14 @@ bool ShouldExcludeType(MethodBase method) var sb = StringBuilderCache.Get(); int stackLength = 0, startFrame = frames.Length - 1; + for (int i = 0; i < frames.Length; i++) { var method = frames[i].GetMethod(); if (stackLength >= options.StackMaxLength - // ASP.NET: no need to continue up the chain - || method.Name == "System.Web.HttpApplication.IExecutionStep.Execute" - || (method.Module.Name == "Microsoft.AspNetCore.Mvc.Core.dll" && method.DeclaringType.Name == "ObjectMethodExecutor")) + // ASP.NET: no need to continue up the chain + || method.Name == "System.Web.HttpApplication.IExecutionStep.Execute" + || (method.Module.Name == "Microsoft.AspNetCore.Mvc.Core.dll" && method.DeclaringType.Name == "ObjectMethodExecutor")) { frames[i] = null; startFrame = i < 0 ? 0 : i - 1; @@ -73,7 +74,6 @@ bool ShouldExcludeType(MethodBase method) } } - //string nextSuffix = null; for (var i = startFrame; i >= 0; i--) { var f = frames[i]; @@ -85,7 +85,6 @@ bool ShouldExcludeType(MethodBase method) sb.Append(" > "); } sb.Append(method.Name); - sb.Append(" (").Append(f.ToString()).Append(")"); } } From bc499891140fcf07005b4c01e55875f225f8bfee Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sun, 24 May 2020 19:53:00 -0400 Subject: [PATCH 13/13] More doc additions --- docs/Releases.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/Releases.md b/docs/Releases.md index ee1189603..48f4314a4 100644 --- a/docs/Releases.md +++ b/docs/Releases.md @@ -11,8 +11,10 @@ This page tracks major changes included in any update starting with version 4.0. - Added dark and "auto" (system preference decides) color themes, total is "Light", "Dark", and "Auto" ([#451](https://github.com/MiniProfiler/dotnet/pull/451)) - Generally moves to CSS 3 variables, for easier custom themes as well ([#451](https://github.com/MiniProfiler/dotnet/pull/451)) - Added `SqlServerFormatter.IncludeParameterValues` for excluding actual values in output if desired ([#463](https://github.com/MiniProfiler/dotnet/pull/463)) + - New "debug" mode (via `.EnableDebugMode`) that outputs stack dumps for every timing (expensive/heavy, and not intended for normal operation - [#482](https://github.com/MiniProfiler/dotnet/pull/482)) - (**.NET Core only**) Added `MiniProfilerOptions.ResultsAuthorizeAsync` and `MiniProfiler.ResultsAuthorizeListAsync` ([#472](https://github.com/MiniProfiler/dotnet/pull/472)) - - (**.NET Core only**) Added profiling to all diagnostic events (views, filters, etc. - [#475](https://github.com/MiniProfiler/dotnet/pull/475)) + - (**.NET Core only**) Added profiling to all diagnostic events (views, filters, etc. - [#475](https://github.com/MiniProfiler/dotnet/pull/475) & [#482](https://github.com/MiniProfiler/dotnet/pull/482)) + - New options around this are in the ASP.NET Core docs on the left. - **Fixes/Changes**: - Fix for ['i.Started.toUTCString is not a function'](https://github.com/MiniProfiler/dotnet/pull/462) when global serializer options are changed. - Removed jQuery (built-in) dependency ([#442](https://github.com/MiniProfiler/dotnet/pull/442))
duration (ms) with children (ms) from start (ms)