MiniProfiler / dotnet

A simple but effective mini-profiler for ASP.NET (and Core) websites
https://miniprofiler.com/dotnet/
MIT License
2.92k stars 602 forks source link

Possible to manually render UI without MVC dependency? #458

Open petertiedemann opened 4 years ago

petertiedemann commented 4 years ago

I am using MiniProfiler in an ASP.NET WebAPI service host (that will soon transition to ASP.NET Core). The application using it is is developed separately using JS. I am currently using RenderPlainText to provide information back from an end-point, but it does not render everything i would like (SQL not expanded as far as i can see ). I could of course just write some custom code to print what i like, but it seems silly when there is an actual UI available.

I noticed that there are methods like RenderIncludes so i was wondering if there would happen to be a nice way to generate the necessary HTML statically or similar?

RubberChickenParadise commented 4 years ago

I just ran into this. I found this stack overflow post https://stackoverflow.com/questions/53321634/unable-to-print-query-using-miniprofiler and use this code

public static string CustomRenderPlainText(this MiniProfiler profiler, bool htmlEncode = false)
        {
            if (profiler == null) return string.Empty;

            var text = StringBuilderCache.Get()
                .Append(htmlEncode ? WebUtility.HtmlEncode(Environment.MachineName) : Environment.MachineName)
                .Append(" at ")
                .Append(DateTime.UtcNow)
                .AppendLine();

            var timings = new Stack<Timing>();
            timings.Push(profiler.Root);

            while (timings.Count > 0)
            {
                var timing = timings.Pop();

                text.AppendFormat("{0} {1} = {2:###,##0.##}[ms]",
                    new string('>', timing.Depth),
                    htmlEncode ? WebUtility.HtmlEncode(timing.Name) : timing.Name,
                    timing.DurationMilliseconds);

                if (timing.HasCustomTimings)
                {
                    // TODO: Customize this code block.

                    // Custom timings grouped by category. Collect all custom timings in a list.
                    var customTimingsFlat = new List<KeyValuePair<string, CustomTiming>>(capacity: timing.CustomTimings.Sum(ct => ct.Value.Count));
                    foreach (var pair in timing.CustomTimings)
                    {
                        var type = pair.Key;
                        var customTimings = pair.Value;

                        customTimingsFlat.AddRange(pair.Value.Select(ct => KeyValuePair.Create(type, ct)));
                        text.AppendFormat(" ({0} = {1:###,##0.##}[ms] in {2} cmd{3})",
                            type,
                            customTimings.Sum(ct => ct.DurationMilliseconds),
                            customTimings.Count,
                            customTimings.Count == 1 ? string.Empty : "s");
                    }

                    foreach (var pair in customTimingsFlat.OrderBy(kvp => kvp.Value.StartMilliseconds))
                    {
                        var type = pair.Key;
                        var ct = pair.Value;

                        text.AppendLine();
                        var mainPart = string.Format("{0}{1} {2:###,##0.##}[ms] +{3:###,##0.##}[ms] ",
                                            new string(' ', timing.Depth + 2),
                                            type,
                                            ct.DurationMilliseconds,
                                            ct.StartMilliseconds);
                        text.Append(mainPart);
                        // Shift command text to closer to the command for better readability.
                        var prefix = new string(' ', mainPart.Length);
                        string cmdLine = null;
                        using (var reader = new StringReader(ct.CommandString))
                        {
                            while ((cmdLine = reader.ReadLine()) != null)
                            {
                                text.Append(cmdLine);
                                if (reader.Peek() == -1 && profiler.Options.ExcludeStackTraceSnippetFromCustomTimings)
                                {
                                    break;
                                }
                                text.AppendLine();
                                text.Append(prefix);
                            }
                        }

                        if (profiler.Options.ExcludeStackTraceSnippetFromCustomTimings)
                        {
                            continue;
                        }
                        text.Append(ct.StackTraceSnippet);
                    }
                }

                text.AppendLine();

                if (timing.HasChildren)
                {
                    var children = timing.Children;
                    for (var i = children.Count - 1; i >= 0; i--) timings.Push(children[i]);
                }
            }

            return text.ToStringRecycle();
        }

It got me what I needed and can obviously be improved upon for your needs.

petertiedemann commented 4 years ago

It got me what I needed and can obviously be improved upon for your needs.

Thanks, i ended up digging out the source code of RenderPlainText and did something very similar to that snippet. As you say, it covers the basics, it just annoys me not to have access to the "fancy" UI :)

NickCraver commented 4 years ago

Catching up on issues here - are you saying you want to generate the Githubissues.

  • Githubissues is a development platform for aggregating issues.