-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds UrlDiscoveryPlugin and preset (#969)
- Loading branch information
1 parent
bae96bd
commit 554bb9e
Showing
6 changed files
with
236 additions
and
66 deletions.
There are no files selected for viewing
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 |
---|---|---|
@@ -1,65 +1,100 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
using System.Text.Json; | ||
using Microsoft.DevProxy.Abstractions; | ||
using Microsoft.DevProxy.Plugins.RequestLogs; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Microsoft.DevProxy.Plugins.Reporters; | ||
|
||
public class JsonReporter(IPluginEvents pluginEvents, IProxyContext context, ILogger logger, ISet<UrlToWatch> urlsToWatch, IConfigurationSection? configSection = null) : BaseReporter(pluginEvents, context, logger, urlsToWatch, configSection) | ||
{ | ||
public override string Name => nameof(JsonReporter); | ||
public override string FileExtension => ".json"; | ||
|
||
private readonly Dictionary<Type, Func<object, object>> _transformers = new() | ||
{ | ||
{ typeof(ExecutionSummaryPluginReportByUrl), TransformExecutionSummary }, | ||
{ typeof(ExecutionSummaryPluginReportByMessageType), TransformExecutionSummary }, | ||
}; | ||
|
||
protected override string GetReport(KeyValuePair<string, object> report) | ||
{ | ||
Logger.LogDebug("Serializing report {reportKey}...", report.Key); | ||
|
||
var reportData = report.Value; | ||
var reportType = reportData.GetType(); | ||
|
||
if (_transformers.TryGetValue(reportType, out var transform)) | ||
{ | ||
Logger.LogDebug("Transforming {reportType} using {transform}...", reportType.Name, transform.Method.Name); | ||
reportData = transform(reportData); | ||
} | ||
else | ||
{ | ||
Logger.LogDebug("No transformer found for {reportType}", reportType.Name); | ||
} | ||
|
||
if (reportData is string strVal) | ||
{ | ||
Logger.LogDebug("{reportKey} is a string. Checking if it's JSON...", report.Key); | ||
|
||
try | ||
{ | ||
JsonSerializer.Deserialize<object>(strVal); | ||
Logger.LogDebug("{reportKey} is already JSON, ignore", report.Key); | ||
// already JSON, ignore | ||
return strVal; | ||
} | ||
catch | ||
{ | ||
Logger.LogDebug("{reportKey} is not JSON, serializing...", report.Key); | ||
} | ||
} | ||
|
||
return JsonSerializer.Serialize(reportData, ProxyUtils.JsonSerializerOptions); | ||
} | ||
|
||
private static object TransformExecutionSummary(object report) | ||
{ | ||
var executionSummaryReport = (ExecutionSummaryPluginReportBase)report; | ||
return executionSummaryReport.Data; | ||
} | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
using System.Text; | ||
using System.Text.Json; | ||
using Microsoft.DevProxy.Abstractions; | ||
using Microsoft.DevProxy.Plugins.RequestLogs; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Microsoft.DevProxy.Plugins.Reporters; | ||
|
||
public class JsonReporter(IPluginEvents pluginEvents, IProxyContext context, ILogger logger, ISet<UrlToWatch> urlsToWatch, IConfigurationSection? configSection = null) : BaseReporter(pluginEvents, context, logger, urlsToWatch, configSection) | ||
{ | ||
public override string Name => nameof(JsonReporter); | ||
private string _fileExtension = ".json"; | ||
public override string FileExtension => _fileExtension; | ||
|
||
private readonly Dictionary<Type, Func<object, object>> _transformers = new() | ||
{ | ||
{ typeof(ExecutionSummaryPluginReportByUrl), TransformExecutionSummary }, | ||
{ typeof(ExecutionSummaryPluginReportByMessageType), TransformExecutionSummary }, | ||
{ typeof(UrlDiscoveryPluginReport), TransformUrlDiscoveryReport } | ||
}; | ||
|
||
protected override string GetReport(KeyValuePair<string, object> report) | ||
{ | ||
Logger.LogDebug("Serializing report {reportKey}...", report.Key); | ||
|
||
var reportData = report.Value; | ||
var reportType = reportData.GetType(); | ||
_fileExtension = reportType.Name == nameof(UrlDiscoveryPluginReport) ? ".jsonc" : ".json"; | ||
|
||
if (_transformers.TryGetValue(reportType, out var transform)) | ||
{ | ||
Logger.LogDebug("Transforming {reportType} using {transform}...", reportType.Name, transform.Method.Name); | ||
reportData = transform(reportData); | ||
} | ||
else | ||
{ | ||
Logger.LogDebug("No transformer found for {reportType}", reportType.Name); | ||
} | ||
|
||
if (reportData is string strVal) | ||
{ | ||
Logger.LogDebug("{reportKey} is a string. Checking if it's JSON...", report.Key); | ||
|
||
try | ||
{ | ||
JsonSerializer.Deserialize<object>(strVal, ProxyUtils.JsonSerializerOptions); | ||
Logger.LogDebug("{reportKey} is already JSON, ignore", report.Key); | ||
// already JSON, ignore | ||
return strVal; | ||
} | ||
catch | ||
{ | ||
Logger.LogDebug("{reportKey} is not JSON, serializing...", report.Key); | ||
} | ||
} | ||
|
||
return JsonSerializer.Serialize(reportData, ProxyUtils.JsonSerializerOptions); | ||
} | ||
|
||
private static object TransformExecutionSummary(object report) | ||
{ | ||
var executionSummaryReport = (ExecutionSummaryPluginReportBase)report; | ||
return executionSummaryReport.Data; | ||
} | ||
|
||
private static object TransformUrlDiscoveryReport(object report) | ||
{ | ||
var urlDiscoveryPluginReport = (UrlDiscoveryPluginReport)report; | ||
|
||
var sb = new StringBuilder(); | ||
sb.AppendLine("{"); | ||
sb.AppendLine(" // Wildcards"); | ||
sb.AppendLine(" // "); | ||
sb.AppendLine(" // You can use wildcards to catch multiple URLs with the same pattern."); | ||
sb.AppendLine(" // For example, you can use the following URL pattern to catch all API requests to"); | ||
sb.AppendLine(" // JSON Placeholder API:"); | ||
sb.AppendLine(" // "); | ||
sb.AppendLine(" // https://jsonplaceholder.typicode.com/*"); | ||
sb.AppendLine(" // "); | ||
sb.AppendLine(" // Excluding URLs"); | ||
sb.AppendLine(" // "); | ||
sb.AppendLine(" // You can exclude URLs with ! to prevent them from being intercepted."); | ||
sb.AppendLine(" // For example, you can exclude the URL https://jsonplaceholder.typicode.com/authors"); | ||
sb.AppendLine(" // by using the following URL pattern:"); | ||
sb.AppendLine(" // "); | ||
sb.AppendLine(" // !https://jsonplaceholder.typicode.com/authors"); | ||
sb.AppendLine(" // https://jsonplaceholder.typicode.com/*"); | ||
sb.AppendLine(" \"urlsToWatch\": ["); | ||
sb.AppendJoin($",{Environment.NewLine}", urlDiscoveryPluginReport.Data.Select(u => $" \"{u}\"")); | ||
sb.AppendLine(""); | ||
sb.AppendLine(" ]"); | ||
sb.AppendLine("}"); | ||
|
||
return sb.ToString(); | ||
} | ||
} |
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
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
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
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,46 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.DevProxy.Abstractions; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Microsoft.DevProxy.Plugins.RequestLogs; | ||
|
||
public class UrlDiscoveryPluginReport | ||
{ | ||
public required List<string> Data { get; init; } | ||
} | ||
|
||
public class UrlDiscoveryPlugin(IPluginEvents pluginEvents, IProxyContext context, ILogger logger, ISet<UrlToWatch> urlsToWatch, IConfigurationSection? configSection = null) : BaseReportingPlugin(pluginEvents, context, logger, urlsToWatch, configSection) | ||
{ | ||
public override string Name => nameof(UrlDiscoveryPlugin); | ||
private readonly ExecutionSummaryPluginConfiguration _configuration = new(); | ||
|
||
public override async Task RegisterAsync() | ||
{ | ||
await base.RegisterAsync(); | ||
|
||
ConfigSection?.Bind(_configuration); | ||
|
||
PluginEvents.AfterRecordingStop += AfterRecordingStopAsync; | ||
} | ||
|
||
private Task AfterRecordingStopAsync(object? sender, RecordingArgs e) | ||
{ | ||
if (!e.RequestLogs.Any()) | ||
{ | ||
Logger.LogRequest("No messages recorded", MessageType.Skipped); | ||
return Task.CompletedTask; | ||
} | ||
|
||
UrlDiscoveryPluginReport report = new() | ||
{ | ||
Data = [.. e.RequestLogs.Select(log => log.Context?.Session.HttpClient.Request.RequestUri.ToString()).Distinct().Order()] | ||
}; | ||
|
||
StoreReport(report, e); | ||
|
||
return Task.CompletedTask; | ||
} | ||
} |
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,19 @@ | ||
{ | ||
"$schema": "https://raw.githubusercontent.com/microsoft/dev-proxy/main/schemas/v0.24.0/rc.schema.json", | ||
"plugins": [ | ||
{ | ||
"name": "UrlDiscoveryPlugin", | ||
"enabled": true, | ||
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll" | ||
}, | ||
{ | ||
"name": "PlainTextReporter", | ||
"enabled": true, | ||
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll" | ||
} | ||
], | ||
"urlsToWatch": [ | ||
"https://*/*" | ||
], | ||
"record": true | ||
} |