Skip to content

Commit 425dc63

Browse files
Improves console output readability. Closes #68 (#117)
* Updates VSCode settings to build sln * Improves console output readability. Closes #68 * Adds default logLevel value * Renames mocks.json to responses.json in the default config * Renames sample responses * Adds empty responses.json file to include with the Proxy * Updates mocks message for readability * Exposes logLevel as CLI option * Adds responses.sample.json to output * Changes port and logLevel options to nullable
1 parent 322968c commit 425dc63

File tree

18 files changed

+560
-191
lines changed

18 files changed

+560
-191
lines changed

.vscode/tasks.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"type": "process",
88
"args": [
99
"build",
10-
"${workspaceFolder}/msgraph-developer-proxy/msgraph-developer-proxy.csproj",
10+
"${workspaceFolder}/msgraph-developer-proxy.sln",
1111
"/property:GenerateFullPaths=true",
1212
"/consoleloggerparameters:NoSummary"
1313
],
@@ -19,7 +19,7 @@
1919
"type": "process",
2020
"args": [
2121
"publish",
22-
"${workspaceFolder}/msgraph-developer-proxy/msgraph-developer-proxy.csproj",
22+
"${workspaceFolder}/msgraph-developer-proxy.sln",
2323
"/property:GenerateFullPaths=true",
2424
"/consoleloggerparameters:NoSummary"
2525
],
@@ -33,7 +33,7 @@
3333
"watch",
3434
"run",
3535
"--project",
36-
"${workspaceFolder}/msgraph-developer-proxy/msgraph-developer-proxy.csproj"
36+
"${workspaceFolder}/msgraph-developer-proxy.sln"
3737
],
3838
"problemMatcher": "$msCompile"
3939
}

msgraph-developer-proxy-abstractions/ILogger.cs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,48 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
3+
using System.Runtime.Serialization;
4+
using Titanium.Web.Proxy.EventArguments;
35

46
namespace Microsoft.Graph.DeveloperProxy.Abstractions;
57

8+
public enum MessageType {
9+
Normal,
10+
InterceptedRequest,
11+
PassedThrough,
12+
Warning,
13+
Tip,
14+
Failed,
15+
Chaos,
16+
Mocked
17+
}
18+
19+
public class LoggingContext {
20+
public SessionEventArgs Session { get; }
21+
22+
public LoggingContext(SessionEventArgs session)
23+
{
24+
Session = session;
25+
}
26+
}
27+
28+
public enum LogLevel {
29+
[EnumMember(Value = "debug")]
30+
Debug,
31+
[EnumMember(Value = "info")]
32+
Info,
33+
[EnumMember(Value = "warn")]
34+
Warn,
35+
[EnumMember(Value = "error")]
36+
Error
37+
}
38+
639
public interface ILogger {
7-
public void Log(string message);
40+
public LogLevel LogLevel { get; set; }
41+
42+
public void LogRequest(string[] message, MessageType messageType, LoggingContext? context = null);
43+
44+
// Logging methods for non-traffic related messages
45+
public void LogInfo(string message);
846
public void LogWarn(string message);
947
public void LogError(string message);
1048
public void LogDebug(string message);

msgraph-developer-proxy-plugins/Guidance/SdkGuidancePlugin.cs renamed to msgraph-developer-proxy-plugins/Guidance/GraphSdkGuidancePlugin.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ private void OnAfterResponse(object? sender, ProxyResponseArgs e) {
4242
&& _urlsToWatch is not null
4343
&& e.HasRequestUrlMatch(_urlsToWatch)
4444
&& WarnNoSdk(request)) {
45-
_logger?.LogWarn(MessageUtils.BuildUseSdkMessage(request));
45+
_logger?.LogRequest(MessageUtils.BuildUseSdkMessage(request), MessageType.Tip, new LoggingContext(e.Session));
4646
}
4747
}
4848

msgraph-developer-proxy-plugins/Guidance/SelectGuidancePlugin.cs renamed to msgraph-developer-proxy-plugins/Guidance/GraphSelectGuidancePlugin.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public void Register(IPluginEvents pluginEvents,
3838
private void AfterResponse(object? sender, ProxyResponseArgs e) {
3939
Request request = e.Session.HttpClient.Request;
4040
if (_urlsToWatch is not null && e.HasRequestUrlMatch(_urlsToWatch) && WarnNoSelect(request))
41-
_logger?.LogWarn(BuildUseSelectMessage(request));
41+
_logger?.LogRequest(BuildUseSelectMessage(request), MessageType.Warning, new LoggingContext(e.Session));
4242
}
4343

4444
private static bool WarnNoSelect(Request request) =>
@@ -47,5 +47,5 @@ private static bool WarnNoSelect(Request request) =>
4747
&& !request.Url.Contains("$select", StringComparison.OrdinalIgnoreCase);
4848

4949
private static string GetSelectParameterGuidanceUrl() => "https://learn.microsoft.com/graph/query-parameters#select-parameter";
50-
private static string BuildUseSelectMessage(Request r) => $"To improve performance of your application, use the $select parameter when calling {r.RequestUriString}. More info at {GetSelectParameterGuidanceUrl()}";
50+
private static string[] BuildUseSelectMessage(Request r) => new[] { $"To improve performance of your application, use the $select parameter.", $"More info at {GetSelectParameterGuidanceUrl()}" };
5151
}

