Пример #1
0
        private static async Task <string> DoWork()
        {
            ProfilingSession.Start("DoWork");

            // Avoid GC of session
            _current = ProfilingSession.Current;

            ITimingSession timingSession = ProfilingSession.Current.Profiler.GetTimingSession();

            using (ProfilingSession.Current.Step("child1"))
            {
                await Task.WhenAll(Task.Run(() =>
                {
                    using (ProfilingSession.Current.Step("child1.1"))
                    {
                        Thread.Sleep(10);
                    }
                }),
                                   Task.Run(() =>
                {
                    using (ProfilingSession.Current.Step("child1.2"))
                    {
                        Thread.Sleep(20);
                    }
                }));
            }
            ProfilingSession.Stop();
            string report = GetReport(timingSession);

            return(report);
        }
Пример #2
0
        public void TestProfilingSession_Start()
        {
            // mock http context
            var mockHttpContext = new HttpContextMock();

            HttpContext.Current = mockHttpContext.Object;

            // ensure HttpContextCallContextProfilingSessionContainer is in use
            Assert.IsTrue(ProfilingSession.ProfilingSessionContainer is WebProfilingSessionContainer);

            // mock profiler and provider
            var profilerId   = Guid.NewGuid();
            var mockProfiler = new Mock <IProfiler>();

            mockProfiler.Setup(p => p.Id).Returns(profilerId);
            mockProfiler.Setup(p => p.GetTimingSession()).Returns(new TimingSession(mockProfiler.Object, "test", null));
            ProfilingSession.CreateProfilerHandler = (s, storage, arg3) => mockProfiler.Object;

            // mock profiling storage
            var mockProfilingStorage = new Mock <IProfilingStorage>();

            ProfilingSession.ProfilingStorage = mockProfilingStorage.Object;
            Assert.AreEqual(mockProfilingStorage.Object, ProfilingSession.ProfilingStorage);

            // execute
            ProfilingSession.Start("test");

            Assert.AreEqual(mockProfiler.Object, ProfilingSession.Current.Profiler);
            Assert.AreEqual(mockProfiler.Object, (mockHttpContext.Object.Items["nano_profiler::current_profiling_session"] as ProfilingSession).Profiler);
            Assert.AreEqual(mockProfiler.Object.Id, CallContext.LogicalGetData("nano_profiler::current_profiling_session_id"));
        }
Пример #3
0
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseCoreProfiler(true);

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });

            // InitializeDatabase is executed in async thread on app startup
            // to profile its performance, we need to call ProfilingSession.Start()/Stop() explicitly
            try
            {
                ProfilingSession.Start("InitializeDatabase");
                InitializeDatabase(app);
            }
            finally
            {
                ProfilingSession.Stop();
            }
        }
        object IDispatchMessageInspector.AfterReceiveRequest(
            ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            if (request == null || request.Headers == null || string.IsNullOrEmpty(request.Headers.Action))
            {
                return(null);
            }

            // fix properties for WCF profiling session
            var profilingSession = GetCurrentProfilingSession();

            if (profilingSession == null)
            {
                // start the profiling session if not started
                // NOTICE:
                //   When not set <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> in web.config,
                //   and if there is already a profiling session started in begin request event when working with HTTP bindings,
                //   since HttpContext.Current is not accessible from WCF context, there will be two profiling sessions
                //   be saved, one for the web request wrapping the WCF call and the other for the WCF call.
                ProfilingSession.Start(request.Headers.Action);
            }
            else
            {
                // if the profiling session has already been started as a normal web profiling session
                // we need to fix the properties of the profiling session first

                // reset ProfilingSessionContainer.CurrentSession
                // which internally tries to cache the profiling session in WcfContext
                // to ensure the profiling session is cached in WcfInstanceContext
                ProfilingSession.ProfilingSessionContainer.CurrentSession = profilingSession;

                // set profiler session's name to the WCF action name
                profilingSession.Profiler.GetTimingSession().Name = request.Headers.Action;
            }

            var correlationId = GetCorrelationIdRequestHeaders(request, channel);

            if (!string.IsNullOrWhiteSpace(correlationId))
            {
                ProfilingSession.Current.AddField("correlationId", correlationId);
            }

            SetProfilingSessionClientIpAndLocalAddress(request, channel);

            return(null);
        }
Пример #5
0
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            ProfilingSession.Start("session" + Thread.CurrentThread.ManagedThreadId);

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseCoreProfiler(drillDown: true);

            app
            .UseMiniProfiler()
            .UseStaticFiles()
            .UseRouting()
            .UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
        }
Пример #6
0
        public static void Main(string[] args)
        {
            //Console.ReadKey();

            // initialize logger as the Console log provider
            // the json storage writes log to the ProfilingSession.LoggerFactory based logger
            ProfilingSession.LoggerFactory.AddConsole();

            // in coreprofiler.json file, we configured the profiling storage as the json storage
            // the json storage use the Microsoft.Extensions.Logging API for profiling log persistence

            // different from in web application, for non-web application,
            // we need to call ProfilingSession.Start()/Stop() explicitly
            // to start/stop a profiling session
            ProfilingSession.Start("session" + Thread.CurrentThread.ManagedThreadId);

            using (ProfilingSession.Current.Step(ProfilingSession.Current.Profiler.GetTimingSession().Name + " - step 1"))
            {
                Thread.Sleep(200);
            }

            using (ProfilingSession.Current.Step(ProfilingSession.Current.Profiler.GetTimingSession().Name + " - step 2"))
            {
                Task.Factory.StartNew(() =>
                {
                    using (ProfilingSession.Current.Step(ProfilingSession.Current.Profiler.GetTimingSession().Name + " - step 3"))
                    {
                        Console.WriteLine("Hello Async");
                        Thread.Sleep(50);
                    }
                }).Wait();

                using (ProfilingSession.Current.Step(ProfilingSession.Current.Profiler.GetTimingSession().Name + " - step 4"))
                {
                    Thread.Sleep(100);
                }
            }

            ProfilingSession.Stop();

            Console.ReadKey();
        }
Пример #7
0
        public void TestProfilingSession_Start_HandleException()
        {
            var exceptionHandled  = false;
            var expectedException = new Exception();

            ProfilingSession.CreateProfilerHandler  = (s, storage, arg3) => { throw expectedException; };
            ProfilingSession.HandleExceptionHandler = (a, b) =>
            {
                Assert.AreEqual(expectedException, a);
                Assert.AreEqual(typeof(ProfilingSession), b);

                exceptionHandled = true;
            };

            // mock profiling storage
            var mockProfilingStorage = new Mock <IProfilingStorage>();

            ProfilingSession.ProfilingStorage = mockProfilingStorage.Object;

            // execute
            ProfilingSession.Start("test");

            Assert.IsTrue(exceptionHandled);
        }
Пример #8
0
        private void ApplicationOnBeginRequest(object sender, EventArgs eventArgs)
        {
            var context = HttpContext.Current;

            if (context == null)
            {
                return;
            }

            #region Start web profiling

            var url = context.Request.Url.ToString();

            // WCF profiling will be started in wcf profiling behavior
            // so it is not necessary to start profiling here
            if (url.Contains(".svc"))
            {
                return;
            }

            ProfilingSession.Start(url);

            var correlationId = GetCorrelationIdFromHeaders(context);
            if (!string.IsNullOrWhiteSpace(correlationId))
            {
                ProfilingSession.Current.AddField("correlationId", correlationId);
            }

            #endregion

            if (ProfilingSession.CircularBuffer == null)
            {
                return;
            }

            ClearIfCurrentProfilingSessionStopped();

            // only supports GET method for view results
            if (context.Request.HttpMethod != "GET")
            {
                return;
            }

            var path = context.Request.Path.TrimEnd('/');

            // generate baseViewPath
            string baseViewPath = null;
            var    posStart     = path.IndexOf(ViewUrl, StringComparison.OrdinalIgnoreCase);
            if (posStart >= 0)
            {
                baseViewPath = path.Substring(0, posStart) + ViewUrl;
            }

            if (path.EndsWith("/nanoprofiler-resources/icons"))
            {
                context.Response.ContentType = "image/png";
                var iconsStream = GetType().Assembly.GetManifestResourceStream("EF.Diagnostics.Profiling.Web.Handlers.icons.png");
                using (var br = new BinaryReader(iconsStream))
                {
                    context.Response.BinaryWrite(br.ReadBytes((int)iconsStream.Length));
                    context.Response.End();
                }
                return;
            }

            if (path.EndsWith("/nanoprofiler-resources/css"))
            {
                context.Response.ContentType = "text/css";
                var cssStream = GetType().Assembly.GetManifestResourceStream("EF.Diagnostics.Profiling.Web.Handlers.treeview_timeline.css");
                using (var sr = new StreamReader(cssStream))
                {
                    context.Response.Write(sr.ReadToEnd());
                    context.Response.End();
                }
                return;
            }

            // view index of all latest results: ~/nanoprofiler/view
            if (path.EndsWith(ViewUrl, StringComparison.OrdinalIgnoreCase))
            {
                context.Response.ContentType = "text/html";

                var sb = new StringBuilder();
                sb.Append("<head>");
                sb.Append("<title>NanoProfiler Latest Profiling Results</title>");
                sb.Append("<style>th { width: 200px; text-align: left; } .gray { background-color: #eee; } .nowrap { white-space: nowrap;padding-right: 20px; vertical-align:top; } </style>");
                sb.Append("</head");
                sb.Append("<body>");
                sb.Append(ViewResultIndexHeaderHtml);

                var tagFilter = context.Request.QueryString["tag"];
                if (!string.IsNullOrWhiteSpace(tagFilter))
                {
                    sb.Append("<div><strong>Filtered by tag:</strong> ");
                    sb.Append(tagFilter);
                    sb.Append("<br/><br /></div>");
                }

                sb.Append("<table>");
                sb.Append("<tr><th class=\"nowrap\">Time (UTC)</th><th class=\"nowrap\">Duration (ms)</th><th>Url</th></tr>");
                var latestResults = ProfilingSession.CircularBuffer.OrderByDescending(r => r.Started);
                var i             = 0;
                foreach (var result in latestResults)
                {
                    if (!string.IsNullOrWhiteSpace(tagFilter) &&
                        (result.Tags == null || !result.Tags.Contains(tagFilter, StringComparer.OrdinalIgnoreCase)))
                    {
                        continue;
                    }

                    sb.Append("<tr");
                    if ((i++) % 2 == 1)
                    {
                        sb.Append(" class=\"gray\"");
                    }
                    sb.Append("><td class=\"nowrap\">");
                    sb.Append(result.Started.ToString("yyyy-MM-ddTHH:mm:ss.FFF"));
                    sb.Append("</td><td class=\"nowrap\">");
                    sb.Append(result.DurationMilliseconds);
                    sb.Append("</td><td><a href=\"");
                    sb.Append(baseViewPath);
                    sb.Append("/");
                    sb.Append(result.Id.ToString());
                    sb.Append("\" target=\"_blank\">");
                    sb.Append(result.Name.Replace("\r\n", " "));
                    sb.Append("</a></td></tr>");
                }
                sb.Append("</table>");

                sb.Append("</body>");

                context.Response.Write(sb.ToString());
                context.Response.End();
                return;
            }

            // view specific result by uuid: ~/nanoprofiler/view/{uuid}
            if (path.IndexOf(ViewUrl, StringComparison.OrdinalIgnoreCase) >= 0)
            {
                context.Response.ContentType = "text/html";

                var sb = new StringBuilder();
                sb.Append("<head>");
                sb.Append("<meta charset=\"utf-8\" />");
                sb.Append("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />");
                sb.Append("<title>NanoProfiler Profiling Result</title>");
                sb.Append("<link rel=\"stylesheet\" href=\"./nanoprofiler-resources/css\" />");
                sb.Append("</head");
                sb.Append("<body>");
                sb.Append("<h1>NanoProfiler Profiling Result</h1>");

                var uuid   = path.Split('/').Last();
                var result = ProfilingSession.CircularBuffer.FirstOrDefault(
                    r => r.Id.ToString().ToLowerInvariant() == uuid.ToLowerInvariant());
                if (result != null)
                {
                    sb.Append("<div class=\"css-treeview\">");

                    // print summary
                    sb.Append("<ul>");
                    sb.Append("<li class=\"summary\">");
                    PrintDrillUpLink(sb, result, baseViewPath);
                    sb.Append(result.Name.Replace("\r\n", " "));
                    sb.Append("</li>");
                    sb.Append("<li class=\"summary\">");
                    if (result.Data != null)
                    {
                        foreach (var keyValue in result.Data)
                        {
                            if (string.IsNullOrWhiteSpace(keyValue.Value))
                            {
                                continue;
                            }

                            sb.Append("<b>");
                            sb.Append(keyValue.Key);
                            sb.Append(": </b>");
                            var encodedValue = HttpUtility.HtmlEncode(keyValue.Value);
                            if (keyValue.Key.EndsWith("Count") || keyValue.Key.EndsWith("Duration"))
                            {
                                sb.Append("<span class=\"");
                                sb.Append(keyValue.Key);
                                sb.Append("\">");
                                sb.Append(encodedValue);
                                sb.Append("</span>");
                            }
                            else
                            {
                                sb.Append(encodedValue);
                            }
                            sb.Append(" &nbsp; ");
                        }
                    }
                    sb.Append("<b>machine: </b>");
                    sb.Append(result.MachineName);
                    sb.Append(" &nbsp; ");
                    if (result.Tags != null && result.Tags.Any())
                    {
                        sb.Append("<b>tags: </b>");
                        sb.Append(string.Join(", ", result.Tags.Select(t => string.Format("<a href=\"{2}?tag={0}\">{1}</a>", HttpUtility.UrlEncode(t), t, baseViewPath))));
                        sb.Append(" &nbsp; ");
                    }
                    sb.Append("</li>");
                    sb.Append("</ul>");

                    var totalLength = result.DurationMilliseconds;
                    if (totalLength == 0)
                    {
                        totalLength = 1;
                    }
                    var factor = 300.0 / totalLength;

                    // print ruler
                    sb.Append("<ul>");
                    sb.Append("<li class=\"ruler\"><span style=\"width:300px\">0</span><span style=\"width:80px\">");
                    sb.Append(totalLength);
                    sb.Append(
                        " (ms)</span><span style=\"width:20px\">&nbsp;</span><span style=\"width:60px\">Start</span><span style=\"width:60px\">Duration</span><span style=\"width:20px\">&nbsp;</span><span>Timing Hierarchy</span></li>");
                    sb.Append("</ul>");

                    // print timings
                    sb.Append("<ul class=\"timing\">");
                    PrintTimings(result, result.Id, sb, factor, baseViewPath);
                    sb.Append("");
                    sb.Append("</ul>");
                    sb.Append("</div>");

                    // print timing data popups
                    foreach (var timing in result.Timings)
                    {
                        if (timing.Data == null || !timing.Data.Any())
                        {
                            continue;
                        }

                        sb.Append("<aside id=\"data_");
                        sb.Append(timing.Id.ToString());
                        sb.Append("\" style=\"display:none\" class=\"modal\">");
                        sb.Append("<div>");
                        sb.Append("<h4><code>");
                        sb.Append(timing.Name.Replace("\r\n", " "));
                        sb.Append("</code></h4>");
                        sb.Append("<textarea>");
                        foreach (var keyValue in timing.Data)
                        {
                            if (string.IsNullOrWhiteSpace(keyValue.Value))
                            {
                                continue;
                            }

                            sb.Append(keyValue.Key);
                            sb.Append(":\r\n");
                            var value = keyValue.Value.Trim();
                            if (value.StartsWith("<"))
                            {
                                // asuume it is XML
                                // try to format XML with indent
                                var doc = new XmlDocument();
                                try
                                {
                                    doc.LoadXml(value);
                                    var ms     = new MemoryStream();
                                    var writer = new XmlTextWriter(ms, null)
                                    {
                                        Formatting = Formatting.Indented
                                    };
                                    doc.Save(writer);
                                    ms.Seek(0, SeekOrigin.Begin);
                                    using (var sr = new StreamReader(ms))
                                    {
                                        value = sr.ReadToEnd();
                                    }
                                }
                                catch
                                {
                                    //squash exception
                                }
                            }
                            sb.Append(value);
                            sb.Append("\r\n\r\n");
                        }
                        if (timing.Tags != null && timing.Tags.Any())
                        {
                            sb.Append("tags:\r\n");
                            sb.Append(timing.Tags);
                            sb.Append("\r\n");
                        }
                        sb.Append("</textarea>");
                        sb.Append(
                            "<a href=\"#close\" title=\"Close\" onclick=\"this.parentNode.parentNode.style.display='none'\">Close</a>");
                        sb.Append("</div>");
                        sb.Append("</aside>");
                    }
                }
                else
                {
                    sb.Append("Specified result does not exist!");
                }
                sb.Append("</body>");

                context.Response.Write(sb.ToString());
                context.Response.End();
                return;
            }
        }
