diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 58772da574..8e5d668070 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -28,9 +28,6 @@ $(DefineConstants);NETCORE3 - - $(DefineConstants);NETSTANDARD21 - portable true @@ -45,7 +42,6 @@ Microsoft\Data\SqlClient\SqlClientEventSource.cs - Microsoft\Data\SqlClient\SqlClientLogger.cs @@ -251,6 +247,14 @@ + + + + + + + + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs similarity index 65% rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs rename to src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs index f15f691a42..da7a59b51b 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs @@ -7,7 +7,10 @@ namespace Microsoft.Data.SqlClient { - internal partial class SqlClientEventSource : EventSource + /// + /// supported frameworks: .Net core 2.1 and .Net standard 2.0 + /// + internal partial class SqlClientEventSource : SqlClientEventSourceBase { private EventCounter _activeHardConnections; private EventCounter _hardConnectsPerSecond; @@ -53,151 +56,31 @@ internal partial class SqlClientEventSource : EventSource private long _stasisConnectionsCounter = 0; private long _reclaimedConnectionsCounter = 0; - public SqlClientEventSource() + protected override void EventCommandMethodCall(EventCommandEventArgs command) { - _activeHardConnections = _activeHardConnections ?? - new EventCounter("active-hard-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Actual active connections are made to servers", - DisplayUnits = "count" -#endif - }; - - _hardConnectsPerSecond = _hardConnectsPerSecond ?? - new EventCounter("hard-connects", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Actual connections are made to servers", - DisplayUnits = "count / sec" -#endif - }; - - _hardDisconnectsPerSecond = _hardDisconnectsPerSecond ?? - new EventCounter("hard-disconnects", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Actual disconnections are made to servers", - DisplayUnits = "count / sec" -#endif - }; - - _activeSoftConnections = _activeSoftConnections ?? - new EventCounter("active-soft-connects", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Active connections got from connection pool", - DisplayUnits = "count" -#endif - }; - - _softConnects = _softConnects ?? - new EventCounter("soft-connects", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Connections got from connection pool", - DisplayUnits = "count / sec" -#endif - }; - - _softDisconnects = _softDisconnects ?? - new EventCounter("soft-disconnects", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Connections returned to the connection pool", - DisplayUnits = "count / sec" -#endif - }; - - _numberOfNonPooledConnections = _numberOfNonPooledConnections ?? - new EventCounter("number-of-non-pooled-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of connections are not using connection pooling", - DisplayUnits = "count / sec" -#endif - }; - - _numberOfPooledConnections = _numberOfPooledConnections ?? - new EventCounter("number-of-pooled-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of connections are managed by connection pooler", - DisplayUnits = "count / sec" -#endif - }; - - _numberOfActiveConnectionPoolGroups = _numberOfActiveConnectionPoolGroups ?? - new EventCounter("number-of-active-connection-pool-groups", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of active unique connection strings", - DisplayUnits = "count" -#endif - }; - - _numberOfInactiveConnectionPoolGroups = _numberOfInactiveConnectionPoolGroups ?? - new EventCounter("number-of-inactive-connection-pool-groups", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of unique connection strings waiting for pruning", - DisplayUnits = "count" -#endif - }; - - _numberOfActiveConnectionPools = _numberOfActiveConnectionPools ?? - new EventCounter("number-of-active-connection-pools", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of active connection pools", - DisplayUnits = "count" -#endif - }; - - _numberOfInactiveConnectionPools = _numberOfInactiveConnectionPools ?? - new EventCounter("number-of-inactive-connection-pools", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of inactive connection pools", - DisplayUnits = "count" -#endif - }; - - _numberOfActiveConnections = _numberOfActiveConnections ?? - new EventCounter("number-of-active-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of active connections", - DisplayUnits = "count" -#endif - }; - - _numberOfFreeConnections = _numberOfFreeConnections ?? - new EventCounter("number-of-free-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of free-ready connections", - DisplayUnits = "count" -#endif - }; - - _numberOfStasisConnections = _numberOfStasisConnections ?? - new EventCounter("number-of-stasis-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of connections currently waiting to be ready", - DisplayUnits = "count" -#endif - }; - - _numberOfReclaimedConnections = _numberOfReclaimedConnections ?? - new EventCounter("number-of-reclaimed-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of reclaimed connections from GC", - DisplayUnits = "count" -#endif - }; + if (command.Command != EventCommand.Enable) + { + return; + } + + _activeHardConnections = _activeHardConnections ?? new EventCounter("active-hard-connections", this); + _hardConnectsPerSecond = _hardConnectsPerSecond ?? new EventCounter("hard-connects", this); + _hardDisconnectsPerSecond = _hardDisconnectsPerSecond ?? new EventCounter("hard-disconnects", this); + + _activeSoftConnections = _activeSoftConnections ?? new EventCounter("active-soft-connects", this); + _softConnects = _softConnects ?? new EventCounter("soft-connects", this); + _softDisconnects = _softDisconnects ?? new EventCounter("soft-disconnects", this); + + _numberOfNonPooledConnections = _numberOfNonPooledConnections ?? new EventCounter("number-of-non-pooled-connections", this); + _numberOfPooledConnections = _numberOfPooledConnections ?? new EventCounter("number-of-pooled-connections", this); + _numberOfActiveConnectionPoolGroups = _numberOfActiveConnectionPoolGroups ?? new EventCounter("number-of-active-connection-pool-groups", this); + _numberOfInactiveConnectionPoolGroups = _numberOfInactiveConnectionPoolGroups ?? new EventCounter("number-of-inactive-connection-pool-groups", this); + _numberOfActiveConnectionPools = _numberOfActiveConnectionPools ?? new EventCounter("number-of-active-connection-pools", this); + _numberOfInactiveConnectionPools = _numberOfInactiveConnectionPools ?? new EventCounter("number-of-inactive-connection-pools", this); + _numberOfActiveConnections = _numberOfActiveConnections ?? new EventCounter("number-of-active-connections", this); + _numberOfFreeConnections = _numberOfFreeConnections ?? new EventCounter("number-of-free-connections", this); + _numberOfStasisConnections = _numberOfStasisConnections ?? new EventCounter("number-of-stasis-connections", this); + _numberOfReclaimedConnections = _numberOfReclaimedConnections ?? new EventCounter("number-of-reclaimed-connections", this); } /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp3.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp3.cs new file mode 100644 index 0000000000..6d27a88cbe --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp3.cs @@ -0,0 +1,352 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics.Tracing; +using System.Threading; + +namespace Microsoft.Data.SqlClient +{ + /// + /// supported frameworks: .Net core 3.1 and .Net standard 2.1 and above + /// + internal partial class SqlClientEventSource : SqlClientEventSourceBase + { + private PollingCounter _activeHardConnections; + private IncrementingPollingCounter _hardConnectsPerSecond; + private IncrementingPollingCounter _hardDisconnectsPerSecond; + + private PollingCounter _activeSoftConnections; + private IncrementingPollingCounter _softConnects; + private IncrementingPollingCounter _softDisconnects; + + private PollingCounter _numberOfNonPooledConnections; + private PollingCounter _numberOfPooledConnections; + + private PollingCounter _numberOfActiveConnectionPoolGroups; + private PollingCounter _numberOfInactiveConnectionPoolGroups; + + private PollingCounter _numberOfActiveConnectionPools; + private PollingCounter _numberOfInactiveConnectionPools; + + private PollingCounter _numberOfActiveConnections; + private PollingCounter _numberOfFreeConnections; + private PollingCounter _numberOfStasisConnections; + private IncrementingPollingCounter _numberOfReclaimedConnections; + + private long _activeHardConnectionsCounter = 0; + private long _hardConnectsCounter = 0; + private long _hardDisconnectsCounter = 0; + + private long _activeSoftConnectionsCounter = 0; + private long _softConnectsCounter = 0; + private long _softDisconnectsCounter = 0; + + private long _nonPooledConnectionsCounter = 0; + private long _pooledConnectionsCounter = 0; + + private long _activeConnectionPoolGroupsCounter = 0; + private long _inactiveConnectionPoolGroupsCounter = 0; + + private long _activeConnectionPoolsCounter = 0; + private long _inactiveConnectionPoolsCounter = 0; + + private long _activeConnectionsCounter = 0; + private long _freeConnectionsCounter = 0; + private long _stasisConnectionsCounter = 0; + private long _reclaimedConnectionsCounter = 0; + + protected override void EventCommandMethodCall(EventCommandEventArgs command) + { + if(command.Command != EventCommand.Enable) + { + return; + } + + _activeHardConnections = _activeHardConnections ?? + new PollingCounter("active-hard-connections", this, () => _activeHardConnectionsCounter) + { + DisplayName = "Actual active connections are made to servers", + DisplayUnits = "count" + }; + + _hardConnectsPerSecond = _hardConnectsPerSecond ?? + new IncrementingPollingCounter("hard-connects", this, () => _hardConnectsCounter) + { + DisplayName = "Actual connections are made to servers", + DisplayUnits = "count / sec", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + + _hardDisconnectsPerSecond = _hardDisconnectsPerSecond ?? + new IncrementingPollingCounter("hard-disconnects", this, () => _hardDisconnectsCounter) + { + DisplayName = "Actual disconnections are made to servers", + DisplayUnits = "count / sec", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + + _activeSoftConnections = _activeSoftConnections ?? + new PollingCounter("active-soft-connects", this, () => _activeSoftConnectionsCounter) + { + DisplayName = "Active connections got from connection pool", + DisplayUnits = "count" + }; + + _softConnects = _softConnects ?? + new IncrementingPollingCounter("soft-connects", this, () => _softConnectsCounter) + { + DisplayName = "Connections got from connection pool", + DisplayUnits = "count / sec", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + + _softDisconnects = _softDisconnects ?? + new IncrementingPollingCounter("soft-disconnects", this, () => _softDisconnectsCounter) + { + DisplayName = "Connections returned to the connection pool", + DisplayUnits = "count / sec", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + + _numberOfNonPooledConnections = _numberOfNonPooledConnections ?? + new PollingCounter("number-of-non-pooled-connections", this, () => _nonPooledConnectionsCounter) + { + DisplayName = "Number of connections are not using connection pooling", + DisplayUnits = "count / sec" + }; + + _numberOfPooledConnections = _numberOfPooledConnections ?? + new PollingCounter("number-of-pooled-connections", this, () => _pooledConnectionsCounter) + { + DisplayName = "Number of connections are managed by connection pooler", + DisplayUnits = "count / sec" + }; + + _numberOfActiveConnectionPoolGroups = _numberOfActiveConnectionPoolGroups ?? + new PollingCounter("number-of-active-connection-pool-groups", this, () => _activeConnectionPoolsCounter) + { + DisplayName = "Number of active unique connection strings", + DisplayUnits = "count" + }; + + _numberOfInactiveConnectionPoolGroups = _numberOfInactiveConnectionPoolGroups ?? + new PollingCounter("number-of-inactive-connection-pool-groups", this, () => _inactiveConnectionPoolGroupsCounter) + { + DisplayName = "Number of unique connection strings waiting for pruning", + DisplayUnits = "count" + }; + + _numberOfActiveConnectionPools = _numberOfActiveConnectionPools ?? + new PollingCounter("number-of-active-connection-pools", this, () => _activeConnectionPoolsCounter) + { + DisplayName = "Number of active connection pools", + DisplayUnits = "count" + }; + + _numberOfInactiveConnectionPools = _numberOfInactiveConnectionPools ?? + new PollingCounter("number-of-inactive-connection-pools", this, () => _inactiveConnectionPoolsCounter) + { + DisplayName = "Number of inactive connection pools", + DisplayUnits = "count" + }; + + _numberOfActiveConnections = _numberOfActiveConnections ?? + new PollingCounter("number-of-active-connections", this, () => _activeConnectionsCounter) + { + DisplayName = "Number of active connections", + DisplayUnits = "count" + }; + + _numberOfFreeConnections = _numberOfFreeConnections ?? + new PollingCounter("number-of-free-connections", this, () => _freeConnectionsCounter) + { + DisplayName = "Number of free-ready connections", + DisplayUnits = "count" + }; + + _numberOfStasisConnections = _numberOfStasisConnections ?? + new PollingCounter("number-of-stasis-connections", this, () => _stasisConnectionsCounter) + { + DisplayName = "Number of connections currently waiting to be ready", + DisplayUnits = "count" + }; + + _numberOfReclaimedConnections = _numberOfReclaimedConnections ?? + new IncrementingPollingCounter("number-of-reclaimed-connections", this, () => _reclaimedConnectionsCounter) + { + DisplayName = "Number of reclaimed connections from GC", + DisplayUnits = "count", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + } + + /// + /// The number of actual connections that are being made to servers + /// + [NonEvent] + internal void HardConnectRequest() + { + if (IsEnabled()) + { + Interlocked.Increment(ref _activeHardConnectionsCounter); + Interlocked.Increment(ref _hardConnectsCounter); + } + } + + /// + /// The number of actual disconnects that are being made to servers + /// + [NonEvent] + internal void HardDisconnectRequest() + { + if (IsEnabled()) + { + Interlocked.Decrement(ref _activeHardConnectionsCounter); + Interlocked.Increment(ref _hardDisconnectsCounter); + } + } + + /// + /// The number of connections we get from the pool + /// + [NonEvent] + internal void SoftConnectRequest() + { + if (IsEnabled()) + { + Interlocked.Increment(ref _activeSoftConnectionsCounter); + Interlocked.Increment(ref _softConnectsCounter); + } + } + + /// + /// The number of connections we return to the pool + /// + [NonEvent] + internal void SoftDisconnectRequest() + { + if (IsEnabled()) + { + Interlocked.Decrement(ref _activeSoftConnectionsCounter); + Interlocked.Increment(ref _softDisconnectsCounter); + } + } + + /// + /// The number of connections that are not using connection pooling + /// + /// + [NonEvent] + internal void NonPooledConnectionRequest(bool increment = true) + { + Request(ref _nonPooledConnectionsCounter, increment); + } + + /// + /// The number of connections that are managed by the connection pooler + /// + /// + [NonEvent] + internal void PooledConnectionRequest(bool increment = true) + { + Request(ref _pooledConnectionsCounter, increment); + } + + /// + /// The number of unique connection strings + /// + /// + [NonEvent] + internal void ActiveConnectionPoolGroupRequest(bool increment = true) + { + Request(ref _activeConnectionPoolGroupsCounter, increment); + } + + /// + /// The number of unique connection strings waiting for pruning + /// + /// + [NonEvent] + internal void InactiveConnectionPoolGroupRequest(bool increment = true) + { + Request(ref _inactiveConnectionPoolGroupsCounter, increment); + } + + /// + /// The number of connection pools + /// + /// + [NonEvent] + internal void ActiveConnectionPoolRequest(bool increment = true) + { + Request(ref _activeConnectionPoolsCounter, increment); + } + + /// + /// The number of connection pools + /// + /// + [NonEvent] + internal void InactiveConnectionPoolRequest(bool increment = true) + { + Request(ref _inactiveConnectionPoolsCounter, increment); + } + + /// + /// The number of connections currently in-use + /// + /// + [NonEvent] + internal void ActiveConnectionRequest(bool increment = true) + { + Request(ref _activeConnectionsCounter, increment); + } + + /// + /// The number of connections currently available for use + /// + /// + [NonEvent] + internal void FreeConnectionRequest(bool increment = true) + { + Request(ref _freeConnectionsCounter, increment); + } + + /// + /// The number of connections currently waiting to be made ready for use + /// + /// + [NonEvent] + internal void StasisConnectionRequest(bool increment = true) + { + Request(ref _stasisConnectionsCounter, increment); + } + + /// + /// The number of connections we reclaim from GC'd external connections + /// + [NonEvent] + internal void ReclaimedConnectionRequest() + { + Request(ref _reclaimedConnectionsCounter, true); + } + + [NonEvent] + private void Request(ref long counter, bool increment) + { + if (IsEnabled()) + { + if (increment) + { + Interlocked.Increment(ref counter); + } + else + { + Interlocked.Decrement(ref counter); + } + } + } + } +} diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 927ddf3c95..a63ed87bce 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -318,16 +318,10 @@ - - Component - - - Component - + + - - Component - + @@ -335,9 +329,7 @@ - - Component - + @@ -407,9 +399,7 @@ - - Component - + diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.Windows.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.Windows.cs index f9af6024e4..cc5db8c738 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.Windows.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.Windows.cs @@ -8,7 +8,7 @@ namespace Microsoft.Data.SqlClient { - internal partial class SqlClientEventSource : EventSource + internal partial class SqlClientEventSource : SqlClientEventSourceBase { private bool _traceLoggingProviderEnabled = false; @@ -29,6 +29,7 @@ internal partial class SqlClientEventSource : EventSource protected override void OnEventCommand(EventCommandEventArgs e) { + base.OnEventCommand(e); // Internally, EventListener.EnableEvents sends an event command, with a reserved value of 0, -2, or -3. // When a command is sent via EnableEvents or SendCommand, check if it is a user-defined value // to enable or disable event tracing in sni.dll. diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs index a2d49e96c8..2febb4b5d9 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs @@ -7,8 +7,19 @@ namespace Microsoft.Data.SqlClient { + internal abstract class SqlClientEventSourceBase : EventSource + { + protected override void OnEventCommand(EventCommandEventArgs command) + { + base.OnEventCommand(command); + EventCommandMethodCall(command); + } + + protected virtual void EventCommandMethodCall(EventCommandEventArgs command){} + } + [EventSource(Name = "Microsoft.Data.SqlClient.EventSource")] - internal partial class SqlClientEventSource : EventSource + internal partial class SqlClientEventSource : SqlClientEventSourceBase { // Defines the singleton instance for the Resources ETW provider internal static readonly SqlClientEventSource Log = new SqlClientEventSource(); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index e65d4e6693..e089868555 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -15,6 +15,7 @@ using Microsoft.Identity.Client; using Microsoft.Data.SqlClient.TestUtilities; using Xunit; +using System.Linq; namespace Microsoft.Data.SqlClient.ManualTesting.Tests { @@ -688,20 +689,62 @@ public static string RetrieveValueFromConnStr(string connStr, string[] keywords) public class TraceEventListener : EventListener { + private const string Name = "Name"; + public List IDs = new List(); + + public Dictionary EventCounters { get; private set; } + + public TraceEventListener() + { + EventCounters = new Dictionary + { + { "active-hard-connections", 0 }, + { "hard-connects", 0 }, + { "hard-disconnects", 0 }, + { "active-soft-connects", 0 }, + { "soft-connects", 0 }, + { "soft-disconnects", 0 }, + { "number-of-non-pooled-connections", 0 }, + { "number-of-pooled-connections", 0 }, + { "number-of-active-connection-pool-groups", 0 }, + { "number-of-inactive-connection-pool-groups", 0 }, + { "number-of-active-connection-pools", 0 }, + { "number-of-inactive-connection-pools", 0 }, + { "number-of-active-connections", 0 }, + { "number-of-free-connections", 0 }, + { "number-of-stasis-connections", 0 }, + { "number-of-reclaimed-connections", 0 } + }; + } protected override void OnEventSourceCreated(EventSource eventSource) { if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource")) { +#if netcoreapp + var options = new Dictionary(); + options.Add("EventCounterIntervalSec", "1"); // Collect all traces for better code coverage + EnableEvents(eventSource, EventLevel.Informational, EventKeywords.All, options); +#else EnableEvents(eventSource, EventLevel.Informational, EventKeywords.All); +#endif } } protected override void OnEventWritten(EventWrittenEventArgs eventData) { - IDs.Add(eventData.EventId); +#if netcoreapp + object counter = null; + eventData.Payload.FirstOrDefault(p => p is IDictionary x && x.TryGetValue(Name, out counter)); + if (counter is string cntName && EventCounters.ContainsKey(cntName)) + { + EventCounters[cntName] += 1; + } + else +#endif + IDs.Add(eventData.EventId); } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventSourceTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventSourceTest.cs index a6a1d2287c..08ae370fe9 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventSourceTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventSourceTest.cs @@ -2,7 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -33,5 +36,39 @@ public void EventSourceTestAll() Assert.All(TraceListener.IDs, item => { Assert.Contains(item, Enumerable.Range(1, 21)); }); } } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public void EventCounterTestAll() + { + var stringBuilder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) + { + Pooling = true, + MaxPoolSize = 20 + }; + + using (var TraceListener = new DataTestUtility.TraceEventListener()) + { + OpenConnections(stringBuilder.ConnectionString); + stringBuilder.Pooling = false; + OpenConnections(stringBuilder.ConnectionString); + + Thread.Sleep(3000); //wait to complete sampling! + Assert.All(TraceListener.EventCounters, item => Assert.True(item.Value > 0)); + } + } + + private void OpenConnections(string cnnString) + { + List tasks = new List(); + + Enumerable.Range(1, 100).ToList().ForEach(i => + { + SqlConnection cnn = new SqlConnection(cnnString); + cnn.Open(); + int x = i; + tasks.Add(Task.Run(() => { Thread.Sleep(x); cnn.Close(); })); + }); + Task.WhenAll(tasks).Wait(); + } } }