-
Notifications
You must be signed in to change notification settings - Fork 140
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
338 additions
and
0 deletions.
There are no files selected for viewing
76 changes: 76 additions & 0 deletions
76
...ft.IIS.Administration.WebServer.HttpRequestTracing/Controllers/RequestTracesController.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
|
||
namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing | ||
{ | ||
using AspNetCore.Mvc; | ||
using Core; | ||
using Core.Http; | ||
using Files; | ||
using Sites; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Web.Administration; | ||
|
||
public class RequestTracesController : ApiBaseController | ||
{ | ||
private IFileProvider _provider; | ||
|
||
public RequestTracesController(IFileProvider provider) | ||
{ | ||
_provider = provider; | ||
} | ||
|
||
[HttpGet] | ||
[ResourceInfo(Name = Defines.TracesName)] | ||
public async Task<object> Get() | ||
{ | ||
string hrtUuid = Context.Request.Query[Defines.IDENTIFIER]; | ||
|
||
if (string.IsNullOrEmpty(hrtUuid)) { | ||
return NotFound(); | ||
} | ||
|
||
var id = new HttpRequestTracingId(hrtUuid); | ||
Site site = id?.SiteId == null ? null : SiteHelper.GetSite(id.SiteId.Value); | ||
|
||
if (site == null) { | ||
return NotFound(); | ||
} | ||
|
||
var helper = new TracesHelper(_provider, site); | ||
|
||
IEnumerable<TraceInfo> traces = await helper.GetTraces(); | ||
|
||
Context.Response.SetItemsCount(traces.Count()); | ||
|
||
return new { | ||
traces = traces.Select(t => helper.ToJsonModel(t, Context.Request.GetFields())) | ||
}; | ||
} | ||
|
||
[HttpGet] | ||
[ResourceInfo(Name = Defines.TraceName)] | ||
public async Task<object> Get(string id) | ||
{ | ||
TraceId traceId = new TraceId(id); | ||
Site site = SiteHelper.GetSite(traceId.SiteId); | ||
|
||
if (site == null) { | ||
return NotFound(); | ||
} | ||
|
||
var helper = new TracesHelper(_provider, site); | ||
|
||
TraceInfo trace = await helper.GetTrace(traceId.Name); | ||
|
||
if (trace == null) { | ||
return NotFound(); | ||
} | ||
|
||
return helper.ToJsonModel(trace, Context.Request.GetFields()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
183 changes: 183 additions & 0 deletions
183
src/Microsoft.IIS.Administration.WebServer.HttpRequestTracing/Helpers/TracesHelper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing | ||
{ | ||
using Core; | ||
using Core.Utils; | ||
using Files; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Dynamic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using System.Xml; | ||
using Web.Administration; | ||
|
||
sealed class TracesHelper | ||
{ | ||
private static readonly Fields RefFields = new Fields("url", "id", "http_status", "method", "time_taken"); | ||
|
||
private static readonly XmlReaderSettings _xmlReaderSettings = new XmlReaderSettings() { | ||
Async = true | ||
}; | ||
|
||
private IFileProvider _provider; | ||
private Site _site; | ||
|
||
public TracesHelper(IFileProvider provider, Site site) | ||
{ | ||
_provider = provider; | ||
_site = site; | ||
} | ||
|
||
public async Task<IEnumerable<TraceInfo>> GetTraces() | ||
{ | ||
IEnumerable<IFileInfo> files = null; | ||
string dir = _site.TraceFailedRequestsLogging.Directory; | ||
string path = string.IsNullOrEmpty(dir) ? null : Path.Combine(PathUtil.GetFullPath(dir), "W3SVC" + _site.Id); | ||
|
||
if (path != null) { | ||
files = _provider.GetFiles(path, "*.xml"); | ||
} | ||
|
||
return await Task.WhenAll(files.Select(f => GetTraceInternal(f))); | ||
} | ||
|
||
public async Task<TraceInfo> GetTrace(string id) | ||
{ | ||
return (await GetTraces()).FirstOrDefault(t => t.File.Name.Equals(id, StringComparison.OrdinalIgnoreCase)); | ||
} | ||
|
||
public object ToJsonModel(TraceInfo trace, Fields fields = null, bool full = true) | ||
{ | ||
TraceId traceId = new TraceId(_site.Id, trace.File.Name); | ||
|
||
if (fields == null) { | ||
fields = Fields.All; | ||
} | ||
|
||
dynamic obj = new ExpandoObject(); | ||
|
||
// | ||
// id | ||
obj.id = traceId.Uuid; | ||
|
||
// | ||
// url | ||
if (fields.Exists("url") && !string.IsNullOrEmpty(trace.Url)) { | ||
obj.url = trace.Url; | ||
} | ||
|
||
// | ||
// method | ||
if (fields.Exists("method") && !string.IsNullOrEmpty(trace.Method)) { | ||
obj.method = trace.Method; | ||
} | ||
|
||
// | ||
// status_code | ||
if (fields.Exists("status_code") && trace.StatusCode > 0) { | ||
obj.status_code = trace.StatusCode; | ||
} | ||
|
||
// | ||
// date | ||
if (fields.Exists("date")) { | ||
obj.date = trace.Date; | ||
} | ||
|
||
// | ||
// time_taken | ||
if (fields.Exists("time_taken")) { | ||
obj.time_taken = trace.TimeTaken; | ||
} | ||
|
||
// | ||
// process_id | ||
if (fields.Exists("process_id") && !string.IsNullOrEmpty(trace.ProcessId)) { | ||
obj.process_id = trace.ProcessId; | ||
} | ||
|
||
// | ||
// activity_id | ||
if (fields.Exists("activity_id") && !string.IsNullOrEmpty(trace.ActivityId)) { | ||
obj.activity_id = trace.ActivityId; | ||
} | ||
|
||
// | ||
// file_info | ||
if (fields.Exists("file_info")) { | ||
obj.file_info = new FilesHelper(_provider).ToJsonModelRef(trace.File, fields.Filter("file_info")); | ||
} | ||
|
||
// | ||
// request_tracing | ||
if (fields.Exists("request_tracing")) { | ||
obj.request_tracing = Helper.ToJsonModelRef(_site, "/"); | ||
} | ||
|
||
return Core.Environment.Hal.Apply(Defines.TracesResource.Guid, obj, full); ; | ||
} | ||
|
||
public object ToJsonModelRef(TraceInfo trace, Fields fields = null) | ||
{ | ||
if (fields == null || !fields.HasFields) { | ||
return ToJsonModel(trace, RefFields, false); | ||
} | ||
else { | ||
return ToJsonModel(trace, fields, false); | ||
} | ||
} | ||
|
||
public static string GetLocation(string id) | ||
{ | ||
return $"/{Defines.TRACES_PATH}/{id}"; | ||
} | ||
|
||
private Task<TraceInfo> GetTraceInternal(IFileInfo trace) | ||
{ | ||
return ParseTrace(trace); | ||
} | ||
|
||
private async Task<TraceInfo> ParseTrace(IFileInfo trace) | ||
{ | ||
TraceInfo info = null; | ||
|
||
|
||
using (var stream = _provider.GetFileStream(trace.Path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) | ||
using (var reader = XmlReader.Create(stream, _xmlReaderSettings)) { | ||
try { | ||
|
||
while (await reader.ReadAsync()) { | ||
if (reader.NodeType == XmlNodeType.Element && reader.Name.Equals("failedRequest")) { | ||
|
||
info = new TraceInfo() { | ||
File = trace, | ||
Url = reader.GetAttribute("url"), | ||
Method = reader.GetAttribute("verb"), | ||
Date = trace.Created, | ||
ProcessId = reader.GetAttribute("processId"), | ||
ActivityId = reader.GetAttribute("activityId") | ||
}; | ||
|
||
float.TryParse(reader.GetAttribute("triggerStatusCode"), out info.StatusCode); | ||
int.TryParse(reader.GetAttribute("timeTaken"), out info.TimeTaken); | ||
|
||
break; | ||
} | ||
} | ||
} | ||
catch(XmlException) { | ||
// Ignore malformatted XML | ||
} | ||
} | ||
|
||
if (info == null) { | ||
info = new TraceInfo() { | ||
File = trace | ||
}; | ||
} | ||
|
||
return info; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
src/Microsoft.IIS.Administration.WebServer.HttpRequestTracing/TraceId.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
|
||
namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing | ||
{ | ||
using System; | ||
|
||
public class TraceId | ||
{ | ||
private const string PURPOSE = "WebServer.HttpRequestTracing.Trace"; | ||
private const char DELIMITER = '\n'; | ||
|
||
private const uint SITE_ID_INDEX = 0; | ||
private const uint NAME_INDEX = 1; | ||
|
||
public long SiteId { get; private set; } | ||
public string Name { get; private set; } | ||
public string Uuid { get; private set; } | ||
|
||
public TraceId(string uuid) | ||
{ | ||
if (string.IsNullOrEmpty(uuid)) { | ||
throw new ArgumentNullException("uuid"); | ||
} | ||
|
||
var info = Core.Utils.Uuid.Decode(uuid, PURPOSE).Split(DELIMITER); | ||
|
||
this.Name = info[NAME_INDEX]; | ||
this.SiteId = long.Parse(info[SITE_ID_INDEX]); | ||
this.Uuid = uuid; | ||
} | ||
|
||
public TraceId(long siteId, string name) | ||
{ | ||
this.SiteId = siteId; | ||
this.Name = name; | ||
this.Uuid = Core.Utils.Uuid.Encode(this.Name + DELIMITER + this.SiteId.ToString(), PURPOSE); | ||
} | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
src/Microsoft.IIS.Administration.WebServer.HttpRequestTracing/TraceInfo.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
|
||
namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing | ||
{ | ||
using Files; | ||
using System; | ||
|
||
class TraceInfo | ||
{ | ||
public IFileInfo File; | ||
public string Url; | ||
public string Method; | ||
public float StatusCode; | ||
public DateTime Date; | ||
public int TimeTaken; | ||
public string ProcessId; | ||
public string ActivityId; | ||
} | ||
} |