Пример #9
0
 public void TestProfilingSession_Start_InvalidName()
 {
     Assert.Throws <ArgumentNullException>(() => ProfilingSession.Start(null));
 }
        public async Task Invoke(HttpContext context)
        {
            // disable view profiling if CircularBuffer is not enabled
            if (ProfilingSession.CircularBuffer == null)
            {
                await _next.Invoke(context);

                return;
            }

            ClearIfCurrentProfilingSessionStopped();

            var url = UriHelper.GetDisplayUrl(context.Request);

            ProfilingSession.Start(url);

            // set correlationId if exists in header
            var correlationId = GetCorrelationIdFromHeaders(context);

            if (!string.IsNullOrWhiteSpace(correlationId))
            {
                ProfilingSession.Current.AddField("correlationId", correlationId);
            }

            // only supports GET method for view results
            if (context.Request.Method != "GET")
            {
                await _next.Invoke(context);

                return;
            }

            var path = context.Request.Path.ToString().TrimEnd('/');

            // generate baseViewPath
            string baseViewPath = null;
            var    posStart     = path.IndexOf(ViewUrl, StringComparison.OrdinalIgnoreCase);

            if (posStart < 0)
            {
                posStart = path.IndexOf(ViewUrlNano, StringComparison.OrdinalIgnoreCase);
            }
            if (posStart >= 0)
            {
                baseViewPath = path.Substring(0, posStart) + ViewUrl;
            }

            if (path.EndsWith("/coreprofiler-resources/icons"))
            {
                context.Response.ContentType = "image/png";
                var iconsStream = GetType().GetTypeInfo().Assembly.GetManifestResourceStream("CoreProfiler.Web.icons.png");
                using (var br = new BinaryReader(iconsStream))
                {
                    await context.Response.Body.WriteAsync(br.ReadBytes((int)iconsStream.Length), 0, (int)iconsStream.Length);
                }
                return;
            }

            if (path.EndsWith("/coreprofiler-resources/css"))
            {
                context.Response.ContentType = "text/css";
                var cssStream = GetType().GetTypeInfo().Assembly.GetManifestResourceStream("CoreProfiler.Web.treeview_timeline.css");
                using (var sr = new StreamReader(cssStream))
                {
                    await context.Response.WriteAsync(sr.ReadToEnd());
                }
                return;
            }

            // view index of all latest results: ~/coreprofiler/view
            if (path.EndsWith(ViewUrl, StringComparison.OrdinalIgnoreCase) ||
                path.EndsWith(ViewUrlNano, StringComparison.OrdinalIgnoreCase))
            {
                // try to handle import/export first
                var import = context.Request.Query[Import];
                if (Uri.IsWellFormedUriString(import, UriKind.Absolute))
                {
                    await ImportSessionsFromUrl(import);

                    return;
                }

                if (context.Request.QueryString.ToString() == Export)
                {
                    context.Response.ContentType = "application/json";

                    await context.Response.WriteAsync(ImportSerializer.SerializeSessions(ProfilingSession.CircularBuffer));

                    return;
                }

                var exportCorrelationId = context.Request.Query[CorrelationId];
                if (!string.IsNullOrEmpty(exportCorrelationId))
                {
                    context.Response.ContentType = "application/json";
                    var result = ProfilingSession.CircularBuffer.FirstOrDefault(
                        r => r.Data != null && r.Data.ContainsKey(CorrelationId) && r.Data[CorrelationId] == exportCorrelationId);
                    if (result != null)
                    {
                        await context.Response.WriteAsync(ImportSerializer.SerializeSessions(new[] { result }));

                        return;
                    }
                }

                // render result list view
                context.Response.ContentType = "text/html";

                var sb = new StringBuilder();
                sb.Append("<head>");
                sb.Append("<title>CoreProfiler Latest Profiling Results</title>");
                sb.Append("<style>th { width: 200px; text-align: left; } .gray { background-color: #eee; } .nowrap { white-space: nowrap;padding-right: 20px; vertical-align:top; } </style>");
                sb.Append("</head");
                sb.Append("<body>");
                sb.Append(ViewResultIndexHeaderHtml);

                var tagFilter = context.Request.Query["tag"];
                if (!string.IsNullOrWhiteSpace(tagFilter))
                {
                    sb.Append("<div><strong>Filtered by tag:</strong> ");
                    sb.Append(tagFilter);
                    sb.Append("<br/><br /></div>");
                }

                sb.Append("<table>");
                sb.Append("<tr><th class=\"nowrap\">Time (UTC)</th><th class=\"nowrap\">Duration (ms)</th><th>Url</th></tr>");
                var latestResults = ProfilingSession.CircularBuffer.OrderByDescending(r => r.Started);
                var i             = 0;
                foreach (var result in latestResults)
                {
                    if (!string.IsNullOrWhiteSpace(tagFilter) &&
                        (result.Tags == null || !result.Tags.Contains <string>(tagFilter, StringComparer.OrdinalIgnoreCase)))
                    {
                        continue;
                    }

                    sb.Append("<tr");
                    if ((i++) % 2 == 1)
                    {
                        sb.Append(" class=\"gray\"");
                    }
                    sb.Append("><td class=\"nowrap\">");
                    sb.Append(result.Started.ToString("yyyy-MM-ddTHH:mm:ss.FFF"));
                    sb.Append("</td><td class=\"nowrap\">");
                    sb.Append(result.DurationMilliseconds);
                    sb.Append("</td><td><a href=\"");
                    sb.Append(baseViewPath);
                    sb.Append("/");
                    sb.Append(result.Id.ToString());
                    sb.Append("\" target=\"_blank\">");
                    sb.Append(result.Name.Replace("\r\n", " "));
                    sb.Append("</a></td></tr>");
                }
                sb.Append("</table>");

                sb.Append("</body>");

                await context.Response.WriteAsync(sb.ToString());

                return;
            }

            // view specific result by uuid: ~/coreprofiler/view/{uuid}
            if (path.IndexOf(ViewUrl, StringComparison.OrdinalIgnoreCase) >= 0 ||
                path.IndexOf(ViewUrlNano, StringComparison.OrdinalIgnoreCase) >= 0)
            {
                context.Response.ContentType = "text/html";

                var sb = new StringBuilder();
                sb.Append("<head>");
                sb.Append("<meta charset=\"utf-8\" />");
                sb.Append("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />");
                sb.Append("<title>CoreProfiler Profiling Result</title>");
                sb.Append("<link rel=\"stylesheet\" href=\"./coreprofiler-resources/css\" />");
                sb.Append("</head");
                sb.Append("<body>");
                sb.Append("<h1>CoreProfiler Profiling Result</h1>");

                var uuid   = path.Split('/').Last();
                var result = ProfilingSession.CircularBuffer.FirstOrDefault(
                    r => r.Id.ToString().ToLowerInvariant() == uuid.ToLowerInvariant());
                if (result != null)
                {
                    if (TryToImportDrillDownResult)
                    {
                        // try to import drill down results
                        foreach (var timing in result.Timings)
                        {
                            if (timing.Data == null || !timing.Data.ContainsKey(CorrelationId))
                            {
                                continue;
                            }
                            Guid parentResultId;
                            if (!Guid.TryParse(timing.Data[CorrelationId], out parentResultId) ||
                                ProfilingSession.CircularBuffer.Any(r => r.Id == parentResultId))
                            {
                                continue;
                            }

                            string remoteAddress;
                            if (!timing.Data.TryGetValue("remoteAddress", out remoteAddress))
                            {
                                remoteAddress = timing.Name;
                            }

                            if (!Uri.IsWellFormedUriString(remoteAddress, UriKind.Absolute))
                            {
                                continue;
                            }

                            if (!remoteAddress.StartsWith("http", StringComparison.OrdinalIgnoreCase))
                            {
                                continue;
                            }

                            var pos = remoteAddress.IndexOf("?");
                            if (pos > 0)
                            {
                                remoteAddress = remoteAddress.Substring(0, pos);
                            }
                            if (remoteAddress.Split('/').Last().Contains("."))
                            {
                                remoteAddress = remoteAddress.Substring(0, remoteAddress.LastIndexOf("/"));
                            }

                            try
                            {
                                await ImportSessionsFromUrl(remoteAddress + "/coreprofiler/view?" + CorrelationId + "=" + parentResultId.ToString("N"));
                            }
                            catch (Exception ex)
                            {
                                System.Diagnostics.Debug.Write(ex.Message);

                                //ignore exceptions
                            }
                        }
                    }

                    // render result tree
                    sb.Append("<div class=\"css-treeview\">");

                    // print summary
                    sb.Append("<ul>");
                    sb.Append("<li class=\"summary\">");
                    PrintDrillUpLink(sb, result, baseViewPath);
                    sb.Append(result.Name.Replace("\r\n", " "));
                    sb.Append("</li>");
                    sb.Append("<li class=\"summary\">");
                    if (result.Data != null)
                    {
                        foreach (var keyValue in result.Data)
                        {
                            if (string.IsNullOrWhiteSpace(keyValue.Value))
                            {
                                continue;
                            }

                            sb.Append("<b>");
                            sb.Append(keyValue.Key);
                            sb.Append(": </b>");
                            var encodedValue = WebUtility.HtmlEncode(keyValue.Value);
                            if (keyValue.Key.EndsWith("Count") || keyValue.Key.EndsWith("Duration"))
                            {
                                sb.Append("<span class=\"");
                                sb.Append(keyValue.Key);
                                sb.Append("\">");
                                sb.Append(encodedValue);
                                sb.Append("</span>");
                            }
                            else
                            {
                                sb.Append(encodedValue);
                            }
                            sb.Append(" &nbsp; ");
                        }
                    }
                    sb.Append("<b>machine: </b>");
                    sb.Append(result.MachineName);
                    sb.Append(" &nbsp; ");
                    if (result.Tags != null && result.Tags.Any())
                    {
                        sb.Append("<b>tags: </b>");
                        sb.Append(string.Join(", ", result.Tags.Select(t => string.Format("<a href=\"{2}?tag={0}\">{1}</a>", HttpUtility.UrlEncode(t), t, baseViewPath))));
                        sb.Append(" &nbsp; ");
                    }
                    sb.Append("</li>");
                    sb.Append("</ul>");

                    var totalLength = result.DurationMilliseconds;
                    if (totalLength == 0)
                    {
                        totalLength = 1;
                    }
                    var factor = 300.0 / totalLength;

                    // print ruler
                    sb.Append("<ul>");
                    sb.Append("<li class=\"ruler\"><span style=\"width:300px\">0</span><span style=\"width:80px\">");
                    sb.Append(totalLength);
                    sb.Append(
                        " (ms)</span><span style=\"width:20px\">&nbsp;</span><span style=\"width:60px\">Start</span><span style=\"width:60px\">Duration</span><span style=\"width:20px\">&nbsp;</span><span>Timing Hierarchy</span></li>");
                    sb.Append("</ul>");

                    // print timings
                    sb.Append("<ul class=\"timing\">");
                    PrintTimings(result, result.Id, sb, factor, baseViewPath);
                    sb.Append("");
                    sb.Append("</ul>");
                    sb.Append("</div>");

                    // print timing data popups
                    foreach (var timing in result.Timings)
                    {
                        if (timing.Data == null || !timing.Data.Any())
                        {
                            continue;
                        }

                        sb.Append("<aside id=\"data_");
                        sb.Append(timing.Id.ToString());
                        sb.Append("\" style=\"display:none\" class=\"modal\">");
                        sb.Append("<div>");
                        sb.Append("<h4><code>");
                        sb.Append(timing.Name.Replace("\r\n", " "));
                        sb.Append("</code></h4>");
                        sb.Append("<textarea>");
                        foreach (var keyValue in timing.Data)
                        {
                            if (string.IsNullOrWhiteSpace(keyValue.Value))
                            {
                                continue;
                            }

                            sb.Append(keyValue.Key);
                            sb.Append(":\r\n");
                            var value = keyValue.Value.Trim();

                            if (value.StartsWith("<"))
                            {
                                // asuume it is XML
                                // try to format XML with indent
                                var doc = new XmlDocument();
                                try
                                {
                                    doc.LoadXml(value);
                                    var ms         = new MemoryStream();
                                    var xwSettings = new XmlWriterSettings
                                    {
                                        Encoding    = new UTF8Encoding(false),
                                        Indent      = true,
                                        IndentChars = "\t"
                                    };
                                    using (var writer = XmlWriter.Create(ms, xwSettings))
                                    {
                                        doc.Save(writer);
                                        ms.Seek(0, SeekOrigin.Begin);
                                        using (var sr = new StreamReader(ms))
                                        {
                                            value = sr.ReadToEnd();
                                        }
                                    }
                                }
                                catch
                                {
                                    //squash exception
                                }
                            }
                            sb.Append(value);
                            sb.Append("\r\n\r\n");
                        }
                        if (timing.Tags != null && timing.Tags.Any())
                        {
                            sb.Append("tags:\r\n");
                            sb.Append(timing.Tags);
                            sb.Append("\r\n");
                        }
                        sb.Append("</textarea>");
                        sb.Append(
                            "<a href=\"#close\" title=\"Close\" onclick=\"this.parentNode.parentNode.style.display='none'\">Close</a>");
                        sb.Append("</div>");
                        sb.Append("</aside>");
                    }
                }
                else
                {
                    sb.Append("Specified result does not exist!");
                }
                sb.Append("</body>");

                await context.Response.WriteAsync(sb.ToString());

                return;
            }

            try
            {
                await _next.Invoke(context);
            }
            catch (System.Exception)
            {
                // stop and save profiling results on error
                using (ProfilingSession.Current.Step("Stop on Error")) { }

                throw;
            }
            finally{
                ProfilingSession.Stop();
            }
        }
