From 84340ed4cf32d9ed75943625f2000f7fed29e230 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marie=20P=C3=ADchov=C3=A1?= <11718369+ManickaP@users.noreply.github.com> Date: Fri, 28 Aug 2020 15:31:29 +0200 Subject: [PATCH] Client side logging for HTTP stress. (#41444) --- .../StressTests/HttpStress/HttpEventListener.cs | 87 ++++++++++++++++++++++ .../tests/StressTests/HttpStress/StressClient.cs | 30 ++++++-- .../tests/StressTests/HttpStress/StressServer.cs | 60 ++------------- .../tests/StressTests/SslStress/Readme.md | 2 +- .../tests/StressTests/SslStress/global.json | 4 +- 5 files changed, 119 insertions(+), 64 deletions(-) create mode 100644 src/libraries/System.Net.Http/tests/StressTests/HttpStress/HttpEventListener.cs diff --git a/src/libraries/System.Net.Http/tests/StressTests/HttpStress/HttpEventListener.cs b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/HttpEventListener.cs new file mode 100644 index 0000000..d9bcc3a --- /dev/null +++ b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/HttpEventListener.cs @@ -0,0 +1,87 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics.Tracing; +using System.Text; +using System.IO; + +namespace HttpStress +{ + public sealed class LogHttpEventListener : EventListener + { + private readonly StreamWriter _log; + + public LogHttpEventListener(string logPath) + { + _log = new StreamWriter(logPath, true) { AutoFlush = true }; + } + + protected override void OnEventSourceCreated(EventSource eventSource) + { + if (eventSource.Name == "Private.InternalDiagnostics.System.Net.Http") + { + EnableEvents(eventSource, EventLevel.LogAlways); + } + } + + protected override void OnEventWritten(EventWrittenEventArgs eventData) + { + lock (_log) + { + var sb = new StringBuilder().Append($"{eventData.TimeStamp:HH:mm:ss.fffffff}[{eventData.EventName}] "); + for (int i = 0; i < eventData.Payload?.Count; i++) + { + if (i > 0) + { + sb.Append(", "); + } + sb.Append(eventData.PayloadNames?[i]).Append(": ").Append(eventData.Payload[i]); + } + _log.WriteLine(sb.ToString()); + } + } + + public override void Dispose() + { + _log.Dispose(); + base.Dispose(); + } + } + + public sealed class ConsoleHttpEventListener : EventListener + { + public ConsoleHttpEventListener() + { } + + protected override void OnEventSourceCreated(EventSource eventSource) + { + if (eventSource.Name == "Private.InternalDiagnostics.System.Net.Http") + { + EnableEvents(eventSource, EventLevel.LogAlways); + } + } + + protected override void OnEventWritten(EventWrittenEventArgs eventData) + { + lock (Console.Out) + { + Console.ForegroundColor = ConsoleColor.DarkYellow; + Console.Write($"{eventData.TimeStamp:HH:mm:ss.fffffff}[{eventData.EventName}] "); + Console.ResetColor(); + for (int i = 0; i < eventData.Payload?.Count; i++) + { + if (i > 0) + { + Console.Write(", "); + } + Console.ForegroundColor = ConsoleColor.DarkGray; + Console.Write(eventData.PayloadNames?[i] + ": "); + Console.ResetColor(); + Console.Write(eventData.Payload[i]); + } + Console.WriteLine(); + } + } + } +} diff --git a/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressClient.cs b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressClient.cs index 4c87df4..142171d 100644 --- a/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressClient.cs +++ b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressClient.cs @@ -6,6 +6,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Concurrent; using System.Diagnostics; +using System.Diagnostics.Tracing; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net.Http; @@ -27,6 +28,7 @@ namespace HttpStress private readonly Stopwatch _stopwatch = new Stopwatch(); private readonly CancellationTokenSource _cts = new CancellationTokenSource(); private Task? _clientTask; + private EventListener? _eventListener; public long TotalErrorCount => _aggregator.TotalErrorCount; @@ -36,6 +38,14 @@ namespace HttpStress _config = configuration; _baseAddress = new Uri(configuration.ServerUri); _aggregator = new StressResultAggregator(clientOperations); + + // Handle command-line arguments. + _eventListener = + configuration.LogPath == null ? + null : + (configuration.LogPath == "console" ? + (EventListener)new ConsoleHttpEventListener() : + (EventListener)new LogHttpEventListener(configuration.LogPath)); } public void Start() @@ -78,7 +88,11 @@ namespace HttpStress } } - public void Dispose() => Stop(); + public void Dispose() + { + Stop(); + _eventListener?.Dispose(); + } private async Task StartCore() { @@ -208,12 +222,12 @@ namespace HttpStress // Representative error text of stress failure public string ErrorText { get; } // Operation id => failure timestamps - public Dictionary> Failures { get; } + public Dictionary> Failures { get; } public StressFailureType(string errorText) { ErrorText = errorText; - Failures = new Dictionary>(); + Failures = new Dictionary>(); } public int FailureCount => Failures.Values.Select(x => x.Count).Sum(); @@ -279,13 +293,13 @@ namespace HttpStress lock (failureType) { - if(!failureType.Failures.TryGetValue(operationIndex, out List? timestamps)) + if(!failureType.Failures.TryGetValue(operationIndex, out List<(DateTime timestamp, TimeSpan duration)>? timestamps)) { - timestamps = new List(); + timestamps = new List<(DateTime timestamp, TimeSpan duration)>(); failureType.Failures.Add(operationIndex, timestamps); } - timestamps.Add(timestamp); + timestamps.Add((timestamp, elapsed)); } (Type exception, string message, string callSite)[] ClassifyFailure(Exception exn) @@ -425,7 +439,7 @@ namespace HttpStress Console.WriteLine(failure.ErrorText); Console.WriteLine(); Console.ForegroundColor = ConsoleColor.Yellow; - foreach (KeyValuePair> operation in failure.Failures) + foreach (KeyValuePair> operation in failure.Failures) { Console.ForegroundColor = ConsoleColor.Cyan; Console.Write($"\t{_operationNames[operation.Key].PadRight(30)}"); @@ -434,7 +448,7 @@ namespace HttpStress Console.Write("Fail: "); Console.ResetColor(); Console.Write(operation.Value.Count); - Console.WriteLine($"\tTimestamps: {string.Join(", ", operation.Value.Select(x => x.ToString("HH:mm:ss")))}"); + Console.WriteLine($"\tTimestamps: {string.Join(", ", operation.Value.Select(x => $"{x.timestamp:HH:mm:ss.fffffff} in {x.duration}"))}"); } Console.ForegroundColor = ConsoleColor.Cyan; diff --git a/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressServer.cs b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressServer.cs index 6d251ba..c9401e3 100644 --- a/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressServer.cs +++ b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressServer.cs @@ -132,8 +132,11 @@ namespace HttpStress // Handle command-line arguments. _eventListener = - configuration.LogPath == null ? null : - new HttpEventListener(configuration.LogPath != "console" ? new StreamWriter(configuration.LogPath) { AutoFlush = true } : null); + configuration.LogPath == null ? + null : + (configuration.LogPath == "console" ? + (EventListener)new ConsoleHttpEventListener() : + (EventListener)new LogHttpEventListener(configuration.LogPath)); SetUpJustInTimeLogging(); @@ -295,7 +298,8 @@ namespace HttpStress public void Dispose() { - _webHost.Dispose(); _eventListener?.Dispose(); + _webHost.Dispose(); + _eventListener?.Dispose(); } private void SetUpJustInTimeLogging() @@ -311,7 +315,7 @@ namespace HttpStress if (Console.ReadKey(intercept: true).Key == ConsoleKey.L) { Console.WriteLine("Enabling console event logger"); - _eventListener = new HttpEventListener(); + _eventListener = new ConsoleHttpEventListener(); break; } } @@ -342,54 +346,6 @@ namespace HttpStress } } - /// EventListener that dumps HTTP events out to either the console or a stream writer. - private sealed class HttpEventListener : EventListener - { - private readonly StreamWriter? _writer; - - public HttpEventListener(StreamWriter? writer = null) => _writer = writer; - - protected override void OnEventSourceCreated(EventSource eventSource) - { - if (eventSource.Name == "Private.InternalDiagnostics.System.Net.Http") - EnableEvents(eventSource, EventLevel.LogAlways); - } - - protected override void OnEventWritten(EventWrittenEventArgs eventData) - { - lock (Console.Out) - { - if (_writer != null) - { - var sb = new StringBuilder().Append($"[{eventData.EventName}] "); - for (int i = 0; i < eventData.Payload?.Count; i++) - { - if (i > 0) - sb.Append(", "); - sb.Append(eventData.PayloadNames?[i]).Append(": ").Append(eventData.Payload[i]); - } - _writer.WriteLine(sb); - } - else - { - Console.ForegroundColor = ConsoleColor.DarkYellow; - Console.Write($"[{eventData.EventName}] "); - Console.ResetColor(); - for (int i = 0; i < eventData.Payload?.Count; i++) - { - if (i > 0) - Console.Write(", "); - Console.ForegroundColor = ConsoleColor.DarkGray; - Console.Write(eventData.PayloadNames?[i] + ": "); - Console.ResetColor(); - Console.Write(eventData.Payload[i]); - } - Console.WriteLine(); - } - } - } - } - private static string CreateResponseContent(HttpContext ctx) { return ServerContentUtils.CreateStringContent(GetExpectedContentLength()); diff --git a/src/libraries/System.Net.Security/tests/StressTests/SslStress/Readme.md b/src/libraries/System.Net.Security/tests/StressTests/SslStress/Readme.md index 06a4b53..ee46422 100644 --- a/src/libraries/System.Net.Security/tests/StressTests/SslStress/Readme.md +++ b/src/libraries/System.Net.Security/tests/StressTests/SslStress/Readme.md @@ -24,7 +24,7 @@ To achieve this, we will first need to build a new sdk from source. This can be ### Running using docker-compose -The prefered way of running the stress suite is using docker-compose, +The preferred way of running the stress suite is using docker-compose, which can be used to target both linux and windows containers. Docker and compose-compose are required for this step (both included in [docker for windows](https://docs.docker.com/docker-for-windows/)). diff --git a/src/libraries/System.Net.Security/tests/StressTests/SslStress/global.json b/src/libraries/System.Net.Security/tests/StressTests/SslStress/global.json index 0db3279..9e26dfe 100644 --- a/src/libraries/System.Net.Security/tests/StressTests/SslStress/global.json +++ b/src/libraries/System.Net.Security/tests/StressTests/SslStress/global.json @@ -1,3 +1 @@ -{ - -} +{} \ No newline at end of file -- 2.7.4