msgraph-developer-proxy-plugins/MessageUtils.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
using Microsoft.Graph.DeveloperProxy.Abstractions;
54
using Titanium.Web.Proxy.Http;
65

76
namespace Microsoft.Graph.DeveloperProxy.Plugins;
87

98
internal class MessageUtils {
10-
public static string BuildUseSdkMessage(Request r) => $"To handle API errors more easily, use the Graph SDK. More info at {GetMoveToSdkUrl(r)}";
9+
public static string[] BuildUseSdkMessage(Request r) => new[] { "To handle API errors more easily, use the Graph SDK.", $"More info at {GetMoveToSdkUrl(r)}" };
1110

1211
public static string GetMoveToSdkUrl(Request request) {
1312
// TODO: return language-specific guidance links based on the language detected from the User-Agent

msgraph-developer-proxy-plugins/MockResponses/MockResponsePlugin.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,5 +169,7 @@ private void ProcessMockResponse(SessionEventArgs e, MockResponse matchingRespon
169169
}
170170
e.GenericResponse(body ?? string.Empty, statusCode, headers);
171171
}
172+
173+
_logger?.LogRequest(new[] { $"{matchingResponse.ResponseCode ?? 200} ${matchingResponse.Url}" }, MessageType.Mocked, new LoggingContext(e));
172174
}
173175
}