Пример #11
0
 public void TestProfilingSession_Start_InvalidName()
 {
     ProfilingSession.Start(null);
 }
Пример #12
0
        static void Main(string[] args)
        {
            // use CircularBuffer to keep latest results in-memory so that we could expose them at runtime
            // by default the profiling results are not kept in memory
            ProfilingSession.CircularBuffer = new CircularBuffer <ITimingSession>();

            // start the Owin host to expose in-memory profiling results via Web
            WebApp.Start <OwinProfilingResultHost>("http://*:2222");

            ProfilingSession.Start("my task starts: " + DateTime.Now.ToString(CultureInfo.InvariantCulture), "tag1", "ta\"\r\ng2");

            // add addtional fields to session
            ProfilingSession.Current.Profiler.GetTimingSession().Data["sessionAdditionalField1"]     = "test1";
            ProfilingSession.Current.Profiler.GetTimingSession().Data["sessionAdditionalField2Size"] = "3";

            // keep an instance of profiling session somewhere to ensure it is not collected by GC
            _profilingSession = ProfilingSession.Current;

            using (ProfilingSession.Current.Step("do something 1"))
            {
                Thread.Sleep(200);

                // you could use a passed-through profiling session instance as well.
                // ProfilingSession.Current holds the profiling session internally by logic CallContext,
                // in complex multi-threading cases where logic CallContext might not work,
                // you might have to pass through the profiling session instead of ProfilingSession.Current
                using (var step = _profilingSession.Step("do something 2", "step tag 1"))
                {
                    // add addtional tag to step
                    step.AddTag("step tag 2");

                    // add addtional step profiling fields
                    step.AddField("stepField1", "test1");
                    step.AddField("stepField2", "test2");

                    Thread.Sleep(200);

                    using (ProfilingSession.Current.Step(() => "do something 3"))
                    {
                        Thread.Sleep(100);
                    }
                }
            }

            // the profiling results is saved asynchronously when Stop() is called
            // in this demo, the log is saved to *.log files to the output folder via log4net
            ProfilingSession.Stop();

            // usually, we import the profiling logs to elasticsearch for visualization in kibana
            // but if you want to view the profiling results at runtime in a web view
            // for the console app or windows service app, you could expose the results in-memory
            // and display the results in another web app.
            //
            // in this demo, we use Owin to expose the results to http://localhost:2222
            // and if you visit the URL below in the web SimpleDemo app,
            // you are able to see the profiling results of the console app.
            // http://localhost:64511/nanoprofiler/view?import=http://localhost:2222

            Console.WriteLine("You could view the profiling results of this ConsoleDemo in the SimpleDemo site:\nhttp://localhost:64511/nanoprofiler/view?import=http://localhost:2222");

            Console.WriteLine("Press any key to exit...");
            Console.ReadLine();
        }
