using System;
using System.Threading;
using System.Web;
using StackExchange.Profiling;
using StackExchange.Profiling.SqlFormatters;
namespace Umbraco.Core.Logging
{
///
/// Implements by using the MiniProfiler framework.
///
internal class WebProfiler : IProfiler
{
private const string BootRequestItemKey = "Umbraco.Core.Logging.WebProfiler__isBootRequest";
private readonly WebProfilerProvider _provider;
private int _first;
public WebProfiler()
{
// create our own provider, which can provide a profiler even during boot
_provider = new WebProfilerProvider();
// settings
MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter();
MiniProfiler.Settings.StackMaxLength = 5000;
MiniProfiler.Settings.ProfilerProvider = _provider;
}
public void UmbracoApplicationBeginRequest(object sender, EventArgs e)
{
// if this is the first request, notify our own provider that this request is the boot request
var first = Interlocked.Exchange(ref _first, 1) == 0;
if (first)
{
_provider.BeginBootRequest();
((HttpApplication) sender).Context.Items[BootRequestItemKey] = true;
// and no need to start anything, profiler is already there
}
// else start a profiler, the normal way
else if (ShouldProfile(sender))
Start();
}
public void UmbracoApplicationEndRequest(object sender, EventArgs e)
{
// if this is the boot request, or if we should profile this request, stop
// (the boot request is always profiled, no matter what)
var isBootRequest = ((HttpApplication) sender).Context.Items[BootRequestItemKey] != null; // fixme perfs
if (isBootRequest)
_provider.EndBootRequest();
if (isBootRequest || ShouldProfile(sender))
Stop();
}
private static bool ShouldProfile(object sender)
{
var request = TryGetRequest(sender);
if (request.Success == false) return false;
if (request.Result.Url.IsClientSideRequest()) return false;
if (bool.TryParse(request.Result.QueryString["umbDebug"], out var umbDebug)) return umbDebug;
if (bool.TryParse(request.Result.Headers["X-UMB-DEBUG"], out var xUmbDebug)) return xUmbDebug;
return false;
}
///
public string Render()
{
return MiniProfiler.RenderIncludes(RenderPosition.Right).ToString();
}
///
public IDisposable Step(string name)
{
return MiniProfiler.Current.Step(name);
}
///
public void Start()
{
MiniProfiler.Start();
}
///
public void Stop(bool discardResults = false)
{
MiniProfiler.Stop(discardResults);
}
private static Attempt TryGetRequest(object sender)
{
var app = sender as HttpApplication;
if (app == null) return Attempt.Fail();
try
{
var req = app.Request;
return Attempt.Succeed(new HttpRequestWrapper(req));
}
catch (HttpException ex)
{
return Attempt.Fail(ex);
}
}
}
}