public void TestRangeQueries() { var now = DateTime.UtcNow; var inASec = now.AddSeconds(1); var in2Secs = now.AddSeconds(2); var in3Secs = now.AddSeconds(3); var profiler = new MiniProfiler { Started = now, Id = Guid.NewGuid() }; var profiler1 = new MiniProfiler { Started = inASec, Id = Guid.NewGuid() }; var profiler2 = new MiniProfiler { Started = in2Secs, Id = Guid.NewGuid() }; var profiler3 = new MiniProfiler { Started = in3Secs, Id = Guid.NewGuid() }; var storage = new HttpRuntimeCacheStorage(new TimeSpan(1, 0, 0)); storage.Save(profiler); storage.Save(profiler3); storage.Save(profiler2); storage.Save(profiler1); var guids = storage.List(100); Assert.AreEqual(4, guids.Count()); guids = storage.List(1); Assert.AreEqual(1, guids.Count()); guids = storage.List(2, now, in2Secs, ListResultsOrder.Decending); Assert.AreEqual(profiler2.Id, guids.First()); Assert.AreEqual(profiler1.Id, guids.Skip(1).First()); Assert.AreEqual(2, guids.Count()); }
public RavenTiming(RequestResultArgs request, MiniProfiler profiler) : base(profiler, null, null) { if (profiler == null) throw new ArgumentNullException("profiler"); _requestUrl = request.Url; var commandTextBuilder = new StringBuilder(); // Basic request information // HTTP GET - 200 (Cached) commandTextBuilder.AppendFormat("HTTP {0} - {1} ({2})\n", request.Method, request.HttpResult, request.Status); // Request URL commandTextBuilder.AppendFormat("{0}\n\n", FormatUrl()); // Append query var query = FormatQuery(); if (!String.IsNullOrWhiteSpace(query)) { commandTextBuilder.AppendFormat("{0}\n\n", query); } // Append POSTed data, if any (multi-get, PATCH, etc.) if (!String.IsNullOrWhiteSpace(request.PostedData)) { commandTextBuilder.Append(request.PostedData); } // Set the command string to a formatted string CommandString = commandTextBuilder.ToString(); }
public void Save(MiniProfiler profiler) { var context = WcfInstanceContext.Current; // Do nothing if we are not being called inside a WCF method // Alternatively, this could throw an Exception if (context == null) return; context.Items[GetCacheKey(profiler.Id)] = profiler; }
public void TestWeCanSaveTheSameProfilerTwice() { var profiler = new MiniProfiler("/") { Started = DateTime.UtcNow, Id = Guid.NewGuid() }; var storage = new HttpRuntimeCacheStorage(new TimeSpan(1, 0, 0)); storage.Save(profiler); storage.Save(profiler); var guids = storage.List(100).ToArray(); Assert.AreEqual(profiler.Id, guids.First()); Assert.AreEqual(1, guids.Count()); }
/// <summary> /// Stores <paramref name="profiler"/> under its <see cref="MiniProfiler.Id"/>. /// </summary> /// <param name="profiler">The results of a profiling session.</param> /// <remarks> /// Should also ensure the profiler is stored as being un-viewed by its profiling <see cref="MiniProfiler.User"/>. /// </remarks> public void Save(MiniProfiler profiler) { // ignore browerLink URL, i.e. "/__browserLink/requestData/44067061dcd44ffcbbca1da" if (profiler.Name == null || profiler.Name.Contains("__browserLink")) return; // Convert the path into something that plays better with Graphite, i.e. "Home/MinSaveMs" -> "Home.MinSaveMs" Metrics.Timer( profiler.Name.Replace("/", "."), (int)profiler.DurationMilliseconds); }
/// <summary> /// Handles <see cref="IElasticsearchResponse"/> and pushes <see cref="CustomTiming"/> to current <see cref="MiniProfiler"/> session. /// </summary> /// <param name="response"><see cref="IElasticsearchResponse"/> to be handled.</param> /// <param name="profiler">Current <see cref="MiniProfiler"/> session instance.</param> internal static void HandleResponse(IElasticsearchResponse response, MiniProfiler profiler) { if (profiler == null || profiler.Head == null || response.Metrics == null) return; profiler.Head.AddCustomTiming("elasticsearch", new CustomTiming(profiler, BuildCommandString(response)) { Id = Guid.NewGuid(), DurationMilliseconds = response.Metrics.Requests.Sum(c => c.EllapsedMilliseconds), ExecuteType = response.RequestMethod, }); }
internal static HtmlString RenderIncludes(MiniProfiler profiler, RenderPosition? position = null, bool? showTrivial = null, bool? showTimeWithChildren = null, int? maxTracesToShow = null, bool xhtml = false, bool? showControls = null) { const string format = @"<link rel=""stylesheet"" type=""text/css"" href=""{path}mini-profiler-includes.css?v={version}""{closeXHTML}> <script type=""text/javascript""> if (!window.jQuery) document.write(unescape(""%3Cscript src='{path}mini-profiler-jquery.1.6.2.js' type='text/javascript'%3E%3C/script%3E"")); if (!window.jQuery || !window.jQuery.tmpl) document.write(unescape(""%3Cscript src='{path}mini-profiler-jquery.tmpl.beta1.js' type='text/javascript'%3E%3C/script%3E"")); </script> <script type=""text/javascript"" src=""{path}mini-profiler-includes.js?v={version}""></script> <script type=""text/javascript""> jQuery(function() {{ MiniProfiler.init({{ ids: {ids}, path: '{path}', version: '{version}', renderPosition: '{position}', showTrivial: {showTrivial}, showChildrenTime: {showChildren}, maxTracesToShow: {maxTracesToShow}, showControls: {showControls} }}); }}); </script>"; var result = ""; if (profiler != null) { // HACK: unviewed ids are added to this list during Storage.Save, but we know we haven't see the current one yet, // so go ahead and add it to the end - it's usually the only id, but if there was a redirect somewhere, it'll be there, too MiniProfiler.Settings.EnsureStorageStrategy(); var ids = MiniProfiler.Settings.Storage.GetUnviewedIds(profiler.User); ids.Add(profiler.Id); result = format.Format(new { //path = VirtualPathUtility.ToAbsolute(MiniProfiler.Settings.RouteBasePath).EnsureTrailingSlash(), path = "", version = MiniProfiler.Settings.Version, ids = ids.ToJson(), position = (position ?? MiniProfiler.Settings.PopupRenderPosition).ToString().ToLower(), showTrivial = showTrivial ?? MiniProfiler.Settings.PopupShowTrivial ? "true" : "false", showChildren = showTimeWithChildren ?? MiniProfiler.Settings.PopupShowTimeWithChildren ? "true" : "false", maxTracesToShow = maxTracesToShow ?? MiniProfiler.Settings.PopupMaxTracesToShow, closeXHTML = xhtml ? "/" : "", showControls = showControls ?? MiniProfiler.Settings.ShowControls ? "true" : "false" }); } return new HtmlString(result); }
/// <summary> /// Stores <paramref name="profiler"/> under its <see cref="MiniProfiler.Id"/> in all of the <see cref="Stores"/>. /// </summary> /// <param name="profiler">The results of a profiling session.</param> /// <remarks> /// Should also ensure the profiler is stored as being un-viewed by its profiling <see cref="MiniProfiler.User"/>. /// </remarks> public void Save(MiniProfiler profiler) { if (Stores != null) { if (AllowParallelOps) { Parallel.ForEach(Stores, x => x.Save(profiler)); } else { Stores.ForEach(x => x.Save(profiler)); } } }
public MiniProfiler GetProfiler() { // does a profiler already exist for this request? var profiler = HttpContext.GetProfiler(); if (profiler != null) return profiler; // might want to decide here (or maybe inside the action) whether you want // to profile this request - for example, using an "IsSystemAdmin" flag against // the user, or similar; this could also all be done in action filters, but this // is simple and practical; just return null for most users. For our test, we'll // profiler only for local requests (seems reasonable) //if (Request.IsLocal) //{ profiler = new MiniProfiler(Request.Url.OriginalString); HttpContext.SetProfiler(profiler); //} return profiler; }
/// <summary> /// Creates a new SqlTiming to profile 'command'. /// </summary> public MongoTiming(string collectionName, string command, ExecuteType type, MiniProfiler profiler) { Id = Guid.NewGuid(); CollectionName = collectionName; CommandString = command; ExecuteType = type; if (!MiniProfiler.Settings.ExcludeStackTraceSnippetFromSqlTimings) StackTraceSnippet = Helpers.StackTraceSnippet.Get(); _profiler = profiler; if (_profiler != null) { _profiler.AddMongoTiming(this); _startTicks = _profiler.ElapsedTicks; StartMilliseconds = _profiler.GetRoundedMilliseconds(_startTicks); } }
/// <summary> /// start the profiler. /// </summary> /// <param name="level">The profile level.</param> /// <returns>the mini profiler.</returns> public override MiniProfiler Start(ProfileLevel level, string sessionName = null) { var context = WcfInstanceContext.Current; if (context == null) return null; var operationContext = OperationContext.Current; if (operationContext == null) return null; var instanceContext = operationContext.InstanceContext; if (instanceContext == null) return null; // TODO: Include the action name here as well, and null protection string serviceName = instanceContext.Host.Description.Name; // BaseAddresses.FirstOrDefault(); // TODO: Ignored paths - currently solely based on servicename // var url = context.Request.Url; // var path = context.Request.AppRelativeCurrentExecutionFilePath.Substring(1); // don't profile /content or /scripts, either - happens in web.dev foreach (var ignored in MiniProfiler.Settings.IgnoredPaths ?? new string[0]) { if (serviceName.ToUpperInvariant().Contains((ignored ?? string.Empty).ToUpperInvariant())) return null; } var result = new MiniProfiler(sessionName ?? GetProfilerName(operationContext, instanceContext), level); SetCurrentProfiler(result); // don't really want to pass in the context to MiniProfler's constructor or access it statically in there, either result.User = (Settings.UserProvider ?? new EmptyUserProvider()).GetUser(/*context.Request*/); SetProfilerActive(result); return result; }
/// <summary> /// Giving freshly selected collections, this method puts them in the correct /// hierarchy under the 'result' MiniProfiler. /// </summary> protected void MapTimings(MiniProfiler result, List<Timing> timings, List<SqlTiming> sqlTimings, List<SqlTimingParameter> sqlParameters) { var stack = new Stack<Timing>(); for (int i = 0; i < timings.Count; i++) { var cur = timings[i]; foreach (var sqlTiming in sqlTimings) { if (sqlTiming.ParentTimingId == cur.Id) { cur.AddSqlTiming(sqlTiming); var parameters = sqlParameters.Where(p => p.ParentSqlTimingId == sqlTiming.Id); if (parameters.Count() > 0) { sqlTiming.Parameters = parameters.ToList(); } } } if (stack.Count > 0) { Timing head; while ((head = stack.Peek()).Id != cur.ParentTimingId) { stack.Pop(); } head.AddChild(cur); } stack.Push(cur); } // TODO: .Root does all the above work again, but it's used after [DataContract] deserialization; refactor it out somehow result.Root = timings.First(); }
/// <summary> /// set the current profiler. /// </summary> /// <param name="profiler">The profiler.</param> private void SetCurrentProfiler(MiniProfiler profiler) { var context = WcfInstanceContext.Current; if (context == null) return; context.Items[WcfCacheKey] = profiler; }
public async Task Step_WithParallelTasks_RealTime() { var profiler = MiniProfiler.Start("root"); profiler.Stopwatch = StopwatchWrapper.StartNew(); Timing timing10 = null, timing11 = null, timing20 = null, timing21 = null, timing30 = null, timing31 = null; // Act // Add 100ms to root await Task.Delay(100).ConfigureAwait(false); // Start tasks in parallel var whenAllTask = Task.WhenAll( Task.Run(async() => { // timing10: 100 + 100 = 200 ms using (timing10 = profiler.Step("step1.0 (Task.Run)")) { await Task.Delay(100).ConfigureAwait(false); await Task.Run(async() => { using (timing11 = profiler.Step("step1.1 (Task.Run)")) { await Task.Delay(100).ConfigureAwait(false); } }).ConfigureAwait(false); } }), Task.Factory.StartNew(async() => { // timing20: 200 + 100 = 300 ms using (timing20 = profiler.Step("step2.0 (Task.Factory.StartNew)")) { await Task.Delay(200).ConfigureAwait(false); await Task.Run(async() => { using (timing21 = profiler.Step("step2.1 (Task.Run)")) { await Task.Delay(100).ConfigureAwait(false); } }).ConfigureAwait(false); } // Important to Unwrap() when using the not-for-mortals StartNew() }).Unwrap(), Task.Factory.StartNew(async() => { // timing30: 300 + 100 = 400 ms using (timing30 = profiler.Step("step3.0 (Task.Factory.StartNew:LongRunning)")) { await Task.Delay(300).ConfigureAwait(false); await Task.Run(async() => { using (timing31 = profiler.Step("step3.1 (Task.Run)")) { await Task.Delay(100).ConfigureAwait(false); } }).ConfigureAwait(false); } // Important to Unwrap() when using the not-for-mortals StartNew() }, TaskCreationOptions.LongRunning).Unwrap() ); await whenAllTask; MiniProfiler.Stop(); // Assert //Console.WriteLine(profiler.RenderPlainText()); // 100ms + longest running task (step3.0 with 300 + 100 ms) = 500ms AssertNear(500, profiler.DurationMilliseconds, 50); // Parent durations are sum of itself and children AssertNear(200, timing10.DurationMilliseconds, 50); AssertNear(100, timing11.DurationMilliseconds, 50); AssertNear(300, timing20.DurationMilliseconds, 50); AssertNear(100, timing21.DurationMilliseconds, 50); AssertNear(400, timing30.DurationMilliseconds, 50); AssertNear(100, timing31.DurationMilliseconds, 50); }
/// <summary> /// Start the profiler /// </summary> /// <remarks> /// set discardResults to false when you want to abandon all profiling, this is useful for /// when someone is not authenticated or you want to clear the results based on some other mechanism. /// </remarks> public void Stop(bool discardResults = false) { MiniProfiler.Stop(discardResults); }
/// <summary> /// Render the UI to display the profiler /// </summary> /// <returns></returns> /// <remarks> /// Generally used for HTML displays /// </remarks> public string Render() { return(MiniProfiler.RenderIncludes(RenderPosition.Right).ToString()); }
/// <summary> /// Increments the currently running <see cref="MiniProfiler.Stopwatch"/> by <paramref name="milliseconds"/>. /// </summary> /// <param name="profiler">The profile to increment.</param> /// <param name="milliseconds">The milliseconds.</param> public static Task IncrementAsync(this MiniProfiler profiler, int milliseconds = BaseTest.StepTimeMilliseconds) => Task.Run(() => Increment(profiler, milliseconds));
private void SaveClientTiming(MiniProfiler profiler) { if (profiler.ClientTimings == null || profiler.ClientTimings.Timings == null || profiler.ClientTimings.Timings.Count == 0) return; foreach (var ct in profiler.ClientTimings.Timings) { ClientTimings.Save(new ClientTimingPoco { Id = profiler.Id.ToString(), Name = ct.Name, Start = (double)ct.Start, Duration = (double)ct.Duration }); } }
public async Task Invoke(HttpContext context) { if (context.Request.Path.Value.StartsWith("/swagger")) { await _next.Invoke(context); } else { var requestId = Guid.NewGuid().ToString(); var correlationId = string.IsNullOrEmpty(context.Request.Headers["X-Correlation-ID"].ToString()) ? requestId : context.Request.Headers["X-Correlation-ID"].ToString(); LogContext.PushProperty("RequestId", requestId); LogContext.PushProperty("CorrelationId", correlationId); var request = new { Path = context.Request.Path.Value, context.Request.Method, context.Request.Headers, QueryParams = context.Request.Query, QueryString = context.Request.QueryString.Value, context.Request.ContentType, context.Request.ContentLength, context.Request.Scheme, Host = context.Request.Host.Value, Content = GetContent(context) }; var maskedRequest = _masker.Mask(request); Log.ForContext("RequestDetail", maskedRequest, true) .Information("Request started: {Method:l} {path}", request.Method, context.Request.Path); var sw = new Stopwatch(); sw.Start(); if (Log.IsEnabled(LogEventLevel.Verbose)) { MiniProfiler.Start(); } await _next.Invoke(context); sw.Stop(); if (MiniProfiler.Current != null) { MiniProfiler.Stop(); Log.ForContext("Profiler", MiniProfiler.Current, true) .Verbose("Request profiler: {Method:l} {path}", context.Request.Method, context.Request.Path); } var response = new { context.Response.StatusCode, context.Response.Headers, context.Response.ContentType }; var httpDetail = new { Request = request, Response = response, DurationInMilliseconds = sw.ElapsedMilliseconds }; var maskedHTTPDetail = _masker.Mask(httpDetail); Log.ForContext("HTTPDetail", maskedHTTPDetail, true) .Information("Request completed: {Method:l} {path} [{StatusCode} {StatusDescription:l}] ({DurationInMilliseconds:n0} ms)", context.Request.Method, context.Request.Path, context.Response.StatusCode, ((HttpStatusCode)context.Response.StatusCode).ToString(), httpDetail.DurationInMilliseconds); } }
/// <summary> /// Increments the currently running <see cref="MiniProfiler.Stopwatch"/> by <paramref name="milliseconds"/>. /// </summary> /// <param name="profiler">The profile to increment.</param> /// <param name="milliseconds">The milliseconds.</param> public static void Increment(this MiniProfiler profiler, int milliseconds = BaseTest.StepTimeMilliseconds) { var sw = (UnitTestStopwatch)profiler.GetStopwatch(); sw.ElapsedTicks += milliseconds * UnitTestStopwatch.TicksPerMillisecond; }
protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); _ltMiniProfiler.Text = MiniProfiler.RenderIncludes().ToHtmlString(); }
public void Init(HttpApplication context) { if (!_applicationStarted) { lock (_applicationStartLock) { if (!_applicationStarted) { // this will run only once per application start OnAppStart(context); // Mark as started so that it doesn't starts again _applicationStarted = true; } } } context.BeginRequest += delegate { // Don't do nothing if profiling is not enabled if (!Settings.Running || !Settings.Enabled) { return; } // Filter requests like CSS, JS, etc if (!FilterRequest()) { return; } // Add the response filter needed to caculate the response size HttpContext.Current.Response.Filter = new ResponseLengthStream(HttpContext.Current.Response.Filter); // We need to know when the headers has been sent, so that // we don't appen the client side tracking cookie HttpContext.Current.Cache["HeadersSent"] = false; }; context.AcquireRequestState += delegate { // Don't do nothing if profiling is not enabled if (!Settings.Running || !Settings.Enabled) { return; } // Filter requests like CSS, JS, etc if (!FilterRequest()) { return; } // Is it within tracked pages? if (Settings.ProfilingFilter.Rows.Count > 0) { bool profiled = false; foreach (DataRow dr in Settings.ProfilingFilter.Rows) { if (HttpContext.Current.Request.Url.PathAndQuery.Contains(dr["UrlString"].ToString())) { profiled = true; break; } } if (!profiled) { return; } } // Start profiler for this request MiniProfiler.Start(); }; context.EndRequest += delegate { // Don't do nothing if profiling is not enabled if (!Settings.Running || !Settings.Enabled) { return; } // Only stop profiler it there's one running if (MiniProfiler.Current != null) { MiniProfiler.Stop(); // Set client side tracking cookie... // Only if there's a context with a valid response if (HttpContext.Current != null && HttpContext.Current.Response != null && // And it's not an AJAX request... !IsAjaxRequest(HttpContext.Current.Request) && // And response headers has not been sent yet... !(bool)HttpContext.Current.Cache["HeadersSent"]) { // Then we write the tracking cookie HttpCookie trackingCookie = new HttpCookie("CorpNetProfilerTracking"); trackingCookie.Value = MiniProfiler.Current.RequestID; HttpContext.Current.Response.AppendCookie(trackingCookie); } } }; context.Error += delegate { // Don't do nothing if profiling is not enabled if (!Settings.Running || !Settings.Enabled) { return; } // Register error info if (MiniProfiler.Current != null) { Exception ex = context.Server.GetLastError(); if (ex != null) { string exceptionInfo = ex.ToString(); if (ex.InnerException != null) { exceptionInfo = ex.InnerException.ToString(); } MiniProfiler.Current.Exception = exceptionInfo; } } }; context.PreSendRequestHeaders += delegate { HttpContext.Current.Cache["HeadersSent"] = true; }; }
private void OnAppStart(HttpApplication context) { // Initialize profiler MiniProfiler.Initialize(); }
/// <summary> /// The assert mini profiler exists. /// </summary> /// <param name="miniProfiler">The mini Profiler.</param> private void AssertMiniProfilerExists(MiniProfiler miniProfiler) { Assert.That(_conn.Query<int>("select count(*) from MiniProfilers where Id = @Id", new { miniProfiler.Id }).Single() == 1); }
/// <summary> /// Renders script tag for including MiniProfiler. /// </summary> /// <param name="profiler">The profiler to render a tag for.</param> /// <param name="path">The root path that MiniProfiler is being served from.</param> /// <param name="isAuthorized">Whether the current user is authorized for MiniProfiler.</param> /// <param name="requestIDs">The request IDs to fetch for this render.</param> /// <param name="renderOptions">The option overrides (if any) to use rendering this MiniProfiler.</param> public static string Includes( MiniProfiler profiler, string path, bool isAuthorized, RenderOptions renderOptions, List<Guid> requestIDs = null) { var sb = StringBuilderCache.Get(); var options = profiler.Options; sb.Append("<script async id=\"mini-profiler\" src=\""); sb.Append(path); sb.Append("includes.min.js?v="); sb.Append(options.VersionHash); sb.Append("\" data-version=\""); sb.Append(options.VersionHash); sb.Append("\" data-path=\""); sb.Append(path); sb.Append("\" data-current-id=\""); sb.Append(profiler.Id.ToString()); sb.Append("\" data-ids=\""); if (requestIDs != null) { var length = requestIDs.Count; for (var i = 0; i < length; i++) { if (i > 0) { sb.Append(','); } var id = requestIDs[i]; sb.Append(id.ToString()); } } sb.Append("\" data-position=\""); sb.Append((renderOptions?.Position ?? options.PopupRenderPosition).ToString()); sb.Append('"'); sb.Append("\" data-scheme=\""); sb.Append((renderOptions?.ColorScheme ?? options.ColorScheme).ToString()); sb.Append('"'); if (isAuthorized) { sb.Append(" data-authorized=\"true\""); } if (renderOptions?.ShowTrivial ?? options.PopupShowTrivial) { sb.Append(" data-trivial=\"true\""); } if (renderOptions?.ShowTimeWithChildren ?? options.PopupShowTimeWithChildren) { sb.Append(" data-children=\"true\""); } if (renderOptions?.ShowControls ?? options.ShowControls) { sb.Append(" data-controls=\"true\""); } if (renderOptions?.StartHidden ?? options.PopupStartHidden) { sb.Append(" data-start-hidden=\"true\""); } if (renderOptions?.Nonce.HasValue() ?? false) { sb.Append(" nonce=\"").Append(System.Web.HttpUtility.HtmlAttributeEncode(renderOptions.Nonce)).Append("\""); } sb.Append(" data-max-traces=\""); sb.Append((renderOptions?.MaxTracesToShow ?? options.PopupMaxTracesToShow).ToString(CultureInfo.InvariantCulture)); sb.Append("\" data-toggle-shortcut=\""); sb.Append(renderOptions?.PopupToggleKeyboardShortcut ?? options.PopupToggleKeyboardShortcut); sb.Append("\" data-trivial-milliseconds=\""); sb.Append((renderOptions?.TrivialDurationThresholdMilliseconds ?? options.TrivialDurationThresholdMilliseconds).ToString(CultureInfo.InvariantCulture)); if (options.IgnoredDuplicateExecuteTypes.Count > 0) { sb.Append("\" data-ignored-duplicate-execute-types=\""); var i = 0; foreach (var executeType in options.IgnoredDuplicateExecuteTypes) { if (i > 0) { sb.Append(','); } sb.Append(executeType); i++; } } sb.Append("\"></script>"); return sb.ToStringRecycle(); }
/// <summary> /// Loads the MiniProfiler identifed by 'id' from the database. /// </summary> public override MiniProfiler Load(Guid id) { var query = Query.EQ("_id", id.ToString()); var profilerPoco = Profilers.FindOne(query); if (profilerPoco != null) { var profiler = new MiniProfiler { Id = Guid.Parse(profilerPoco.Id), Name = profilerPoco.Name, Started = profilerPoco.Started, MachineName = profilerPoco.MachineName, User = profilerPoco.User, Level = profilerPoco.Level, HasUserViewed = profilerPoco.HasUserViewed }; if (profiler != null) //This is very similar to the Load logic in the SqlServerStorage. //Perhaps another abstraction layer(or moving some logic into the Base) which both Mongo and Sql inherit from would eliminate somewhat repetitive code. { var timings = LoadTimings(profiler.Id); var sqlTimings = LoadSqlTimings(profiler.Id); var mongoTimings = LoadMongoTimings(profiler.Id); var sqlParams = LoadSqlTimingParameters(profiler.Id); var clientTimingList = LoadClientTimings(profiler.Id); ClientTimings clientTimings = null; if (clientTimingList.Count > 0) { clientTimings = new ClientTimings(); clientTimings.Timings = clientTimingList; } MapTimings(profiler, timings, sqlTimings, sqlParams, clientTimings, mongoTimings); } profiler.OnDeserialized(); return profiler; } return null; }
/// <summary> /// Renders script tag for including MiniProfiler. /// </summary> /// <param name="profiler">The profiler to render a tag for.</param> /// <param name="path">The root path that MiniProfiler is being served from.</param> /// <param name="isAuthorized">Whether the current user is authorized for MiniProfiler.</param> /// <param name="requestIDs">The request IDs to fetch for this render.</param> /// <param name="position">The UI position to render the profiler in (defaults to <see cref="MiniProfiler.Settings.PopupRenderPosition"/>).</param> /// <param name="showTrivial">Whether to show trivial timings column initially or not (defaults to <see cref="MiniProfiler.Settings.PopupShowTrivial"/>).</param> /// <param name="showTimeWithChildren">Whether to show time with children column initially or not (defaults to <see cref="MiniProfiler.Settings.PopupShowTimeWithChildren"/>).</param> /// <param name="maxTracesToShow">The maximum number of profilers to show (before the oldest is removed - defaults to <see cref="MiniProfiler.Settings.PopupMaxTracesToShow"/>).</param> /// <param name="showControls">Whether to show the controls (defaults to <see cref="MiniProfiler.Settings.ShowControls"/>).</param> /// <param name="startHidden">Whether to start hidden (defaults to <see cref="MiniProfiler.Settings.PopupStartHidden"/>).</param> public static string RenderIncludes( this MiniProfiler profiler, string path, bool isAuthorized, List <Guid> requestIDs = null, RenderPosition?position = null, bool?showTrivial = null, bool?showTimeWithChildren = null, int?maxTracesToShow = null, bool?showControls = null, bool?startHidden = null) { var sb = StringBuilderCache.Get(); sb.Append("<script async=\"async\" id=\"mini-profiler\" src=\""); sb.Append(path); sb.Append("includes.js?v="); sb.Append(MiniProfiler.Settings.VersionHash); sb.Append("\" data-version=\""); sb.Append(MiniProfiler.Settings.VersionHash); sb.Append("\" data-path=\""); sb.Append(path); sb.Append("\" data-current-id=\""); sb.Append(profiler.Id.ToString()); sb.Append("\" data-ids=\""); if (requestIDs != null) { var length = requestIDs.Count; for (var i = 0; i < length; i++) { if (i > 0) { sb.Append(','); } var id = requestIDs[i]; sb.Append(id.ToString()); } } sb.Append("\" data-position=\""); sb.Append((position ?? MiniProfiler.Settings.PopupRenderPosition).ToString().ToLower()); sb.Append('"'); if (isAuthorized) { sb.Append(" data-authorized=\"true\""); } if (showTrivial ?? MiniProfiler.Settings.PopupShowTrivial) { sb.Append(" data-trivial=\"true\""); } if (showTimeWithChildren ?? MiniProfiler.Settings.PopupShowTimeWithChildren) { sb.Append(" data-children=\"true\""); } if (showControls ?? MiniProfiler.Settings.ShowControls) { sb.Append(" data-controls=\"true\""); } if (startHidden ?? MiniProfiler.Settings.PopupStartHidden) { sb.Append(" data-start-hidden=\"true\""); } sb.Append(" data-max-traces=\""); sb.Append((maxTracesToShow ?? MiniProfiler.Settings.PopupMaxTracesToShow).ToString(CultureInfo.InvariantCulture)); sb.Append("\" data-toggle-shortcut=\""); sb.Append(MiniProfiler.Settings.PopupToggleKeyboardShortcut); sb.Append("\" data-trivial-milliseconds=\""); sb.Append(MiniProfiler.Settings.TrivialDurationThresholdMilliseconds.ToString(CultureInfo.InvariantCulture)); if (MiniProfiler.Settings.IgnoredDuplicateExecuteTypes.Count > 0) { sb.Append("\" data-ignored-duplicate-execute-types=\""); var i = 0; foreach (var executeType in MiniProfiler.Settings.IgnoredDuplicateExecuteTypes) { if (i > 0) { sb.Append(','); } sb.Append(executeType); i++; } } sb.Append("\"></script>"); return(sb.ToStringRecycle()); }
/// <summary> /// Saves parameter Timing to the sqltimingparams collection. /// </summary> private void SaveSqlTimingParameters(MiniProfiler profiler, SqlTiming s) { foreach (var p in s.Parameters) { var sqltimingParamPoco = new SqlTimingParameterPoco { MiniProfilerId = profiler.Id.ToString(), ParentSqlTimingId = s.Id.ToString(), Name = Truncate(p.Name, 150), DbType = Truncate(p.DbType, 50), Size = p.Size, Value = p.Value }; SqlTimingParams.Insert(sqltimingParamPoco); } }
/// <summary> /// The service method that is not profiled. /// </summary> /// <returns>a method that is not profiled.</returns> public string ServiceMethodThatIsNotProfiled() { MiniProfiler.Stop(true); return("Result"); }
/// <summary> /// Saves parameter Timing to the dbo.MiniProfilerTimings table. /// </summary> protected virtual void SaveTiming(DbConnection conn, MiniProfiler profiler, Timing t) { const string sql = @"insert into MiniProfilerTimings (Id, MiniProfilerId, ParentTimingId, Name, Depth, StartMilliseconds, DurationMilliseconds, DurationWithoutChildrenMilliseconds, SqlTimingsDurationMilliseconds, IsRoot, HasChildren, IsTrivial, HasSqlTimings, HasDuplicateSqlTimings, ExecutedReaders, ExecutedScalars, ExecutedNonQueries) values (@Id, @MiniProfilerId, @ParentTimingId, @Name, @Depth, @StartMilliseconds, @DurationMilliseconds, @DurationWithoutChildrenMilliseconds, @SqlTimingsDurationMilliseconds, @IsRoot, @HasChildren, @IsTrivial, @HasSqlTimings, @HasDuplicateSqlTimings, @ExecutedReaders, @ExecutedScalars, @ExecutedNonQueries)"; conn.Execute(sql, new { Id = t.Id, MiniProfilerId = profiler.Id, ParentTimingId = t.IsRoot ? (Guid?)null : t.ParentTiming.Id, Name = t.Name.Truncate(200), Depth = t.Depth, StartMilliseconds = t.StartMilliseconds, DurationMilliseconds = t.DurationMilliseconds, DurationWithoutChildrenMilliseconds = t.DurationWithoutChildrenMilliseconds, SqlTimingsDurationMilliseconds = t.SqlTimingsDurationMilliseconds, IsRoot = t.IsRoot, HasChildren = t.HasChildren, IsTrivial = t.IsTrivial, HasSqlTimings = t.HasSqlTimings, HasDuplicateSqlTimings = t.HasDuplicateSqlTimings, ExecutedReaders = t.ExecutedReaders, ExecutedScalars = t.ExecutedScalars, ExecutedNonQueries = t.ExecutedNonQueries }); if (t.HasSqlTimings) { foreach (var st in t.SqlTimings) { SaveSqlTiming(conn, profiler, st); } } if (t.HasChildren) { foreach (var child in t.Children) { SaveTiming(conn, profiler, child); } } }
public async Task StartAsync(CancellationToken cancellationToken) { Logger.LogDebug("SchemaScripter started"); var hasConfigError = false; if (string.IsNullOrWhiteSpace(Config.Server)) { Logger.LogError($"Invalid {nameof(Config.Server)}"); hasConfigError = true; } if (string.IsNullOrWhiteSpace(Config.User)) { Logger.LogError($"Invalid {nameof(Config.User)}"); hasConfigError = true; } if (string.IsNullOrWhiteSpace(Config.Password)) { Logger.LogError($"Invalid {nameof(Config.Password)}"); hasConfigError = true; } if (string.IsNullOrWhiteSpace(Config.Database)) { Logger.LogError($"Invalid {nameof(Config.Database)}"); hasConfigError = true; } if (string.IsNullOrWhiteSpace(Config.ExportFolder)) { Logger.LogError($"Invalid {nameof(Config.ExportFolder)}"); hasConfigError = true; } if (hasConfigError) { ApplicationLifetime.StopApplication(); return; } var availability = await DB.CheckAvailabilityAsync(); if (!availability.IsSuccess) { Logger.LogError(availability.ErrorMessage ?? "Error connecting to server"); ApplicationLifetime.StopApplication(); return; } if (!await DB.UseDatabaseAsync(Config.Database)) { Logger.LogError($"Cannot connect to database {Config.Database}"); ApplicationLifetime.StopApplication(); return; } Profiler = MiniProfiler.StartNew(nameof(SchemaScripterService)); using (Profiler.Step("Tables")) { await ExportTablesAsync(cancellationToken); } using (Profiler.Step("Stored Procedures")) { await ExportStoredProceduresAsync(cancellationToken); } using (Profiler.Step("Views")) { await ExportViewsAsync(cancellationToken); } using (Profiler.Step("Functions")) { await ExportFunctionsAsync(cancellationToken); } ExportViaSMO(); await Profiler.StopAsync(); Logger.LogDebug(Profiler.RenderPlainText()); ApplicationLifetime.StopApplication(); }
/// <summary> /// Start the profiler /// </summary> public void Start() { MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter(); MiniProfiler.Settings.StackMaxLength = 5000; MiniProfiler.Start(); }
public void SaveProfilingRecord(DbProfilingRecord dbProfilingRecord) { const string sqlProfiling = @"INSERT INTO [Profiling] ( [Name], [Url], [Referer], [Action], [Event], [ClientIP], [ClientAgent], [RequestID], [ActiveUser], [MachineName], [Started], [Duration], [ResponseSize], [RequestSize], [Exception], [SessionID]) VALUES ( @Name, @Url, @Referer, @Action, @Event, @ClientIP, @ClientAgent, @RequestID, @ActiveUser, @MachineName, @Started, @Duration, @ResponseSize, @RequestSize, @Exception, @SessionID) SELECT SCOPE_IDENTITY()" ; const string sqlProfilingClient = @"INSERT INTO [ProfilingClient] ( [RequestID], [ClientTotalDuration], [ClientRedirectDuration], [ClientDnsDuration], [ClientConnectionDuration], [ClientRequestDuration], [ClientResponseDuration], [ClientDomDuration], [ClientLoadDuration]) SELECT @RequestID, @ClientTotalDuration, @ClientRedirectDuration, @ClientDnsDuration, @ClientConnectionDuration, @ClientRequestDuration, @ClientResponseDuration, @ClientDomDuration, @ClientLoadDuration WHERE NOT EXISTS (SELECT 1 FROM ProfilingClient PC2 WHERE PC2.RequestID = @RequestID)" ; try { using (var conn = DataHelper.GetOpenConnection()) { // Connection created succesfully? It should be the case always, but... if (conn == null) { throw new Exception("Mini Profiler Error. Couldn't create connection to database. Suspending..."); } // Create command DbCommand cmd = conn.CreateCommand(); // Command created succesfully? if (cmd == null) { throw new Exception("Mini Profiler Error. Couldn't create command. Suspending..."); } cmd.CommandText = sqlProfiling; cmd.Parameters.Add(new SqlParameter("Name", dbProfilingRecord.Name.Truncate(64))); cmd.Parameters.Add(new SqlParameter("Url", dbProfilingRecord.Url.Truncate(256))); cmd.Parameters.Add(new SqlParameter("Referer", dbProfilingRecord.Referer.Truncate(256).ToDBNull())); cmd.Parameters.Add(new SqlParameter("Action", dbProfilingRecord.Action.Truncate(10).ToDBNull())); cmd.Parameters.Add(new SqlParameter("Event", dbProfilingRecord.Event.Truncate(128).ToDBNull())); cmd.Parameters.Add(new SqlParameter("ClientIP", dbProfilingRecord.ClientIP.Truncate(15).ToDBNull())); cmd.Parameters.Add(new SqlParameter("ClientAgent", dbProfilingRecord.ClientAgent.Truncate(128).ToDBNull())); cmd.Parameters.Add(new SqlParameter("RequestID", dbProfilingRecord.RequestID.Truncate(36).ToDBNull())); cmd.Parameters.Add(new SqlParameter("ActiveUser", dbProfilingRecord.ActiveUser.Truncate(30).ToDBNull())); cmd.Parameters.Add(new SqlParameter("MachineName", dbProfilingRecord.MachineName.Truncate(100))); cmd.Parameters.Add(new SqlParameter("Started", dbProfilingRecord.Started)); cmd.Parameters.Add(new SqlParameter("Duration", dbProfilingRecord.Duration)); cmd.Parameters.Add(new SqlParameter("ResponseSize", dbProfilingRecord.ResponseSize)); cmd.Parameters.Add(new SqlParameter("RequestSize", dbProfilingRecord.RequestSize)); cmd.Parameters.Add(new SqlParameter("Exception", dbProfilingRecord.Exception.Truncate(512).ToDBNull())); cmd.Parameters.Add(new SqlParameter("SessionID", dbProfilingRecord.SessionID.Truncate(24).ToDBNull())); // Capture Profiling ID dbProfilingRecord.ProfilingId = cmd.ExecuteScalar().ToInt(); // Save client tracking if (dbProfilingRecord.ClientRequestID != null) { cmd = conn.CreateCommand(); cmd.CommandText = sqlProfilingClient; cmd.Parameters.Add(new SqlParameter("RequestID", dbProfilingRecord.ClientRequestID)); cmd.Parameters.Add(new SqlParameter("ClientTotalDuration", dbProfilingRecord.ClientTotalDuration.MaxDigits(6))); cmd.Parameters.Add(new SqlParameter("ClientRedirectDuration", dbProfilingRecord.ClientRedirectDuration.MaxDigits(6))); cmd.Parameters.Add(new SqlParameter("ClientDnsDuration", dbProfilingRecord.ClientDnsDuration.MaxDigits(6))); cmd.Parameters.Add(new SqlParameter("ClientConnectionDuration", dbProfilingRecord.ClientConnectionDuration.MaxDigits(6))); cmd.Parameters.Add(new SqlParameter("ClientRequestDuration", dbProfilingRecord.ClientRequestDuration.MaxDigits(6))); cmd.Parameters.Add(new SqlParameter("ClientResponseDuration", dbProfilingRecord.ClientResponseDuration.MaxDigits(6))); cmd.Parameters.Add(new SqlParameter("ClientDomDuration", dbProfilingRecord.ClientDomDuration.MaxDigits(6))); cmd.Parameters.Add(new SqlParameter("ClientLoadDuration", dbProfilingRecord.ClientLoadDuration.MaxDigits(6))); cmd.ExecuteNonQuery(); } // Save timings if (dbProfilingRecord.Timings != null) { foreach (DbProfilingTimingRecord dbProfilingTimingRecord in dbProfilingRecord.Timings) { SaveTimingRecord(conn, dbProfilingRecord, dbProfilingTimingRecord); } } } } catch (Exception ex) { // Log exception Logger.Log(ex); // Error? Suspend profiling MiniProfiler.SuspendStorage(ex); } }
public async Task Step_WithParallelTasks_SimulatedTime() { var profiler = MiniProfiler.Start("root"); var waiters = new ConcurrentBag <CountdownEvent>(); Timing timing10 = null, timing11 = null, timing20 = null, timing21 = null, timing30 = null, timing31 = null; // Add 1ms to root Increment(); // Start tasks in parallel var whenAllTask = Task.WhenAll( Task.Run(async() => { // timing10: 1 + 1 = 2 ms using (timing10 = profiler.Step("step1.0 (Task.Run)")) { var ce = new CountdownEvent(1); waiters.Add(ce); ce.Wait(); await Task.Run(() => { using (timing11 = profiler.Step("step1.1 (Task.Run)")) { var ce2 = new CountdownEvent(1); waiters.Add(ce2); ce2.Wait(); } }).ConfigureAwait(false); } }), Task.Factory.StartNew(async() => { // timing20: 2 + 1 = 2 ms using (timing20 = profiler.Step("step2.0 (Task.Factory.StartNew)")) { var ce = new CountdownEvent(2); waiters.Add(ce); ce.Wait(); await Task.Run(() => { using (timing21 = profiler.Step("step2.1 (Task.Run)")) { var ce2 = new CountdownEvent(1); waiters.Add(ce2); ce2.Wait(); } }).ConfigureAwait(false); } }), Task.Factory.StartNew(async() => { // timing20: 3 + 1 = 2 ms using (timing30 = profiler.Step("step3.0 (Task.Factory.StartNew:LongRunning)")) { var ce = new CountdownEvent(3); waiters.Add(ce); ce.Wait(); await Task.Run(() => { using (timing31 = profiler.Step("step3.1 (Task.Run)")) { var ce2 = new CountdownEvent(1); waiters.Add(ce2); ce2.Wait(); } }).ConfigureAwait(false); } }, TaskCreationOptions.LongRunning) ); Func <List <CountdownEvent>, bool> hasPendingTasks = handlers2 => (handlers2.Count == 0) || handlers2.Any(y => !y.IsSet); // TODO Make this a thread safe signaling lock step to avoid sleeping // Wait for tasks to run and call their Step() methods Thread.Sleep(50); List <CountdownEvent> handlers; while (hasPendingTasks(handlers = waiters.ToList())) { Increment(); handlers.ForEach(x => { if (!x.IsSet) { x.Signal(); } }); // TODO Make this a thread safe signaling lock step to avoid sleeping // Wait for sub-tasks to run and call their Step() methods Thread.Sleep(50); } await whenAllTask; MiniProfiler.Stop(); // Assert //Console.WriteLine(profiler.RenderPlainText()); // 1ms added to root AssertNear(5, profiler.DurationMilliseconds, maxDelta: 2); // Parent durations are sum of itself and children AssertNear(2, timing10.DurationMilliseconds, maxDelta: 2); AssertNear(1, timing11.DurationMilliseconds, maxDelta: 2); AssertNear(3, timing20.DurationMilliseconds, maxDelta: 2); AssertNear(1, timing21.DurationMilliseconds, maxDelta: 2); AssertNear(4, timing30.DurationMilliseconds, maxDelta: 2); AssertNear(1, timing31.DurationMilliseconds, maxDelta: 2); }
/// <summary> /// Renders script tag found in "include.partial.html" - this is shared with all other language implementations, so if you change it, you MUST /// provide changes for those other implementations, e.g. ruby. /// </summary> internal static HtmlString RenderIncludes( MiniProfiler profiler, RenderPosition? position = null, bool? showTrivial = null, bool? showTimeWithChildren = null, int? maxTracesToShow = null, bool? showControls = null, bool? startHidden = null) { if (profiler == null) return new HtmlString(""); MiniProfiler.Settings.EnsureStorageStrategy(); var authorized = MiniProfiler.Settings.Results_Authorize == null || MiniProfiler.Settings.Results_Authorize(HttpContext.Current.Request); // unviewed ids are added to this list during Storage.Save, but we know we haven't see the current one yet, so go ahead and add it to the end var ids = authorized ? MiniProfiler.Settings.Storage.GetUnviewedIds(profiler.User) : new List<Guid>(); ids.Add(profiler.Id); var format = GetResource("include.partial.html"); var result = format.Format(new { path = VirtualPathUtility.ToAbsolute(MiniProfiler.Settings.RouteBasePath).EnsureTrailingSlash(), version = MiniProfiler.Settings.Version, ids = string.Join(",", ids.Select(guid => guid.ToString())), position = (position ?? MiniProfiler.Settings.PopupRenderPosition).ToString().ToLower(), showTrivial = (showTrivial ?? MiniProfiler.Settings.PopupShowTrivial).ToJs(), showChildren = (showTimeWithChildren ?? MiniProfiler.Settings.PopupShowTimeWithChildren).ToJs(), maxTracesToShow = maxTracesToShow ?? MiniProfiler.Settings.PopupMaxTracesToShow, showControls = (showControls ?? MiniProfiler.Settings.ShowControls).ToJs(), currentId = profiler.Id, authorized = authorized.ToJs(), toggleShortcut = MiniProfiler.Settings.PopupToggleKeyboardShortcut, startHidden = (startHidden ?? MiniProfiler.Settings.PopupStartHidden).ToJs() }); return new HtmlString(result); }
/// <summary> /// Makes sure 'profiler' has a Name, pulling it from route data or url. /// </summary> /// <param name="profiler">The profiler.</param> private static void EnsureServiceName(MiniProfiler profiler/*, HttpRequest request*/) { // also set the profiler name to Controller/Action or /url if (string.IsNullOrWhiteSpace(profiler.Name)) { profiler.Name = "Unknown"; var operationContext = OperationContext.Current; if (operationContext == null) return; var instanceContext = operationContext.InstanceContext; if (instanceContext == null) return; profiler.Name = GetProfilerName(operationContext, instanceContext); } }
/// <summary> /// set the JSON results and the content type. /// </summary> /// <param name="context">The context.</param> /// <param name="profiler">The profiler.</param> /// <returns>a string containing the JSON results.</returns> private static string ResultsJson(HttpContext context, MiniProfiler profiler) { context.Response.ContentType = "application/json"; return MiniProfiler.ToJson(profiler); }
public void AssertProfilersAreEqual(MiniProfiler mp1, MiniProfiler mp2) { Assert.Equal(mp1, mp2); AssertPublicPropertiesAreEqual(mp1, mp2); AssertTimingsAreEqualAndRecurse(mp1.Root, mp2.Root); }
/// <summary> /// Renders the parameter <see cref="MiniProfiler"/> to JSON. /// </summary> /// <param name="profiler">The <see cref="MiniProfiler"/> to serialize.</param> /// <param name="htmlEscape">Whether to HTML escape the output.</param> public static string ToJson(this MiniProfiler profiler, bool htmlEscape = false) => profiler != default(object) ? (htmlEscape ? JsonConvert.SerializeObject(profiler, htmlEscapeSettings) : JsonConvert.SerializeObject(profiler, defaultSettings)) : null;
protected void Application_BeginRequest() { MiniProfiler.Start(); }
/// <summary> /// Start the profiler /// </summary> public void Start() { MiniProfiler.Start(); }
public async System.Threading.Tasks.Task WorkspaceChangedAsync(object sender, WorkspaceChangeEventArgs e) { var profiler = MiniProfiler.StartNew(nameof(WorkspaceChangedAsync)); profiler.Storage = new NLogStorage(LogManager.GetLogger("profiler")); var workspace = sender as VisualStudioWorkspace; switch (e.Kind) { case WorkspaceChangeKind.SolutionAdded: try { using (profiler.Step(WorkspaceChangeKind.SolutionAdded.ToString())) { await _indexingQueue.EnqueueMultipleAsync(workspace.CurrentSolution.Projects); } } catch (Exception ex) { LogManager.GetLogger("error").Error(ex, "WorkspaceChangeKind.SolutionAdded"); await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); OutputWindowLogger.WriteLn($"Exception occured during adding solution: {ex.Message}"); } break; case WorkspaceChangeKind.SolutionChanged: break; case WorkspaceChangeKind.SolutionRemoved: break; case WorkspaceChangeKind.SolutionCleared: break; case WorkspaceChangeKind.SolutionReloaded: break; case WorkspaceChangeKind.ProjectAdded: try { using (profiler.Step(WorkspaceChangeKind.SolutionAdded.ToString())) { await _indexingQueue.EnqueueMultipleAsync(workspace.CurrentSolution.Projects); } } catch (Exception ex) { LogManager.GetLogger("error").Error(ex, "WorkspaceChangeKind.ProjectAdded"); OutputWindowLogger.WriteLn($"Exception occured during adding projects: {ex.Message}"); } break; case WorkspaceChangeKind.ProjectRemoved: break; case WorkspaceChangeKind.ProjectChanged: break; case WorkspaceChangeKind.ProjectReloaded: break; case WorkspaceChangeKind.DocumentAdded: var documentAddedChanges = e.NewSolution.GetChanges(e.OldSolution); var addedDocuments = documentAddedChanges.GetProjectChanges() .SelectMany(x => x.GetAddedDocuments()) .Select(x => workspace.CurrentSolution.GetDocument(x)); await DocumentsAddedActionAsync(addedDocuments); break; case WorkspaceChangeKind.DocumentRemoved: var documentRemovedChanges = e.NewSolution.GetChanges(e.OldSolution); var removedDocuments = documentRemovedChanges.GetProjectChanges() .SelectMany(x => x.GetRemovedDocuments()); await DocumentRemovedActionAsync(removedDocuments); break; case WorkspaceChangeKind.DocumentReloaded: break; case WorkspaceChangeKind.DocumentChanged: break; case WorkspaceChangeKind.AdditionalDocumentAdded: break; case WorkspaceChangeKind.AdditionalDocumentRemoved: break; case WorkspaceChangeKind.AdditionalDocumentReloaded: break; case WorkspaceChangeKind.AdditionalDocumentChanged: break; default: break; } await profiler.StopAsync(); }
/// <summary> /// Stores to <c>dbo.MiniProfilers</c> under its <see cref="MiniProfiler.Id"/>; /// </summary> /// <param name="profiler">The Mini Profiler</param> public override void Save(MiniProfiler profiler) { const string sql = @"insert into MiniProfilers (Id, RootTimingId, Started, DurationMilliseconds, [User], HasUserViewed, MachineName, CustomLinksJson, ClientTimingsRedirectCount) select @Id, @RootTimingId, @Started, @DurationMilliseconds, @User, @HasUserViewed, @MachineName, @CustomLinksJson, @ClientTimingsRedirectCount where not exists (select 1 from MiniProfilers where Id = @Id)"; // this syntax works on both mssql and sqlite using (var conn = GetOpenConnection()) { conn.Execute( sql, new { profiler.Id, profiler.Started, User = profiler.User.Truncate(100), RootTimingId = profiler.Root != null ? profiler.Root.Id : (Guid?)null, profiler.DurationMilliseconds, profiler.HasUserViewed, MachineName = profiler.MachineName.Truncate(100), profiler.CustomLinksJson, ClientTimingsRedirectCount = profiler.ClientTimings != null ? profiler.ClientTimings.RedirectCount : (int?)null }); var timings = new List <Timing>(); if (profiler.Root != null) { profiler.Root.MiniProfilerId = profiler.Id; FlattenTimings(profiler.Root, timings); } SaveTimings(timings, conn); if (profiler.ClientTimings != null && profiler.ClientTimings.Timings != null && profiler.ClientTimings.Timings.Any()) { // set the profilerId (isn't needed unless we are storing it) profiler.ClientTimings.Timings.ForEach(x => { x.MiniProfilerId = profiler.Id; x.Id = Guid.NewGuid(); }); SaveClientTimings(profiler.ClientTimings.Timings, conn); } } }
/// <summary> /// demonstrate a recursive method. /// </summary> /// <param name="depth">recursion depth</param> /// <param name="connection">the connection</param> /// <param name="profiler">The profiler.</param> private void RecursiveMethod(ref int depth, DbConnection connection, MiniProfiler profiler) { Thread.Sleep(5); // ensure we show up in the profiler if (depth >= 10) { return; } using (profiler.Step("Nested call " + depth)) { // run some meaningless queries to illustrate formatting connection.Query( @"select * from MiniProfilers where Name like @name or Name = @name or DurationMilliseconds >= @duration or HasSqlTimings = @hasSqlTimings or Started > @yesterday ", new { name = "Home/Index", duration = 100.5, hasSqlTimings = true, yesterday = DateTime.UtcNow.AddDays(-1) }); connection.Query(@"select RouteName, HitCount from RouteHits where HitCount < 100000000 or HitCount > 0 order by HitCount, RouteName -- this should hopefully wrap"); // massive query to test if max-height is properly removed from <pre> stylings connection.Query( @"select * from (select RouteName, HitCount from RouteHits where HitCount between 0 and 9 union all select RouteName, HitCount from RouteHits where HitCount between 10 and 19 union all select RouteName, HitCount from RouteHits where HitCount between 20 and 29 union all select RouteName, HitCount from RouteHits where HitCount between 30 and 39 union all select RouteName, HitCount from RouteHits where HitCount between 40 and 49 union all select RouteName, HitCount from RouteHits where HitCount between 50 and 59 union all select RouteName, HitCount from RouteHits where HitCount between 60 and 69 union all select RouteName, HitCount from RouteHits where HitCount between 70 and 79 union all select RouteName, HitCount from RouteHits where HitCount between 80 and 89 union all select RouteName, HitCount from RouteHits where HitCount between 90 and 99 union all select RouteName, HitCount from RouteHits where HitCount > 100) order by RouteName"); // need a long title to test max-width using (profiler.Step("Incrementing a reference parameter named i")) { depth++; } RecursiveMethod(ref depth, connection, profiler); } }
private static string ResultsJson(HttpContext context, MiniProfiler profiler) { context.Response.ContentType = "application/json"; return(MiniProfiler.ToJson(profiler)); }
protected void Application_EndRequest() { MiniProfiler.Stop(); }
void Global_EndRequest(object sender, EventArgs e) { MiniProfiler.Stop(); }
/// <summary> /// results full page. /// </summary> /// <param name="context">The context.</param> /// <param name="profiler">The profiler.</param> /// <returns>a string containing the results page</returns> private static string ResultsFullPage(HttpContext context, MiniProfiler profiler) { context.Response.ContentType = "text/html"; var template = GetResource("share.html"); return template.Format(new { name = profiler.Name, duration = profiler.DurationMilliseconds.ToString(CultureInfo.InvariantCulture), path = VirtualPathUtility.ToAbsolute(MiniProfiler.Settings.RouteBasePath).EnsureTrailingSlash(), json = MiniProfiler.ToJson(profiler), includes = RenderIncludes(profiler), version = MiniProfiler.Settings.Version }); }
void Global_BeginRequest(object sender, EventArgs e) { MiniProfiler.Start(); }
/// <summary> /// Stores to <c>dbo.MiniProfilers</c> under its <see cref="MiniProfiler.Id"/>; /// </summary> /// <param name="profiler">The Mini Profiler</param> public override void Save(MiniProfiler profiler) { const string sql = @"insert into MiniProfilers (Id, RootTimingId, Started, DurationMilliseconds, [User], HasUserViewed, MachineName, CustomLinksJson, ClientTimingsRedirectCount) select @Id, @RootTimingId, @Started, @DurationMilliseconds, @User, @HasUserViewed, @MachineName, @CustomLinksJson, @ClientTimingsRedirectCount where not exists (select 1 from MiniProfilers where Id = @Id)"; // this syntax works on both mssql and sqlite using (var conn = GetOpenConnection()) { conn.Execute( sql, new { profiler.Id, profiler.Started, User = profiler.User.Truncate(100), RootTimingId = profiler.Root != null ? profiler.Root.Id : (Guid?)null, profiler.DurationMilliseconds, profiler.HasUserViewed, MachineName = profiler.MachineName.Truncate(100), profiler.CustomLinksJson, ClientTimingsRedirectCount = profiler.ClientTimings != null ? profiler.ClientTimings.RedirectCount : (int?)null }); var timings = new List<Timing>(); if (profiler.Root != null) { profiler.Root.MiniProfilerId = profiler.Id; FlattenTimings(profiler.Root, timings); } SaveTimings(timings, conn); if (profiler.ClientTimings != null && profiler.ClientTimings.Timings != null && profiler.ClientTimings.Timings.Any()) { // set the profilerId (isn't needed unless we are storing it) profiler.ClientTimings.Timings.ForEach(x => { x.MiniProfilerId = profiler.Id; x.Id = Guid.NewGuid(); }); SaveClientTimings(profiler.ClientTimings.Timings, conn); } } }
/// <summary> /// Customize aspects of the MiniProfiler. /// </summary> private void InitProfilerSettings() { // MiniProfiler的一個強大功能是能夠與其他開發人員共享與結果的鏈接。但是,默認情況下,長期結果緩存是在HttpRuntime.Cache中完成的,這是非常不穩定的。 // 讓我們將我們的探查器結果序列化到數據庫中,這樣他們就可以在應用程序重啟後繼續運行。 MiniProfiler.Configure(new MiniProfilerOptions { // 設置用於MiniProfiler資源的路由: // 這裡,〜/ profiler用於/profiler/mini-profiler-includes.js之類的東西 // includes.min.js還需要在web.config的system.webServer->handlers中增加MiniProfiler RouteBasePath = "~/profiler", // 設置MultiStorage提供程序。 這將把結果存儲在MemoryCacheStorage(通常是默認值)和SqlLite中。 Storage = new MultiStorageProvider( new MemoryCacheStorage(new TimeSpan(1, 0, 0)), // RecreateDatabase調用僅用於測試目的,因此我們不會檢查db to source控件。但在這裡我們已經使用實體的sqlite,以便於後續進行查詢 new SqliteMiniProfilerStorage(SQLiteConnectionString).RecreateDatabase("create table IF NOT EXISTS RouteHits(RouteName,HitCount,unique(RouteName))") ), // 不同的RDBMS有不同的方式來聲明sql參數 - SQLite可以理解內聯sql參數就好了。 // 默認情況下,將顯示sql參數。 //SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter(), // 這些設置是可選的,並且都具有默認值。在.RenderIncludes()中指定的任何匹配設置將覆蓋此處指定的應用程序範圍的默認值,例如,如果您同時具有: // PopupRenderPosition = RenderPosition.Right; // 並在頁面中: // @MiniProfiler.Current.RenderIncludes(position: RenderPosition.Left) // ...然後,該位置將位於該頁面的左側,而右側(應用程序默認值)位於.RenderIncludes()調用中未指定位置的任何位置。 PopupRenderPosition = RenderPosition.Right, // defaults to left PopupMaxTracesToShow = 10, // defaults to 15 // ResultsAuthorize(可選 - 默認情況下對所有人開放): // 因為探查器結果可以包含敏感數據(例如顯示參數值的sql查詢),我們可以定義一個函數來授權客戶端查看JSON或整頁結果。 // 我們在http://stackoverflow.com上使用它來檢查請求cookie是否屬於有效的開發人員。 ResultsAuthorize = request => { // 如果您需要在每個請求的基礎上限制性能分析的可見性,則可以實現此操作 // 例如,對於此特定路徑,我們將僅允許在設置查詢參數時進行分析 if ("/MiniProfiler/ResultsAuthorization".Equals(request.Url.LocalPath, StringComparison.OrdinalIgnoreCase)) { return((request.Url.Query).IndexOf("isauthorized", StringComparison.OrdinalIgnoreCase) >= 0); } // 所有其他路徑可以檢查我們的全局切換 return(!DisableProfilingResults); }, // ResultsListAuthorize(可選 - 默認情況下對所有人開放) // 默認情況下,儲存的所有會話的列表都受到限制,您必須返回true以允許它 ResultsListAuthorize = request => { // 如果您需要在每個請求的基礎上限制性能分析列表的可見性,則可以實現此操作 return(true); // 所有要求在我們快樂的世界中都是合法的 }, // Stack trace settings StackMaxLength = 256, // default is 120 characters // (可選) 您可以禁用 "Connection Open()", "Connection Close()" (和異步變數) 追踪 // (默認為true,並追踪連接打開/關閉) TrackConnectionOpenClose = true } // 可選設置,用於控制詳細信息窗格中的堆棧跟踪輸出 .ExcludeType("SessionFactory") // 忽略任何名為SessionFactory的類 .ExcludeAssembly("NHibernate") // 忽略任何名為NHibernate的程序集 .ExcludeMethod("Flush") // 忽略名稱為Flush的任何方法 .AddViewProfiling() // 添加MVC視圖分析 ); MiniProfilerEF6.Initialize(); }
/// <summary> /// The assert timings exist. /// </summary> /// <param name="profiler">The profiler.</param> /// <param name="count">The count.</param> private void AssertTimingsExist(MiniProfiler profiler, int count) { Assert.That(_conn.Query<int>("select count(*) from MiniProfilerTimings where MiniProfilerId = @Id", new { profiler.Id }).Single() == count); }
public ProfiledSqlDbConnection(SqlConnection connection, MiniProfiler profiler) : base(connection, profiler) { Connection = connection; }
/// <summary> /// Stores <param name="profiler"/> to MongoDB under its <see cref="MiniProfiler.Id"/>; /// stores all child Timings and SqlTimings to their respective tables. /// </summary> public override void Save(MiniProfiler profiler) { var profilerPoco = new MiniProfilerPoco { Id = profiler.Id.ToString(), Name = Truncate(profiler.Name, 200), Started = profiler.Started, MachineName = Truncate(profiler.MachineName, 100), User = Truncate(profiler.User, 100), Level = profiler.Level, RootTimingId = profiler.Root.Id, DurationMilliseconds = (double)profiler.DurationMilliseconds, DurationMillisecondsInSql = (double)profiler.DurationMillisecondsInSql, HasSqlTimings = profiler.HasSqlTimings, HasDuplicateSqlTimings = profiler.HasDuplicateSqlTimings, HasTrivialTimings = profiler.HasTrivialTimings, HasAllTrivialTimings = profiler.HasAllTrivialTimings, TrivialDurationThresholdMilliseconds = (double)profiler.TrivialDurationThresholdMilliseconds, HasUserViewed = profiler.HasUserViewed }; var result = Profilers.Save(profilerPoco, SafeMode.True); if (result.UpdatedExisting == false) { //Save Root Timing SaveTiming(profiler, profiler.Root); } // we may have a missing client timing - re save if (profiler.ClientTimings != null) { SaveClientTiming(profiler); } }
/// <summary> /// Stores <param name="profiler"/> to dbo.MiniProfilers under its <see cref="MiniProfiler.Id"/>; /// stores all child Timings and SqlTimings to their respective tables. /// </summary> public override void Save(MiniProfiler profiler) { const string sql = @"insert into MiniProfilers (Id, Name, Started, MachineName, [User], Level, RootTimingId, DurationMilliseconds, DurationMillisecondsInSql, HasSqlTimings, HasDuplicateSqlTimings, HasTrivialTimings, HasAllTrivialTimings, TrivialDurationThresholdMilliseconds, HasUserViewed) select @Id, @Name, @Started, @MachineName, @User, @Level, @RootTimingId, @DurationMilliseconds, @DurationMillisecondsInSql, @HasSqlTimings, @HasDuplicateSqlTimings, @HasTrivialTimings, @HasAllTrivialTimings, @TrivialDurationThresholdMilliseconds, @HasUserViewed where not exists (select 1 from MiniProfilers where Id = @Id)"; // this syntax works on both mssql and sqlite using (var conn = GetOpenConnection()) { var insertCount = conn.Execute(sql, new { Id = profiler.Id, Name = profiler.Name.Truncate(200), Started = profiler.Started, MachineName = profiler.MachineName.Truncate(100), User = profiler.User.Truncate(100), Level = profiler.Level, RootTimingId = profiler.Root.Id, DurationMilliseconds = profiler.DurationMilliseconds, DurationMillisecondsInSql = profiler.DurationMillisecondsInSql, HasSqlTimings = profiler.HasSqlTimings, HasDuplicateSqlTimings = profiler.HasDuplicateSqlTimings, HasTrivialTimings = profiler.HasTrivialTimings, HasAllTrivialTimings = profiler.HasAllTrivialTimings, TrivialDurationThresholdMilliseconds = profiler.TrivialDurationThresholdMilliseconds, HasUserViewed = profiler.HasUserViewed }); if (insertCount > 0) SaveTiming(conn, profiler, profiler.Root); } }
/// <summary> /// Saves parameter Timing to the sqltimings collection. /// </summary> private void SaveSqlTiming(MiniProfiler profiler, SqlTiming s) { var sqlTimingPoco = new SqlTimingPoco { Id = s.Id.ToString(), MiniProfilerId = profiler.Id.ToString(), ParentTimingId = s.ParentTiming.Id.ToString(), ExecuteType = s.ExecuteType, StartMilliseconds = (double)s.StartMilliseconds, DurationMilliseconds = (double)s.DurationMilliseconds, FirstFetchDurationMilliseconds = (double)s.FirstFetchDurationMilliseconds, IsDuplicate = s.IsDuplicate, StackTraceSnippet = Truncate(s.StackTraceSnippet, 200), CommandString = s.CommandString }; SqlTimings.Insert(sqlTimingPoco); if (s.Parameters != null && s.Parameters.Count > 0) { SaveSqlTimingParameters(profiler, s); } }
/// <summary> /// Saves parameter SqlTiming to the dbo.MiniProfilerSqlTimings table. /// </summary> protected virtual void SaveSqlTiming(DbConnection conn, MiniProfiler profiler, SqlTiming st) { const string sql = @"insert into MiniProfilerSqlTimings (Id, MiniProfilerId, ParentTimingId, ExecuteType, StartMilliseconds, DurationMilliseconds, FirstFetchDurationMilliseconds, IsDuplicate, StackTraceSnippet, CommandString) values (@Id, @MiniProfilerId, @ParentTimingId, @ExecuteType, @StartMilliseconds, @DurationMilliseconds, @FirstFetchDurationMilliseconds, @IsDuplicate, @StackTraceSnippet, @CommandString)"; conn.Execute(sql, new { Id = st.Id, MiniProfilerId = profiler.Id, ParentTimingId = st.ParentTiming.Id, ExecuteType = st.ExecuteType, StartMilliseconds = st.StartMilliseconds, DurationMilliseconds = st.DurationMilliseconds, FirstFetchDurationMilliseconds = st.FirstFetchDurationMilliseconds, IsDuplicate = st.IsDuplicate, StackTraceSnippet = st.StackTraceSnippet.Truncate(200), CommandString = st.CommandString }); if (st.Parameters != null && st.Parameters.Count > 0) { SaveSqlTimingParameters(conn, profiler, st); } }
/// <summary> /// Saves parameter Timing to the timings table. /// </summary> private void SaveTiming(MiniProfiler profiler, Timing t) { var timingPoco = new TimingPoco { Id = t.Id.ToString(), MiniProfilerId = profiler.Id.ToString(), ParentTimingId = t.IsRoot ? (string)null : t.ParentTiming.Id.ToString(), Name = Truncate(t.Name, 200), Depth = t.Depth, StartMilliseconds = (double)t.StartMilliseconds, DurationMilliseconds = (double)t.DurationMilliseconds, DurationWithoutChildrenMilliseconds = (double)t.DurationWithoutChildrenMilliseconds, SqlTimingsDurationMilliseconds = (double)t.SqlTimingsDurationMilliseconds, IsRoot = t.IsRoot, HasChildren = t.HasChildren, IsTrivial = t.IsTrivial, HasSqlTimings = t.HasSqlTimings, HasDuplicateSqlTimings = t.HasDuplicateSqlTimings, ExecutedReaders = t.ExecutedReaders, ExecutedScalars = t.ExecutedScalars, ExecutedNonQueries = t.ExecutedNonQueries }; Timings.Insert(timingPoco); if (t.HasSqlTimings) { foreach (var st in t.SqlTimings) { SaveSqlTiming(profiler, st); } } if (t.HasChildren) { foreach (var child in t.Children) { SaveTiming(profiler, child); } } }
/// <summary> /// Saves any SqlTimingParameters used in the profiled SqlTiming to the dbo.MiniProfilerSqlTimingParameters table. /// </summary> protected virtual void SaveSqlTimingParameters(DbConnection conn, MiniProfiler profiler, SqlTiming st) { const string sql = @"insert into MiniProfilerSqlTimingParameters (MiniProfilerId, ParentSqlTimingId, Name, DbType, Size, Value) values (@MiniProfilerId, @ParentSqlTimingId, @Name, @DbType, @Size, @Value)"; foreach (var p in st.Parameters) { conn.Execute(sql, new { MiniProfilerId = profiler.Id, ParentSqlTimingId = st.Id, Name = p.Name.Truncate(130), DbType = p.DbType.Truncate(50), Size = p.Size, Value = p.Value }); } }