Пример #13
0
        public async Task Invoke(HttpContext context)
        {
            if (context == null)
            {
                await _next.Invoke(context);

                return;
            }

            if (ProfilingSession.Disabled)
            {
                await _next.Invoke(context);

                return;
            }

            // disable view profiling if CircularBuffer is not enabled
            if (ProfilingSession.CircularBuffer == null)
            {
                await _next.Invoke(context);

                return;
            }

            ClearIfCurrentProfilingSessionStopped();

            var url = UriHelper.GetDisplayUrl(context.Request);

            ProfilingSession.Start(url);

            // set correlationId if exists in header
            var correlationId = GetCorrelationIdFromHeaders(context);

            if (!string.IsNullOrWhiteSpace(correlationId))
            {
                ProfilingSession.Current.AddField("correlationId", correlationId);
            }

            // only supports GET method for view results
            //if (context.Request.Method != "GET")
            //{
            //    try
            //    {
            //        await _next.Invoke(context);
            //    }
            //    catch (System.Exception)
            //    {
            //        // stop and save profiling results on error
            //        using (ProfilingSession.Current.Step("Stop on Error")) { }

            //        throw;
            //    }
            //    finally
            //    {
            //        ProfilingSession.Stop();
            //    }
            //    return;
            //}

            var path = context.Request.Path.ToString().TrimEnd('/');

            // generate baseViewPath
            string baseViewPath = null;
            var    posStart     = path.IndexOf(ViewUrl, StringComparison.OrdinalIgnoreCase);

            //if (posStart < 0)
            //    posStart = path.IndexOf(ViewUrlNano, StringComparison.OrdinalIgnoreCase);
            if (posStart >= 0)
            {
                baseViewPath = path.Substring(0, posStart) + ViewUrl;
            }

            // prepend pathbase if specified
            baseViewPath = context.Request.PathBase + baseViewPath;


            if (path.EndsWith("/pureprofiler-resources/icons"))
            {
                context.Response.ContentType = "image/png";
                var iconsStream = GetType().Assembly.GetManifestResourceStream("Pure.Profiler.Web.Handlers.icons.png");

                using (var br = new BinaryReader(iconsStream))
                {
                    await context.Response.Body.WriteAsync(br.ReadBytes((int)iconsStream.Length), 0, (int)iconsStream.Length);
                }
                return;
            }
            if (path.EndsWith("/pureprofiler-resources/images/json"))
            {
                context.Response.ContentType = "image/png";
                var iconsStream = GetType().Assembly.GetManifestResourceStream("Pure.Profiler.Web.Handlers.json.png");
                using (var br = new BinaryReader(iconsStream))
                {
                    await context.Response.Body.WriteAsync(br.ReadBytes((int)iconsStream.Length), 0, (int)iconsStream.Length);
                }
                return;
            }


            if (path.EndsWith("/pureprofiler-resources/css"))
            {
                context.Response.ContentType = "text/css;charset=utf-8";
                var cssStream = GetType().Assembly.GetManifestResourceStream("Pure.Profiler.Web.Handlers.treeview_timeline.css");
                using (var sr = new StreamReader(cssStream))
                {
                    await context.Response.WriteAsync(sr.ReadToEnd());
                }
                return;
            }

            if (path.EndsWith("/pureprofiler-resources/js"))
            {
                context.Response.ContentType = "text/javascript;charset=utf-8";
                var cssStream = GetType().Assembly.GetManifestResourceStream("Pure.Profiler.Web.Handlers.pureprofiler.js");
                using (var sr = new StreamReader(cssStream))
                {
                    await context.Response.WriteAsync(sr.ReadToEnd());
                }
                return;
            }

            //clear  ~/pureprofiler/view/clear
            if (path.EndsWith(ViewUrlClear, StringComparison.OrdinalIgnoreCase))
            {
                ProfilingSession.CircularBuffer.Clear();
                context.Response.Redirect(ViewUrl);
                return;
            }



            // view index of all latest results: ~/coreprofiler/view
            if (path.EndsWith(ViewUrl, StringComparison.OrdinalIgnoreCase)
                )
            {
                // try to handle import/export first
                //var import = context.Request.Query[Import];
                //if (Uri.IsWellFormedUriString(import, UriKind.Absolute))
                //{
                //    await ImportSessionsFromUrl(import);
                //    return;
                //}

                //if (context.Request.QueryString.ToString() == Export)
                //{
                //    context.Response.ContentType = "application/json;charset=utf-8";
                //    await context.Response.WriteAsync(ImportSerializer.SerializeSessions(ProfilingSession.CircularBuffer));
                //    return;
                //}

                //var exportCorrelationId = context.Request.Query[CorrelationId];
                //if (!string.IsNullOrEmpty(exportCorrelationId))
                //{
                //    context.Response.ContentType = "application/json;charset=utf-8";
                //    var result = ProfilingSession.CircularBuffer.FirstOrDefault(
                //            r => r.Data != null && r.Data.ContainsKey(CorrelationId) && r.Data[CorrelationId] == exportCorrelationId);
                //    if (result != null)
                //    {
                //        await context.Response.WriteAsync(ImportSerializer.SerializeSessions(new[] { result }));
                //        return;
                //    }
                //}

                //-----------------------展示列表项目详情--------------------------


                // render result list view

                context.Response.ContentType = "text/html;charset=utf-8";

                var sb = new StringBuilder();
                sb.Append("<head>");
                sb.Append("<title>页面资源加载时序</title>");
                sb.Append("<link rel=\"stylesheet\" href=\"./pureprofiler-resources/css\" />");
                sb.Append("<script type=\"text/javascript\" src=\"./pureprofiler-resources/js\"></script>");
                sb.Append("<style>th {   text-align: left;background: #BD6840;color: #fff;font-size: 14px; } .gray { background-color: #eee; } .pure-profiler-error-row {  color: #f00 ; } .nowrap { white-space: nowrap;padding-right: 20px; vertical-align:top; } </style>");
                sb.Append("</head");
                sb.Append("<body class='pureprofiler-pagebody' style=\"background:#EAF2FF;z-index:99999;\">");
                sb.Append(ViewResultIndexHeaderHtml);
                sb.Append("<a target='_self' href='" + ViewUrl + "'>Refresh</a>");
                sb.Append("&nbsp; <a target='_blank' href='export?exporttype=json'>Json</a>");
                sb.Append("&nbsp; <a target='_self' href='view/clear'>Clear</a>");
                sb.Append("&nbsp; <a target='_self' href=\"#\" onclick=\"return clickGlobal();\">Global</a>");

                //tab
                sb.Append("<p>");
                sb.Append("<div id=\"tabs1box\">");
                sb.Append("        <div class=\"menu1box\">");
                sb.Append("            <ul id=\"menu1\">");
                sb.Append("                <li class=\"hover\" onmouseover=\"setPureProfilerTab(1,0)\"><a href=\"#\">Configuration</a></li>");
                sb.Append("                <li onmouseover=\"setPureProfilerTab(1, 1)\"><a href=\"#\">Session/Cache</a></li>");
                sb.Append("                <li onmouseover=\"setPureProfilerTab(1, 2)\"><a href=\"#\">Environment</a></li>");
                sb.Append("                <li onmouseover=\"setPureProfilerTab(1, 3)\"><a href=\"#\">ServerVariables</a></li>");
                sb.Append("                <li onmouseover=\"setPureProfilerTab(1, 4)\"><a href=\"#\">PureProfiler</a></li>");
                sb.Append("            </ul>");
                sb.Append("        </div>");
                sb.Append("        <div class=\"tab-main1box\">");
                sb.Append("            <div class=\"tab-main\" id=\"tab-main1\">");
                sb.Append("                <ul class=\"block\"><li>" + ProfilingSession.AppConfigString + WebProfilingSessionContainer.WebConfigString + "</li></ul>");
                sb.Append("                <ul><li>" + WebProfilingSessionContainer.GetSessions(context) + ProfilingSession.NEWLINE + RuntimeCacheGetter.GetCaches(context) + "</li></ul>");
                sb.Append("                <ul><li>" + WebProfilingSessionContainer.EnvironmentString + "</li></ul>");
                sb.Append("                <ul><li>" + WebProfilingSessionContainer.GetServerVariables(context) + "</li></ul>");
                sb.Append("                <ul><li>" + ProfilingSession.ConfigurationString + "</li></ul>");
                sb.Append("            </div>");
                sb.Append("        </div>");
                sb.Append("    </div>");


                sb.Append("</p>");

                sb.Append("<table>");
                sb.Append("<tr><th class=\"nowrap\">发生时间 (UTC)</th><th class=\"nowrap\">耗时 (ms)</th><th class=\"nowrap\">Http Verb</th><th class=\"nowrap\">Is Ajax</th><th class=\"nowrap\">状态码</th><th>Url地址</th></tr>");
                var latestResults = ProfilingSession.CircularBuffer.OrderByDescending(r => r.Started);
                var i             = 0;
                foreach (var result in latestResults)
                {
                    string statusCode = "";
                    string errorClass = "";
                    if (result.Data != null && result.Data.ContainsKey("ResponseStatusCode"))
                    {
                        statusCode = result.Data["ResponseStatusCode"];
                    }
                    if (statusCode != "" && statusCode != "200")
                    {
                        errorClass = "pure-profiler-error-row ";
                    }

                    sb.Append("<tr");
                    if ((i++) % 2 == 1)
                    {
                        sb.Append(" class=\"gray " + errorClass + "\"");
                    }
                    else
                    {
                        sb.Append(" class=\"" + errorClass + "\"");
                    }
                    sb.Append("><td class=\"nowrap\">");
                    sb.Append(result.Started.ToString("yyyy-MM-dd HH:mm:ss.FFF"));
                    sb.Append("</td><td class=\"nowrap\">");
                    sb.Append(result.DurationMilliseconds);
                    sb.Append("</td><td class=\"nowrap\">");
                    string httpverb = "";
                    if (result.Data != null && result.Data.ContainsKey("Http Verb"))
                    {
                        httpverb = result.Data["Http Verb"];
                    }
                    sb.Append(httpverb);
                    sb.Append("</td><td class=\"nowrap\">");
                    string IsAjaxString = "";
                    if (result.Data != null && result.Data.ContainsKey("IsAjax"))
                    {
                        IsAjaxString = result.Data["IsAjax"];
                    }
                    sb.Append(IsAjaxString);
                    sb.Append("</td><td class=\"nowrap\">");

                    sb.Append(statusCode);
                    sb.Append("</td><td><a href=\"view/");
                    sb.Append(result.Id.ToString());
                    sb.Append("\" target=\"_blank\">");
                    sb.Append(result.Name.Replace("\r\n", " "));
                    sb.Append("</a></td></tr>");
                }
                sb.Append("</table>");

                //author
                //sb.Append("<%--PureProfiler @ 郭建斌--%>");

                sb.Append("</body>");


                await context.Response.WriteAsync(sb.ToString());


                //context.Response.ContentType = "text/html;charset=utf-8";

                //var sb = new StringBuilder();
                //sb.Append("<head>");
                //sb.Append("<title>PureProfiler Latest Profiling Results</title>");
                //sb.Append("<style>th { width: 200px; text-align: left; } .gray { background-color: #eee; } .nowrap { white-space: nowrap;padding-right: 20px; vertical-align:top; } </style>");
                //sb.Append("</head");
                //sb.Append("<body>");
                //sb.Append(ViewResultIndexHeaderHtml);

                //var tagFilter = context.Request.Query["tag"];
                //if (!string.IsNullOrWhiteSpace(tagFilter))
                //{
                //    sb.Append("<div><strong>Filtered by tag:</strong> ");
                //    sb.Append(tagFilter);
                //    sb.Append("<br/><br /></div>");
                //}

                //sb.Append("<table>");
                //sb.Append("<tr><th class=\"nowrap\">Time (UTC)</th><th class=\"nowrap\">Duration (ms)</th><th>Url</th></tr>");
                //var latestResults = ProfilingSession.CircularBuffer.OrderByDescending(r => r.Started);
                //var i = 0;
                //foreach (var result in latestResults)
                //{
                //    if (!string.IsNullOrWhiteSpace(tagFilter) &&
                //        (result.Tags == null || !result.Tags.Contains<string>(tagFilter, StringComparer.OrdinalIgnoreCase)))
                //    {
                //        continue;
                //    }

                //    sb.Append("<tr");
                //    if ((i++) % 2 == 1)
                //    {
                //        sb.Append(" class=\"gray\"");
                //    }
                //    sb.Append("><td class=\"nowrap\">");
                //    sb.Append(result.Started.ToString("yyyy-MM-ddTHH:mm:ss.FFF"));
                //    sb.Append("</td><td class=\"nowrap\">");
                //    sb.Append(result.DurationMilliseconds);
                //    sb.Append("</td><td><a href=\"");
                //    sb.Append(baseViewPath);
                //    sb.Append("/");
                //    sb.Append(result.Id.ToString());
                //    sb.Append("\" target=\"_blank\">");
                //    sb.Append(result.Name.Replace("\r\n", " "));
                //    sb.Append("</a></td></tr>");
                //}
                //sb.Append("</table>");

                //sb.Append("</body>");

                //await context.Response.WriteAsync(sb.ToString());
                return;
            }


            ///内嵌的列表项目集合

            // view index of all latest results: ~/pureprofiler/view/include
            if (path.EndsWith(ViewUrlInclude, StringComparison.OrdinalIgnoreCase))
            {
                context.Response.ContentType = "text/javascript;charset=utf-8";
                //var curr = ProfilingSession.Current.Profiler.GetTimingSession();
                var latestResults = ProfilingSession.CircularBuffer.OrderByDescending(r => r.Started);


                var sb = new StringBuilder();


                var    position       = context.Request.Query["position"];
                string positionString = "right: 20px;top: 350px;";
                if (position == "left")
                {
                    positionString = "left: 20px;top: 20px;";
                }
                else if (position == "right")
                {
                    positionString = "right: 20px;top: 20px;";
                }
                else if (position == "bottomleft")
                {
                    positionString = "left: 20px;bottom: 20px;";
                }
                else if (position == "bottomright")
                {
                    positionString = "right: 20px;bottom: 20px;";
                }
                else if (position == "middleleft")
                {
                    positionString = "left: 20px;top: 350px;";
                }
                else if (position == "middleright")
                {
                    positionString = "right: 20px;top: 350px;";
                }

                var autoshow = context.Request.Query["autoshow"] == "1";
                if (autoshow == false)
                {
                    var pureprofiler_autoshow = context.Request.Cookies["pureprofiler_autoshow"] != null ? context.Request.Cookies["pureprofiler_autoshow"] == "1" : false;
                    if (pureprofiler_autoshow)
                    {
                        autoshow = pureprofiler_autoshow;
                    }
                }

                string autoshowStrig = autoshow ? "" : ".pureprofiler{display:none;} ";

                var    rooturl       = context.Request.Query["rooturl"];
                string roolurlString = !string.IsNullOrEmpty(rooturl) ? rooturl.ToString().TrimEnd('/') : "";

                sb.Append("<script type=\"text/javascript\" src=\"./pureprofiler-resources/js\"></script>");


                sb.Append("<style>" + autoshowStrig + ".pureprofiler{position:fixed;z-index: 99900;bottom:0;width:100%;height:300px;}  .pureprofiler-pin{height:32px;line-height:30px;padding:5px;position: fixed;" + positionString + "z-index: 99999; background: #008c5e;color:#fff;border-radius: 10px;box-shadow: 0 5px 10px rgba(0,0,0,.28);} .pureprofiler-refresh{color:#fff;background:#f00; padding: 5px;border-radius:10px;}  th { width: 200px; text-align: left; } .gray { background-color: #eee; } .nowrap { white-space: nowrap;padding-right: 20px; vertical-align:top; } </style>");


                sb.Append("<div class=\"pureprofiler-pin\" id=\"pureprofiler-pin\">");
                sb.Append("<span class=\"pureprofiler-refresh\"  id=\"pureprofiler-refresh\"> 刷新 </span>");
                sb.Append("<span class=\"pureprofiler-show\"  id=\"pureprofiler-show\">耗时:");

                sb.Append(CalcTime(latestResults) + " ms");
                sb.Append("</span>");
                sb.Append("</div>");


                sb.Append("<div class=\"pureprofiler\" id=\"pureprofiler\"><iframe src=" + ViewUrl + " name=\"iframepureprofiler\" id=\"iframepureprofiler\"  style=\"background:#EAF2FF;z-index:99999;\" width=\"100%\" height=\"300px\" marginwidth=\"0\" marginheight=\"0\" frameborder=\"0\" scrolling=\"auto\"  ></iframe>");
                sb.Append("</div>");



                //js


                sb.Append("<script>function getStyle(obj, attr) {if (obj.currentStyle) {return obj.currentStyle[attr];} else {return getComputedStyle(obj, false)[attr];}}</script>");


                sb.Append("<script> var divProfilerShow = document.getElementById(\"pureprofiler-show\");divProfilerShow.onclick = function () { var divProfile =document.getElementById(\"pureprofiler\"); if(getStyle(divProfile, \"display\") ==\"none\"){ divProfile.style.display=\"block\";setCookie(\"pureprofiler_autoshow\",\"1\",30);}else{divProfile.style.display=\"none\";setCookie(\"pureprofiler_autoshow\",\"0\",30);}}</script>");
                sb.Append("<script>var divProfilerRefresh = document.getElementById(\"pureprofiler-refresh\");divProfilerRefresh.onclick = function () { document.getElementById(\"iframepureprofiler\").src = \"" + ViewUrl + "\";}</script>");



                string html = "document.write('" + sb.ToString() + "')";


                await context.Response.WriteAsync(html);

                return;
            }



            // view specific result by uuid: ~/pureprofiler/view/{uuid}
            if (path.IndexOf(ViewUrl, StringComparison.OrdinalIgnoreCase) >= 0)
            {
                context.Response.ContentType = "text/html;charset=utf-8";

                var sb = new StringBuilder();
                sb.Append("<head>");
                sb.Append("<meta charset=\"utf-8\" />");
                sb.Append("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />");
                sb.Append("<title>性能检测报告</title>");
                sb.Append("<link rel=\"stylesheet\" href=\"./pureprofiler-resources/css\" />");
                sb.Append("<script type=\"text/javascript\" src=\"./pureprofiler-resources/js\"></script>");
                sb.Append("</head");
                sb.Append("<body>");
                sb.Append("<h1>性能检测报告</h1>");

                var uuid   = path.Split('/').Last();
                var result = ProfilingSession.CircularBuffer.FirstOrDefault(
                    r => r.Id.ToString().ToLowerInvariant() == uuid.ToLowerInvariant());
                if (result != null)
                {
                    if (TryToImportDrillDownResult)
                    {
                        // try to import drill down results
                        foreach (var timing in result.Timings)
                        {
                            if (timing.Data == null || !timing.Data.ContainsKey(CorrelationId))
                            {
                                continue;
                            }
                            Guid parentResultId;
                            if (!Guid.TryParse(timing.Data[CorrelationId], out parentResultId) ||
                                ProfilingSession.CircularBuffer.Any(r => r.Id == parentResultId))
                            {
                                continue;
                            }

                            string remoteAddress;
                            if (!timing.Data.TryGetValue("remoteAddress", out remoteAddress))
                            {
                                remoteAddress = timing.Name;
                            }

                            if (!Uri.IsWellFormedUriString(remoteAddress, UriKind.Absolute))
                            {
                                continue;
                            }

                            if (!remoteAddress.StartsWith("http", StringComparison.OrdinalIgnoreCase))
                            {
                                continue;
                            }

                            var pos = remoteAddress.IndexOf("?");
                            if (pos > 0)
                            {
                                remoteAddress = remoteAddress.Substring(0, pos);
                            }
                            if (remoteAddress.Split('/').Last().Contains("."))
                            {
                                remoteAddress = remoteAddress.Substring(0, remoteAddress.LastIndexOf("/"));
                            }

                            try
                            {
                                await ImportSessionsFromUrl(remoteAddress + "/pureprofiler/view?" + CorrelationId + "=" + parentResultId.ToString("N"));
                            }
                            catch (Exception ex)
                            {
                                System.Diagnostics.Debug.Write(ex.Message);

                                //ignore exceptions
                            }
                        }
                    }
                    sb.Append("<div class=\"css-treeview\">");

                    // print summary
                    sb.Append("<ul>");
                    sb.Append("<li class=\"summary\">");
                    PrintDrillUpLink(sb, result, baseViewPath);
                    sb.Append(result.Name.Replace("\r\n", " "));
                    sb.Append("<p class='exportbar'>");
                    sb.Append("<a target='_blank' href='../export?exporttype=json&id=" + uuid + "'>Json</a>");
                    sb.Append("</p>");

                    sb.Append("</li>");
                    sb.Append("<li class=\"summary\">");
                    if (result.Data != null)
                    {
                        foreach (var keyValue in result.Data)
                        {
                            if (string.IsNullOrWhiteSpace(keyValue.Value))
                            {
                                continue;
                            }
                            if ((keyValue.Key) == "RequestBody")
                            {
                                continue;
                            }
                            if ((keyValue.Key) == "ResponseBody")
                            {
                                continue;
                            }
                            if ((keyValue.Key) == "ResponseBody2")
                            {
                                continue;
                            }

                            sb.Append("<b>");
                            sb.Append(keyValue.Key);
                            sb.Append(": </b>");
                            var encodedValue = WebUtility.HtmlEncode(keyValue.Value);
                            if (keyValue.Key.EndsWith("Count") || keyValue.Key.EndsWith("Duration"))
                            {
                                sb.Append("<span class=\"");
                                sb.Append(keyValue.Key);
                                sb.Append("\">");
                                sb.Append(encodedValue);
                                sb.Append("</span>");
                            }
                            else
                            {
                                sb.Append(encodedValue);
                            }
                            sb.Append(" &nbsp; ");
                        }
                    }
                    sb.Append("<b>所在机器: </b>");
                    sb.Append(result.MachineName);
                    sb.Append(" &nbsp; ");
                    if (result.Tags != null && result.Tags.Any())
                    {
                        sb.Append("<b>标签: </b>");
                        sb.Append(string.Join(", ", result.Tags.Select(t => string.Format("<a href=\"{2}?tag={0}\">{1}</a>", HttpUtility.UrlEncode(t), t, baseViewPath))));
                        sb.Append(" &nbsp; ");
                    }
                    sb.Append("</li>");
                    sb.Append("</ul>");

                    if (result.Data != null)
                    {
                        //Web请求内容
                        if (result.Data.ContainsKey("RequestBody"))
                        {
                            sb.Append(
                                "<br><a title=\"RequestBody\" onclick='clickRequestBody()'>RequestBody</a>");
                            var encodedValue = (result.Data["RequestBody"]);
                            sb.Append("<p class=\"pureprofiler-RequestBody\" id=\"pureprofiler-RequestBody\">");
                            sb.Append(encodedValue);
                            sb.Append("</p> ");
                        }

                        //Web响应内容
                        if (result.Data.ContainsKey("ResponseBody"))
                        {
                            sb.Append(
                                "<br><a title=\"ResponseBody\" onclick='clickResponseBody()'>ResponseBody</a>");
                            var encodedValue = result.Data["ResponseBody"];//
                            if (result.Data.ContainsKey("ResponseBody2"))
                            {
                                encodedValue += "<b>Body</b><br>" + HttpUtility.HtmlEncode(result.Data["ResponseBody2"]);
                            }

                            sb.Append("<p class=\"pureprofiler-ResponseBody\" id=\"pureprofiler-ResponseBody\">");
                            sb.Append(encodedValue);
                            sb.Append("</p> ");
                        }
                    }

                    var totalLength = result.DurationMilliseconds;
                    if (totalLength == 0)
                    {
                        totalLength = 1;
                    }
                    var factor = 300.0 / totalLength;

                    // print ruler
                    sb.Append("<ul>");
                    sb.Append("<li class=\"ruler\"><span style=\"width:300px\">0</span><span style=\"width:80px\">");
                    sb.Append(totalLength);
                    sb.Append(
                        " (ms)</span><span style=\"width:20px\">&nbsp;</span><span style=\"width:60px\">开始</span><span style=\"width:60px\">耗时(ms)</span><span style=\"width:20px\">&nbsp;</span><span>执行时序</span></li>");
                    sb.Append("</ul>");

                    // print timings
                    sb.Append("<ul class=\"timing\">");
                    PrintTimings(result, result.Id, sb, factor, baseViewPath);
                    sb.Append("");
                    sb.Append("</ul>");
                    sb.Append("</div>");

                    // print timing data popups
                    foreach (var timing in result.Timings)
                    {
                        if (timing.Data == null || !timing.Data.Any())
                        {
                            continue;
                        }

                        sb.Append("<aside id=\"data_");
                        sb.Append(timing.Id.ToString());
                        sb.Append("\" style=\"display:none\" class=\"modal\">");
                        sb.Append("<div>");
                        sb.Append("<h4><code>");
                        sb.Append(timing.Name.Replace("\r\n", " "));
                        sb.Append("</code></h4>");
                        sb.Append("<textarea readonly=\"readonly\">");
                        foreach (var keyValue in timing.Data)
                        {
                            if (string.IsNullOrWhiteSpace(keyValue.Value))
                            {
                                continue;
                            }

                            sb.Append(keyValue.Key);
                            sb.Append(":\r\n");
                            var value = keyValue.Value.Trim();
                            if (value.StartsWith("<"))
                            {
                                // asuume it is XML
                                // try to format XML with indent
                                var doc = new XmlDocument();
                                try
                                {
                                    doc.LoadXml(value);
                                    var ms         = new MemoryStream();
                                    var xwSettings = new XmlWriterSettings
                                    {
                                        Encoding    = new UTF8Encoding(false),
                                        Indent      = true,
                                        IndentChars = "\t"
                                    };
                                    using (var writer = XmlWriter.Create(ms, xwSettings))
                                    {
                                        doc.Save(writer);
                                        ms.Seek(0, SeekOrigin.Begin);
                                        using (var sr = new StreamReader(ms))
                                        {
                                            value = sr.ReadToEnd();
                                        }
                                    }
                                }
                                catch
                                {
                                    //squash exception
                                }
                            }
                            sb.Append(value);
                            sb.Append("\r\n\r\n");
                        }
                        if (timing.Tags != null && timing.Tags.Any())
                        {
                            sb.Append("tags:\r\n");
                            sb.Append(timing.Tags);
                            sb.Append("\r\n");
                        }
                        sb.Append("</textarea>");
                        sb.Append(
                            "<a href=\"#close\" title=\"Close\" onclick=\"this.parentNode.parentNode.style.display='none'\">关闭</a>");
                        sb.Append("</div>");
                        sb.Append("</aside>");
                    }
                }
                else
                {
                    sb.Append("你所访问的结果报告不存在。");
                }
                sb.Append("</body>");

                await context.Response.WriteAsync(sb.ToString());

                return;
            }


            //导出数据
            if (path.IndexOf(ExportUrl, StringComparison.OrdinalIgnoreCase) >= 0)
            {
                var import = context.Request.Query[Import];
                if (Uri.IsWellFormedUriString(import, UriKind.Absolute))
                {
                    await ImportSessionsFromUrl(import);

                    return;
                }

                if (context.Request.Query[ExportType] == (ExportJson))
                {
                    context.Response.ContentType = "application/json;charset=utf-8";
                    await context.Response.WriteAsync(ImportSerializer.SerializeSessions(ProfilingSession.CircularBuffer));

                    return;
                }

                var exportCorrelationId = context.Request.Query[CorrelationId];
                if (!string.IsNullOrEmpty(exportCorrelationId))
                {
                    context.Response.ContentType = "application/json;charset=utf-8";
                    var result = ProfilingSession.CircularBuffer.FirstOrDefault(
                        r => r.Data != null && r.Data.ContainsKey(CorrelationId) && r.Data[CorrelationId] == exportCorrelationId);
                    if (result != null)
                    {
                        if (context.Request.Query[ExportType] == (ExportJson))
                        {
                            context.Response.ContentType = "application/json;charset=utf-8";
                            await context.Response.WriteAsync(ImportSerializer.SerializeSessions(new[] { result }));

                            return;
                        }
                    }
                }
            }
            else if (TryToImportDrillDownResult && path.IndexOf(ExportUrl, StringComparison.OrdinalIgnoreCase) >= 0)
            {
                var uuid   = path.Split('/').Last();
                var result = ProfilingSession.CircularBuffer.FirstOrDefault(
                    r => r.Id.ToString().ToLowerInvariant() == uuid.ToLowerInvariant());
                if (result != null)
                {
                    foreach (var timing in result.Timings)
                    {
                        if (timing.Data == null || !timing.Data.ContainsKey(CorrelationId))
                        {
                            continue;
                        }
                        Guid correlationId2;
                        if (!Guid.TryParse(timing.Data[CorrelationId], out correlationId2) ||
                            ProfilingSession.CircularBuffer.Any(r => r.Id == correlationId2))
                        {
                            continue;
                        }

                        string remoteAddress;
                        if (!timing.Data.TryGetValue("remoteAddress", out remoteAddress))
                        {
                            remoteAddress = timing.Name;
                        }

                        if (!Uri.IsWellFormedUriString(remoteAddress, UriKind.Absolute))
                        {
                            continue;
                        }

                        if (!remoteAddress.StartsWith("http", StringComparison.OrdinalIgnoreCase))
                        {
                            continue;
                        }

                        var pos = remoteAddress.IndexOf("?");
                        if (pos > 0)
                        {
                            remoteAddress = remoteAddress.Substring(0, pos);
                        }
                        if (remoteAddress.Split('/').Last().Contains("."))
                        {
                            remoteAddress = remoteAddress.Substring(0, remoteAddress.LastIndexOf("/"));
                        }

                        try
                        {
                            await ImportSessionsFromUrl(remoteAddress + "/pureprofiler/view?" + CorrelationId + "=" + correlationId.ToString());
                        }
                        catch (Exception ex)
                        {
                            System.Diagnostics.Debug.Write(ex.Message);

                            //ignore exceptions
                        }

                        return;
                    }
                }
            }



            try
            {
                await _next.Invoke(context);
            }
            catch (System.Exception ex)
            {
                // stop and save profiling results on error
                //using (ProfilingSession.Current.Step("Stop on Error")) { }

                bool showError = ProfilingSession.Configuration.PureProfilerConfiguration.ShowError;
                if (showError)
                {
                    string newLine = "-----" + System.Environment.NewLine;// "</br>";

                    // stop and save profiling results on error
                    string err = "";

                    Exception objErr = ex;
                    err = "Error at:      " + context.Request.GetDisplayUrl() + newLine +
                          "Error Message:      " + objErr.Message.ToString() + newLine +
                          "Error Source:      " + objErr.Source.ToString() + newLine +
                          "Stack Trace:      " + objErr.StackTrace.ToString() + newLine;

                    if (objErr.InnerException != null)
                    {
                        err += "InnerException:      " + newLine +
                               "InnerError Message:      " + objErr.Message.ToString() + newLine +
                               "InnerError Source:      " + objErr.Source.ToString() + newLine +
                               "InnerStack Trace:      " + objErr.StackTrace.ToString() + newLine;
                    }


                    using (ProfilingSession.Current.Step(() => (err)))
                    {
                    }
                }
                else
                {
                    using (ProfilingSession.Current.Step("Stop on Error"))
                    {
                    }
                }



                throw;
            }
            finally
            {
                if (ProfilingSession.ProfilingSessionContainer is WebProfilingSessionContainer)
                {
                    WebProfilingSessionContainer container = ProfilingSession.ProfilingSessionContainer as WebProfilingSessionContainer;
                    if (container != null)
                    {
                        container.SetResponseContent();
                    }
                }

                ProfilingSession.Stop();
            }
        }