\r\n | ");
+#line 25 "LogPage.cshtml"
+WriteTo(__razor_helper_writer, string.Format("{0:MM/dd/yy}", log.Time));
+
+#line default
+#line hidden
+ WriteLiteralTo(__razor_helper_writer, " | \r\n ");
+#line 26 "LogPage.cshtml"
+WriteTo(__razor_helper_writer, string.Format("{0:H:mm:ss}", log.Time));
+
+#line default
+#line hidden
+ WriteLiteralTo(__razor_helper_writer, " | \r\n (log.Name, 844), false));
+ WriteLiteralTo(__razor_helper_writer, ">");
+#line 27 "LogPage.cshtml"
+ WriteTo(__razor_helper_writer, log.Name);
+
+#line default
+#line hidden
+ WriteLiteralTo(__razor_helper_writer, " | \r\n (log.Severity.ToString().ToLowerInvariant(), 894), false));
+ WriteLiteralTo(__razor_helper_writer, ">");
+#line 28 "LogPage.cshtml"
+ WriteTo(__razor_helper_writer, log.Severity);
+
+#line default
+#line hidden
+ WriteLiteralTo(__razor_helper_writer, " | \r\n (log.Message, 982), false));
+ WriteLiteralTo(__razor_helper_writer, ">\r\n");
+#line 30 "LogPage.cshtml"
+
+
+#line default
+#line hidden
+
+#line 30 "LogPage.cshtml"
+ for (var i = 0; i < level; i++)
+ {
+
+#line default
+#line hidden
+
+ WriteLiteralTo(__razor_helper_writer, " \r\n");
+#line 33 "LogPage.cshtml"
+ }
+
+#line default
+#line hidden
+
+ WriteLiteralTo(__razor_helper_writer, " ");
+#line 34 "LogPage.cshtml"
+WriteTo(__razor_helper_writer, log.Message);
+
+#line default
+#line hidden
+ WriteLiteralTo(__razor_helper_writer, "\r\n | \r\n (log.Exception, 1205), false));
+ WriteLiteralTo(__razor_helper_writer, ">");
+#line 36 "LogPage.cshtml"
+ WriteTo(__razor_helper_writer, log.Exception);
+
+#line default
+#line hidden
+ WriteLiteralTo(__razor_helper_writer, " | \r\n
\r\n");
+#line 38 "LogPage.cshtml"
+ }
+
+#line default
+#line hidden
+
+ }
+ );
+#line 39 "LogPage.cshtml"
+}
+
+#line default
+#line hidden
+
+public HelperResult
+#line 41 "LogPage.cshtml"
+Traverse(ScopeNode node, int level)
+{
+
+#line default
+#line hidden
+ return new HelperResult((__razor_helper_writer) => {
+#line 42 "LogPage.cshtml"
+
+ // print start of scope
+
+
+#line default
+#line hidden
+
+#line 44 "LogPage.cshtml"
+WriteTo(__razor_helper_writer, LogRow(new LogInfo()
+ {
+ Name = node.Name,
+ Time = node.StartTime,
+ Severity = LogLevel.Verbose,
+ Message = "Beginning " + node.State,
+ }, level));
+
+#line default
+#line hidden
+#line 50 "LogPage.cshtml"
+ ;
+ var messageIndex = 0;
+ var childIndex = 0;
+ while (messageIndex < node.Messages.Count && childIndex < node.Children.Count)
+ {
+ if (node.Messages[messageIndex].Time < node.Children[childIndex].StartTime)
+ {
+
+
+#line default
+#line hidden
+
+#line 57 "LogPage.cshtml"
+WriteTo(__razor_helper_writer, LogRow(node.Messages[messageIndex], level));
+
+#line default
+#line hidden
+#line 57 "LogPage.cshtml"
+
+ messageIndex++;
+ }
+ else
+ {
+
+
+#line default
+#line hidden
+
+#line 62 "LogPage.cshtml"
+WriteTo(__razor_helper_writer, Traverse(node.Children[childIndex], level + 1));
+
+#line default
+#line hidden
+#line 62 "LogPage.cshtml"
+
+ childIndex++;
+ }
+ }
+ if (messageIndex < node.Messages.Count)
+ {
+ for (var i = messageIndex; i < node.Messages.Count; i++)
+ {
+
+
+#line default
+#line hidden
+
+#line 70 "LogPage.cshtml"
+WriteTo(__razor_helper_writer, LogRow(node.Messages[i], level));
+
+#line default
+#line hidden
+#line 70 "LogPage.cshtml"
+
+ }
+ }
+ else
+ {
+ for (var i = childIndex; i < node.Children.Count; i++)
+ {
+
+
+#line default
+#line hidden
+
+#line 77 "LogPage.cshtml"
+WriteTo(__razor_helper_writer, Traverse(node.Children[i], level + 1));
+
+#line default
+#line hidden
+#line 77 "LogPage.cshtml"
+
+ }
+ }
+ // print end of scope
+
+
+#line default
+#line hidden
+
+#line 81 "LogPage.cshtml"
+WriteTo(__razor_helper_writer, LogRow(new LogInfo()
+ {
+ Name = node.Name,
+ Time = node.EndTime,
+ Severity = LogLevel.Verbose,
+ Message = string.Format("Completed {0} in {1}ms", node.State, node.EndTime - node.StartTime)
+ }, level));
+
+#line default
+#line hidden
+#line 87 "LogPage.cshtml"
+ ;
+
+#line default
+#line hidden
+
+ }
+ );
+#line 88 "LogPage.cshtml"
+}
+
+#line default
+#line hidden
+
+#line 10 "LogPage.cshtml"
+
+ public LogPage(LogPageModel model)
+ {
+ Model = model;
+ }
+
+ public LogPageModel Model { get; set; }
+
+#line default
+#line hidden
+ #line hidden
+ public LogPage()
+ {
+ }
+
+ #pragma warning disable 1998
+ public override async Task ExecuteAsync()
+ {
+ WriteLiteral("\r\n");
+ WriteLiteral("\r\n\r\n");
+ WriteLiteral("\r\n");
+ WriteLiteral(@"
+
+
+
+ Activities { get; set; }
+
+ public ViewOptions Options { get; set; }
+
+ public PathString Path { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Diagnostics.Elm/Views/RequestPage.cs b/src/Microsoft.AspNet.Diagnostics.Elm/Views/RequestPage.cs
new file mode 100644
index 00000000..fbee9111
--- /dev/null
+++ b/src/Microsoft.AspNet.Diagnostics.Elm/Views/RequestPage.cs
@@ -0,0 +1,716 @@
+namespace Microsoft.AspNet.Diagnostics.Elm.Views
+{
+#line 1 "RequestPage.cshtml"
+using System
+
+#line default
+#line hidden
+ ;
+#line 2 "RequestPage.cshtml"
+using System.Globalization
+
+#line default
+#line hidden
+ ;
+#line 3 "RequestPage.cshtml"
+using System.Linq
+
+#line default
+#line hidden
+ ;
+#line 4 "RequestPage.cshtml"
+using Microsoft.AspNet.Diagnostics.Elm
+
+#line default
+#line hidden
+ ;
+#line 5 "RequestPage.cshtml"
+using Microsoft.AspNet.Diagnostics.Views
+
+#line default
+#line hidden
+ ;
+#line 6 "RequestPage.cshtml"
+using Microsoft.AspNet.Diagnostics.Elm.Views
+
+#line default
+#line hidden
+ ;
+#line 7 "RequestPage.cshtml"
+using Microsoft.Framework.Logging
+
+#line default
+#line hidden
+ ;
+ using System.Threading.Tasks;
+
+ public class RequestPage : Microsoft.AspNet.Diagnostics.Views.BaseView
+ {
+public HelperResult
+#line 19 "RequestPage.cshtml"
+LogRow(LogInfo log)
+{
+
+#line default
+#line hidden
+ return new HelperResult((__razor_helper_writer) => {
+#line 20 "RequestPage.cshtml"
+
+ if (log.Severity >= Model.Options.MinLevel &&
+ (string.IsNullOrEmpty(Model.Options.NamePrefix) || log.Name.StartsWith(Model.Options.NamePrefix, StringComparison.Ordinal)))
+ {
+
+#line default
+#line hidden
+
+ WriteLiteralTo(__razor_helper_writer, " \r\n | ");
+#line 25 "RequestPage.cshtml"
+WriteTo(__razor_helper_writer, string.Format("{0:MM/dd/yy}", log.Time));
+
+#line default
+#line hidden
+ WriteLiteralTo(__razor_helper_writer, " | \r\n ");
+#line 26 "RequestPage.cshtml"
+WriteTo(__razor_helper_writer, string.Format("{0:H:mm:ss}", log.Time));
+
+#line default
+#line hidden
+ WriteLiteralTo(__razor_helper_writer, " | \r\n (log.Severity.ToString().ToLowerInvariant(), 776), false));
+ WriteLiteralTo(__razor_helper_writer, ">");
+#line 27 "RequestPage.cshtml"
+ WriteTo(__razor_helper_writer, log.Severity);
+
+#line default
+#line hidden
+ WriteLiteralTo(__razor_helper_writer, " | \r\n (log.Name, 864), false));
+ WriteLiteralTo(__razor_helper_writer, ">");
+#line 28 "RequestPage.cshtml"
+ WriteTo(__razor_helper_writer, log.Name);
+
+#line default
+#line hidden
+ WriteLiteralTo(__razor_helper_writer, " | \r\n (log.Message, 914), false));
+ WriteLiteralTo(__razor_helper_writer, " class=\"logState\" width=\"100px\">");
+#line 29 "RequestPage.cshtml"
+ WriteTo(__razor_helper_writer, log.Message);
+
+#line default
+#line hidden
+ WriteLiteralTo(__razor_helper_writer, " | \r\n (log.Exception, 1001), false));
+ WriteLiteralTo(__razor_helper_writer, ">");
+#line 30 "RequestPage.cshtml"
+ WriteTo(__razor_helper_writer, log.Exception);
+
+#line default
+#line hidden
+ WriteLiteralTo(__razor_helper_writer, " | \r\n
\r\n");
+#line 32 "RequestPage.cshtml"
+ }
+
+#line default
+#line hidden
+
+ }
+ );
+#line 33 "RequestPage.cshtml"
+}
+
+#line default
+#line hidden
+
+public HelperResult
+#line 35 "RequestPage.cshtml"
+Traverse(ScopeNode node)
+{
+
+#line default
+#line hidden
+ return new HelperResult((__razor_helper_writer) => {
+#line 36 "RequestPage.cshtml"
+
+ var messageIndex = 0;
+ var childIndex = 0;
+ while (messageIndex < node.Messages.Count && childIndex < node.Children.Count)
+ {
+ if (node.Messages[messageIndex].Time < node.Children[childIndex].StartTime)
+ {
+
+
+#line default
+#line hidden
+
+#line 43 "RequestPage.cshtml"
+WriteTo(__razor_helper_writer, LogRow(node.Messages[messageIndex]));
+
+#line default
+#line hidden
+#line 43 "RequestPage.cshtml"
+
+ messageIndex++;
+ }
+ else
+ {
+
+
+#line default
+#line hidden
+
+#line 48 "RequestPage.cshtml"
+WriteTo(__razor_helper_writer, Traverse(node.Children[childIndex]));
+
+#line default
+#line hidden
+#line 48 "RequestPage.cshtml"
+
+ childIndex++;
+ }
+ }
+ if (messageIndex < node.Messages.Count)
+ {
+ for (var i = messageIndex; i < node.Messages.Count; i++)
+ {
+
+
+#line default
+#line hidden
+
+#line 56 "RequestPage.cshtml"
+WriteTo(__razor_helper_writer, LogRow(node.Messages[i]));
+
+#line default
+#line hidden
+#line 56 "RequestPage.cshtml"
+
+ }
+ }
+ else
+ {
+ for (var i = childIndex; i < node.Children.Count; i++)
+ {
+
+
+#line default
+#line hidden
+
+#line 63 "RequestPage.cshtml"
+WriteTo(__razor_helper_writer, Traverse(node.Children[i]));
+
+#line default
+#line hidden
+#line 63 "RequestPage.cshtml"
+
+ }
+ }
+
+#line default
+#line hidden
+
+ }
+ );
+#line 66 "RequestPage.cshtml"
+}
+
+#line default
+#line hidden
+
+#line 10 "RequestPage.cshtml"
+
+ public RequestPage(RequestPageModel model)
+ {
+ Model = model;
+ }
+
+ public RequestPageModel Model { get; set; }
+
+#line default
+#line hidden
+ #line hidden
+ public RequestPage()
+ {
+ }
+
+ #pragma warning disable 1998
+ public override async Task ExecuteAsync()
+ {
+ WriteLiteral("\r\n");
+ WriteLiteral("\r\n");
+ WriteLiteral("\r\n");
+ WriteLiteral(@"
+
+
+
+ ASP.NET Logs
+
+
+
+
+ ASP.NET Logs
+");
+#line 80 "RequestPage.cshtml"
+
+
+#line default
+#line hidden
+
+#line 80 "RequestPage.cshtml"
+
+ var context = Model.Activity?.HttpInfo;
+
+
+#line default
+#line hidden
+
+ WriteLiteral("\r\n");
+#line 83 "RequestPage.cshtml"
+
+
+#line default
+#line hidden
+
+#line 83 "RequestPage.cshtml"
+ if (context != null)
+ {
+
+#line default
+#line hidden
+
+ WriteLiteral(" \r\n \r\n \r\n\r\n " +
+" \r\n | Path | \r\n ");
+#line 91 "RequestPage.cshtml"
+ Write(context.Path);
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n
\r\n \r\n | Host | \r\n " +
+" ");
+#line 95 "RequestPage.cshtml"
+ Write(context.Host);
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n
\r\n \r\n | Content Type | " +
+"\r\n ");
+#line 99 "RequestPage.cshtml"
+ Write(context.ContentType);
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n
\r\n \r\n | Method | \r\n " +
+" ");
+#line 103 "RequestPage.cshtml"
+ Write(context.Method);
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n
\r\n \r\n | Protocol | \r\n " +
+" ");
+#line 107 "RequestPage.cshtml"
+ Write(context.Protocol);
+
+#line default
+#line hidden
+ WriteLiteral(@" |
+
+
+ | Headers |
+
+
+
+
+ | Variable |
+ Value |
+
+
+
+");
+#line 120 "RequestPage.cshtml"
+
+
+#line default
+#line hidden
+
+#line 120 "RequestPage.cshtml"
+ foreach (var header in context.Headers)
+ {
+
+#line default
+#line hidden
+
+ WriteLiteral(" \r\n | ");
+#line 123 "RequestPage.cshtml"
+ Write(header.Key);
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n ");
+#line 124 "RequestPage.cshtml"
+ Write(string.Join(";", header.Value));
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n \r\n");
+#line 126 "RequestPage.cshtml"
+ }
+
+#line default
+#line hidden
+
+ WriteLiteral(" \r\n \r\n <" +
+"/td>\r\n |
\r\n \r\n | Status Code | \r" +
+"\n ");
+#line 133 "RequestPage.cshtml"
+ Write(context.StatusCode);
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n
\r\n \r\n | User | \r\n " +
+" ");
+#line 137 "RequestPage.cshtml"
+ Write(context.User.Identity.Name);
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n
\r\n \r\n | Claims | \r\n " +
+" \r\n");
+#line 142 "RequestPage.cshtml"
+
+
+#line default
+#line hidden
+
+#line 142 "RequestPage.cshtml"
+ if (context.User.Claims.Any())
+ {
+
+#line default
+#line hidden
+
+ WriteLiteral(@"
+
+
+ | Issuer |
+ Value |
+
+
+
+");
+#line 152 "RequestPage.cshtml"
+
+
+#line default
+#line hidden
+
+#line 152 "RequestPage.cshtml"
+ foreach (var claim in context.User.Claims)
+ {
+
+#line default
+#line hidden
+
+ WriteLiteral(" \r\n " +
+" | ");
+#line 155 "RequestPage.cshtml"
+ Write(claim.Issuer);
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n ");
+#line 156 "RequestPage.cshtml"
+ Write(claim.Value);
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n \r\n");
+#line 158 "RequestPage.cshtml"
+ }
+
+#line default
+#line hidden
+
+ WriteLiteral(" \r\n \r\n");
+#line 161 "RequestPage.cshtml"
+ }
+
+#line default
+#line hidden
+
+ WriteLiteral(" | \r\n
\r\n \r\n | S" +
+"cheme | \r\n ");
+#line 166 "RequestPage.cshtml"
+ Write(context.Scheme);
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n
\r\n \r\n | Query | \r\n " +
+" ");
+#line 170 "RequestPage.cshtml"
+ Write(context.Query.Value);
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n
\r\n \r\n | Cookies | \r\n " +
+" \r\n");
+#line 175 "RequestPage.cshtml"
+
+
+#line default
+#line hidden
+
+#line 175 "RequestPage.cshtml"
+ if (context.Cookies.Any())
+ {
+
+#line default
+#line hidden
+
+ WriteLiteral(@"
+
+
+ | Variable |
+ Value |
+
+
+
+");
+#line 185 "RequestPage.cshtml"
+
+
+#line default
+#line hidden
+
+#line 185 "RequestPage.cshtml"
+ foreach (var cookie in context.Cookies)
+ {
+
+#line default
+#line hidden
+
+ WriteLiteral(" \r\n " +
+" | ");
+#line 188 "RequestPage.cshtml"
+ Write(cookie.Key);
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n ");
+#line 189 "RequestPage.cshtml"
+ Write(string.Join(";", cookie.Value));
+
+#line default
+#line hidden
+ WriteLiteral(" | \r\n \r\n");
+#line 191 "RequestPage.cshtml"
+ }
+
+#line default
+#line hidden
+
+ WriteLiteral(" \r\n \r\n");
+#line 194 "RequestPage.cshtml"
+ }
+
+#line default
+#line hidden
+
+ WriteLiteral(" | \r\n
\r\n
\r\n");
+#line 198 "RequestPage.cshtml"
+ }
+
+#line default
+#line hidden
+
+ WriteLiteral(" Logs
\r\n
+
+
+
+ | Date |
+ Time |
+ Severity |
+ Name |
+ State |
+ Error |
+
+
+ ");
+#line 229 "RequestPage.cshtml"
+ Write(Traverse(Model.Activity.Root));
+
+#line default
+#line hidden
+ WriteLiteral(@"
+
+
+
+");
+ }
+ #pragma warning restore 1998
+ }
+}
diff --git a/src/Microsoft.AspNet.Diagnostics.Elm/Views/RequestPage.cshtml b/src/Microsoft.AspNet.Diagnostics.Elm/Views/RequestPage.cshtml
new file mode 100644
index 00000000..60a4bf1b
--- /dev/null
+++ b/src/Microsoft.AspNet.Diagnostics.Elm/Views/RequestPage.cshtml
@@ -0,0 +1,239 @@
+@using System
+@using System.Globalization
+@using System.Linq
+@using Microsoft.AspNet.Diagnostics.Elm
+@using Microsoft.AspNet.Diagnostics.Views
+@using Microsoft.AspNet.Diagnostics.Elm.Views
+@using Microsoft.Framework.Logging
+
+@functions
+{
+ public RequestPage(RequestPageModel model)
+ {
+ Model = model;
+ }
+
+ public RequestPageModel Model { get; set; }
+}
+
+@helper LogRow(LogInfo log)
+{
+ if (log.Severity >= Model.Options.MinLevel &&
+ (string.IsNullOrEmpty(Model.Options.NamePrefix) || log.Name.StartsWith(Model.Options.NamePrefix, StringComparison.Ordinal)))
+ {
+
+ | @string.Format("{0:MM/dd/yy}", log.Time) |
+ @string.Format("{0:H:mm:ss}", log.Time) |
+ @log.Severity |
+ @log.Name |
+ @log.Message |
+ @log.Exception |
+
+ }
+}
+
+@helper Traverse(ScopeNode node)
+{
+ var messageIndex = 0;
+ var childIndex = 0;
+ while (messageIndex < node.Messages.Count && childIndex < node.Children.Count)
+ {
+ if (node.Messages[messageIndex].Time < node.Children[childIndex].StartTime)
+ {
+ @LogRow(node.Messages[messageIndex])
+ messageIndex++;
+ }
+ else
+ {
+ @Traverse(node.Children[childIndex])
+ childIndex++;
+ }
+ }
+ if (messageIndex < node.Messages.Count)
+ {
+ for (var i = messageIndex; i < node.Messages.Count; i++)
+ {
+ @LogRow(node.Messages[i])
+ }
+ }
+ else
+ {
+ for (var i = childIndex; i < node.Children.Count; i++)
+ {
+ @Traverse(node.Children[i])
+ }
+ }
+}
+
+
+
+
+ ASP.NET Logs
+
+
+
+
+ ASP.NET Logs
+ @{
+ var context = Model.Activity?.HttpInfo;
+ }
+ @if (context != null)
+ {
+
+
+
+
+
+ | Path |
+ @context.Path |
+
+
+ | Host |
+ @context.Host |
+
+
+ | Content Type |
+ @context.ContentType |
+
+
+ | Method |
+ @context.Method |
+
+
+ | Protocol |
+ @context.Protocol |
+
+
+ | Headers |
+
+
+
+ | Status Code |
+ @context.StatusCode |
+
+
+ | User |
+ @context.User.Identity.Name |
+
+
+ | Claims |
+
+ @if (context.User.Claims.Any())
+ {
+
+
+
+ | Issuer |
+ Value |
+
+
+
+ @foreach (var claim in context.User.Claims)
+ {
+
+ | @claim.Issuer |
+ @claim.Value |
+
+ }
+
+
+ }
+ |
+
+
+ | Scheme |
+ @context.Scheme |
+
+
+ | Query |
+ @context.Query.Value |
+
+
+ | Cookies |
+
+ @if (context.Cookies.Any())
+ {
+
+
+
+ | Variable |
+ Value |
+
+
+
+ @foreach (var cookie in context.Cookies)
+ {
+
+ | @cookie.Key |
+ @string.Join(";", cookie.Value) |
+
+ }
+
+
+ }
+ |
+
+
+ }
+ Logs
+
+
+
+
+ | Date |
+ Time |
+ Severity |
+ Name |
+ State |
+ Error |
+
+
+ @Traverse(Model.Activity.Root)
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Diagnostics.Elm/Views/RequestPage.css b/src/Microsoft.AspNet.Diagnostics.Elm/Views/RequestPage.css
new file mode 100644
index 00000000..d0803ebf
--- /dev/null
+++ b/src/Microsoft.AspNet.Diagnostics.Elm/Views/RequestPage.css
@@ -0,0 +1,56 @@
+body {
+ font-size: 0.9em;
+ width: 90%;
+ margin: 0px auto;
+}
+
+h1 {
+ padding-bottom: 10px;
+}
+
+h2 {
+ font-weight: normal;
+}
+
+table {
+ border-spacing: 0px;
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid black;
+ white-space: pre-wrap;
+}
+
+th {
+ font-family: Arial;
+}
+
+td, th {
+ padding: 8px;
+}
+
+#headerTable, #cookieTable {
+ border: none;
+ height: 100%;
+}
+
+#headerTd {
+ white-space: normal;
+}
+
+#label {
+ width: 20%;
+ border-right: 1px solid black;
+}
+
+#logs{
+ margin-top: 10px;
+ margin-bottom: 20px;
+}
+
+#logs>tbody>tr>td {
+ border-right: 1px dashed lightgray;
+}
+
+#logs>thead>tr>th {
+ border: 1px solid black;
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Diagnostics.Elm/Views/RequestPageModel.cs b/src/Microsoft.AspNet.Diagnostics.Elm/Views/RequestPageModel.cs
new file mode 100644
index 00000000..b42fa3cc
--- /dev/null
+++ b/src/Microsoft.AspNet.Diagnostics.Elm/Views/RequestPageModel.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+
+namespace Microsoft.AspNet.Diagnostics.Elm.Views
+{
+ public class RequestPageModel
+ {
+ public Guid RequestID { get; set; }
+
+ public ActivityContext Activity { get; set; }
+
+ public ViewOptions Options { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Diagnostics.Elm/Views/Shared.css b/src/Microsoft.AspNet.Diagnostics.Elm/Views/Shared.css
new file mode 100644
index 00000000..7f355343
--- /dev/null
+++ b/src/Microsoft.AspNet.Diagnostics.Elm/Views/Shared.css
@@ -0,0 +1,39 @@
+body {
+ font-family: 'Segoe UI', Tahoma, Arial, Helvtica, sans-serif;
+ line-height: 1.4em;
+}
+
+h1 {
+ font-family: 'Segoe UI', Helvetica, sans-serif;
+ font-size: 2.5em;
+}
+
+td {
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+
+tr:nth-child(2n) {
+ background-color: #F6F6F6;
+}
+
+.critical {
+ background-color: red;
+ color: white;
+}
+
+.error {
+ color: red;
+}
+
+.information {
+ color: blue;
+}
+
+.verbose {
+ color: black;
+}
+
+.warning {
+ color: orange;
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Diagnostics.Elm/project.json b/src/Microsoft.AspNet.Diagnostics.Elm/project.json
new file mode 100644
index 00000000..5014719b
--- /dev/null
+++ b/src/Microsoft.AspNet.Diagnostics.Elm/project.json
@@ -0,0 +1,29 @@
+{
+ "version": "1.0.0-*",
+ "dependencies": {
+ "Microsoft.AspNet.Diagnostics": "1.0.0-*",
+ "Microsoft.AspNet.Http": "1.0.0-*",
+ "Microsoft.AspNet.Mvc.Razor": "6.0.0-*",
+ "Microsoft.AspNet.RequestContainer": "1.0.0-*",
+ "Microsoft.Framework.Logging.Interfaces": { "version": "1.0.0-*", "type": "build" },
+ "Microsoft.Framework.Runtime.Interfaces": { "version": "1.0.0-*", "type": "build" }
+ },
+
+ "frameworks": {
+ "aspnet50": { },
+ "aspnetcore50": {
+ "dependencies": {
+ "System.Collections.Concurrent": "4.0.0-beta-*",
+ "System.Collections": "4.0.10-beta-*",
+ "System.Diagnostics.TraceSource": "4.0.0-beta-*",
+ "System.Globalization": "4.0.10-beta-*",
+ "System.Runtime": "4.0.20-beta-*",
+ "System.Runtime.Extensions": "4.0.10-beta-*",
+ "System.Runtime.InteropServices": "4.0.20-beta-*",
+ "System.Linq": "4.0.0-beta-*",
+ "System.Threading": "4.0.0-beta-*",
+ "System.Threading.ExecutionContext": "4.0.0-beta-*"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Diagnostics/Views/BaseView.cs b/src/Microsoft.AspNet.Diagnostics/Views/BaseView.cs
index ee2c49d4..f3f91794 100644
--- a/src/Microsoft.AspNet.Diagnostics/Views/BaseView.cs
+++ b/src/Microsoft.AspNet.Diagnostics/Views/BaseView.cs
@@ -100,6 +100,35 @@ protected void WriteAttribute(
WriteLiteral(trailer.Item1);
}
+ protected void WriteAttributeTo(
+ TextWriter writer,
+ string name,
+ Tuple leader,
+ Tuple trailer,
+ Tuple, Tuple, bool> part1)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+ if (leader == null)
+ {
+ throw new ArgumentNullException("leader");
+ }
+ if (trailer == null)
+ {
+ throw new ArgumentNullException("trailer");
+ }
+ if (part1 == null)
+ {
+ throw new ArgumentNullException("part1");
+ }
+ WriteLiteralTo(writer, leader.Item1);
+ WriteLiteralTo(writer, part1.Item1.Item1);
+ WriteTo(writer, part1.Item2.Item1);
+ WriteLiteralTo(writer, trailer.Item1);
+ }
+
///
///
///
@@ -421,7 +450,7 @@ protected void WriteAttribute(
///
private void WriteEncoded(string value)
{
- Output.Write(WebUtility.HtmlEncode(value));
+ WriteLiteralTo(Output, WebUtility.HtmlEncode(value));
}
///
@@ -441,5 +470,72 @@ protected void Write(string value)
{
WriteEncoded(value);
}
+
+ ///
+ /// is invoked
+ ///
+ /// The to invoke
+ protected void Write(HelperResult result)
+ {
+ WriteTo(Output, result);
+ }
+
+ ///
+ /// Writes the specified to .
+ ///
+ /// The instance to write to.
+ /// The to write.
+ ///
+ /// is invoked for types.
+ /// For all other types, the encoded result of is written to the
+ /// .
+ ///
+ protected void WriteTo(TextWriter writer, object value)
+ {
+ if (value != null)
+ {
+ var helperResult = value as HelperResult;
+ if (helperResult != null)
+ {
+ helperResult.WriteTo(writer);
+ }
+ else
+ {
+ WriteTo(writer, value.ToString());
+ }
+ }
+ }
+
+ ///
+ /// Writes the specified with HTML encoding to .
+ ///
+ /// The instance to write to.
+ /// The to write.
+ protected void WriteTo(TextWriter writer, string value)
+ {
+ WriteLiteralTo(writer, WebUtility.HtmlEncode(value));
+ }
+
+ ///
+ /// Writes the specified without HTML encoding to the .
+ ///
+ /// The instance to write to.
+ /// The to write.
+ protected void WriteLiteralTo(TextWriter writer, object value)
+ {
+ WriteLiteralTo(writer, Convert.ToString(value, CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// Writes the specified without HTML encoding to .
+ ///
+ /// The to write.
+ protected void WriteLiteralTo(TextWriter writer, string value)
+ {
+ if (!string.IsNullOrEmpty(value))
+ {
+ writer.Write(value);
+ }
+ }
}
}
diff --git a/src/Microsoft.AspNet.Diagnostics/Views/HelperResult.cs b/src/Microsoft.AspNet.Diagnostics/Views/HelperResult.cs
new file mode 100644
index 00000000..e8f0e769
--- /dev/null
+++ b/src/Microsoft.AspNet.Diagnostics/Views/HelperResult.cs
@@ -0,0 +1,42 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+
+namespace Microsoft.AspNet.Diagnostics.Views
+{
+ ///
+ /// Represents a deferred write operation in a .
+ ///
+ public class HelperResult
+ {
+ private readonly Action _action;
+
+ ///
+ /// Creates a new instance of .
+ ///
+ /// The delegate to invoke when is called.
+ public HelperResult(Action action)
+ {
+ _action = action;
+ }
+
+ ///
+ /// Gets the delegate to invoke when is called.
+ ///
+ public Action WriteAction
+ {
+ get { return _action; }
+ }
+
+ ///
+ /// Method invoked to produce content from the .
+ ///
+ /// The instance to write to.
+ public virtual void WriteTo(TextWriter writer)
+ {
+ _action(writer);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/PageGenerator/PageGenerator.kproj b/src/PageGenerator/PageGenerator.kproj
index dc172378..5fc6e933 100644
--- a/src/PageGenerator/PageGenerator.kproj
+++ b/src/PageGenerator/PageGenerator.kproj
@@ -15,6 +15,10 @@
2.0
+ 0
+
+
+
\ No newline at end of file
diff --git a/src/PageGenerator/Program.cs b/src/PageGenerator/Program.cs
index a4f84c78..11bd19b4 100644
--- a/src/PageGenerator/Program.cs
+++ b/src/PageGenerator/Program.cs
@@ -6,6 +6,7 @@
using System.IO;
using System.Linq;
using Microsoft.AspNet.Razor;
+using Microsoft.AspNet.Razor.Generator;
using Microsoft.Framework.Runtime;
namespace PageGenerator
@@ -76,6 +77,15 @@ private static void GenerateCodeFile(string cshtmlFilePath, string rootNamespace
var codeLang = new CSharpRazorCodeLanguage();
var host = new RazorEngineHost(codeLang);
host.DefaultBaseClass = "Microsoft.AspNet.Diagnostics.Views.BaseView";
+ host.GeneratedClassContext = new GeneratedClassContext(
+ GeneratedClassContext.DefaultExecuteMethodName,
+ GeneratedClassContext.DefaultWriteMethodName,
+ GeneratedClassContext.DefaultWriteLiteralMethodName,
+ "WriteTo",
+ "WriteLiteralTo",
+ "HelperResult",
+ "DefineSection",
+ new GeneratedTagHelperContext());
var engine = new RazorTemplateEngine(host);
using (var fileStream = File.OpenText(cshtmlFilePath))
diff --git a/src/PageGenerator/project.json b/src/PageGenerator/project.json
index 228d7c87..177e5624 100644
--- a/src/PageGenerator/project.json
+++ b/src/PageGenerator/project.json
@@ -2,6 +2,7 @@
"version": "1.0.0-*",
"dependencies": {
"Microsoft.AspNet.Diagnostics": "1.0.0-*",
+ "Microsoft.AspNet.Diagnostics.Elm": "1.0.0-*",
"Microsoft.AspNet.Razor": "4.0.0-*",
"Microsoft.Framework.Runtime.Interfaces": "1.0.0-*"
},
diff --git a/test/Microsoft.AspNet.Diagnostics.Tests/ElmLoggerTest.cs b/test/Microsoft.AspNet.Diagnostics.Tests/ElmLoggerTest.cs
new file mode 100644
index 00000000..e4fa4a65
--- /dev/null
+++ b/test/Microsoft.AspNet.Diagnostics.Tests/ElmLoggerTest.cs
@@ -0,0 +1,343 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using Microsoft.AspNet.Diagnostics.Elm;
+using Microsoft.Framework.Logging;
+using Xunit;
+
+namespace Microsoft.AspNet.Diagnostics.Tests
+{
+ public class ElmLoggerTest
+ {
+ private const string _name = "test";
+ private const string _state = "This is a test";
+ private Func _filter = (_, __) => true;
+
+ private Tuple SetUp(Func filter = null, string name = null)
+ {
+ // Arrange
+ var store = new ElmStore();
+ var options = new ElmOptions() { Filter = filter ?? _filter };
+ var provider = new ElmLoggerProvider(store, options);
+ var logger = (ElmLogger)provider.Create(name ?? _name);
+
+ return new Tuple(logger, store);
+ }
+
+ [Fact]
+ public void LogsWhenNullFormatterGiven()
+ {
+ // Arrange
+ var t = SetUp();
+ var logger = t.Item1;
+ var store = t.Item2;
+
+ // Act
+ logger.Write(LogLevel.Information, 0, _state, null, null);
+
+ // Assert
+ Assert.Single(store.GetActivities());
+ }
+
+ [Fact]
+ public void DoesNotLogWithEmptyStateAndException()
+ {
+ // Arrange
+ var t = SetUp();
+ var logger = t.Item1;
+ var store = t.Item2;
+
+ // Act
+ logger.Write(LogLevel.Information, 0, null, null, null);
+
+ // Assert
+ Assert.Empty(store.GetActivities());
+ }
+
+ [Fact]
+ public void DefaultLogsForAllLogLevels()
+ {
+ // Arrange
+ var t = SetUp();
+ var logger = t.Item1;
+ var store = t.Item2;
+
+ // Act
+ logger.Write(LogLevel.Verbose, 0, _state, null, null);
+ logger.Write(LogLevel.Information, 0, _state, null, null);
+ logger.Write(LogLevel.Warning, 0, _state, null, null);
+ logger.Write(LogLevel.Error, 0, _state, null, null);
+ logger.Write(LogLevel.Critical, 0, _state, null, null);
+
+ // Assert
+ Assert.Equal(5, (store.GetActivities().SelectMany(a => NodeLogs(a.Root, new List()))).ToList().Count);
+ }
+
+ [Theory]
+ [InlineData(LogLevel.Warning, "", 3)]
+ [InlineData(LogLevel.Warning, "te", 3)]
+ [InlineData(LogLevel.Warning, "bad", 0)]
+ [InlineData(LogLevel.Critical, "", 1)]
+ [InlineData(LogLevel.Critical, "test", 1)]
+ [InlineData(LogLevel.Verbose, "t", 5)]
+ public void Filter_LogsWhenAppropriate(LogLevel minLevel, string prefix, int count)
+ {
+ // Arrange
+ var t = SetUp((name, level) => (name.StartsWith(prefix, StringComparison.Ordinal) && level >= minLevel), _name);
+ var logger = t.Item1;
+ var store = t.Item2;
+
+ // Act
+ logger.Write(LogLevel.Verbose, 0, _state, null, null);
+ logger.Write(LogLevel.Information, 0, _state, null, null);
+ logger.Write(LogLevel.Warning, 0, _state, null, null);
+ logger.Write(LogLevel.Error, 0, _state, null, null);
+ logger.Write(LogLevel.Critical, 0, _state, null, null);
+
+ // Assert
+ Assert.Equal(count, (store.GetActivities().SelectMany(a => NodeLogs(a.Root, new List()))).ToList().Count);
+ }
+
+ [Fact]
+ public void CountReturnsCorrectNumber()
+ {
+ // Arrange
+ var t = SetUp();
+ var logger = t.Item1;
+ var store = t.Item2;
+
+ // Act
+ using (logger.BeginScope("test14"))
+ {
+ for (var i = 0; i < 25; i++)
+ {
+ logger.WriteWarning("hello world");
+ }
+ using (logger.BeginScope("test15"))
+ {
+ for (var i = 0; i < 25; i++)
+ {
+ logger.WriteCritical("goodbye world");
+ }
+ }
+ }
+
+ // Assert
+ Assert.Equal(50, store.Count());
+ }
+
+ [Fact]
+ public void ThreadsHaveSeparateActivityContexts()
+ {
+ // Arrange
+ var t = SetUp();
+ var logger = t.Item1;
+ var store = t.Item2;
+
+ var testThread = new TestThread(logger);
+ Thread workerThread = new Thread(testThread.work);
+
+ // Act
+ workerThread.Start();
+ using (logger.BeginScope("test1"))
+ {
+ logger.WriteWarning("hello world");
+ Thread.Sleep(1000);
+ logger.WriteCritical("goodbye world");
+ }
+ workerThread.Join();
+
+ // Assert
+ Assert.Equal(17, (store.GetActivities().SelectMany(a => NodeLogs(a.Root, new List()))).ToList().Count);
+ Assert.Equal(2, store.GetActivities().ToList().Count);
+ }
+
+ [Fact]
+ public void ScopesHaveProperTreeStructure()
+ {
+ // Arrange
+ var t = SetUp();
+ var logger = t.Item1;
+ var store = t.Item2;
+
+ var testThread = new TestThread(logger);
+ Thread workerThread = new Thread(testThread.work);
+
+ // Act
+ workerThread.Start();
+ using (logger.BeginScope("test2"))
+ {
+ logger.WriteWarning("hello world");
+ Thread.Sleep(1000);
+ logger.WriteCritical("goodbye world");
+ }
+ workerThread.Join();
+
+ // Assert
+ // get the root of the activity for scope "test2"
+ var root1 = (store.GetActivities()).Where(a => a.Root.State.Equals("test2"))?.FirstOrDefault()?.Root;
+ Assert.NotNull(root1);
+ var root2 = (store.GetActivities()).Where(a => a.Root.State.Equals("test12"))?.FirstOrDefault()?.Root;
+ Assert.NotNull(root2);
+
+ Assert.Equal(0, root1.Children.Count);
+ Assert.Equal(2, root1.Messages.Count);
+ Assert.Equal(1, root2.Children.Count);
+ Assert.Equal(12, root2.Messages.Count);
+ Assert.Equal(0, root2.Children.First().Children.Count);
+ Assert.Equal(3, root2.Children.First().Messages.Count);
+ }
+
+ [Fact]
+ public void CollapseTree_CollapsesWhenNoLogsInSingleScope()
+ {
+ // Arrange
+ var t = SetUp();
+ var logger = t.Item1;
+ var store = t.Item2;
+
+ // Act
+ using (logger.BeginScope("test3"))
+ {
+ }
+
+ // Assert
+ Assert.Empty(store.GetActivities());
+ }
+
+ [Fact]
+ public void CollapseTree_CollapsesWhenNoLogsInNestedScope()
+ {
+ // Arrange
+ var t = SetUp();
+ var logger = t.Item1;
+ var store = t.Item2;
+
+ // Act
+ using (logger.BeginScope("test4"))
+ {
+ using (logger.BeginScope("test5"))
+ {
+ }
+ }
+
+ // Assert
+ Assert.Empty(store.GetActivities());
+ }
+
+ [Fact]
+ public void CollapseTree_DoesNotCollapseWhenLogsExist()
+ {
+ // Arrange
+ var t = SetUp();
+ var logger = t.Item1;
+ var store = t.Item2;
+
+ // Act
+ using (logger.BeginScope("test6"))
+ {
+ using (logger.BeginScope("test7"))
+ {
+ logger.WriteVerbose("hi");
+ }
+ }
+
+ // Assert
+ Assert.Single(store.GetActivities());
+ }
+
+ [Fact]
+ public void CollapseTree_CollapsesAppropriateNodes()
+ {
+ // Arrange
+ var t = SetUp();
+ var logger = t.Item1;
+ var store = t.Item2;
+
+ // Act
+ using (logger.BeginScope("test8"))
+ {
+ logger.WriteVerbose("hi");
+ using (logger.BeginScope("test9"))
+ {
+ }
+ }
+
+ // Assert
+ Assert.Single(store.GetActivities());
+ var context = store.GetActivities().Where(a => a.Root.State.Equals("test8")).First();
+ Assert.Empty(context.Root.Children);
+ }
+
+ [Fact]
+ public void CollapseTree_WorksWithFilter()
+ {
+ // Arrange
+ var t = SetUp((_, level) => level >= LogLevel.Warning, null);
+ var logger = t.Item1;
+ var store = t.Item2;
+
+ // Act
+ using (logger.BeginScope("test10"))
+ {
+ using (logger.BeginScope("test11"))
+ {
+ logger.WriteInformation("hi");
+ }
+ }
+
+ // Assert
+ Assert.Empty(store.GetActivities());
+ }
+
+
+ private List NodeLogs(ScopeNode node, List logs)
+ {
+ if (node != null)
+ {
+ logs.AddRange(node.Messages);
+ foreach (var child in node.Children)
+ {
+ NodeLogs(child, logs);
+ }
+ }
+ return logs;
+ }
+
+ private class TestThread
+ {
+ private ILogger _logger;
+
+ public TestThread(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public void work()
+ {
+ using (_logger.BeginScope("test12"))
+ {
+ for (var i = 0; i < 5; i++)
+ {
+ _logger.WriteVerbose(string.Format("xxx {0}", i));
+ Thread.Sleep(5);
+ }
+ using (_logger.BeginScope("test13"))
+ {
+ for (var i = 0; i < 3; i++)
+ {
+ _logger.WriteVerbose(string.Format("yyy {0}", i));
+ Thread.Sleep(200);
+ }
+ }
+ for (var i = 0; i < 7; i++)
+ {
+ _logger.WriteVerbose(string.Format("zzz {0}", i));
+ Thread.Sleep(40);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Diagnostics.Tests/ElmMiddlewareTest.cs b/test/Microsoft.AspNet.Diagnostics.Tests/ElmMiddlewareTest.cs
new file mode 100644
index 00000000..f6862ca7
--- /dev/null
+++ b/test/Microsoft.AspNet.Diagnostics.Tests/ElmMiddlewareTest.cs
@@ -0,0 +1,212 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.IO;
+using System.Security.Claims;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Builder;
+using Microsoft.AspNet.Diagnostics.Elm;
+using Microsoft.AspNet.Http;
+using Microsoft.Framework.Logging;
+using Microsoft.Framework.OptionsModel;
+#if ASPNET50
+using Moq;
+#endif
+using Xunit;
+
+namespace Microsoft.AspNet.Diagnostics.Tests
+{
+ public class ElmMiddlewareTest
+ {
+ private const string DefaultPath = "/Elm";
+
+ [Fact]
+ public void DefaultPageOptions_HasDefaultPath()
+ {
+ // Arrange & act
+ var options = new ElmOptions();
+
+ // Assert
+ Assert.Equal(DefaultPath, options.Path.Value);
+ }
+
+#if ASPNET50
+ [Fact]
+ public async void Invoke_WithNonMatchingPath_IgnoresRequest()
+ {
+ // Arrange
+ var elmStore = new ElmStore();
+ var factory = new LoggerFactory();
+ var optionsMock = new Mock>();
+ optionsMock
+ .SetupGet(o => o.Options)
+ .Returns(new ElmOptions());
+ factory.AddProvider(new ElmLoggerProvider(elmStore, optionsMock.Object.Options));
+
+ RequestDelegate next = _ =>
+ {
+ return Task.FromResult