msgraph-developer-proxy-plugins/MockResponses/MockResponsesLoader.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public MockResponsesLoader(ILogger logger, MockResponseConfiguration configurati
2020

2121
public void LoadResponses() {
2222
if (!File.Exists(_responsesFilePath)) {
23-
_logger.LogWarn($"Unable to find {_configuration.MocksFile}, no mocks will be provided");
23+
_logger.LogWarn($"File {_configuration.MocksFile} not found in the current directory. No mocks will be provided");
2424
_configuration.Responses = Array.Empty<MockResponse>();
2525
return;
2626
}
@@ -31,7 +31,7 @@ public void LoadResponses() {
3131
IEnumerable<MockResponse>? configResponses = responsesConfig?.Responses;
3232
if (configResponses is not null) {
3333
_configuration.Responses = configResponses;
34-
_logger.Log($"Mock responses for {configResponses.Count()} url patterns loaded from from {_configuration.MocksFile}");
34+
_logger.LogInfo($"Mock responses for {configResponses.Count()} url patterns loaded from from {_configuration.MocksFile}");
3535
}
3636
}
3737
catch (Exception ex) {

msgraph-developer-proxy-plugins/RandomErrors/RandomErrorPlugin.cs

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ internal enum FailMode {
2020
PassThru
2121
}
2222

23-
public class RandomErrorConfguration {
23+
public class RandomErrorConfiguration {
2424
public int Rate { get; set; } = 0;
2525
public List<int> AllowedErrors { get; set; } = new();
2626
}
@@ -30,62 +30,62 @@ public class RandomErrorPlugin : IProxyPlugin {
3030
private ILogger? _logger;
3131
private readonly Option<int?> _rate;
3232
private readonly Option<IEnumerable<int>> _allowedErrors;
33-
private readonly RandomErrorConfguration _configuration = new();
33+
private readonly RandomErrorConfiguration _configuration = new();
3434

3535
public string Name => nameof(RandomErrorPlugin);
3636

3737
private const int retryAfterInSeconds = 5;
3838
private readonly Dictionary<string, HttpStatusCode[]> _methodStatusCode = new()
3939
{
40-
{
41-
"GET", new[] {
42-
HttpStatusCode.TooManyRequests,
43-
HttpStatusCode.InternalServerError,
44-
HttpStatusCode.BadGateway,
45-
HttpStatusCode.ServiceUnavailable,
46-
HttpStatusCode.GatewayTimeout
47-
}
48-
},
49-
{
50-
"POST", new[] {
51-
HttpStatusCode.TooManyRequests,
52-
HttpStatusCode.InternalServerError,
53-
HttpStatusCode.BadGateway,
54-
HttpStatusCode.ServiceUnavailable,
55-
HttpStatusCode.GatewayTimeout,
56-
HttpStatusCode.InsufficientStorage
57-
}
58-
},
59-
{
60-
"PUT", new[] {
61-
HttpStatusCode.TooManyRequests,
62-
HttpStatusCode.InternalServerError,
63-
HttpStatusCode.BadGateway,
64-
HttpStatusCode.ServiceUnavailable,
65-
HttpStatusCode.GatewayTimeout,
66-
HttpStatusCode.InsufficientStorage
67-
}
68-
},
69-
{
70-
"PATCH", new[] {
71-
HttpStatusCode.TooManyRequests,
72-
HttpStatusCode.InternalServerError,
73-
HttpStatusCode.BadGateway,
74-
HttpStatusCode.ServiceUnavailable,
75-
HttpStatusCode.GatewayTimeout
76-
}
77-
},
78-
{
79-
"DELETE", new[] {
80-
HttpStatusCode.TooManyRequests,
81-
HttpStatusCode.InternalServerError,
82-
HttpStatusCode.BadGateway,
83-
HttpStatusCode.ServiceUnavailable,
84-
HttpStatusCode.GatewayTimeout,
85-
HttpStatusCode.InsufficientStorage
86-
}
40+
{
41+
"GET", new[] {
42+
HttpStatusCode.TooManyRequests,
43+
HttpStatusCode.InternalServerError,
44+
HttpStatusCode.BadGateway,
45+
HttpStatusCode.ServiceUnavailable,
46+
HttpStatusCode.GatewayTimeout
8747
}
88-
};
48+
},
49+
{
50+
"POST", new[] {
51+
HttpStatusCode.TooManyRequests,
52+
HttpStatusCode.InternalServerError,
53+
HttpStatusCode.BadGateway,
54+
HttpStatusCode.ServiceUnavailable,
55+
HttpStatusCode.GatewayTimeout,
56+
HttpStatusCode.InsufficientStorage
57+
}
58+
},
59+
{
60+
"PUT", new[] {
61+
HttpStatusCode.TooManyRequests,
62+
HttpStatusCode.InternalServerError,
63+
HttpStatusCode.BadGateway,
64+
HttpStatusCode.ServiceUnavailable,
65+
HttpStatusCode.GatewayTimeout,
66+
HttpStatusCode.InsufficientStorage
67+
}
68+
},
69+
{
70+
"PATCH", new[] {
71+
HttpStatusCode.TooManyRequests,
72+
HttpStatusCode.InternalServerError,
73+
HttpStatusCode.BadGateway,
74+
HttpStatusCode.ServiceUnavailable,
75+
HttpStatusCode.GatewayTimeout
76+
}
77+
},
78+
{
79+
"DELETE", new[] {
80+
HttpStatusCode.TooManyRequests,
81+
HttpStatusCode.InternalServerError,
82+
HttpStatusCode.BadGateway,
83+
HttpStatusCode.ServiceUnavailable,
84+
HttpStatusCode.GatewayTimeout,
85+
HttpStatusCode.InsufficientStorage
86+
}
87+
}
88+
};
8989

9090
private readonly Dictionary<string, DateTime> _throttledRequests;
9191
private readonly Random _random;
@@ -115,7 +115,7 @@ private FailMode ShouldFail(ProxyRequestArgs e) {
115115
string key = BuildThrottleKey(r);
116116
if (_throttledRequests.TryGetValue(key, out DateTime retryAfterDate)) {
117117
if (retryAfterDate > DateTime.Now) {
118-
_logger?.LogError($"Calling {r.Url} again before waiting for the Retry-After period. Request will be throttled");
118+
_logger?.LogRequest(new[] { $"Calling {r.Url} again before waiting for the Retry-After period.", "Request will be throttled" }, MessageType.Failed, new LoggingContext(e.Session));
119119
// update the retryAfterDate to extend the throttling window to ensure that brute forcing won't succeed.
120120
_throttledRequests[key] = retryAfterDate.AddSeconds(retryAfterInSeconds);
121121
return FailMode.Throttled;
@@ -164,7 +164,7 @@ private void UpdateProxyResponse(ProxyRequestArgs ev, HttpStatusCode errorStatus
164164
}
165165
})
166166
);
167-
_logger?.Log($"\tFailed {request.Url} with {errorStatus}");
167+
_logger?.LogRequest(new[] { $"{(int)errorStatus} {errorStatus.ToString()}" }, MessageType.Chaos, new LoggingContext(ev.Session));
168168
session.GenericResponse(body ?? string.Empty, errorStatus, headers);
169169
}
170170
private static string BuildApiErrorMessage(Request r) => $"Some error was generated by the proxy. {(ProxyUtils.IsGraphRequest(r) ? ProxyUtils.IsSdkRequest(r) ? "" : MessageUtils.BuildUseSdkMessage(r) : "")}";
@@ -220,7 +220,7 @@ private void OnRequest(object? sender, ProxyRequestArgs e) {
220220
var failMode = ShouldFail(e);
221221

222222
if (failMode == FailMode.PassThru && _configuration.Rate != 100) {
223-
_logger?.Log($"\tPassed through {session.HttpClient.Request.Url}");
223+
_logger?.LogRequest(new[] { "Passed through" }, MessageType.PassedThrough, new LoggingContext(e.Session));
224224
return;
225225
}
226226
FailResponse(e, failMode);

0 commit comments

Comments
 (0)