From d3199700654c46994157eb4974f98a4bcb6edf76 Mon Sep 17 00:00:00 2001 From: Alexander Nikolaev <55398552+alnikola@users.noreply.github.com> Date: Tue, 28 Jul 2020 16:55:12 +0200 Subject: [PATCH] System.Net.Sockets telemetry counters (#39708) Counters in SocketsTelemetry measuring `bytes-received` (Bytes Received) The cumulative total number of bytes received by all Socket objects since the process started. `bytes-sent` (Bytes Sent) The cumulative number of bytes sent by all Socket objects since the process started. `outgoing-connections-established` (Outgoing Connections Established) The cumulative total number of outgoing connections established by Socket objects for stream sockets since the process started. `incoming-connections-established` (Incoming Connections Established) The cumulative total number of incoming connections established by Socket objects for stream sockets since the process started. `datagrams-received` (Datagrams Received) The cumulative total number of datagram packets received by all Socket objects since the process started. `datagrams-sent` (Datagrams Sent) The cumulative total number of datagram packets sent by all Socket objects since the process started. Contributes to #37428 --- .../Diagnostics/Tracing/TestEventListener.cs | 17 ++- .../src/System/Net/Sockets/Socket.cs | 103 ++++++++++++++++++ .../src/System/Net/Sockets/SocketAsyncEventArgs.cs | 38 ++++++- .../src/System/Net/Sockets/SocketsTelemetry.cs | 120 +++++++++++++++++++++ .../tests/FunctionalTests/TelemetryTest.cs | 61 ++++++++--- 5 files changed, 320 insertions(+), 19 deletions(-) diff --git a/src/libraries/Common/tests/System/Diagnostics/Tracing/TestEventListener.cs b/src/libraries/Common/tests/System/Diagnostics/Tracing/TestEventListener.cs index bc210b2..b12f502 100644 --- a/src/libraries/Common/tests/System/Diagnostics/Tracing/TestEventListener.cs +++ b/src/libraries/Common/tests/System/Diagnostics/Tracing/TestEventListener.cs @@ -12,24 +12,27 @@ namespace System.Diagnostics.Tracing private readonly string _targetSourceName; private readonly Guid _targetSourceGuid; private readonly EventLevel _level; + private readonly double? _eventCounterInterval; private Action _eventWritten; private List _tmpEventSourceList = new List(); - public TestEventListener(string targetSourceName, EventLevel level) + public TestEventListener(string targetSourceName, EventLevel level, double? eventCounterInterval = null) { // Store the arguments _targetSourceName = targetSourceName; _level = level; + _eventCounterInterval = eventCounterInterval; LoadSourceList(); } - public TestEventListener(Guid targetSourceGuid, EventLevel level) + public TestEventListener(Guid targetSourceGuid, EventLevel level, double? eventCounterInterval = null) { // Store the arguments _targetSourceGuid = targetSourceGuid; _level = level; + _eventCounterInterval = eventCounterInterval; LoadSourceList(); } @@ -80,7 +83,15 @@ namespace System.Diagnostics.Tracing if (source.Name.Equals(_targetSourceName) || source.Guid.Equals(_targetSourceGuid)) { - EnableEvents(source, _level); + if (_eventCounterInterval != null) + { + var args = new Dictionary { { "EventCounterIntervalSec", _eventCounterInterval?.ToString() } }; + EnableEvents(source, _level, EventKeywords.All, args); + } + else + { + EnableEvents(source, _level); + } } } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index a874c7f..08eae7d 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -1087,6 +1087,8 @@ namespace System.Net.Sockets IPEndPointExtensions.Serialize(_rightEndPoint) : new Internals.SocketAddress(_addressFamily, SocketPal.MaximumAddressSize); // may be different size. + if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AcceptStart(socketAddress); + // This may throw ObjectDisposedException. SafeSocketHandle acceptedSocketHandle; SocketError errorCode = SocketPal.Accept( @@ -1098,10 +1100,16 @@ namespace System.Net.Sockets // Throw an appropriate SocketException if the native call fails. if (errorCode != SocketError.Success) { + if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AcceptFailedAndStop(errorCode, null); + Debug.Assert(acceptedSocketHandle.IsInvalid); UpdateAcceptSocketErrorForDisposed(ref errorCode); UpdateStatusAfterSocketErrorAndThrowException(errorCode); } + else + { + if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AcceptStop(); + } Debug.Assert(!acceptedSocketHandle.IsInvalid); @@ -1169,9 +1177,16 @@ namespace System.Net.Sockets // Update the internal state of this socket according to the error before throwing. UpdateStatusAfterSocketError(errorCode); if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(this, new SocketException((int)errorCode)); + // Don't log transfered byte count in case of a failure. return 0; } + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesSent(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramSent(); + } + return bytesTransferred; } @@ -1223,6 +1238,12 @@ namespace System.Net.Sockets return 0; } + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesSent(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramSent(); + } + if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"Send returns:{bytesTransferred}"); @@ -1258,6 +1279,14 @@ namespace System.Net.Sockets if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(this, new SocketException((int)errorCode)); bytesTransferred = 0; } + else + { + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesSent(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramSent(); + } + } return bytesTransferred; } @@ -1322,6 +1351,14 @@ namespace System.Net.Sockets UpdateStatusAfterSocketErrorAndThrowException(errorCode); } + else + { + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesSent(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramSent(); + } + } if (_rightEndPoint == null) { @@ -1400,6 +1437,11 @@ namespace System.Net.Sockets int bytesTransferred; errorCode = SocketPal.Receive(_handle, buffer, offset, size, socketFlags, out bytesTransferred); + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesReceived(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived(); + } UpdateReceiveSocketErrorForDisposed(ref errorCode, bytesTransferred); @@ -1433,6 +1475,11 @@ namespace System.Net.Sockets int bytesTransferred; errorCode = SocketPal.Receive(_handle, buffer, socketFlags, out bytesTransferred); + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesReceived(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived(); + } UpdateReceiveSocketErrorForDisposed(ref errorCode, bytesTransferred); @@ -1482,6 +1529,12 @@ namespace System.Net.Sockets int bytesTransferred; errorCode = SocketPal.Receive(_handle, buffers, socketFlags, out bytesTransferred); + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesReceived(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived(); + } + UpdateReceiveSocketErrorForDisposed(ref errorCode, bytesTransferred); if (errorCode != SocketError.Success) @@ -1542,6 +1595,11 @@ namespace System.Net.Sockets Internals.SocketAddress receiveAddress; int bytesTransferred; SocketError errorCode = SocketPal.ReceiveMessageFrom(this, _handle, buffer, offset, size, ref socketFlags, socketAddress, out receiveAddress, out ipPacketInformation, out bytesTransferred); + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesReceived(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived(); + } UpdateReceiveSocketErrorForDisposed(ref errorCode, bytesTransferred); @@ -1618,6 +1676,11 @@ namespace System.Net.Sockets int bytesTransferred; SocketError errorCode = SocketPal.ReceiveFrom(_handle, buffer, offset, size, socketFlags, socketAddress.Buffer, ref socketAddress.InternalSize, out bytesTransferred); + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesReceived(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived(); + } UpdateReceiveSocketErrorForDisposed(ref errorCode, bytesTransferred); @@ -2587,6 +2650,12 @@ namespace System.Net.Sockets return 0; } + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesSent(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramSent(); + } + return bytesTransferred; } @@ -2761,6 +2830,14 @@ namespace System.Net.Sockets UpdateSendSocketErrorForDisposed(ref errorCode); UpdateStatusAfterSocketErrorAndThrowException(errorCode); } + else + { + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesSent(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramSent(); + } + } return bytesTransferred; } @@ -2985,6 +3062,11 @@ namespace System.Net.Sockets int bytesTransferred = castedAsyncResult.InternalWaitForCompletionInt32Result(); castedAsyncResult.EndCalled = true; + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesReceived(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived(); + } // Throw an appropriate SocketException if the native call failed asynchronously. errorCode = (SocketError)castedAsyncResult.ErrorCode; @@ -3141,6 +3223,11 @@ namespace System.Net.Sockets int bytesTransferred = castedAsyncResult.InternalWaitForCompletionInt32Result(); castedAsyncResult.EndCalled = true; + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesReceived(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived(); + } // Update socket address size. castedAsyncResult.SocketAddress!.InternalSize = castedAsyncResult.GetSocketAddressSize(); @@ -3344,6 +3431,11 @@ namespace System.Net.Sockets int bytesTransferred = castedAsyncResult.InternalWaitForCompletionInt32Result(); castedAsyncResult.EndCalled = true; + if (SocketsTelemetry.Log.IsEnabled()) + { + SocketsTelemetry.Log.BytesReceived(bytesTransferred); + if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived(); + } // Update socket address size. castedAsyncResult.SocketAddress!.InternalSize = castedAsyncResult.GetSocketAddressSize(); @@ -3446,6 +3538,7 @@ namespace System.Net.Sockets asyncResult.AcceptSocket = GetOrCreateAcceptSocket(acceptSocket, false, nameof(acceptSocket), out acceptHandle); if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"AcceptSocket:{acceptSocket}"); + if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AcceptStart(_rightEndPoint); int socketAddressSize = GetAddressSize(_rightEndPoint); SocketError errorCode = SocketPal.AcceptAsync(this, _handle, acceptHandle, receiveSize, socketAddressSize, asyncResult); @@ -3455,9 +3548,13 @@ namespace System.Net.Sockets // Throw an appropriate SocketException if the native call fails synchronously. if (!CheckErrorAndUpdateStatus(errorCode)) { + if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AcceptFailedAndStop(errorCode, null); + UpdateAcceptSocketErrorForDisposed(ref errorCode); throw new SocketException((int)errorCode); } + + if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AcceptStop(); } // Routine Description: @@ -3521,9 +3618,15 @@ namespace System.Net.Sockets SocketError errorCode = (SocketError)castedAsyncResult.ErrorCode; if (errorCode != SocketError.Success) { + if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AcceptFailedAndStop(errorCode, null); + UpdateAcceptSocketErrorForDisposed(ref errorCode); UpdateStatusAfterSocketErrorAndThrowException(errorCode); } + else + { + if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AcceptStop(); + } if (NetEventSource.Log.IsEnabled()) NetEventSource.Accepted(socket, socket.RemoteEndPoint, socket.LocalEndPoint); return socket; diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs index 213cb30..114a65d 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs @@ -547,6 +547,8 @@ namespace System.Net.Sockets _acceptBuffer = new byte[_acceptAddressBufferCount]; } } + + if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AcceptStart(_currentSocket!._rightEndPoint!); } internal void StartOperationConnect(MultipleConnectAsync? multipleConnect, bool userSocket) @@ -587,9 +589,10 @@ namespace System.Net.Sockets { SetResults(socketError, bytesTransferred, flags); - if (SocketsTelemetry.Log.IsEnabled() && _multipleConnect == null && _completedOperation == SocketAsyncOperation.Connect) + if (SocketsTelemetry.Log.IsEnabled()) { - SocketsTelemetry.Log.ConnectFailedAndStop(socketError, null); + if (_multipleConnect == null && _completedOperation == SocketAsyncOperation.Connect) SocketsTelemetry.Log.ConnectFailedAndStop(socketError, null); + if (_completedOperation == SocketAsyncOperation.Accept) SocketsTelemetry.Log.AcceptFailedAndStop(socketError, null); } // This will be null if we're doing a static ConnectAsync to a DnsEndPoint with AddressFamily.Unspecified; @@ -615,6 +618,8 @@ namespace System.Net.Sockets break; } + // Don't log transfered byte count in case of a failure. + Complete(); } @@ -665,6 +670,8 @@ namespace System.Net.Sockets _currentSocket = connectSocket; _connectSocket = connectSocket; + if (SocketsTelemetry.Log.IsEnabled()) LogBytesTransferEvents(connectSocket?.SocketType, SocketAsyncOperation.Connect, bytesTransferred); + // Complete the operation and raise the event. ExecutionContext? context = _context; // store context before it's cleared as part of completing the operation Complete(); @@ -708,9 +715,13 @@ namespace System.Net.Sockets } catch (ObjectDisposedException) { } } + + if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AcceptStop(); } else { + if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AcceptFailedAndStop(socketError, null); + SetResults(socketError, bytesTransferred, flags); _acceptSocket = null; _currentSocket.UpdateStatusAfterSocketError(socketError); @@ -789,6 +800,8 @@ namespace System.Net.Sockets break; } + if (SocketsTelemetry.Log.IsEnabled()) LogBytesTransferEvents(_currentSocket?.SocketType, _completedOperation, bytesTransferred); + Complete(); } @@ -822,5 +835,26 @@ namespace System.Net.Sockets FinishOperationSyncFailure(socketError, bytesTransferred, flags); } } + + private static void LogBytesTransferEvents(SocketType? socketType, SocketAsyncOperation operation, int bytesTransferred) + { + switch (operation) + { + case SocketAsyncOperation.Receive: + case SocketAsyncOperation.ReceiveFrom: + case SocketAsyncOperation.ReceiveMessageFrom: + case SocketAsyncOperation.Accept: + SocketsTelemetry.Log.BytesReceived(bytesTransferred); + if (socketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived(); + break; + case SocketAsyncOperation.Send: + case SocketAsyncOperation.SendTo: + case SocketAsyncOperation.SendPackets: + case SocketAsyncOperation.Connect: + SocketsTelemetry.Log.BytesSent(bytesTransferred); + if (socketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramSent(); + break; + } + } } } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs index 7f0e2a7..f3430e7 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.Tracing; +using System.Threading; namespace System.Net.Sockets { @@ -10,9 +11,24 @@ namespace System.Net.Sockets { public static readonly SocketsTelemetry Log = new SocketsTelemetry(); + private PollingCounter? _outgoingConnectionsEstablishedCounter; + private PollingCounter? _incomingConnectionsEstablishedCounter; + private PollingCounter? _bytesReceivedCounter; + private PollingCounter? _bytesSentCounter; + private PollingCounter? _datagramsReceivedCounter; + private PollingCounter? _datagramsSentCounter; + + private long _outgoingConnectionsEstablished; + private long _incomingConnectionsEstablished; + private long _bytesReceived; + private long _bytesSent; + private long _datagramsReceived; + private long _datagramsSent; + [Event(1, Level = EventLevel.Informational)] public void ConnectStart(string? address) { + Interlocked.Increment(ref _outgoingConnectionsEstablished); if (IsEnabled(EventLevel.Informational, EventKeywords.All)) { WriteEvent(eventId: 1, address ?? ""); @@ -46,6 +62,34 @@ namespace System.Net.Sockets } } + [Event(5, Level = EventLevel.Informational)] + public void AcceptStart(string? address) + { + Interlocked.Increment(ref _incomingConnectionsEstablished); + if (IsEnabled(EventLevel.Informational, EventKeywords.All)) + { + WriteEvent(eventId: 5, address ?? ""); + } + } + + [Event(6, Level = EventLevel.Informational)] + public void AcceptStop() + { + if (IsEnabled(EventLevel.Informational, EventKeywords.All)) + { + WriteEvent(eventId: 6); + } + } + + [Event(7, Level = EventLevel.Error)] + public void AcceptFailed(SocketError error, string? exceptionMessage) + { + if (IsEnabled(EventLevel.Error, EventKeywords.All)) + { + WriteEvent(eventId: 7, (int)error, exceptionMessage ?? string.Empty); + } + } + [NonEvent] public void ConnectStart(Internals.SocketAddress address) { @@ -71,5 +115,81 @@ namespace System.Net.Sockets ConnectFailed(error, exceptionMessage); ConnectStop(); } + + [NonEvent] + public void AcceptStart(Internals.SocketAddress address) + { + AcceptStart(address.ToString()); + } + + [NonEvent] + public void AcceptStart(EndPoint address) + { + AcceptStart(address.ToString()); + } + + [NonEvent] + public void AcceptFailedAndStop(SocketError error, string? exceptionMessage) + { + AcceptFailed(error, exceptionMessage); + AcceptStop(); + } + + [NonEvent] + public void BytesReceived(int count) + { + Interlocked.Add(ref _bytesReceived, count); + } + + [NonEvent] + public void BytesSent(int count) + { + Interlocked.Add(ref _bytesSent, count); + } + + [NonEvent] + public void DatagramReceived() + { + Interlocked.Increment(ref _datagramsReceived); + } + + [NonEvent] + public void DatagramSent() + { + Interlocked.Increment(ref _datagramsSent); + } + + protected override void OnEventCommand(EventCommandEventArgs command) + { + if (command.Command == EventCommand.Enable) + { + // This is the convention for initializing counters in the RuntimeEventSource (lazily on the first enable command). + + _outgoingConnectionsEstablishedCounter ??= new PollingCounter("outgoing-connections-established", this, () => Interlocked.Read(ref _outgoingConnectionsEstablished)) + { + DisplayName = "Outgoing Connections Established", + }; + _incomingConnectionsEstablishedCounter ??= new PollingCounter("incoming-connections-established", this, () => Interlocked.Read(ref _incomingConnectionsEstablished)) + { + DisplayName = "Incoming Connections Established", + }; + _bytesReceivedCounter ??= new PollingCounter("bytes-received", this, () => Interlocked.Read(ref _bytesReceived)) + { + DisplayName = "Bytes Received", + }; + _bytesSentCounter ??= new PollingCounter("bytes-sent", this, () => Interlocked.Read(ref _bytesSent)) + { + DisplayName = "Bytes Sent", + }; + _datagramsReceivedCounter ??= new PollingCounter("datagrams-received", this, () => Interlocked.Read(ref _datagramsReceived)) + { + DisplayName = "Datagrams Received", + }; + _datagramsSentCounter ??= new PollingCounter("datagrams-sent", this, () => Interlocked.Read(ref _datagramsSent)) + { + DisplayName = "Datagrams Sent", + }; + } + } } } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs index 33529f9..783fbf5 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs @@ -1,8 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections; using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.Tracing; +using System.Linq; +using System.Threading.Tasks; using Microsoft.DotNet.RemoteExecutor; using Xunit; using Xunit.Abstractions; @@ -36,32 +41,60 @@ namespace System.Net.Sockets.Tests { RemoteExecutor.Invoke(() => { - using (var listener = new TestEventListener("System.Net.Sockets", EventLevel.Verbose)) + using (var listener = new TestEventListener("System.Net.Sockets", EventLevel.Verbose, 0.1)) { var events = new ConcurrentQueue(); - listener.RunWithCallback(events.Enqueue, () => + listener.RunWithCallbackAsync(events.Enqueue, async () => { // Invoke several tests to execute code paths while tracing is enabled - new SendReceiveSync(null).SendRecv_Stream_TCP(IPAddress.Loopback, false).GetAwaiter(); - new SendReceiveSync(null).SendRecv_Stream_TCP(IPAddress.Loopback, true).GetAwaiter(); + await new SendReceiveSync(null).SendRecv_Stream_TCP(IPAddress.Loopback, false).ConfigureAwait(false); + await new SendReceiveSync(null).SendRecv_Stream_TCP(IPAddress.Loopback, true).ConfigureAwait(false); - new SendReceiveTask(null).SendRecv_Stream_TCP(IPAddress.Loopback, false).GetAwaiter(); - new SendReceiveTask(null).SendRecv_Stream_TCP(IPAddress.Loopback, true).GetAwaiter(); + await new SendReceiveTask(null).SendRecv_Stream_TCP(IPAddress.Loopback, false).ConfigureAwait(false); + await new SendReceiveTask(null).SendRecv_Stream_TCP(IPAddress.Loopback, true).ConfigureAwait(false); - new SendReceiveEap(null).SendRecv_Stream_TCP(IPAddress.Loopback, false).GetAwaiter(); - new SendReceiveEap(null).SendRecv_Stream_TCP(IPAddress.Loopback, true).GetAwaiter(); + await new SendReceiveEap(null).SendRecv_Stream_TCP(IPAddress.Loopback, false).ConfigureAwait(false); + await new SendReceiveEap(null).SendRecv_Stream_TCP(IPAddress.Loopback, true).ConfigureAwait(false); - new SendReceiveApm(null).SendRecv_Stream_TCP(IPAddress.Loopback, false).GetAwaiter(); - new SendReceiveApm(null).SendRecv_Stream_TCP(IPAddress.Loopback, true).GetAwaiter(); + await new SendReceiveApm(null).SendRecv_Stream_TCP(IPAddress.Loopback, false).ConfigureAwait(false); + await new SendReceiveApm(null).SendRecv_Stream_TCP(IPAddress.Loopback, true).ConfigureAwait(false); - new NetworkStreamTest().CopyToAsync_AllDataCopied(4096, true).GetAwaiter().GetResult(); - new NetworkStreamTest().Timeout_ValidData_Roundtrips().GetAwaiter().GetResult(); - }); + await new SendReceiveUdpClient().SendToRecvFromAsync_Datagram_UDP_UdpClient(IPAddress.Loopback).ConfigureAwait(false); + await new SendReceiveUdpClient().SendToRecvFromAsync_Datagram_UDP_UdpClient(IPAddress.Loopback).ConfigureAwait(false); + + await new NetworkStreamTest().CopyToAsync_AllDataCopied(4096, true).ConfigureAwait(false); + await new NetworkStreamTest().Timeout_ValidData_Roundtrips().ConfigureAwait(false); + await Task.Delay(300).ConfigureAwait(false); + }).Wait(); Assert.DoesNotContain(events, ev => ev.EventId == 0); // errors from the EventSource itself - Assert.InRange(events.Count, 1, int.MaxValue); + VerifyEvents(events, "ConnectStart", 10); + VerifyEvents(events, "ConnectStop", 10); + + Dictionary eventCounters = events.Where(e => e.EventName == "EventCounters").Select(e => (IDictionary) e.Payload.Single()) + .GroupBy(d => (string)d["Name"], d => (double)d["Mean"], (k, v) => new { Name = k, Value = v.Sum() }) + .ToDictionary(p => p.Name, p => p.Value); + + VerifyEventCounter("incoming-connections-established", eventCounters); + VerifyEventCounter("outgoing-connections-established", eventCounters); + VerifyEventCounter("bytes-received", eventCounters); + VerifyEventCounter("bytes-sent", eventCounters); + VerifyEventCounter("datagrams-received", eventCounters); + VerifyEventCounter("datagrams-sent", eventCounters); } }).Dispose(); } + + private static void VerifyEvents(IEnumerable events, string eventName, int expectedCount) + { + EventWrittenEventArgs[] starts = events.Where(e => e.EventName == eventName).ToArray(); + Assert.Equal(expectedCount, starts.Length); + } + + private static void VerifyEventCounter(string name, Dictionary eventCounters) + { + Assert.True(eventCounters.ContainsKey(name)); + Assert.True(eventCounters[name] > 0); + } } } -- 2.7.4