elm logger
This commit is contained in:
parent
e6fdb8cbd2
commit
ce59419893
|
|
@ -33,6 +33,7 @@ EndProject
|
|||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Diagnostics.Entity.Tests", "test\Microsoft.AspNet.Diagnostics.Entity.Tests\Microsoft.AspNet.Diagnostics.Entity.Tests.kproj", "{5486117B-A742-49E0-94FC-12B76F061803}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Diagnostics.Entity.FunctionalTests", "test\Microsoft.AspNet.Diagnostics.Entity.FunctionalTests\Microsoft.AspNet.Diagnostics.Entity.FunctionalTests.kproj", "{2F9B479D-8247-4210-804B-78E6DD5C3E98}"
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Diagnostics.Elm", "src\Microsoft.AspNet.Diagnostics.Elm\Microsoft.AspNet.Diagnostics.Elm.kproj", "{624B0019-956A-4157-B008-270C5B229553}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
|
@ -150,6 +151,18 @@ Global
|
|||
{2F9B479D-8247-4210-804B-78E6DD5C3E98}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{2F9B479D-8247-4210-804B-78E6DD5C3E98}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2F9B479D-8247-4210-804B-78E6DD5C3E98}.Release|x86.Build.0 = Release|Any CPU
|
||||
{624B0019-956A-4157-B008-270C5B229553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{624B0019-956A-4157-B008-270C5B229553}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{624B0019-956A-4157-B008-270C5B229553}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{624B0019-956A-4157-B008-270C5B229553}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{624B0019-956A-4157-B008-270C5B229553}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{624B0019-956A-4157-B008-270C5B229553}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{624B0019-956A-4157-B008-270C5B229553}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{624B0019-956A-4157-B008-270C5B229553}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{624B0019-956A-4157-B008-270C5B229553}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{624B0019-956A-4157-B008-270C5B229553}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{624B0019-956A-4157-B008-270C5B229553}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{624B0019-956A-4157-B008-270C5B229553}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -165,5 +178,6 @@ Global
|
|||
{4F5A6A72-FFE4-49C4-B4C6-58132CFCB9FE} = {509A6F36-AD80-4A18-B5B1-717D38DFF29D}
|
||||
{5486117B-A742-49E0-94FC-12B76F061803} = {2AF90579-B118-4583-AE88-672EFACB5BC4}
|
||||
{2F9B479D-8247-4210-804B-78E6DD5C3E98} = {2AF90579-B118-4583-AE88-672EFACB5BC4}
|
||||
{624B0019-956A-4157-B008-270C5B229553} = {509A6F36-AD80-4A18-B5B1-717D38DFF29D}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Elm
|
||||
{
|
||||
public class ActivityContext
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public HttpInfo HttpInfo { get; set; }
|
||||
|
||||
public ScopeNode Root { get; set; }
|
||||
|
||||
public DateTimeOffset Time { get; set; }
|
||||
|
||||
public bool IsCollapsed { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.Framework.Logging;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Elm
|
||||
{
|
||||
/// <summary>
|
||||
/// Enables the Elm logging service.
|
||||
/// </summary>
|
||||
public class ElmCaptureMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ElmOptions _options;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public ElmCaptureMiddleware(RequestDelegate next, ILoggerFactory factory, IOptions<ElmOptions> options)
|
||||
{
|
||||
_next = next;
|
||||
_options = options.Options;
|
||||
_logger = factory.Create<ElmCaptureMiddleware>();
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
var requestId = Guid.NewGuid();
|
||||
using (_logger.BeginScope(string.Format("request {0}", requestId)))
|
||||
{
|
||||
var p = ElmScope.Current;
|
||||
ElmScope.Current.Context.HttpInfo = GetHttpInfo(context, requestId);
|
||||
try
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ElmScope.Current.Context.HttpInfo.StatusCode = context.Response.StatusCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes the info from the given HttpContext and copies it to an HttpInfo object
|
||||
/// </summary>
|
||||
/// <returns>The HttpInfo for the current elm context</returns>
|
||||
private static HttpInfo GetHttpInfo(HttpContext context, Guid requestId)
|
||||
{
|
||||
return new HttpInfo()
|
||||
{
|
||||
RequestID = requestId,
|
||||
Host = context.Request.Host,
|
||||
ContentType = context.Request.ContentType,
|
||||
Path = context.Request.Path,
|
||||
Scheme = context.Request.Scheme,
|
||||
StatusCode = context.Response.StatusCode,
|
||||
User = context.User,
|
||||
Method = context.Request.Method,
|
||||
Protocol = context.Request.Protocol,
|
||||
Headers = context.Request.Headers,
|
||||
Query = context.Request.QueryString,
|
||||
Cookies = context.Request.Cookies
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
// 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 Jetbrains.Annotations;
|
||||
using Microsoft.AspNet.Diagnostics.Elm;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.Logging;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Builder
|
||||
{
|
||||
public static class ElmExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Enables the Elm logging service, which can be accessed via the <see cref="ElmPageMiddleware"/>.
|
||||
/// </summary>
|
||||
public static IApplicationBuilder UseElmCapture([NotNull] this IApplicationBuilder builder)
|
||||
{
|
||||
// add the elm provider to the factory here so the logger can start capturing logs immediately
|
||||
var factory = builder.ApplicationServices.GetRequiredService<ILoggerFactory>();
|
||||
var store = builder.ApplicationServices.GetRequiredService<ElmStore>();
|
||||
var options = builder.ApplicationServices.GetService<IOptions<ElmOptions>>();
|
||||
factory.AddProvider(new ElmLoggerProvider(store, options?.Options ?? new ElmOptions()));
|
||||
|
||||
return builder.UseMiddleware<ElmCaptureMiddleware>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables viewing logs captured by the <see cref="ElmCaptureMiddleware"/>.
|
||||
/// </summary>
|
||||
public static IApplicationBuilder UseElmPage([NotNull] this IApplicationBuilder builder)
|
||||
{
|
||||
return builder.UseMiddleware<ElmPageMiddleware>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers an <see cref="ElmStore"/> and configures <see cref="ElmOptions"/>.
|
||||
/// </summary>
|
||||
public static IServiceCollection AddElm([NotNull] this IServiceCollection services, Action<ElmOptions> configureOptions = null)
|
||||
{
|
||||
services.AddSingleton<ElmStore>(); // registering the service so it can be injected into constructors
|
||||
return services.Configure(configureOptions ?? (o => { }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
// 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 Microsoft.Framework.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Elm
|
||||
{
|
||||
public class ElmLogger : ILogger
|
||||
{
|
||||
private readonly string _name;
|
||||
private readonly ElmOptions _options;
|
||||
private readonly ElmStore _store;
|
||||
|
||||
public ElmLogger(string name, ElmOptions options, ElmStore store)
|
||||
{
|
||||
_name = name;
|
||||
_options = options;
|
||||
_store = store;
|
||||
}
|
||||
|
||||
public void Write(LogLevel logLevel, int eventId, object state, Exception exception,
|
||||
Func<object, Exception, string> formatter)
|
||||
{
|
||||
if (!IsEnabled(logLevel) || (state == null && exception == null))
|
||||
{
|
||||
return;
|
||||
}
|
||||
LogInfo info = new LogInfo()
|
||||
{
|
||||
ActivityContext = GetCurrentActivityContext(),
|
||||
Name = _name,
|
||||
EventID = eventId,
|
||||
Severity = logLevel,
|
||||
Exception = exception,
|
||||
State = state,
|
||||
Message = formatter == null ? state.ToString() : formatter(state, exception),
|
||||
Time = DateTimeOffset.UtcNow
|
||||
};
|
||||
if (ElmScope.Current != null)
|
||||
{
|
||||
ElmScope.Current.Node.Messages.Add(info);
|
||||
}
|
||||
// The log does not belong to any scope - create a new context for it
|
||||
else
|
||||
{
|
||||
var context = GetNewActivityContext();
|
||||
context.Id = Guid.Empty; // mark as a non-scope log
|
||||
context.Root = new ScopeNode();
|
||||
context.Root.Messages.Add(info);
|
||||
_store.AddActivity(context);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
return _options.Filter(_name, logLevel);
|
||||
}
|
||||
|
||||
public IDisposable BeginScope(object state)
|
||||
{
|
||||
var scope = new ElmScope(_name, state);
|
||||
scope.Context = ElmScope.Current?.Context ?? GetNewActivityContext();
|
||||
return ElmScope.Push(scope, _store);
|
||||
}
|
||||
|
||||
private ActivityContext GetNewActivityContext()
|
||||
{
|
||||
return new ActivityContext()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Time = DateTimeOffset.UtcNow
|
||||
};
|
||||
}
|
||||
|
||||
private ActivityContext GetCurrentActivityContext()
|
||||
{
|
||||
return ElmScope.Current?.Context ?? GetNewActivityContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// 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 Jetbrains.Annotations;
|
||||
using Microsoft.Framework.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Elm
|
||||
{
|
||||
public class ElmLoggerProvider : ILoggerProvider
|
||||
{
|
||||
private readonly ElmStore _store;
|
||||
private readonly ElmOptions _options;
|
||||
|
||||
public ElmLoggerProvider([NotNull] ElmStore store, [NotNull] ElmOptions options)
|
||||
{
|
||||
_store = store;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public ILogger Create(string name)
|
||||
{
|
||||
return new ElmLogger(name, _options, _store);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// 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 Microsoft.AspNet.Http;
|
||||
using Microsoft.Framework.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Elm
|
||||
{
|
||||
/// <summary>
|
||||
/// Options for ElmMiddleware
|
||||
/// </summary>
|
||||
public class ElmOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the path to view the logs.
|
||||
/// </summary>
|
||||
public PathString Path { get; set; } = new PathString("/Elm");
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether log statements should be logged based on the name of the logger
|
||||
/// and the <see cref="LogLevel"/> of the message.
|
||||
/// </summary>
|
||||
public Func<string, LogLevel, bool> Filter { get; set; } = (name, level) => true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Diagnostics.Elm.Views;
|
||||
using Microsoft.Framework.Logging;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Elm
|
||||
{
|
||||
/// <summary>
|
||||
/// Enables viewing logs captured by the <see cref="ElmCaptureMiddleware"/>.
|
||||
/// </summary>
|
||||
public class ElmPageMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ElmOptions _options;
|
||||
private readonly ElmStore _store;
|
||||
|
||||
public ElmPageMiddleware(RequestDelegate next, IOptions<ElmOptions> options, ElmStore store)
|
||||
{
|
||||
_next = next;
|
||||
_options = options.Options;
|
||||
_store = store;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
if (!context.Request.Path.StartsWithSegments(_options.Path))
|
||||
{
|
||||
await _next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
var options = ParseParams(context);
|
||||
if (context.Request.Path == _options.Path)
|
||||
{
|
||||
RenderMainLogPage(options, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderRequestDetailsPage(options, context);
|
||||
}
|
||||
}
|
||||
|
||||
private async void RenderMainLogPage(ViewOptions options, HttpContext context)
|
||||
{
|
||||
var model = new LogPageModel()
|
||||
{
|
||||
// sort so most recent logs are first
|
||||
Activities = _store.GetActivities(),
|
||||
Options = options,
|
||||
Path = _options.Path
|
||||
};
|
||||
var logPage = new LogPage(model);
|
||||
|
||||
await logPage.ExecuteAsync(context);
|
||||
}
|
||||
|
||||
private async void RenderRequestDetailsPage(ViewOptions options, HttpContext context)
|
||||
{
|
||||
var parts = context.Request.Path.Value.Split('/');
|
||||
var id = Guid.Empty;
|
||||
if (!Guid.TryParse(parts[parts.Length - 1], out id))
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
await context.Response.WriteAsync("Invalid Request Id");
|
||||
return;
|
||||
}
|
||||
var model = new RequestPageModel()
|
||||
{
|
||||
RequestID = id,
|
||||
Activity = _store.GetActivities().Where(a => a.HttpInfo?.RequestID == id).FirstOrDefault(),
|
||||
Options = options
|
||||
};
|
||||
var requestPage = new RequestPage(model);
|
||||
await requestPage.ExecuteAsync(context);
|
||||
}
|
||||
|
||||
private ViewOptions ParseParams(HttpContext context)
|
||||
{
|
||||
var options = new ViewOptions()
|
||||
{
|
||||
MinLevel = LogLevel.Verbose,
|
||||
NamePrefix = string.Empty
|
||||
};
|
||||
if (context.Request.Query.ContainsKey("level"))
|
||||
{
|
||||
var minLevel = options.MinLevel;
|
||||
if (Enum.TryParse<LogLevel>(context.Request.Query["level"], out minLevel))
|
||||
{
|
||||
options.MinLevel = minLevel;
|
||||
}
|
||||
}
|
||||
if (context.Request.Query.ContainsKey("name"))
|
||||
{
|
||||
var namePrefix = context.Request.Query.GetValues("name")[0];
|
||||
options.NamePrefix = namePrefix;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
using System;
|
||||
#if ASPNET50
|
||||
using System.Runtime.Remoting;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
#endif
|
||||
using System.Threading;
|
||||
using Jetbrains.Annotations;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Elm
|
||||
{
|
||||
public class ElmScope
|
||||
{
|
||||
private readonly string _name;
|
||||
private readonly object _state;
|
||||
|
||||
public ElmScope(string name, object state)
|
||||
{
|
||||
_name = name;
|
||||
_state = state;
|
||||
}
|
||||
|
||||
public ActivityContext Context { get; set; }
|
||||
|
||||
public ElmScope Parent { get; set; }
|
||||
|
||||
public ScopeNode Node { get; set; }
|
||||
|
||||
#if ASPNET50
|
||||
private static string FieldKey = typeof(ElmScope).FullName + ".Value";
|
||||
public static ElmScope Current
|
||||
{
|
||||
get
|
||||
{
|
||||
var handle = CallContext.LogicalGetData(FieldKey) as ObjectHandle;
|
||||
|
||||
if (handle == null)
|
||||
{
|
||||
return default(ElmScope);
|
||||
}
|
||||
|
||||
return (ElmScope)handle.Unwrap();
|
||||
}
|
||||
set
|
||||
{
|
||||
CallContext.LogicalSetData(FieldKey, new ObjectHandle(value));
|
||||
}
|
||||
}
|
||||
#else
|
||||
private static AsyncLocal<ElmScope> _value = new AsyncLocal<ElmScope>();
|
||||
public static ElmScope Current
|
||||
{
|
||||
set
|
||||
{
|
||||
_value.Value = value;
|
||||
}
|
||||
get
|
||||
{
|
||||
return _value.Value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static IDisposable Push([NotNull] ElmScope scope, [NotNull] ElmStore store)
|
||||
{
|
||||
var temp = Current;
|
||||
Current = scope;
|
||||
Current.Parent = temp;
|
||||
|
||||
Current.Node = new ScopeNode()
|
||||
{
|
||||
StartTime = DateTimeOffset.UtcNow,
|
||||
State = Current._state,
|
||||
Name = Current._name
|
||||
};
|
||||
|
||||
if (Current.Parent != null)
|
||||
{
|
||||
Current.Node.Parent = Current.Parent.Node;
|
||||
Current.Parent.Node.Children.Add(Current.Node);
|
||||
}
|
||||
else
|
||||
{
|
||||
Current.Context.Root = Current.Node;
|
||||
store.AddActivity(Current.Context);
|
||||
}
|
||||
|
||||
return new DisposableAction(() =>
|
||||
{
|
||||
Current.Node.EndTime = DateTimeOffset.UtcNow;
|
||||
Current = Current.Parent;
|
||||
});
|
||||
}
|
||||
|
||||
private class DisposableAction : IDisposable
|
||||
{
|
||||
private Action _action;
|
||||
|
||||
public DisposableAction(Action action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_action != null)
|
||||
{
|
||||
_action.Invoke();
|
||||
_action = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Jetbrains.Annotations;
|
||||
using Microsoft.Framework.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Elm
|
||||
{
|
||||
public class ElmStore
|
||||
{
|
||||
private const int Capacity = 200;
|
||||
|
||||
private LinkedList<ActivityContext> Activities { get; set; } = new LinkedList<ActivityContext>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns an IEnumerable of the contexts of the logs.
|
||||
/// </summary>
|
||||
/// <returns>An IEnumerable of <see cref="ActivityContext"/> objects where each context stores
|
||||
/// information about a top level scope.</returns>
|
||||
public IEnumerable<ActivityContext> GetActivities()
|
||||
{
|
||||
for (var context = Activities.First; context != null; context = context.Next)
|
||||
{
|
||||
if (!context.Value.IsCollapsed && CollapseActivityContext(context.Value))
|
||||
{
|
||||
Activities.Remove(context);
|
||||
}
|
||||
}
|
||||
return Activities;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new <see cref="ActivityContext"/> to the store.
|
||||
/// </summary>
|
||||
/// <param name="context">The context to be added to the store.</param>
|
||||
public void AddActivity([NotNull] ActivityContext activity)
|
||||
{
|
||||
lock (Activities)
|
||||
{
|
||||
Activities.AddLast(activity);
|
||||
while (Count() > Capacity)
|
||||
{
|
||||
Activities.RemoveFirst();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the total number of logs in all activities in the store
|
||||
/// </summary>
|
||||
/// <returns>The total log count</returns>
|
||||
public int Count()
|
||||
{
|
||||
return Activities.Sum(a => Count(a.Root));
|
||||
}
|
||||
|
||||
private int Count(ScopeNode node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
var sum = node.Messages.Count;
|
||||
foreach (var child in node.Children)
|
||||
{
|
||||
sum += Count(child);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes any nodes on the context's scope tree that doesn't have any logs
|
||||
/// This may occur as a result of the filters turned on
|
||||
/// </summary>
|
||||
/// <param name="context">The context who's node should be condensed</param>
|
||||
/// <returns>true if the node has been condensed to null, false otherwise</returns>
|
||||
private bool CollapseActivityContext(ActivityContext context)
|
||||
{
|
||||
context.Root = CollapseHelper(context.Root);
|
||||
context.IsCollapsed = true;
|
||||
return context.Root == null;
|
||||
}
|
||||
|
||||
private ScopeNode CollapseHelper(ScopeNode node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
for (int i = 0; i < node.Children.Count; i++)
|
||||
{
|
||||
node.Children[i] = CollapseHelper(node.Children[i]);
|
||||
}
|
||||
node.Children.RemoveAll(c => c == null);
|
||||
if (node.Children.Count == 0 && node.Messages.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// 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.Security.Claims;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Elm
|
||||
{
|
||||
public class HttpInfo
|
||||
{
|
||||
public Guid RequestID { get; set; }
|
||||
|
||||
public HostString Host { get; set; }
|
||||
|
||||
public PathString Path { get; set; }
|
||||
|
||||
public string ContentType { get; set; }
|
||||
|
||||
public string Scheme { get; set; }
|
||||
|
||||
public int StatusCode { get; set; }
|
||||
|
||||
public ClaimsPrincipal User { get; set; }
|
||||
|
||||
public string Method { get; set; }
|
||||
|
||||
public string Protocol { get; set; }
|
||||
|
||||
public IHeaderDictionary Headers { get; set; }
|
||||
|
||||
public QueryString Query { get; set; }
|
||||
|
||||
public IReadableStringCollection Cookies { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// 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 Microsoft.Framework.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Elm
|
||||
{
|
||||
public class LogInfo
|
||||
{
|
||||
public ActivityContext ActivityContext { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public object State { get; set; }
|
||||
|
||||
public Exception Exception { get; set; }
|
||||
|
||||
public string Message { get; set; }
|
||||
|
||||
public LogLevel Severity { get; set; }
|
||||
|
||||
public int EventID { get; set; }
|
||||
|
||||
public DateTimeOffset Time { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>624b0019-956a-4157-b008-270c5b229553</ProjectGuid>
|
||||
<RootNamespace>Microsoft.AspNet.Diagnostics.Elm</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// 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;
|
||||
|
||||
namespace Jetbrains.Annotations
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
|
||||
internal sealed class NotNullAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Elm
|
||||
{
|
||||
public class ScopeNode
|
||||
{
|
||||
public ScopeNode Parent { get; set; }
|
||||
|
||||
public List<ScopeNode> Children { get; private set; } = new List<ScopeNode>();
|
||||
|
||||
public List<LogInfo> Messages { get; private set; } = new List<LogInfo>();
|
||||
|
||||
public DateTimeOffset StartTime { get; set; }
|
||||
|
||||
public DateTimeOffset EndTime { get; set; }
|
||||
|
||||
public object State { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// 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 Microsoft.Framework.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Elm
|
||||
{
|
||||
/// <summary>
|
||||
/// Options for viewing elm logs.
|
||||
/// </summary>
|
||||
public class ViewOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The minimum <see cref="LogLevel"/> of logs shown on the elm page.
|
||||
/// </summary>
|
||||
public LogLevel MinLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The prefix for the logger names of logs shown on the elm page.
|
||||
/// </summary>
|
||||
public string NamePrefix { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,665 @@
|
|||
namespace Microsoft.AspNet.Diagnostics.Elm.Views
|
||||
{
|
||||
#line 1 "LogPage.cshtml"
|
||||
using System
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
;
|
||||
#line 2 "LogPage.cshtml"
|
||||
using System.Globalization
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
;
|
||||
#line 3 "LogPage.cshtml"
|
||||
using System.Linq
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
;
|
||||
#line 4 "LogPage.cshtml"
|
||||
using Microsoft.AspNet.Diagnostics.Elm.Views
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
;
|
||||
#line 5 "LogPage.cshtml"
|
||||
using Microsoft.AspNet.Diagnostics.Elm
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
;
|
||||
#line 6 "LogPage.cshtml"
|
||||
using Microsoft.AspNet.Diagnostics.Views
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
;
|
||||
#line 7 "LogPage.cshtml"
|
||||
using Microsoft.Framework.Logging
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class LogPage : Microsoft.AspNet.Diagnostics.Views.BaseView
|
||||
{
|
||||
public HelperResult
|
||||
#line 20 "LogPage.cshtml"
|
||||
LogRow(LogInfo log, int level) {
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
return new HelperResult((__razor_helper_writer) => {
|
||||
#line 20 "LogPage.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, " <tr class=\"logRow\">\r\n <td>");
|
||||
#line 25 "LogPage.cshtml"
|
||||
WriteTo(__razor_helper_writer, string.Format("{0:MM/dd/yy}", log.Time));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteralTo(__razor_helper_writer, "</td>\r\n <td>");
|
||||
#line 26 "LogPage.cshtml"
|
||||
WriteTo(__razor_helper_writer, string.Format("{0:H:mm:ss}", log.Time));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteralTo(__razor_helper_writer, "</td>\r\n <td");
|
||||
WriteAttributeTo(__razor_helper_writer, "title", Tuple.Create(" title=\"", 836), Tuple.Create("\"", 853),
|
||||
Tuple.Create(Tuple.Create("", 844), Tuple.Create<System.Object, System.Int32>(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, "</td>\r\n <td");
|
||||
WriteAttributeTo(__razor_helper_writer, "class", Tuple.Create(" class=\"", 886), Tuple.Create("\"", 937),
|
||||
Tuple.Create(Tuple.Create("", 894), Tuple.Create<System.Object, System.Int32>(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, "</td>\r\n <td");
|
||||
WriteAttributeTo(__razor_helper_writer, "title", Tuple.Create(" title=\"", 974), Tuple.Create("\"", 994),
|
||||
Tuple.Create(Tuple.Create("", 982), Tuple.Create<System.Object, System.Int32>(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, " <span class=\"tab\"></span>\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 </td>\r\n <td");
|
||||
WriteAttributeTo(__razor_helper_writer, "title", Tuple.Create(" title=\"", 1197), Tuple.Create("\"", 1219),
|
||||
Tuple.Create(Tuple.Create("", 1205), Tuple.Create<System.Object, System.Int32>(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, "</td>\r\n </tr>\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(@"
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=""utf-8"" />
|
||||
<title>ASP.NET Logs</title>
|
||||
<style>
|
||||
body {
|
||||
font-size: .813em;
|
||||
white-space: nowrap;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
col:nth-child(2) {
|
||||
background-color: #FAFAFA;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 0px auto;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td, th {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
thead {
|
||||
font-size: 1em;
|
||||
font-family: Arial;
|
||||
}
|
||||
|
||||
tr {
|
||||
height: 23px;
|
||||
}
|
||||
|
||||
#requestHeader {
|
||||
border-bottom: solid 1px gray;
|
||||
border-top: solid 1px gray;
|
||||
margin-bottom: 2px;
|
||||
font-size: 1em;
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
.date, .time {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.logHeader {
|
||||
border-bottom: 1px solid lightgray;
|
||||
color: gray;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.logState {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logTd {
|
||||
border-left: 1px solid gray;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.logs {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.logRow:hover {
|
||||
background-color: #D6F5FF;
|
||||
}
|
||||
|
||||
.requestRow>td {
|
||||
border-bottom: solid 1px gray;
|
||||
}
|
||||
|
||||
.severity {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.tab {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
#viewOptions {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
#viewOptions > * {
|
||||
margin: 5px;
|
||||
}
|
||||
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;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>ASP.NET Logs</h1>
|
||||
<form id=""viewOptions"" method=""get"">
|
||||
<select name=""level"">
|
||||
");
|
||||
#line 104 "LogPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 104 "LogPage.cshtml"
|
||||
foreach (var severity in Enum.GetValues(typeof(LogLevel)))
|
||||
{
|
||||
var severityInt = (int)severity;
|
||||
if ((int)Model.Options.MinLevel == severityInt)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <option");
|
||||
WriteAttribute("value", Tuple.Create(" value=\"", 3202), Tuple.Create("\"", 3222),
|
||||
Tuple.Create(Tuple.Create("", 3210), Tuple.Create<System.Object, System.Int32>(severityInt, 3210), false));
|
||||
WriteLiteral(" selected=\"selected\">");
|
||||
#line 109 "LogPage.cshtml"
|
||||
Write(severity);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</option>\r\n");
|
||||
#line 110 "LogPage.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <option");
|
||||
WriteAttribute("value", Tuple.Create(" value=\"", 3351), Tuple.Create("\"", 3371),
|
||||
Tuple.Create(Tuple.Create("", 3359), Tuple.Create<System.Object, System.Int32>(severityInt, 3359), false));
|
||||
WriteLiteral(">");
|
||||
#line 113 "LogPage.cshtml"
|
||||
Write(severity);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</option>\r\n");
|
||||
#line 114 "LogPage.cshtml"
|
||||
}
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" </select>\r\n <input type=\"text\" name=\"name\"");
|
||||
WriteAttribute("value", Tuple.Create(" value=\"", 3484), Tuple.Create("\"", 3517),
|
||||
Tuple.Create(Tuple.Create("", 3492), Tuple.Create<System.Object, System.Int32>(Model.Options.NamePrefix, 3492), false));
|
||||
WriteLiteral(@" />
|
||||
<input type=""submit"" value=""filter"" />
|
||||
</form>
|
||||
|
||||
<table id=""requestTable"">
|
||||
<thead id=""requestHeader"">
|
||||
<tr>
|
||||
<th class=""path"">Path</th>
|
||||
<th class=""host"">Host</th>
|
||||
<th class=""statusCode"">Status Code</th>
|
||||
<th class=""logs"">Logs</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<colgroup>
|
||||
<col />
|
||||
<col />
|
||||
<col />
|
||||
<col />
|
||||
</colgroup>
|
||||
");
|
||||
#line 136 "LogPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 136 "LogPage.cshtml"
|
||||
foreach (var activity in Model.Activities.Reverse())
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <tbody>\r\n <tr class=\"requestRow\">\r\n");
|
||||
#line 140 "LogPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 140 "LogPage.cshtml"
|
||||
|
||||
if (activity.HttpInfo != null)
|
||||
{
|
||||
var requestPath = Model.Path.Value + "/" + activity.HttpInfo.RequestID;
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <td><a");
|
||||
WriteAttribute("href", Tuple.Create(" href=\"", 4400), Tuple.Create("\"", 4419),
|
||||
Tuple.Create(Tuple.Create("", 4407), Tuple.Create<System.Object, System.Int32>(requestPath, 4407), false));
|
||||
WriteAttribute("title", Tuple.Create(" title=\"", 4420), Tuple.Create("\"", 4451),
|
||||
Tuple.Create(Tuple.Create("", 4428), Tuple.Create<System.Object, System.Int32>(activity.HttpInfo.Path, 4428), false));
|
||||
WriteLiteral(">");
|
||||
#line 144 "LogPage.cshtml"
|
||||
Write(activity.HttpInfo.Path);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</a></td>\r\n <td>");
|
||||
#line 145 "LogPage.cshtml"
|
||||
Write(activity.HttpInfo.Host);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n <td>");
|
||||
#line 146 "LogPage.cshtml"
|
||||
Write(activity.HttpInfo.StatusCode);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n");
|
||||
#line 147 "LogPage.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <td colspan=\"3\">");
|
||||
#line 150 "LogPage.cshtml"
|
||||
Write(activity.Root.State);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n");
|
||||
#line 151 "LogPage.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(@"
|
||||
<td class=""logTd"">
|
||||
<table class=""logTable"">
|
||||
<thead class=""logHeader"">
|
||||
<tr>
|
||||
<th class=""date"">Date</th>
|
||||
<th class=""time"">Time</th>
|
||||
<th class=""name"">Name</th>
|
||||
<th class=""severity"">Severity</th>
|
||||
<th class=""state"">State</th>
|
||||
<th>Error</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
");
|
||||
#line 166 "LogPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 166 "LogPage.cshtml"
|
||||
if (activity.Id.Equals(Guid.Empty))
|
||||
{
|
||||
// message not within a scope
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 169 "LogPage.cshtml"
|
||||
Write(LogRow(activity.Root.Messages.FirstOrDefault(), 0));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
#line 169 "LogPage.cshtml"
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 173 "LogPage.cshtml"
|
||||
Write(Traverse(activity.Root, 0));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
#line 173 "LogPage.cshtml"
|
||||
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" </tbody>\r\n </table>\r\n " +
|
||||
" </td>\r\n </tr>\r\n </tbody>\r\n");
|
||||
#line 180 "LogPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" </table>\r\n</body>\r\n</html>");
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
@using System
|
||||
@using System.Globalization
|
||||
@using System.Linq
|
||||
@using Microsoft.AspNet.Diagnostics.Elm.Views
|
||||
@using Microsoft.AspNet.Diagnostics.Elm
|
||||
@using Microsoft.AspNet.Diagnostics.Views
|
||||
@using Microsoft.Framework.Logging
|
||||
|
||||
@functions
|
||||
{
|
||||
public LogPage(LogPageModel model)
|
||||
{
|
||||
Model = model;
|
||||
}
|
||||
|
||||
public LogPageModel Model { get; set; }
|
||||
}
|
||||
|
||||
@* writes one log row indented by the given level *@
|
||||
@helper LogRow(LogInfo log, int level) {
|
||||
if (log.Severity >= Model.Options.MinLevel &&
|
||||
(string.IsNullOrEmpty(Model.Options.NamePrefix) || log.Name.StartsWith(Model.Options.NamePrefix, StringComparison.Ordinal)))
|
||||
{
|
||||
<tr class="logRow">
|
||||
<td>@string.Format("{0:MM/dd/yy}", log.Time)</td>
|
||||
<td>@string.Format("{0:H:mm:ss}", log.Time)</td>
|
||||
<td title="@log.Name">@log.Name</td>
|
||||
<td class="@log.Severity.ToString().ToLowerInvariant()">@log.Severity</td>
|
||||
<td title="@log.Message">
|
||||
@for (var i = 0; i < level; i++)
|
||||
{
|
||||
<span class="tab"></span>
|
||||
}
|
||||
@log.Message
|
||||
</td>
|
||||
<td title="@log.Exception">@log.Exception</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
|
||||
@helper Traverse(ScopeNode node, int level)
|
||||
{
|
||||
// print start of scope
|
||||
@LogRow(new LogInfo()
|
||||
{
|
||||
Name = node.Name,
|
||||
Time = node.StartTime,
|
||||
Severity = LogLevel.Verbose,
|
||||
Message = "Beginning " + node.State,
|
||||
}, level);
|
||||
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], level)
|
||||
messageIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
@Traverse(node.Children[childIndex], level + 1)
|
||||
childIndex++;
|
||||
}
|
||||
}
|
||||
if (messageIndex < node.Messages.Count)
|
||||
{
|
||||
for (var i = messageIndex; i < node.Messages.Count; i++)
|
||||
{
|
||||
@LogRow(node.Messages[i], level)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = childIndex; i < node.Children.Count; i++)
|
||||
{
|
||||
@Traverse(node.Children[i], level + 1)
|
||||
}
|
||||
}
|
||||
// print end of scope
|
||||
@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);
|
||||
}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>ASP.NET Logs</title>
|
||||
<style>
|
||||
<%$ include: LogPage.css %>
|
||||
<%$ include: Shared.css %>
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>ASP.NET Logs</h1>
|
||||
<form id="viewOptions" method="get">
|
||||
<select name="level">
|
||||
@foreach (var severity in Enum.GetValues(typeof(LogLevel)))
|
||||
{
|
||||
var severityInt = (int)severity;
|
||||
if ((int)Model.Options.MinLevel == severityInt)
|
||||
{
|
||||
<option value="@severityInt" selected="selected">@severity</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@severityInt">@severity</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
<input type="text" name="name" value="@Model.Options.NamePrefix" />
|
||||
<input type="submit" value="filter" />
|
||||
</form>
|
||||
|
||||
<table id="requestTable">
|
||||
<thead id="requestHeader">
|
||||
<tr>
|
||||
<th class="path">Path</th>
|
||||
<th class="host">Host</th>
|
||||
<th class="statusCode">Status Code</th>
|
||||
<th class="logs">Logs</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<colgroup>
|
||||
<col />
|
||||
<col />
|
||||
<col />
|
||||
<col />
|
||||
</colgroup>
|
||||
@foreach (var activity in Model.Activities.Reverse())
|
||||
{
|
||||
<tbody>
|
||||
<tr class="requestRow">
|
||||
@{
|
||||
if (activity.HttpInfo != null)
|
||||
{
|
||||
var requestPath = Model.Path.Value + "/" + activity.HttpInfo.RequestID;
|
||||
<td><a href="@requestPath" title="@activity.HttpInfo.Path">@activity.HttpInfo.Path</a></td>
|
||||
<td>@activity.HttpInfo.Host</td>
|
||||
<td>@activity.HttpInfo.StatusCode</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
<td colspan="3">@activity.Root.State</td>
|
||||
}
|
||||
}
|
||||
<td class="logTd">
|
||||
<table class="logTable">
|
||||
<thead class="logHeader">
|
||||
<tr>
|
||||
<th class="date">Date</th>
|
||||
<th class="time">Time</th>
|
||||
<th class="name">Name</th>
|
||||
<th class="severity">Severity</th>
|
||||
<th class="state">State</th>
|
||||
<th>Error</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (activity.Id.Equals(Guid.Empty))
|
||||
{
|
||||
// message not within a scope
|
||||
@LogRow(activity.Root.Messages.FirstOrDefault(), 0)
|
||||
}
|
||||
else
|
||||
{
|
||||
@Traverse(activity.Root, 0)
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
}
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
body {
|
||||
font-size: .813em;
|
||||
white-space: nowrap;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
col:nth-child(2) {
|
||||
background-color: #FAFAFA;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 0px auto;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td, th {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
thead {
|
||||
font-size: 1em;
|
||||
font-family: Arial;
|
||||
}
|
||||
|
||||
tr {
|
||||
height: 23px;
|
||||
}
|
||||
|
||||
#requestHeader {
|
||||
border-bottom: solid 1px gray;
|
||||
border-top: solid 1px gray;
|
||||
margin-bottom: 2px;
|
||||
font-size: 1em;
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
.date, .time {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.logHeader {
|
||||
border-bottom: 1px solid lightgray;
|
||||
color: gray;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.logState {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logTd {
|
||||
border-left: 1px solid gray;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.logs {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.logRow:hover {
|
||||
background-color: #D6F5FF;
|
||||
}
|
||||
|
||||
.requestRow>td {
|
||||
border-bottom: solid 1px gray;
|
||||
}
|
||||
|
||||
.severity {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.tab {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
#viewOptions {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
#viewOptions > * {
|
||||
margin: 5px;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Elm.Views
|
||||
{
|
||||
public class LogPageModel
|
||||
{
|
||||
public IEnumerable<ActivityContext> Activities { get; set; }
|
||||
|
||||
public ViewOptions Options { get; set; }
|
||||
|
||||
public PathString Path { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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, " <tr>\r\n <td>");
|
||||
#line 25 "RequestPage.cshtml"
|
||||
WriteTo(__razor_helper_writer, string.Format("{0:MM/dd/yy}", log.Time));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteralTo(__razor_helper_writer, "</td>\r\n <td>");
|
||||
#line 26 "RequestPage.cshtml"
|
||||
WriteTo(__razor_helper_writer, string.Format("{0:H:mm:ss}", log.Time));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteralTo(__razor_helper_writer, "</td>\r\n <td");
|
||||
WriteAttributeTo(__razor_helper_writer, "class", Tuple.Create(" class=\"", 768), Tuple.Create("\"", 819),
|
||||
Tuple.Create(Tuple.Create("", 776), Tuple.Create<System.Object, System.Int32>(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, "</td>\r\n <td");
|
||||
WriteAttributeTo(__razor_helper_writer, "title", Tuple.Create(" title=\"", 856), Tuple.Create("\"", 873),
|
||||
Tuple.Create(Tuple.Create("", 864), Tuple.Create<System.Object, System.Int32>(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, "</td>\r\n <td");
|
||||
WriteAttributeTo(__razor_helper_writer, "title", Tuple.Create(" title=\"", 906), Tuple.Create("\"", 926),
|
||||
Tuple.Create(Tuple.Create("", 914), Tuple.Create<System.Object, System.Int32>(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, "</td>\r\n <td");
|
||||
WriteAttributeTo(__razor_helper_writer, "title", Tuple.Create(" title=\"", 993), Tuple.Create("\"", 1015),
|
||||
Tuple.Create(Tuple.Create("", 1001), Tuple.Create<System.Object, System.Int32>(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, "</td>\r\n </tr>\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(@"<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=""utf-8"" />
|
||||
<title>ASP.NET Logs</title>
|
||||
<script src=""http://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.1.min.js""></script>
|
||||
<style>
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>ASP.NET Logs</h1>
|
||||
");
|
||||
#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(" <h2 id=\"requestHeader\">Request Details</h2>\r\n <table id=\"requestDe" +
|
||||
"tails\">\r\n <colgroup><col id=\"label\" /><col /></colgroup>\r\n\r\n " +
|
||||
" <tr>\r\n <th>Path</th>\r\n <td>");
|
||||
#line 91 "RequestPage.cshtml"
|
||||
Write(context.Path);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n </tr>\r\n <tr>\r\n <th>Host</th>\r\n " +
|
||||
" <td>");
|
||||
#line 95 "RequestPage.cshtml"
|
||||
Write(context.Host);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n </tr>\r\n <tr>\r\n <th>Content Type</th>" +
|
||||
"\r\n <td>");
|
||||
#line 99 "RequestPage.cshtml"
|
||||
Write(context.ContentType);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n </tr>\r\n <tr>\r\n <th>Method</th>\r\n " +
|
||||
" <td>");
|
||||
#line 103 "RequestPage.cshtml"
|
||||
Write(context.Method);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n </tr>\r\n <tr>\r\n <th>Protocol</th>\r\n " +
|
||||
" <td>");
|
||||
#line 107 "RequestPage.cshtml"
|
||||
Write(context.Protocol);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Headers</th>
|
||||
<td id=""headerTd"">
|
||||
<table id=""headerTable"">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
");
|
||||
#line 120 "RequestPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 120 "RequestPage.cshtml"
|
||||
foreach (var header in context.Headers)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <tr>\r\n <td>");
|
||||
#line 123 "RequestPage.cshtml"
|
||||
Write(header.Key);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n <td>");
|
||||
#line 124 "RequestPage.cshtml"
|
||||
Write(string.Join(";", header.Value));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n </tr>\r\n");
|
||||
#line 126 "RequestPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" </tbody>\r\n </table>\r\n <" +
|
||||
"/td>\r\n </tr>\r\n <tr>\r\n <th>Status Code</th>\r" +
|
||||
"\n <td>");
|
||||
#line 133 "RequestPage.cshtml"
|
||||
Write(context.StatusCode);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n </tr>\r\n <tr>\r\n <th>User</th>\r\n " +
|
||||
" <td>");
|
||||
#line 137 "RequestPage.cshtml"
|
||||
Write(context.User.Identity.Name);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n </tr>\r\n <tr>\r\n <th>Claims</th>\r\n " +
|
||||
" <td>\r\n");
|
||||
#line 142 "RequestPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 142 "RequestPage.cshtml"
|
||||
if (context.User.Claims.Any())
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(@" <table id=""claimsTable"">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Issuer</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
");
|
||||
#line 152 "RequestPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 152 "RequestPage.cshtml"
|
||||
foreach (var claim in context.User.Claims)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <tr>\r\n " +
|
||||
" <td>");
|
||||
#line 155 "RequestPage.cshtml"
|
||||
Write(claim.Issuer);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n <td>");
|
||||
#line 156 "RequestPage.cshtml"
|
||||
Write(claim.Value);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n </tr>\r\n");
|
||||
#line 158 "RequestPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" </tbody>\r\n </table>\r\n");
|
||||
#line 161 "RequestPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" </td>\r\n </tr>\r\n <tr>\r\n <th>S" +
|
||||
"cheme</th>\r\n <td>");
|
||||
#line 166 "RequestPage.cshtml"
|
||||
Write(context.Scheme);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n </tr>\r\n <tr>\r\n <th>Query</th>\r\n " +
|
||||
" <td>");
|
||||
#line 170 "RequestPage.cshtml"
|
||||
Write(context.Query.Value);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n </tr>\r\n <tr>\r\n <th>Cookies</th>\r\n " +
|
||||
" <td>\r\n");
|
||||
#line 175 "RequestPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 175 "RequestPage.cshtml"
|
||||
if (context.Cookies.Any())
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(@" <table id=""cookieTable"">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
");
|
||||
#line 185 "RequestPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 185 "RequestPage.cshtml"
|
||||
foreach (var cookie in context.Cookies)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <tr>\r\n " +
|
||||
" <td>");
|
||||
#line 188 "RequestPage.cshtml"
|
||||
Write(cookie.Key);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n <td>");
|
||||
#line 189 "RequestPage.cshtml"
|
||||
Write(string.Join(";", cookie.Value));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</td>\r\n </tr>\r\n");
|
||||
#line 191 "RequestPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" </tbody>\r\n </table>\r\n");
|
||||
#line 194 "RequestPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" </td>\r\n </tr>\r\n </table>\r\n");
|
||||
#line 198 "RequestPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <h2>Logs</h2>\r\n <form method=\"get\">\r\n <select name=\"level\">\r\n");
|
||||
#line 202 "RequestPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 202 "RequestPage.cshtml"
|
||||
foreach (var severity in Enum.GetValues(typeof(LogLevel)))
|
||||
{
|
||||
var severityInt = (int)severity;
|
||||
if ((int)Model.Options.MinLevel == severityInt)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <option");
|
||||
WriteAttribute("value", Tuple.Create(" value=\"", 6703), Tuple.Create("\"", 6723),
|
||||
Tuple.Create(Tuple.Create("", 6711), Tuple.Create<System.Object, System.Int32>(severityInt, 6711), false));
|
||||
WriteLiteral(" selected=\"selected\">");
|
||||
#line 207 "RequestPage.cshtml"
|
||||
Write(severity);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</option>\r\n");
|
||||
#line 208 "RequestPage.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <option");
|
||||
WriteAttribute("value", Tuple.Create(" value=\"", 6852), Tuple.Create("\"", 6872),
|
||||
Tuple.Create(Tuple.Create("", 6860), Tuple.Create<System.Object, System.Int32>(severityInt, 6860), false));
|
||||
WriteLiteral(">");
|
||||
#line 211 "RequestPage.cshtml"
|
||||
Write(severity);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</option>\r\n");
|
||||
#line 212 "RequestPage.cshtml"
|
||||
}
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" </select>\r\n <input type=\"text\" name=\"name\"");
|
||||
WriteAttribute("value", Tuple.Create(" value=\"", 6985), Tuple.Create("\"", 7018),
|
||||
Tuple.Create(Tuple.Create("", 6993), Tuple.Create<System.Object, System.Int32>(Model.Options.NamePrefix, 6993), false));
|
||||
WriteLiteral(@" />
|
||||
<input type=""submit"" value=""filter"" />
|
||||
</form>
|
||||
<table id=""logs"">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Time</th>
|
||||
<th>Severity</th>
|
||||
<th>Name</th>
|
||||
<th>State</th>
|
||||
<th>Error</th>
|
||||
</tr>
|
||||
</thead>
|
||||
");
|
||||
#line 229 "RequestPage.cshtml"
|
||||
Write(Traverse(Model.Activity.Root));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@"
|
||||
</table>
|
||||
<script type=""text/javascript"">
|
||||
$(document).ready(function () {
|
||||
$(""#requestHeader"").click(function () {
|
||||
$(""#requestDetails"").toggle();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>");
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
}
|
||||
}
|
||||
|
|
@ -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)))
|
||||
{
|
||||
<tr>
|
||||
<td>@string.Format("{0:MM/dd/yy}", log.Time)</td>
|
||||
<td>@string.Format("{0:H:mm:ss}", log.Time)</td>
|
||||
<td class="@log.Severity.ToString().ToLowerInvariant()">@log.Severity</td>
|
||||
<td title="@log.Name">@log.Name</td>
|
||||
<td title="@log.Message" class="logState" width="100px">@log.Message</td>
|
||||
<td title="@log.Exception">@log.Exception</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
|
||||
@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])
|
||||
}
|
||||
}
|
||||
}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>ASP.NET Logs</title>
|
||||
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.1.min.js"></script>
|
||||
<style>
|
||||
<%$ include: Shared.css %>
|
||||
<%$ include: RequestPage.css %>
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>ASP.NET Logs</h1>
|
||||
@{
|
||||
var context = Model.Activity?.HttpInfo;
|
||||
}
|
||||
@if (context != null)
|
||||
{
|
||||
<h2 id="requestHeader">Request Details</h2>
|
||||
<table id="requestDetails">
|
||||
<colgroup><col id="label" /><col /></colgroup>
|
||||
|
||||
<tr>
|
||||
<th>Path</th>
|
||||
<td>@context.Path</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Host</th>
|
||||
<td>@context.Host</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Content Type</th>
|
||||
<td>@context.ContentType</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Method</th>
|
||||
<td>@context.Method</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Protocol</th>
|
||||
<td>@context.Protocol</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Headers</th>
|
||||
<td id="headerTd">
|
||||
<table id="headerTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var header in context.Headers)
|
||||
{
|
||||
<tr>
|
||||
<td>@header.Key</td>
|
||||
<td>@string.Join(";", header.Value)</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Status Code</th>
|
||||
<td>@context.StatusCode</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>User</th>
|
||||
<td>@context.User.Identity.Name</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Claims</th>
|
||||
<td>
|
||||
@if (context.User.Claims.Any())
|
||||
{
|
||||
<table id="claimsTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Issuer</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var claim in context.User.Claims)
|
||||
{
|
||||
<tr>
|
||||
<td>@claim.Issuer</td>
|
||||
<td>@claim.Value</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Scheme</th>
|
||||
<td>@context.Scheme</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Query</th>
|
||||
<td>@context.Query.Value</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Cookies</th>
|
||||
<td>
|
||||
@if (context.Cookies.Any())
|
||||
{
|
||||
<table id="cookieTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var cookie in context.Cookies)
|
||||
{
|
||||
<tr>
|
||||
<td>@cookie.Key</td>
|
||||
<td>@string.Join(";", cookie.Value)</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
}
|
||||
<h2>Logs</h2>
|
||||
<form method="get">
|
||||
<select name="level">
|
||||
@foreach (var severity in Enum.GetValues(typeof(LogLevel)))
|
||||
{
|
||||
var severityInt = (int)severity;
|
||||
if ((int)Model.Options.MinLevel == severityInt)
|
||||
{
|
||||
<option value="@severityInt" selected="selected">@severity</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@severityInt">@severity</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
<input type="text" name="name" value="@Model.Options.NamePrefix" />
|
||||
<input type="submit" value="filter" />
|
||||
</form>
|
||||
<table id="logs">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Time</th>
|
||||
<th>Severity</th>
|
||||
<th>Name</th>
|
||||
<th>State</th>
|
||||
<th>Error</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@Traverse(Model.Activity.Root)
|
||||
</table>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$("#requestHeader").click(function () {
|
||||
$("#requestDetails").toggle();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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-*"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,7 @@ namespace Microsoft.AspNet.Diagnostics.Views
|
|||
[NotNull] Tuple<string, int> trailer,
|
||||
params AttributeValue[] values)
|
||||
{
|
||||
|
||||
|
||||
WriteLiteralTo(writer, leader.Item1);
|
||||
foreach (var value in values)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@
|
|||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<DevelopmentServerPort>0</DevelopmentServerPort>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<DebugTarget />
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -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-*"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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<string, LogLevel, bool> _filter = (_, __) => true;
|
||||
|
||||
private Tuple<ElmLogger, ElmStore> SetUp(Func<string, LogLevel, bool> 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<ElmLogger, ElmStore>(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<LogInfo>()))).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<LogInfo>()))).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<LogInfo>()))).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<LogInfo> NodeLogs(ScopeNode node, List<LogInfo> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<IOptions<ElmOptions>>();
|
||||
optionsMock
|
||||
.SetupGet(o => o.Options)
|
||||
.Returns(new ElmOptions());
|
||||
factory.AddProvider(new ElmLoggerProvider(elmStore, optionsMock.Object.Options));
|
||||
|
||||
RequestDelegate next = _ =>
|
||||
{
|
||||
return Task.FromResult<object>(null);
|
||||
};
|
||||
|
||||
var captureMiddleware = new ElmCaptureMiddleware(
|
||||
next,
|
||||
factory,
|
||||
optionsMock.Object);
|
||||
var pageMiddleware = new ElmPageMiddleware(
|
||||
next,
|
||||
optionsMock.Object,
|
||||
elmStore);
|
||||
|
||||
var contextMock = GetMockContext("/nonmatchingpath");
|
||||
|
||||
// Act
|
||||
await captureMiddleware.Invoke(contextMock.Object);
|
||||
await pageMiddleware.Invoke(contextMock.Object);
|
||||
|
||||
// Assert
|
||||
// Request.Query is used by the ElmPageMiddleware to parse the query parameters
|
||||
contextMock.VerifyGet(c => c.Request.Query, Times.Never());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void Invoke_WithMatchingPath_FulfillsRequest()
|
||||
{
|
||||
// Arrange
|
||||
var elmStore = new ElmStore();
|
||||
var factory = new LoggerFactory();
|
||||
var optionsMock = new Mock<IOptions<ElmOptions>>();
|
||||
optionsMock
|
||||
.SetupGet(o => o.Options)
|
||||
.Returns(new ElmOptions());
|
||||
factory.AddProvider(new ElmLoggerProvider(elmStore, optionsMock.Object.Options));
|
||||
|
||||
RequestDelegate next = _ =>
|
||||
{
|
||||
return Task.FromResult<object>(null);
|
||||
};
|
||||
|
||||
var captureMiddleware = new ElmCaptureMiddleware(
|
||||
next,
|
||||
factory,
|
||||
optionsMock.Object);
|
||||
var pageMiddleware = new ElmPageMiddleware(
|
||||
next,
|
||||
optionsMock.Object,
|
||||
elmStore);
|
||||
var contextMock = GetMockContext("/Elm");
|
||||
|
||||
using (var responseStream = new MemoryStream())
|
||||
{
|
||||
contextMock
|
||||
.SetupGet(c => c.Response.Body)
|
||||
.Returns(responseStream);
|
||||
|
||||
// Act
|
||||
await captureMiddleware.Invoke(contextMock.Object);
|
||||
await pageMiddleware.Invoke(contextMock.Object);
|
||||
|
||||
string response = Encoding.UTF8.GetString(responseStream.ToArray());
|
||||
|
||||
// Assert
|
||||
contextMock.VerifyGet(c => c.Request.Query, Times.AtLeastOnce());
|
||||
Assert.True(response.Contains("<title>ASP.NET Logs</title>"));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void Invoke_BadRequestShowsError()
|
||||
{
|
||||
// Arrange
|
||||
var elmStore = new ElmStore();
|
||||
var factory = new LoggerFactory();
|
||||
var optionsMock = new Mock<IOptions<ElmOptions>>();
|
||||
optionsMock
|
||||
.SetupGet(o => o.Options)
|
||||
.Returns(new ElmOptions());
|
||||
factory.AddProvider(new ElmLoggerProvider(elmStore, optionsMock.Object.Options));
|
||||
|
||||
RequestDelegate next = _ =>
|
||||
{
|
||||
return Task.FromResult<object>(null);
|
||||
};
|
||||
|
||||
var captureMiddleware = new ElmCaptureMiddleware(
|
||||
next,
|
||||
factory,
|
||||
optionsMock.Object);
|
||||
var pageMiddleware = new ElmPageMiddleware(
|
||||
next,
|
||||
optionsMock.Object,
|
||||
elmStore);
|
||||
var contextMock = GetMockContext("/Elm/666");
|
||||
|
||||
using (var responseStream = new MemoryStream())
|
||||
{
|
||||
contextMock
|
||||
.SetupGet(c => c.Response.Body)
|
||||
.Returns(responseStream);
|
||||
|
||||
// Act
|
||||
await captureMiddleware.Invoke(contextMock.Object);
|
||||
await pageMiddleware.Invoke(contextMock.Object);
|
||||
|
||||
string response = Encoding.UTF8.GetString(responseStream.ToArray());
|
||||
|
||||
// Assert
|
||||
contextMock.VerifyGet(c => c.Request.Query, Times.AtLeastOnce());
|
||||
Assert.True(response.Contains("Invalid Request Id"));
|
||||
}
|
||||
}
|
||||
|
||||
private Mock<HttpContext> GetMockContext(string path)
|
||||
{
|
||||
var contextMock = new Mock<HttpContext>(MockBehavior.Strict);
|
||||
contextMock
|
||||
.SetupGet(c => c.Request.Path)
|
||||
.Returns(new PathString(path));
|
||||
contextMock
|
||||
.SetupGet(c => c.Request.Host)
|
||||
.Returns(new HostString("localhost"));
|
||||
contextMock
|
||||
.SetupGet(c => c.Request.ContentType)
|
||||
.Returns("");
|
||||
contextMock
|
||||
.SetupGet(c => c.Request.Scheme)
|
||||
.Returns("http");
|
||||
contextMock
|
||||
.SetupGet(c => c.Request.Scheme)
|
||||
.Returns("http");
|
||||
contextMock
|
||||
.SetupGet(c => c.Response.StatusCode)
|
||||
.Returns(200);
|
||||
contextMock
|
||||
.SetupGet(c => c.Response.Body)
|
||||
.Returns(new Mock<Stream>().Object);
|
||||
contextMock
|
||||
.SetupGet(c => c.User)
|
||||
.Returns(new ClaimsPrincipal());
|
||||
contextMock
|
||||
.SetupGet(c => c.Request.Method)
|
||||
.Returns("GET");
|
||||
contextMock
|
||||
.SetupGet(c => c.Request.Protocol)
|
||||
.Returns("HTTP/1.1");
|
||||
contextMock
|
||||
.SetupGet(c => c.Request.Headers)
|
||||
.Returns(new Mock<IHeaderDictionary>().Object);
|
||||
contextMock
|
||||
.SetupGet(c => c.Request.QueryString)
|
||||
.Returns(new QueryString());
|
||||
contextMock
|
||||
.SetupGet(c => c.Request.Query)
|
||||
.Returns(new Mock<IReadableStringCollection>().Object);
|
||||
contextMock
|
||||
.SetupGet(c => c.Request.Cookies)
|
||||
.Returns(new Mock<IReadableStringCollection>().Object);
|
||||
|
||||
return contextMock;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,8 @@
|
|||
"warningsAsErrors": true
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Diagnostics": "",
|
||||
"Microsoft.AspNet.Diagnostics": "1.0.0-*",
|
||||
"Microsoft.AspNet.Diagnostics.Elm": "1.0.0-*",
|
||||
"Xunit.KRunner": "1.0.0-*"
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue