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 279c861b45..42ca312302 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
@@ -227,6 +227,9 @@
Microsoft\Data\SqlClient\Diagnostics\SqlClientConnectionOpenError.netcore.cs
+
+ Microsoft\Data\SqlClient\Diagnostics\SqlClientMetrics.cs
+
Microsoft\Data\SqlClient\Diagnostics\SqlClientTransactionCommitAfter.netcore.cs
@@ -745,7 +748,6 @@
-
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.NetCoreApp.cs
deleted file mode 100644
index c0312ca219..0000000000
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs
+++ /dev/null
@@ -1,396 +0,0 @@
-// 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 currently made to servers",
- DisplayUnits = "count"
- };
-
- _hardConnectsPerSecond = _hardConnectsPerSecond ??
- new IncrementingPollingCounter("hard-connects", this, () => _hardConnectsCounter)
- {
- DisplayName = "Actual connection rate to servers",
- DisplayUnits = "count / sec",
- DisplayRateTimeScale = TimeSpan.FromSeconds(1)
- };
-
- _hardDisconnectsPerSecond = _hardDisconnectsPerSecond ??
- new IncrementingPollingCounter("hard-disconnects", this, () => _hardDisconnectsCounter)
- {
- DisplayName = "Actual disconnection rate from servers",
- DisplayUnits = "count / sec",
- DisplayRateTimeScale = TimeSpan.FromSeconds(1)
- };
-
- _activeSoftConnections = _activeSoftConnections ??
- new PollingCounter("active-soft-connects", this, () => _activeSoftConnectionsCounter)
- {
- DisplayName = "Active connections retrieved from the connection pool",
- DisplayUnits = "count"
- };
-
- _softConnects = _softConnects ??
- new IncrementingPollingCounter("soft-connects", this, () => _softConnectsCounter)
- {
- DisplayName = "Rate of connections retrieved from the connection pool",
- DisplayUnits = "count / sec",
- DisplayRateTimeScale = TimeSpan.FromSeconds(1)
- };
-
- _softDisconnects = _softDisconnects ??
- new IncrementingPollingCounter("soft-disconnects", this, () => _softDisconnectsCounter)
- {
- DisplayName = "Rate of 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 not using connection pooling",
- DisplayUnits = "count"
- };
-
- _numberOfPooledConnections = _numberOfPooledConnections ??
- new PollingCounter("number-of-pooled-connections", this, () => _pooledConnectionsCounter)
- {
- DisplayName = "Number of connections managed by the connection pool",
- DisplayUnits = "count"
- };
-
- _numberOfActiveConnectionPoolGroups = _numberOfActiveConnectionPoolGroups ??
- new PollingCounter("number-of-active-connection-pool-groups", this, () => _activeConnectionPoolGroupsCounter)
- {
- 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 ready connections in the connection pool",
- 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 override void HardConnectRequest()
- {
- Interlocked.Increment(ref _activeHardConnectionsCounter);
- Interlocked.Increment(ref _hardConnectsCounter);
- }
-
- ///
- /// The number of actual disconnects that are being made to servers
- ///
- [NonEvent]
- internal override void HardDisconnectRequest()
- {
- Interlocked.Decrement(ref _activeHardConnectionsCounter);
- Interlocked.Increment(ref _hardDisconnectsCounter);
- }
-
- ///
- /// The number of connections we get from the pool
- ///
- [NonEvent]
- internal override void SoftConnectRequest()
- {
- Interlocked.Increment(ref _activeSoftConnectionsCounter);
- Interlocked.Increment(ref _softConnectsCounter);
- }
-
- ///
- /// The number of connections we return to the pool
- ///
- [NonEvent]
- internal override void SoftDisconnectRequest()
- {
- Interlocked.Decrement(ref _activeSoftConnectionsCounter);
- Interlocked.Increment(ref _softDisconnectsCounter);
- }
-
- ///
- /// The number of connections that are not using connection pooling
- ///
- [NonEvent]
- internal override void EnterNonPooledConnection()
- {
- Interlocked.Increment(ref _nonPooledConnectionsCounter);
- }
-
- ///
- /// The number of connections that are not using connection pooling
- ///
- [NonEvent]
- internal override void ExitNonPooledConnection()
- {
- Interlocked.Decrement(ref _nonPooledConnectionsCounter);
- }
-
- ///
- /// The number of connections that are managed by the connection pool
- ///
- [NonEvent]
- internal override void EnterPooledConnection()
- {
- Interlocked.Increment(ref _pooledConnectionsCounter);
- }
-
- ///
- /// The number of connections that are managed by the connection pool
- ///
- [NonEvent]
- internal override void ExitPooledConnection()
- {
- Interlocked.Decrement(ref _pooledConnectionsCounter);
- }
-
- ///
- /// The number of unique connection strings
- ///
- [NonEvent]
- internal override void EnterActiveConnectionPoolGroup()
- {
- Interlocked.Increment(ref _activeConnectionPoolGroupsCounter);
- }
-
- ///
- /// The number of unique connection strings
- ///
- [NonEvent]
- internal override void ExitActiveConnectionPoolGroup()
- {
- Interlocked.Decrement(ref _activeConnectionPoolGroupsCounter);
- }
-
- ///
- /// The number of unique connection strings waiting for pruning
- ///
- [NonEvent]
- internal override void EnterInactiveConnectionPoolGroup()
- {
- Interlocked.Increment(ref _inactiveConnectionPoolGroupsCounter);
- }
-
- ///
- /// The number of unique connection strings waiting for pruning
- ///
- [NonEvent]
- internal override void ExitInactiveConnectionPoolGroup()
- {
- Interlocked.Decrement(ref _inactiveConnectionPoolGroupsCounter);
- }
-
- ///
- /// The number of connection pools
- ///
- [NonEvent]
- internal override void EnterActiveConnectionPool()
- {
- Interlocked.Increment(ref _activeConnectionPoolsCounter);
- }
-
- ///
- /// The number of connection pools
- ///
- [NonEvent]
- internal override void ExitActiveConnectionPool()
- {
- Interlocked.Decrement(ref _activeConnectionPoolsCounter);
- }
-
- ///
- /// The number of connection pools
- ///
- [NonEvent]
- internal override void EnterInactiveConnectionPool()
- {
- Interlocked.Increment(ref _inactiveConnectionPoolsCounter);
- }
-
- ///
- /// The number of connection pools
- ///
- [NonEvent]
- internal override void ExitInactiveConnectionPool()
- {
- Interlocked.Decrement(ref _inactiveConnectionPoolsCounter);
- }
-
- ///
- /// The number of connections currently in-use
- ///
- [NonEvent]
- internal override void EnterActiveConnection()
- {
- Interlocked.Increment(ref _activeConnectionsCounter);
- }
-
- ///
- /// The number of connections currently in-use
- ///
- [NonEvent]
- internal override void ExitActiveConnection()
- {
- Interlocked.Decrement(ref _activeConnectionsCounter);
- }
-
- ///
- /// The number of connections currently available for use
- ///
- [NonEvent]
- internal override void EnterFreeConnection()
- {
- Interlocked.Increment(ref _freeConnectionsCounter);
- }
-
- ///
- /// The number of connections currently available for use
- ///
- [NonEvent]
- internal override void ExitFreeConnection()
- {
- Interlocked.Decrement(ref _freeConnectionsCounter);
- }
-
- ///
- /// The number of connections currently waiting to be made ready for use
- ///
- [NonEvent]
- internal override void EnterStasisConnection()
- {
- Interlocked.Increment(ref _stasisConnectionsCounter);
- }
-
- ///
- /// The number of connections currently waiting to be made ready for use
- ///
- [NonEvent]
- internal override void ExitStasisConnection()
- {
- Interlocked.Decrement(ref _stasisConnectionsCounter);
- }
-
- ///
- /// The number of connections we reclaim from GC'd external connections
- ///
- [NonEvent]
- internal override void ReclaimedConnectionRequest()
- {
- Interlocked.Increment(ref _reclaimedConnectionsCounter);
- }
- }
-}
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 7408ce42ac..8b8bda848e 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
@@ -288,9 +288,6 @@
Microsoft\Data\SqlClient\ConnectionPool\DbConnectionPoolAuthenticationContextKey.cs
-
- Microsoft\Data\SqlClient\ConnectionPool\DbConnectionPoolCounters.netfx.cs
-
Microsoft\Data\SqlClient\ConnectionPool\DbConnectionPoolGroup.cs
@@ -327,6 +324,9 @@
Microsoft\Data\SqlClient\ConnectionPool\SqlConnectionPoolProviderInfo.cs
+
+ Microsoft\Data\SqlClient\Diagnostics\SqlClientMetrics.cs
+
Microsoft\Data\ProviderBase\DbMetaDataFactory.cs
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionFactory.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionFactory.cs
index 34b496ab02..d3402a48bd 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionFactory.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionFactory.cs
@@ -18,7 +18,7 @@ namespace Microsoft.Data.SqlClient
{
sealed internal class SqlConnectionFactory : DbConnectionFactory
{
- private SqlConnectionFactory() : base(SqlPerformanceCounters.SingletonInstance)
+ private SqlConnectionFactory() : base()
{
}
@@ -343,19 +343,5 @@ override internal void SetInnerConnectionTo(DbConnection owningObject, DbConnect
}
}
-
- [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name = "FullTrust")]
- sealed internal class SqlPerformanceCounters : DbConnectionPoolCounters
- {
- private const string CategoryName = ".NET Data Provider for SqlServer";
- private const string CategoryHelp = "Counters for Microsoft.Data.SqlClient";
-
- public static readonly SqlPerformanceCounters SingletonInstance = new SqlPerformanceCounters();
-
- [System.Diagnostics.PerformanceCounterPermissionAttribute(System.Security.Permissions.SecurityAction.Assert, PermissionAccess = PerformanceCounterPermissionAccess.Write, MachineName = ".", CategoryName = CategoryName)]
- private SqlPerformanceCounters() : base(CategoryName, CategoryHelp)
- {
- }
- }
}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs
index f357e6109b..61c4e18579 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs
@@ -34,25 +34,6 @@ internal abstract class DbConnectionFactory
private static Task[] s_pendingOpenNonPooled = new Task[Environment.ProcessorCount];
private static Task s_completedTask;
-#if NETFRAMEWORK
- private readonly DbConnectionPoolCounters _performanceCounters;
-
- protected DbConnectionFactory() : this(DbConnectionPoolCountersNoCounters.SingletonInstance) { }
-
- protected DbConnectionFactory(DbConnectionPoolCounters performanceCounters)
- {
- _performanceCounters = performanceCounters;
- _connectionPoolGroups = new Dictionary();
- _poolsToRelease = new List();
- _poolGroupsToRelease = new List();
- _pruningTimer = CreatePruningTimer();
- }
-
- internal DbConnectionPoolCounters PerformanceCounters
- {
- get { return _performanceCounters; }
- }
-#else
protected DbConnectionFactory()
{
_connectionPoolGroups = new Dictionary();
@@ -60,7 +41,6 @@ protected DbConnectionFactory()
_poolGroupsToRelease = new List();
_pruningTimer = CreatePruningTimer();
}
-#endif
public abstract DbProviderFactory ProviderFactory
{
@@ -135,13 +115,8 @@ internal DbConnectionInternal CreateNonPooledConnection(DbConnection owningConne
DbConnectionInternal newConnection = CreateConnection(connectionOptions, poolKey, poolGroupProviderInfo, null, owningConnection, userOptions);
if (newConnection != null)
{
-#if NETFRAMEWORK
- PerformanceCounters.HardConnectsPerSecond.Increment();
- newConnection.MakeNonPooledObject(owningConnection, PerformanceCounters);
-#else
- SqlClientEventSource.Log.HardConnectRequest();
+ SqlClientEventSource.Metrics.HardConnectRequest();
newConnection.MakeNonPooledObject(owningConnection);
-#endif
}
SqlClientEventSource.Log.TryTraceEvent(" {0}, Non-pooled database connection created.", ObjectID);
return newConnection;
@@ -155,11 +130,8 @@ internal DbConnectionInternal CreatePooledConnection(DbConnectionPool pool, DbCo
if (newConnection != null)
{
-#if NETFRAMEWORK
- PerformanceCounters.HardConnectsPerSecond.Increment();
-#else
- SqlClientEventSource.Log.HardConnectRequest();
-#endif
+ SqlClientEventSource.Metrics.HardConnectRequest();
+
newConnection.MakePooledConnection(pool);
}
SqlClientEventSource.Log.TryTraceEvent(" {0}, Pooled database connection created.", ObjectID);
@@ -289,11 +261,8 @@ internal bool TryGetConnection(DbConnection owningConnection, TaskCompletionSour
}
connection = CreateNonPooledConnection(owningConnection, poolGroup, userOptions);
-#if NETFRAMEWORK
- PerformanceCounters.NumberOfNonPooledConnections.Increment();
-#else
- SqlClientEventSource.Log.EnterNonPooledConnection();
-#endif
+
+ SqlClientEventSource.Metrics.EnterNonPooledConnection();
}
else
{
@@ -397,11 +366,7 @@ private void TryGetConnectionCompletedContinuation(Task ta
}
else
{
-#if NETFRAMEWORK
- PerformanceCounters.NumberOfNonPooledConnections.Increment();
-#else
- SqlClientEventSource.Log.EnterNonPooledConnection();
-#endif
+ SqlClientEventSource.Metrics.EnterNonPooledConnection();
}
}
}
@@ -510,11 +475,8 @@ internal DbConnectionPoolGroup GetConnectionPoolGroup(DbConnectionPoolKey key, D
// lock prevents race condition with PruneConnectionPoolGroups
newConnectionPoolGroups.Add(key, newConnectionPoolGroup);
-#if NETFRAMEWORK
- PerformanceCounters.NumberOfActiveConnectionPoolGroups.Increment();
-#else
- SqlClientEventSource.Log.EnterActiveConnectionPoolGroup();
-#endif
+
+ SqlClientEventSource.Metrics.EnterActiveConnectionPoolGroup();
connectionPoolGroup = newConnectionPoolGroup;
_connectionPoolGroups = newConnectionPoolGroups;
}
@@ -579,11 +541,8 @@ private void PruneConnectionPoolGroups(object state)
{
_poolsToRelease.Remove(pool);
SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, ReleasePool={1}", ObjectID, pool.ObjectId);
-#if NETFRAMEWORK
- PerformanceCounters.NumberOfInactiveConnectionPools.Decrement();
-#else
- SqlClientEventSource.Log.ExitInactiveConnectionPool();
-#endif
+
+ SqlClientEventSource.Metrics.ExitInactiveConnectionPool();
}
}
}
@@ -608,11 +567,8 @@ private void PruneConnectionPoolGroups(object state)
{
_poolGroupsToRelease.Remove(poolGroup);
SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, ReleasePoolGroup={1}", ObjectID, poolGroup.ObjectID);
-#if NETFRAMEWORK
- PerformanceCounters.NumberOfInactiveConnectionPoolGroups.Decrement();
-#else
- SqlClientEventSource.Log.ExitInactiveConnectionPoolGroup();
-#endif
+
+ SqlClientEventSource.Metrics.ExitInactiveConnectionPoolGroup();
}
}
}
@@ -639,9 +595,6 @@ private void PruneConnectionPoolGroups(object state)
if (entry.Value.Prune())
{
// may add entries to _poolsToRelease
-#if NETFRAMEWORK
- PerformanceCounters.NumberOfActiveConnectionPoolGroups.Decrement();
-#endif
QueuePoolGroupForRelease(entry.Value);
}
else
@@ -674,12 +627,8 @@ internal void QueuePoolForRelease(DbConnectionPool pool, bool clearing)
}
_poolsToRelease.Add(pool);
}
-#if NETFRAMEWORK
- PerformanceCounters.NumberOfInactiveConnectionPools.Increment();
-#else
- SqlClientEventSource.Log.EnterInactiveConnectionPool();
- SqlClientEventSource.Log.ExitActiveConnectionPool();
-#endif
+ SqlClientEventSource.Metrics.EnterInactiveConnectionPool();
+ SqlClientEventSource.Metrics.ExitActiveConnectionPool();
}
internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup)
@@ -691,12 +640,9 @@ internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup)
{
_poolGroupsToRelease.Add(poolGroup);
}
-#if NETFRAMEWORK
- PerformanceCounters.NumberOfInactiveConnectionPoolGroups.Increment();
-#else
- SqlClientEventSource.Log.EnterInactiveConnectionPoolGroup();
- SqlClientEventSource.Log.ExitActiveConnectionPoolGroup();
-#endif
+
+ SqlClientEventSource.Metrics.EnterInactiveConnectionPoolGroup();
+ SqlClientEventSource.Metrics.ExitActiveConnectionPoolGroup();
}
virtual protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs
index 7268f00eea..b2cf6c25af 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs
@@ -324,10 +324,6 @@ protected internal DbConnection Owner
get => _owningObject.TryGetTarget(out DbConnection connection) ? connection : null;
}
- #if NETFRAMEWORK
- protected DbConnectionPoolCounters PerformanceCounters { get; private set; }
- #endif
-
protected virtual bool ReadyToPrepareTransaction
{
get => true;
@@ -368,11 +364,7 @@ internal void ActivateConnection(Transaction transaction)
Activate(transaction);
- #if NETFRAMEWORK
- PerformanceCounters.NumberOfActiveConnections.Increment();
- #else
- SqlClientEventSource.Log.EnterActiveConnection();
- #endif
+ SqlClientEventSource.Metrics.EnterActiveConnection();
}
internal void AddWeakReference(object value, int tag)
@@ -485,11 +477,7 @@ internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFac
// and transactions may not get cleaned up...
Deactivate();
- #if NETFRAMEWORK
- PerformanceCounters.HardDisconnectsPerSecond.Increment();
- #else
- SqlClientEventSource.Log.HardDisconnectRequest();
- #endif
+ SqlClientEventSource.Metrics.HardDisconnectRequest();
// To prevent an endless recursion, we need to clear the owning object
// before we call dispose so that we can't get here a second time...
@@ -504,16 +492,8 @@ internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFac
}
else
{
- #if NETFRAMEWORK
- PerformanceCounters.NumberOfNonPooledConnections.Decrement();
- if (this is not SqlInternalConnectionSmi)
- {
- Dispose();
- }
- #else
- SqlClientEventSource.Log.ExitNonPooledConnection();
+ SqlClientEventSource.Metrics.ExitNonPooledConnection();
Dispose();
- #endif
}
}
}
@@ -543,15 +523,7 @@ internal void DeactivateConnection()
Debug.Assert(activateCount == 0, "activated multiple times?");
#endif
- #if NETFRAMEWORK
- if (PerformanceCounters is not null)
- {
- // Pool.Clear will DestroyObject that will clean performanceCounters before going here
- PerformanceCounters.NumberOfActiveConnections.Decrement();
- }
- #else
- SqlClientEventSource.Log.ExitActiveConnection();
- #endif
+ SqlClientEventSource.Metrics.ExitActiveConnection();
if (!IsConnectionDoomed && Pool.UseLoadBalancing)
{
@@ -611,11 +583,7 @@ internal virtual void DelegatedTransactionEnded()
// once and for all, or the server will have fits about us
// leaving connections open until the client-side GC kicks
// in.
- #if NETFRAMEWORK
- PerformanceCounters.NumberOfNonPooledConnections.Decrement();
- #else
- SqlClientEventSource.Log.ExitNonPooledConnection();
- #endif
+ SqlClientEventSource.Metrics.ExitNonPooledConnection();
Dispose();
}
@@ -690,10 +658,6 @@ public virtual void Dispose()
IsConnectionDoomed = true;
_enlistedTransactionOriginal = null; // should not be disposed
- #if NETFRAMEWORK
- PerformanceCounters = null;
- #endif
-
// Dispose of the _enlistedTransaction since it is a clone of the original reference.
// VSDD 780271 - _enlistedTransaction can be changed by another thread (TX end event)
Transaction enlistedTransaction = Interlocked.Exchange(ref _enlistedTransaction, null);
@@ -723,16 +687,8 @@ public virtual void Dispose()
///
/// Used by DbConnectionFactory to indicate that this object IS NOT part of a connection pool.
///
- #if NETFRAMEWORK
- internal void MakeNonPooledObject(DbConnection owningObject, DbConnectionPoolCounters performanceCounters)
- #else
internal void MakeNonPooledObject(DbConnection owningObject)
- #endif
{
- #if NETFRAMEWORK
- PerformanceCounters = performanceCounters;
- #endif
-
Pool = null;
_owningObject.SetTarget(owningObject);
_pooledCount = -1;
@@ -746,10 +702,6 @@ internal void MakePooledConnection(DbConnectionPool connectionPool)
{
_createTime = DateTime.UtcNow;
Pool = connectionPool;
-
- #if NETFRAMEWORK
- PerformanceCounters = connectionPool.PerformanceCounters;
- #endif
}
internal void NotifyWeakReference(int message) =>
@@ -849,11 +801,7 @@ internal void SetInStasis()
IsTxRootWaitingForTxEnd = true;
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Non-Pooled Connection has Delegated Transaction, waiting to Dispose.", ObjectID);
- #if NETFRAMEWORK
- PerformanceCounters.NumberOfStasisConnections.Increment();
- #else
- SqlClientEventSource.Log.EnterStasisConnection();
- #endif
+ SqlClientEventSource.Metrics.EnterStasisConnection();
}
///
@@ -1005,11 +953,7 @@ private void TerminateStasis(bool returningToPool)
: "Delegated Transaction has ended, connection is closed/leaked. Disposing.";
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, {1}", ObjectID, message);
- #if NETFRAMEWORK
- PerformanceCounters.NumberOfStasisConnections.Decrement();
- #else
- SqlClientEventSource.Log.ExitStasisConnection();
- #endif
+ SqlClientEventSource.Metrics.ExitStasisConnection();
IsTxRootWaitingForTxEnd = false;
}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/DbConnectionPool.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/DbConnectionPool.cs
index a4efd25d2c..0d00227469 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/DbConnectionPool.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/DbConnectionPool.cs
@@ -33,9 +33,6 @@ internal abstract class DbConnectionPool
internal abstract bool IsRunning { get; }
-#if NETFRAMEWORK
- internal abstract DbConnectionPoolCounters PerformanceCounters { get; }
-#endif
internal abstract DbConnectionPoolGroup PoolGroup { get; }
internal abstract DbConnectionPoolGroupOptions PoolGroupOptions { get; }
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/DbConnectionPoolCounters.netfx.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/DbConnectionPoolCounters.netfx.cs
deleted file mode 100644
index 1ca4fe3aa6..0000000000
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/DbConnectionPoolCounters.netfx.cs
+++ /dev/null
@@ -1,361 +0,0 @@
-// 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 Interop.Windows.Kernel32;
-
-#if NETFRAMEWORK
-
-namespace Microsoft.Data.SqlClient.ConnectionPool
-{
-
- using System;
- using System.Diagnostics;
- using System.Reflection;
- using System.Runtime.ConstrainedExecution;
- using System.Runtime.Versioning;
- using System.Security.Permissions;
- using Microsoft.Data.Common;
-
- internal abstract class DbConnectionPoolCounters
- {
- private static class CreationData
- {
-
- static internal readonly CounterCreationData HardConnectsPerSecond = new CounterCreationData(
- "HardConnectsPerSecond",
- "The number of actual connections per second that are being made to servers",
- PerformanceCounterType.RateOfCountsPerSecond32);
-
- static internal readonly CounterCreationData HardDisconnectsPerSecond = new CounterCreationData(
- "HardDisconnectsPerSecond",
- "The number of actual disconnects per second that are being made to servers",
- PerformanceCounterType.RateOfCountsPerSecond32);
-
- static internal readonly CounterCreationData SoftConnectsPerSecond = new CounterCreationData(
- "SoftConnectsPerSecond",
- "The number of connections we get from the pool per second",
- PerformanceCounterType.RateOfCountsPerSecond32);
-
- static internal readonly CounterCreationData SoftDisconnectsPerSecond = new CounterCreationData(
- "SoftDisconnectsPerSecond",
- "The number of connections we return to the pool per second",
- PerformanceCounterType.RateOfCountsPerSecond32);
-
- static internal readonly CounterCreationData NumberOfNonPooledConnections = new CounterCreationData(
- "NumberOfNonPooledConnections",
- "The number of connections that are not using connection pooling",
- PerformanceCounterType.NumberOfItems32);
-
- static internal readonly CounterCreationData NumberOfPooledConnections = new CounterCreationData(
- "NumberOfPooledConnections",
- "The number of connections that are managed by the connection pooler",
- PerformanceCounterType.NumberOfItems32);
-
- static internal readonly CounterCreationData NumberOfActiveConnectionPoolGroups = new CounterCreationData(
- "NumberOfActiveConnectionPoolGroups",
- "The number of unique connection strings",
- PerformanceCounterType.NumberOfItems32);
-
- static internal readonly CounterCreationData NumberOfInactiveConnectionPoolGroups = new CounterCreationData(
- "NumberOfInactiveConnectionPoolGroups",
- "The number of unique connection strings waiting for pruning",
- PerformanceCounterType.NumberOfItems32);
-
- static internal readonly CounterCreationData NumberOfActiveConnectionPools = new CounterCreationData(
- "NumberOfActiveConnectionPools",
- "The number of connection pools",
- PerformanceCounterType.NumberOfItems32);
-
- static internal readonly CounterCreationData NumberOfInactiveConnectionPools = new CounterCreationData(
- "NumberOfInactiveConnectionPools",
- "The number of connection pools",
- PerformanceCounterType.NumberOfItems32);
-
- static internal readonly CounterCreationData NumberOfActiveConnections = new CounterCreationData(
- "NumberOfActiveConnections",
- "The number of connections currently in-use",
- PerformanceCounterType.NumberOfItems32);
-
- static internal readonly CounterCreationData NumberOfFreeConnections = new CounterCreationData(
- "NumberOfFreeConnections",
- "The number of connections currently available for use",
- PerformanceCounterType.NumberOfItems32);
-
- static internal readonly CounterCreationData NumberOfStasisConnections = new CounterCreationData(
- "NumberOfStasisConnections",
- "The number of connections currently waiting to be made ready for use",
- PerformanceCounterType.NumberOfItems32);
-
- static internal readonly CounterCreationData NumberOfReclaimedConnections = new CounterCreationData(
- "NumberOfReclaimedConnections",
- "The number of connections we reclaim from GC'd external connections",
- PerformanceCounterType.NumberOfItems32);
- };
-
- sealed internal class Counter
- {
- private PerformanceCounter _instance;
-
- internal Counter(string categoryName, string instanceName, string counterName, PerformanceCounterType counterType)
- {
- if (ADP.s_isPlatformNT5)
- {
- try
- {
- if (!string.IsNullOrEmpty(categoryName) && !string.IsNullOrEmpty(instanceName))
- {
- PerformanceCounter instance = new PerformanceCounter();
- instance.CategoryName = categoryName;
- instance.CounterName = counterName;
- instance.InstanceName = instanceName;
- instance.InstanceLifetime = PerformanceCounterInstanceLifetime.Process;
- instance.ReadOnly = false;
- instance.RawValue = 0; // make sure we start out at zero
- _instance = instance;
- }
- }
- catch (InvalidOperationException e)
- {
- ADP.TraceExceptionWithoutRethrow(e);
- // TODO: generate Application EventLog entry about inability to find perf counter
- }
- }
- }
-
-
- internal void Decrement()
- {
- PerformanceCounter instance = _instance;
- if (instance != null)
- {
- instance.Decrement();
- }
- }
-
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
- internal void Dispose()
- { // TODO: race condition, Dispose at the same time as Increment/Decrement
- PerformanceCounter instance = _instance;
- _instance = null;
- if (instance != null)
- {
- instance.RemoveInstance();
- // should we be calling instance.Close?
- // if we do will it exacerbate the Dispose vs. Decrement race condition
- //instance.Close();
- }
- }
-
- internal void Increment()
- {
- PerformanceCounter instance = _instance;
- if (instance != null)
- {
- instance.Increment();
- }
- }
- };
-
- const int CounterInstanceNameMaxLength = 127;
-
- internal readonly Counter HardConnectsPerSecond;
- internal readonly Counter HardDisconnectsPerSecond;
- internal readonly Counter SoftConnectsPerSecond;
- internal readonly Counter SoftDisconnectsPerSecond;
- internal readonly Counter NumberOfNonPooledConnections;
- internal readonly Counter NumberOfPooledConnections;
- internal readonly Counter NumberOfActiveConnectionPoolGroups;
- internal readonly Counter NumberOfInactiveConnectionPoolGroups;
- internal readonly Counter NumberOfActiveConnectionPools;
- internal readonly Counter NumberOfInactiveConnectionPools;
- internal readonly Counter NumberOfActiveConnections;
- internal readonly Counter NumberOfFreeConnections;
- internal readonly Counter NumberOfStasisConnections;
- internal readonly Counter NumberOfReclaimedConnections;
-
- protected DbConnectionPoolCounters() : this(null, null)
- {
- }
-
- protected DbConnectionPoolCounters(string categoryName, string categoryHelp)
- {
- AppDomain.CurrentDomain.DomainUnload += new EventHandler(this.UnloadEventHandler);
- AppDomain.CurrentDomain.ProcessExit += new EventHandler(this.ExitEventHandler);
- AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(this.ExceptionEventHandler);
-
- string instanceName = null;
-
- if (!string.IsNullOrEmpty(categoryName))
- {
- if (ADP.s_isPlatformNT5)
- {
- instanceName = GetInstanceName();
- }
- }
-
- // level 0-3: hard connects/disconnects, plus basic pool/pool entry statistics
- string basicCategoryName = categoryName;
- HardConnectsPerSecond = new Counter(basicCategoryName, instanceName, CreationData.HardConnectsPerSecond.CounterName, CreationData.HardConnectsPerSecond.CounterType);
- HardDisconnectsPerSecond = new Counter(basicCategoryName, instanceName, CreationData.HardDisconnectsPerSecond.CounterName, CreationData.HardDisconnectsPerSecond.CounterType);
- NumberOfNonPooledConnections = new Counter(basicCategoryName, instanceName, CreationData.NumberOfNonPooledConnections.CounterName, CreationData.NumberOfNonPooledConnections.CounterType);
- NumberOfPooledConnections = new Counter(basicCategoryName, instanceName, CreationData.NumberOfPooledConnections.CounterName, CreationData.NumberOfPooledConnections.CounterType);
- NumberOfActiveConnectionPoolGroups = new Counter(basicCategoryName, instanceName, CreationData.NumberOfActiveConnectionPoolGroups.CounterName, CreationData.NumberOfActiveConnectionPoolGroups.CounterType);
- NumberOfInactiveConnectionPoolGroups = new Counter(basicCategoryName, instanceName, CreationData.NumberOfInactiveConnectionPoolGroups.CounterName, CreationData.NumberOfInactiveConnectionPoolGroups.CounterType);
- NumberOfActiveConnectionPools = new Counter(basicCategoryName, instanceName, CreationData.NumberOfActiveConnectionPools.CounterName, CreationData.NumberOfActiveConnectionPools.CounterType);
- NumberOfInactiveConnectionPools = new Counter(basicCategoryName, instanceName, CreationData.NumberOfInactiveConnectionPools.CounterName, CreationData.NumberOfInactiveConnectionPools.CounterType);
- NumberOfStasisConnections = new Counter(basicCategoryName, instanceName, CreationData.NumberOfStasisConnections.CounterName, CreationData.NumberOfStasisConnections.CounterType);
- NumberOfReclaimedConnections = new Counter(basicCategoryName, instanceName, CreationData.NumberOfReclaimedConnections.CounterName, CreationData.NumberOfReclaimedConnections.CounterType);
-
- // level 4: expensive stuff
- string verboseCategoryName = null;
- if (!string.IsNullOrEmpty(categoryName))
- {
- // don't load TraceSwitch if no categoryName so that Odbc/OleDb have a chance of not loading TraceSwitch
- // which are also used by System.Diagnostics.PerformanceCounter.ctor & System.Transactions.get_Current
- TraceSwitch perfCtrSwitch = new TraceSwitch("ConnectionPoolPerformanceCounterDetail", "level of detail to track with connection pool performance counters");
- if (TraceLevel.Verbose == perfCtrSwitch.Level)
- {
- verboseCategoryName = categoryName;
- }
- }
- SoftConnectsPerSecond = new Counter(verboseCategoryName, instanceName, CreationData.SoftConnectsPerSecond.CounterName, CreationData.SoftConnectsPerSecond.CounterType);
- SoftDisconnectsPerSecond = new Counter(verboseCategoryName, instanceName, CreationData.SoftDisconnectsPerSecond.CounterName, CreationData.SoftDisconnectsPerSecond.CounterType);
- NumberOfActiveConnections = new Counter(verboseCategoryName, instanceName, CreationData.NumberOfActiveConnections.CounterName, CreationData.NumberOfActiveConnections.CounterType);
- NumberOfFreeConnections = new Counter(verboseCategoryName, instanceName, CreationData.NumberOfFreeConnections.CounterName, CreationData.NumberOfFreeConnections.CounterType);
- }
-
- [FileIOPermission(SecurityAction.Assert, Unrestricted = true)]
- private string GetAssemblyName()
- {
- string result = null;
-
- // First try GetEntryAssembly name, then AppDomain.FriendlyName.
- Assembly assembly = Assembly.GetEntryAssembly();
-
- if (assembly != null)
- {
- AssemblyName name = assembly.GetName();
- if (name != null)
- {
- result = name.Name; // MDAC 73469
- }
- }
- return result;
- }
-
- // SxS: this method uses GetCurrentProcessId to construct the instance name.
- // TODO: VSDD 534795 - remove the Resource* attributes if you do not use GetCurrentProcessId after the fix
- [ResourceExposure(ResourceScope.None)]
- [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
- private string GetInstanceName()
- {
- string result = null;
-
- string instanceName = GetAssemblyName(); // instance perfcounter name
-
- if (string.IsNullOrEmpty(instanceName))
- {
- AppDomain appDomain = AppDomain.CurrentDomain;
- if (appDomain != null)
- {
- instanceName = appDomain.FriendlyName;
- }
- }
-
- // TODO: If you do not use GetCurrentProcessId after fixing VSDD 534795, please remove Resource* attributes from this method
- int pid = Kernel32Safe.GetCurrentProcessId();
-
-
- // SQLBUDT #366157 -there are several characters which have special meaning
- // to PERFMON. They recommend that we translate them as shown below, to
- // prevent problems.
-
- result = String.Format((IFormatProvider)null, "{0}[{1}]", instanceName, pid);
- result = result.Replace('(', '[').Replace(')', ']').Replace('#', '_').Replace('/', '_').Replace('\\', '_');
-
- // SQLBUVSTS #94625 - counter instance name cannot be greater than 127
- if (result.Length > CounterInstanceNameMaxLength)
- {
- // Replacing the middle part with "[...]"
- // For example: if path is c:\long_path\very_(Ax200)_long__path\perftest.exe and process ID is 1234 than the resulted instance name will be:
- // c:\long_path\very_(AxM)[...](AxN)_long__path\perftest.exe[1234]
- // while M and N are adjusted to make each part before and after the [...] = 61 (making the total = 61 + 5 + 61 = 127)
- const string insertString = "[...]";
- int firstPartLength = (CounterInstanceNameMaxLength - insertString.Length) / 2;
- int lastPartLength = CounterInstanceNameMaxLength - firstPartLength - insertString.Length;
- result = string.Format((IFormatProvider)null, "{0}{1}{2}",
- result.Substring(0, firstPartLength),
- insertString,
- result.Substring(result.Length - lastPartLength, lastPartLength));
-
- Debug.Assert(result.Length == CounterInstanceNameMaxLength,
- string.Format((IFormatProvider)null, "wrong calculation of the instance name: expected {0}, actual: {1}", CounterInstanceNameMaxLength, result.Length));
- }
-
- return result;
- }
-
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
- public void Dispose()
- {
- // ExceptionEventHandler with IsTerminating may be called before
- // the Connection Close is called or the variables are initialized
- SafeDispose(HardConnectsPerSecond);
- SafeDispose(HardDisconnectsPerSecond);
- SafeDispose(SoftConnectsPerSecond);
- SafeDispose(SoftDisconnectsPerSecond);
- SafeDispose(NumberOfNonPooledConnections);
- SafeDispose(NumberOfPooledConnections);
- SafeDispose(NumberOfActiveConnectionPoolGroups);
- SafeDispose(NumberOfInactiveConnectionPoolGroups);
- SafeDispose(NumberOfActiveConnectionPools);
- SafeDispose(NumberOfActiveConnections);
- SafeDispose(NumberOfFreeConnections);
- SafeDispose(NumberOfStasisConnections);
- SafeDispose(NumberOfReclaimedConnections);
- }
-
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
- private void SafeDispose(Counter counter)
- { // WebData 103603
- if (counter != null)
- {
- counter.Dispose();
- }
- }
-
- [PrePrepareMethod]
- void ExceptionEventHandler(object sender, UnhandledExceptionEventArgs e)
- {
- if (e != null && e.IsTerminating)
- {
- Dispose();
- }
- }
-
- [PrePrepareMethod]
- void ExitEventHandler(object sender, EventArgs e)
- {
- Dispose();
- }
-
- [PrePrepareMethod]
- void UnloadEventHandler(object sender, EventArgs e)
- {
- Dispose();
- }
- }
-
- sealed internal class DbConnectionPoolCountersNoCounters : DbConnectionPoolCounters
- {
-
- public static readonly DbConnectionPoolCountersNoCounters SingletonInstance = new DbConnectionPoolCountersNoCounters();
-
- private DbConnectionPoolCountersNoCounters() : base()
- {
- }
- }
-}
-
-#endif
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/DbConnectionPoolGroup.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/DbConnectionPoolGroup.cs
index 5aaa4fdcd7..af3b2d6bdf 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/DbConnectionPoolGroup.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/DbConnectionPoolGroup.cs
@@ -132,9 +132,7 @@ internal int Clear()
if (pool != null)
{
DbConnectionFactory connectionFactory = pool.ConnectionFactory;
-#if NETFRAMEWORK
- connectionFactory.PerformanceCounters.NumberOfActiveConnectionPools.Decrement();
-#endif
+
connectionFactory.QueuePoolForRelease(pool, true);
}
}
@@ -197,10 +195,8 @@ internal DbConnectionPool GetConnectionPool(DbConnectionFactory connectionFactor
newPool.Startup(); // must start pool before usage
bool addResult = _poolCollection.TryAdd(currentIdentity, newPool);
Debug.Assert(addResult, "No other pool with current identity should exist at this point");
- SqlClientEventSource.Log.EnterActiveConnectionPool();
-#if NETFRAMEWORK
- connectionFactory.PerformanceCounters.NumberOfActiveConnectionPools.Increment();
-#endif
+ SqlClientEventSource.Metrics.EnterActiveConnectionPool();
+
pool = newPool;
}
else
@@ -276,9 +272,7 @@ internal bool Prune()
// pool into a list of pools to be released when they
// are completely empty.
DbConnectionFactory connectionFactory = pool.ConnectionFactory;
-#if NETFRAMEWORK
- connectionFactory.PerformanceCounters.NumberOfActiveConnectionPools.Decrement();
-#endif
+
connectionFactory.QueuePoolForRelease(pool, false);
}
else
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs
index 8dd1a7d745..9db1c7a5ec 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs
@@ -228,11 +228,8 @@ internal void PutTransactedObject(Transaction transaction, DbConnectionInternal
}
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Transaction {1}, Connection {2}, Added.", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID);
}
-#if NET
- SqlClientEventSource.Log.EnterFreeConnection();
-#else
- Pool.PerformanceCounters.NumberOfFreeConnections.Increment();
-#endif
+
+ SqlClientEventSource.Metrics.EnterFreeConnection();
}
internal void TransactionEnded(Transaction transaction, DbConnectionInternal transactedObject)
@@ -295,11 +292,8 @@ internal void TransactionEnded(Transaction transaction, DbConnectionInternal tra
// connections, we'll put it back...
if (0 <= entry)
{
-#if NET
- SqlClientEventSource.Log.ExitFreeConnection();
-#else
- Pool.PerformanceCounters.NumberOfFreeConnections.Decrement();
-#endif
+
+ SqlClientEventSource.Metrics.ExitFreeConnection();
Pool.PutObjectFromTransactedPool(transactedObject);
}
}
@@ -505,10 +499,6 @@ internal override bool IsRunning
private int MinPoolSize => PoolGroupOptions.MinPoolSize;
-#if NETFRAMEWORK
- internal override DbConnectionPoolCounters PerformanceCounters => _connectionFactory.PerformanceCounters;
-#endif
-
internal override DbConnectionPoolGroup PoolGroup => _connectionPoolGroup;
internal override DbConnectionPoolGroupOptions PoolGroupOptions => _connectionPoolGroupOptions;
@@ -559,11 +549,8 @@ private void CleanupCallback(object state)
{
Debug.Assert(obj != null, "null connection is not expected");
// If we obtained one from the old stack, destroy it.
-#if NET
- SqlClientEventSource.Log.ExitFreeConnection();
-#else
- PerformanceCounters.NumberOfFreeConnections.Decrement();
-#endif
+
+ SqlClientEventSource.Metrics.ExitFreeConnection();
// Transaction roots must survive even aging out (TxEnd event will clean them up).
bool shouldDestroy = true;
@@ -660,21 +647,15 @@ internal override void Clear()
while (_stackNew.TryPop(out obj))
{
Debug.Assert(obj != null, "null connection is not expected");
-#if NET
- SqlClientEventSource.Log.ExitFreeConnection();
-#else
- PerformanceCounters.NumberOfFreeConnections.Decrement();
-#endif
+
+ SqlClientEventSource.Metrics.ExitFreeConnection();
DestroyObject(obj);
}
while (_stackOld.TryPop(out obj))
{
Debug.Assert(obj != null, "null connection is not expected");
-#if NET
- SqlClientEventSource.Log.ExitFreeConnection();
-#else
- PerformanceCounters.NumberOfFreeConnections.Decrement();
-#endif
+
+ SqlClientEventSource.Metrics.ExitFreeConnection();
DestroyObject(obj);
}
@@ -749,11 +730,8 @@ private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectio
}
_objectList.Add(newObj);
_totalObjects = _objectList.Count;
-#if NET
- SqlClientEventSource.Log.EnterPooledConnection();
-#else
- PerformanceCounters.NumberOfPooledConnections.Increment(); // TODO: Performance: Consider moving outside of lock?
-#endif
+
+ SqlClientEventSource.Metrics.EnterPooledConnection();
}
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Connection {1}, Added to pool.", ObjectId, newObj?.ObjectID);
@@ -981,19 +959,13 @@ internal override void DestroyObject(DbConnectionInternal obj)
if (removed)
{
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Connection {1}, Removed from pool.", ObjectId, obj.ObjectID);
-#if NET
- SqlClientEventSource.Log.ExitPooledConnection();
-#else
- PerformanceCounters.NumberOfPooledConnections.Decrement();
-#endif
+
+ SqlClientEventSource.Metrics.ExitPooledConnection();
}
obj.Dispose();
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Connection {1}, Disposed.", ObjectId, obj.ObjectID);
-#if NET
- SqlClientEventSource.Log.HardDisconnectRequest();
-#else
- PerformanceCounters.HardDisconnectsPerSecond.Increment();
-#endif
+
+ SqlClientEventSource.Metrics.HardDisconnectRequest();
}
}
@@ -1199,9 +1171,7 @@ private bool TryGetConnection(DbConnection owningObject, uint waitForMultipleObj
{
DbConnectionInternal obj = null;
Transaction transaction = null;
-#if NETFRAMEWORK
- PerformanceCounters.SoftConnectsPerSecond.Increment();
-#endif
+
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Getting connection.", ObjectId);
// If automatic transaction enlistment is required, then we try to
@@ -1386,9 +1356,9 @@ private bool TryGetConnection(DbConnection owningObject, uint waitForMultipleObj
}
connection = obj;
-#if NET
- SqlClientEventSource.Log.SoftConnectRequest();
-#endif
+
+ SqlClientEventSource.Metrics.SoftConnectRequest();
+
return true;
}
@@ -1420,17 +1390,12 @@ private void PrepareConnection(DbConnection owningObject, DbConnectionInternal o
/// A new inner connection that is attached to the
internal override DbConnectionInternal ReplaceConnection(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
{
-#if NETFRAMEWORK
- PerformanceCounters.SoftConnectsPerSecond.Increment();
-#endif
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, replacing connection.", ObjectId);
DbConnectionInternal newConnection = UserCreateRequest(owningObject, userOptions, oldConnection);
if (newConnection != null)
{
-#if NET
- SqlClientEventSource.Log.SoftConnectRequest();
-#endif
+ SqlClientEventSource.Metrics.SoftConnectRequest();
PrepareConnection(owningObject, newConnection, oldConnection.EnlistedTransaction);
oldConnection.PrepareForReplaceConnection();
oldConnection.DeactivateConnection();
@@ -1468,11 +1433,8 @@ private DbConnectionInternal GetFromGeneralPool()
if (obj != null)
{
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Connection {1}, Popped from general pool.", ObjectId, obj.ObjectID);
-#if NET
- SqlClientEventSource.Log.ExitFreeConnection();
-#else
- PerformanceCounters.NumberOfFreeConnections.Decrement();
-#endif
+
+ SqlClientEventSource.Metrics.ExitFreeConnection();
}
return obj;
}
@@ -1489,11 +1451,8 @@ private DbConnectionInternal GetFromTransactedPool(out Transaction transaction)
if (obj != null)
{
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Connection {1}, Popped from transacted pool.", ObjectId, obj.ObjectID);
-#if NET
- SqlClientEventSource.Log.ExitFreeConnection();
-#else
- PerformanceCounters.NumberOfFreeConnections.Decrement();
-#endif
+
+ SqlClientEventSource.Metrics.ExitFreeConnection();
if (obj.IsTransactionRoot)
{
@@ -1662,11 +1621,8 @@ internal override void PutNewObject(DbConnectionInternal obj)
_stackNew.Push(obj);
_waitHandles.PoolSemaphore.Release(1);
-#if NET
- SqlClientEventSource.Log.EnterFreeConnection();
-#else
- PerformanceCounters.NumberOfFreeConnections.Increment();
-#endif
+
+ SqlClientEventSource.Metrics.EnterFreeConnection();
}
@@ -1674,11 +1630,7 @@ internal override void PutObject(DbConnectionInternal obj, object owningObject)
{
Debug.Assert(obj != null, "null obj?");
-#if NET
- SqlClientEventSource.Log.SoftDisconnectRequest();
-#else
- PerformanceCounters.SoftDisconnectsPerSecond.Increment();
-#endif
+ SqlClientEventSource.Metrics.SoftDisconnectRequest();
// Once a connection is closing (which is the state that we're in at
// this point in time) you cannot delegate a transaction to or enlist
@@ -1795,11 +1747,8 @@ private bool ReclaimEmancipatedObjects()
{
DbConnectionInternal obj = reclaimedObjects[i];
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Connection {1}, Reclaiming.", ObjectId, obj.ObjectID);
-#if NET
- SqlClientEventSource.Log.ReclaimedConnectionRequest();
-#else
- PerformanceCounters.NumberOfReclaimedConnections.Increment();
-#endif
+
+ SqlClientEventSource.Metrics.ReclaimedConnectionRequest();
emancipatedObjectFound = true;
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Diagnostics/SqlClientMetrics.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Diagnostics/SqlClientMetrics.cs
new file mode 100644
index 0000000000..f62c65b122
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Diagnostics/SqlClientMetrics.cs
@@ -0,0 +1,570 @@
+// 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;
+
+#if NET
+using System.Threading;
+#else
+using Interop.Windows.Kernel32;
+using Microsoft.Data.Common;
+
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.Versioning;
+using System.Security.Permissions;
+#endif
+
+#nullable enable
+
+namespace Microsoft.Data.SqlClient.Diagnostics
+{
+#if NETFRAMEWORK
+ [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
+#endif
+ internal sealed partial class SqlClientMetrics
+ {
+#if NETFRAMEWORK
+ private const string PerformanceCounterCategoryName = ".NET Data Provider for SqlServer";
+ private const string PerformanceCounterCategoryHelp = "Counters for Microsoft.Data.SqlClient";
+ private const int CounterInstanceNameMaxLength = 127;
+#endif
+
+ private readonly SqlClientEventSource _eventSource;
+ // The names of the below variables must match between .NET Framework and .NET Core.
+#if NET
+ private PollingCounter? _activeHardConnectionsCounter;
+ private long _activeHardConnections = 0;
+ private IncrementingPollingCounter? _hardConnectsPerSecondCounter;
+ private long _hardConnectsRate = 0;
+ private IncrementingPollingCounter? _hardDisconnectsPerSecondCounter;
+ private long _hardDisconnectsRate = 0;
+
+ private PollingCounter? _activeSoftConnectionsCounter;
+ private long _activeSoftConnections = 0;
+ private IncrementingPollingCounter? _softConnectsPerSecondCounter;
+ private long _softConnectsRate = 0;
+ private IncrementingPollingCounter? _softDisconnectsPerSecondCounter;
+ private long _softDisconnectsRate = 0;
+
+ private PollingCounter? _numberOfNonPooledConnectionsCounter;
+ private long _nonPooledConnections = 0;
+ private PollingCounter? _numberOfPooledConnectionsCounter;
+ private long _pooledConnections = 0;
+
+ private PollingCounter? _numberOfActiveConnectionPoolGroupsCounter;
+ private long _activeConnectionPoolGroups = 0;
+ private PollingCounter? _numberOfInactiveConnectionPoolGroupsCounter;
+ private long _inactiveConnectionPoolGroups = 0;
+
+ private PollingCounter? _numberOfActiveConnectionPoolsCounter;
+ private long _activeConnectionPools = 0;
+ private PollingCounter? _numberOfInactiveConnectionPoolsCounter;
+ private long _inactiveConnectionPools = 0;
+
+ private PollingCounter? _numberOfActiveConnectionsCounter;
+ private long _activeConnections = 0;
+ private PollingCounter? _numberOfFreeConnectionsCounter;
+ private long _freeConnections = 0;
+ private PollingCounter? _numberOfStasisConnectionsCounter;
+ private long _stasisConnections = 0;
+ private IncrementingPollingCounter? _numberOfReclaimedConnectionsCounter;
+ private long _reclaimedConnections = 0;
+#else
+ private PerformanceCounter? _hardConnectsRate;
+ private PerformanceCounter? _hardDisconnectsRate;
+ private PerformanceCounter? _softConnectsRate;
+ private PerformanceCounter? _softDisconnectsRate;
+ private PerformanceCounter? _nonPooledConnections;
+ private PerformanceCounter? _pooledConnections;
+ private PerformanceCounter? _activeConnectionPoolGroups;
+ private PerformanceCounter? _inactiveConnectionPoolGroups;
+ private PerformanceCounter? _activeConnectionPools;
+ private PerformanceCounter? _inactiveConnectionPools;
+ private PerformanceCounter? _activeConnections;
+ private PerformanceCounter? _freeConnections;
+ private PerformanceCounter? _stasisConnections;
+ private PerformanceCounter? _reclaimedConnections;
+
+ private string? _instanceName;
+#endif
+
+ public SqlClientMetrics(SqlClientEventSource eventSource)
+ {
+ _eventSource = eventSource;
+
+#if NETFRAMEWORK
+ // On .NET Framework, metrics are exposed as performance counters and are always enabled.
+ // On .NET Core, metrics are exposed as EventCounters, and require explicit enablement.
+ EnablePerformanceCounters();
+#endif
+ }
+
+#if NET
+ private static void IncrementPlatformSpecificCounter(ref long counter)
+ => Interlocked.Increment(ref counter);
+
+ private static void DecrementPlatformSpecificCounter(ref long counter)
+ => Interlocked.Decrement(ref counter);
+#else
+ // .NET Framework doesn't strictly require the PerformanceCounter parameter to be passed as a ref, but doing
+ // so means that IncrementPlatformSpecificCounter and DecrementPlatformSpecificCounter can be called in identical
+ // ways between .NET Framework and .NET Core.
+ private static void IncrementPlatformSpecificCounter(ref PerformanceCounter? counter)
+ => counter?.Increment();
+
+ private static void DecrementPlatformSpecificCounter(ref PerformanceCounter? counter)
+ => counter?.Decrement();
+#endif
+
+ ///
+ /// The number of actual connections that are being made to servers
+ ///
+ internal void HardConnectRequest()
+ {
+#if NET
+ IncrementPlatformSpecificCounter(ref _activeHardConnections);
+#endif
+ IncrementPlatformSpecificCounter(ref _hardConnectsRate);
+ }
+
+ ///
+ /// The number of actual disconnects that are being made to servers
+ ///
+ internal void HardDisconnectRequest()
+ {
+#if NET
+ DecrementPlatformSpecificCounter(ref _activeHardConnections);
+#endif
+ IncrementPlatformSpecificCounter(ref _hardDisconnectsRate);
+ }
+
+ ///
+ /// The number of connections we get from the pool
+ ///
+ internal void SoftConnectRequest()
+ {
+#if NET
+ IncrementPlatformSpecificCounter(ref _activeSoftConnections);
+#endif
+ IncrementPlatformSpecificCounter(ref _softConnectsRate);
+ }
+
+ ///
+ /// The number of connections we return to the pool
+ ///
+ internal void SoftDisconnectRequest()
+ {
+#if NET
+ DecrementPlatformSpecificCounter(ref _activeSoftConnections);
+#endif
+ IncrementPlatformSpecificCounter(ref _softDisconnectsRate);
+ }
+
+ ///
+ /// The number of connections that are not using connection pooling
+ ///
+ internal void EnterNonPooledConnection()
+ {
+ IncrementPlatformSpecificCounter(ref _nonPooledConnections);
+ }
+
+ ///
+ /// The number of connections that are not using connection pooling
+ ///
+ internal void ExitNonPooledConnection()
+ {
+ DecrementPlatformSpecificCounter(ref _nonPooledConnections);
+ }
+
+ ///
+ /// The number of connections that are managed by the connection pool
+ ///
+ internal void EnterPooledConnection()
+ {
+ IncrementPlatformSpecificCounter(ref _pooledConnections);
+ }
+
+ ///
+ /// The number of connections that are managed by the connection pool
+ ///
+ internal void ExitPooledConnection()
+ {
+ DecrementPlatformSpecificCounter(ref _pooledConnections);
+ }
+
+ ///
+ /// The number of unique connection strings
+ ///
+ internal void EnterActiveConnectionPoolGroup()
+ {
+ IncrementPlatformSpecificCounter(ref _activeConnectionPoolGroups);
+ }
+
+ ///
+ /// The number of unique connection strings
+ ///
+ internal void ExitActiveConnectionPoolGroup()
+ {
+ DecrementPlatformSpecificCounter(ref _activeConnectionPoolGroups);
+ }
+
+ ///
+ /// The number of unique connection strings waiting for pruning
+ ///
+ internal void EnterInactiveConnectionPoolGroup()
+ {
+ IncrementPlatformSpecificCounter(ref _inactiveConnectionPoolGroups);
+ }
+
+ ///
+ /// The number of unique connection strings waiting for pruning
+ ///
+ internal void ExitInactiveConnectionPoolGroup()
+ {
+ DecrementPlatformSpecificCounter(ref _inactiveConnectionPoolGroups);
+ }
+
+ ///
+ /// The number of connection pools
+ ///
+ internal void EnterActiveConnectionPool()
+ {
+ IncrementPlatformSpecificCounter(ref _activeConnectionPools);
+ }
+
+ ///
+ /// The number of connection pools
+ ///
+ internal void ExitActiveConnectionPool()
+ {
+ DecrementPlatformSpecificCounter(ref _activeConnectionPools);
+ }
+
+ ///
+ /// The number of connection pools
+ ///
+ internal void EnterInactiveConnectionPool()
+ {
+ IncrementPlatformSpecificCounter(ref _inactiveConnectionPools);
+ }
+
+ ///
+ /// The number of connection pools
+ ///
+ internal void ExitInactiveConnectionPool()
+ {
+ DecrementPlatformSpecificCounter(ref _inactiveConnectionPools);
+ }
+
+ ///
+ /// The number of connections currently in-use
+ ///
+ internal void EnterActiveConnection()
+ {
+ IncrementPlatformSpecificCounter(ref _activeConnections);
+ }
+
+ ///
+ /// The number of connections currently in-use
+ ///
+ internal void ExitActiveConnection()
+ {
+ DecrementPlatformSpecificCounter(ref _activeConnections);
+ }
+
+ ///
+ /// The number of connections currently available for use
+ ///
+ internal void EnterFreeConnection()
+ {
+ IncrementPlatformSpecificCounter(ref _freeConnections);
+ }
+
+ ///
+ /// The number of connections currently available for use
+ ///
+ internal void ExitFreeConnection()
+ {
+ DecrementPlatformSpecificCounter(ref _freeConnections);
+ }
+
+ ///
+ /// The number of connections currently waiting to be made ready for use
+ ///
+ internal void EnterStasisConnection()
+ {
+ IncrementPlatformSpecificCounter(ref _stasisConnections);
+ }
+
+ ///
+ /// The number of connections currently waiting to be made ready for use
+ ///
+ internal void ExitStasisConnection()
+ {
+ DecrementPlatformSpecificCounter(ref _stasisConnections);
+ }
+
+ ///
+ /// The number of connections we reclaim from GC'd external connections
+ ///
+ internal void ReclaimedConnectionRequest()
+ {
+ IncrementPlatformSpecificCounter(ref _reclaimedConnections);
+ }
+
+#if NET
+ public void EnableEventCounters()
+ {
+ _activeHardConnectionsCounter ??= new PollingCounter("active-hard-connections", _eventSource, () => _activeHardConnections)
+ {
+ DisplayName = "Actual active connections currently made to servers",
+ DisplayUnits = "count"
+ };
+
+ _hardConnectsPerSecondCounter ??= new IncrementingPollingCounter("hard-connects", _eventSource, () => _hardConnectsRate)
+ {
+ DisplayName = "Actual connection rate to servers",
+ DisplayUnits = "count / sec",
+ DisplayRateTimeScale = TimeSpan.FromSeconds(1)
+ };
+
+ _hardDisconnectsPerSecondCounter ??= new IncrementingPollingCounter("hard-disconnects", _eventSource, () => _hardDisconnectsRate)
+ {
+ DisplayName = "Actual disconnection rate from servers",
+ DisplayUnits = "count / sec",
+ DisplayRateTimeScale = TimeSpan.FromSeconds(1)
+ };
+
+ _activeSoftConnectionsCounter ??= new PollingCounter("active-soft-connects", _eventSource, () => _activeSoftConnections)
+ {
+ DisplayName = "Active connections retrieved from the connection pool",
+ DisplayUnits = "count"
+ };
+
+ _softConnectsPerSecondCounter ??= new IncrementingPollingCounter("soft-connects", _eventSource, () => _softConnectsRate)
+ {
+ DisplayName = "Rate of connections retrieved from the connection pool",
+ DisplayUnits = "count / sec",
+ DisplayRateTimeScale = TimeSpan.FromSeconds(1)
+ };
+
+ _softDisconnectsPerSecondCounter ??= new IncrementingPollingCounter("soft-disconnects", _eventSource, () => _softDisconnectsRate)
+ {
+ DisplayName = "Rate of connections returned to the connection pool",
+ DisplayUnits = "count / sec",
+ DisplayRateTimeScale = TimeSpan.FromSeconds(1)
+ };
+
+ _numberOfNonPooledConnectionsCounter ??= new PollingCounter("number-of-non-pooled-connections", _eventSource, () => _nonPooledConnections)
+ {
+ DisplayName = "Number of connections not using connection pooling",
+ DisplayUnits = "count"
+ };
+
+ _numberOfPooledConnectionsCounter ??= new PollingCounter("number-of-pooled-connections", _eventSource, () => _pooledConnections)
+ {
+ DisplayName = "Number of connections managed by the connection pool",
+ DisplayUnits = "count"
+ };
+
+ _numberOfActiveConnectionPoolGroupsCounter ??= new PollingCounter("number-of-active-connection-pool-groups", _eventSource, () => _activeConnectionPoolGroups)
+ {
+ DisplayName = "Number of active unique connection strings",
+ DisplayUnits = "count"
+ };
+
+ _numberOfInactiveConnectionPoolGroupsCounter ??= new PollingCounter("number-of-inactive-connection-pool-groups", _eventSource, () => _inactiveConnectionPoolGroups)
+ {
+ DisplayName = "Number of unique connection strings waiting for pruning",
+ DisplayUnits = "count"
+ };
+
+ _numberOfActiveConnectionPoolsCounter ??= new PollingCounter("number-of-active-connection-pools", _eventSource, () => _activeConnectionPools)
+ {
+ DisplayName = "Number of active connection pools",
+ DisplayUnits = "count"
+ };
+
+ _numberOfInactiveConnectionPoolsCounter ??= new PollingCounter("number-of-inactive-connection-pools", _eventSource, () => _inactiveConnectionPools)
+ {
+ DisplayName = "Number of inactive connection pools",
+ DisplayUnits = "count"
+ };
+
+ _numberOfActiveConnectionsCounter ??= new PollingCounter("number-of-active-connections", _eventSource, () => _activeConnections)
+ {
+ DisplayName = "Number of active connections",
+ DisplayUnits = "count"
+ };
+
+ _numberOfFreeConnectionsCounter ??= new PollingCounter("number-of-free-connections", _eventSource, () => _freeConnections)
+ {
+ DisplayName = "Number of ready connections in the connection pool",
+ DisplayUnits = "count"
+ };
+
+ _numberOfStasisConnectionsCounter ??= new PollingCounter("number-of-stasis-connections", _eventSource, () => _stasisConnections)
+ {
+ DisplayName = "Number of connections currently waiting to be ready",
+ DisplayUnits = "count"
+ };
+
+ _numberOfReclaimedConnectionsCounter ??= new IncrementingPollingCounter("number-of-reclaimed-connections", _eventSource, () => _reclaimedConnections)
+ {
+ DisplayName = "Number of reclaimed connections from GC",
+ DisplayUnits = "count",
+ DisplayRateTimeScale = TimeSpan.FromSeconds(1)
+ };
+ }
+#else
+ [PerformanceCounterPermission(SecurityAction.Assert, PermissionAccess = PerformanceCounterPermissionAccess.Write,
+ MachineName = ".", CategoryName = PerformanceCounterCategoryName)]
+ private void EnablePerformanceCounters()
+ {
+ AppDomain.CurrentDomain.DomainUnload += ExitOrUnloadEventHandler;
+ AppDomain.CurrentDomain.ProcessExit += ExitOrUnloadEventHandler;
+ AppDomain.CurrentDomain.UnhandledException += ExceptionEventHandler;
+
+ // level 0-3: hard connects/disconnects, plus basic pool/pool entry statistics
+ _hardConnectsRate = CreatePerformanceCounter("HardConnectsPerSecond", PerformanceCounterType.RateOfCountsPerSecond32);
+ _hardDisconnectsRate = CreatePerformanceCounter("HardDisconnectsPerSecond", PerformanceCounterType.RateOfCountsPerSecond32);
+ _nonPooledConnections = CreatePerformanceCounter("NumberOfNonPooledConnections", PerformanceCounterType.NumberOfItems32);
+ _pooledConnections = CreatePerformanceCounter("NumberOfPooledConnections", PerformanceCounterType.NumberOfItems32);
+ _activeConnectionPoolGroups = CreatePerformanceCounter("NumberOfActiveConnectionPoolGroups", PerformanceCounterType.NumberOfItems32);
+ _inactiveConnectionPoolGroups = CreatePerformanceCounter("NumberOfInactiveConnectionPoolGroups", PerformanceCounterType.NumberOfItems32);
+ _activeConnectionPools = CreatePerformanceCounter("NumberOfActiveConnectionPools", PerformanceCounterType.NumberOfItems32);
+ _inactiveConnectionPools = CreatePerformanceCounter("NumberOfInactiveConnectionPools", PerformanceCounterType.NumberOfItems32);
+ _stasisConnections = CreatePerformanceCounter("NumberOfStasisConnections", PerformanceCounterType.NumberOfItems32);
+ _reclaimedConnections = CreatePerformanceCounter("NumberOfReclaimedConnections", PerformanceCounterType.NumberOfItems32);
+
+ TraceSwitch perfCtrSwitch = new TraceSwitch("ConnectionPoolPerformanceCounterDetail", "level of detail to track with connection pool performance counters");
+ if (TraceLevel.Verbose == perfCtrSwitch.Level)
+ {
+ _softConnectsRate = CreatePerformanceCounter("SoftConnectsPerSecond", PerformanceCounterType.RateOfCountsPerSecond32);
+ _softDisconnectsRate = CreatePerformanceCounter("SoftDisconnectsPerSecond", PerformanceCounterType.RateOfCountsPerSecond32);
+ _activeConnections = CreatePerformanceCounter("NumberOfActiveConnections", PerformanceCounterType.NumberOfItems32);
+ _freeConnections = CreatePerformanceCounter("NumberOfFreeConnections", PerformanceCounterType.NumberOfItems32);
+ }
+ }
+
+ [PrePrepareMethod]
+ private void ExitOrUnloadEventHandler(object sender, EventArgs e)
+ {
+ RemovePerformanceCounters();
+ }
+
+ [PrePrepareMethod]
+ private void ExceptionEventHandler(object sender, UnhandledExceptionEventArgs e)
+ {
+ if (e != null && e.IsTerminating)
+ {
+ RemovePerformanceCounters();
+ }
+ }
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+ private void RemovePerformanceCounters()
+ {
+ // ExceptionEventHandler with IsTerminating may be called before
+ // the Connection Close is called or the variables are initialized
+ _hardConnectsRate?.RemoveInstance();
+ _hardDisconnectsRate?.RemoveInstance();
+ _softConnectsRate?.RemoveInstance();
+ _softDisconnectsRate?.RemoveInstance();
+ _nonPooledConnections?.RemoveInstance();
+ _pooledConnections?.RemoveInstance();
+ _activeConnectionPoolGroups?.RemoveInstance();
+ _inactiveConnectionPoolGroups?.RemoveInstance();
+ _activeConnectionPools?.RemoveInstance();
+ _inactiveConnectionPools?.RemoveInstance();
+ _activeConnections?.RemoveInstance();
+ _freeConnections?.RemoveInstance();
+ _stasisConnections?.RemoveInstance();
+ _reclaimedConnections?.RemoveInstance();
+ }
+
+ private PerformanceCounter? CreatePerformanceCounter(string counterName, PerformanceCounterType counterType)
+ {
+ PerformanceCounter? instance = null;
+
+ _instanceName ??= GetInstanceName();
+ try
+ {
+ instance = new PerformanceCounter();
+ instance.CategoryName = PerformanceCounterCategoryName;
+ instance.CounterName = counterName;
+ instance.InstanceName = _instanceName;
+ instance.InstanceLifetime = PerformanceCounterInstanceLifetime.Process;
+ instance.ReadOnly = false;
+ instance.RawValue = 0; // make sure we start out at zero
+ }
+ catch (InvalidOperationException e)
+ {
+ ADP.TraceExceptionWithoutRethrow(e);
+ }
+
+ return instance;
+ }
+
+ // SxS: this method uses GetCurrentProcessId to construct the instance name.
+ // TODO: VSDD 534795 - remove the Resource* attributes if you do not use GetCurrentProcessId after the fix
+ [ResourceExposure(ResourceScope.None)]
+ [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
+ private static string GetInstanceName()
+ {
+ string result;
+ string? instanceName = GetAssemblyName(); // instance perfcounter name
+
+ if (string.IsNullOrEmpty(instanceName))
+ {
+ instanceName = AppDomain.CurrentDomain?.FriendlyName;
+ }
+
+ // TODO: If you do not use GetCurrentProcessId after fixing VSDD 534795, please remove Resource* attributes from this method
+ int pid = Kernel32Safe.GetCurrentProcessId();
+
+ // SQLBUDT #366157 -there are several characters which have special meaning
+ // to PERFMON. They recommend that we translate them as shown below, to
+ // prevent problems.
+
+ result = string.Format(null, "{0}[{1}]", instanceName, pid);
+ result = result.Replace('(', '[').Replace(')', ']').Replace('#', '_').Replace('/', '_').Replace('\\', '_');
+
+ // SQLBUVSTS #94625 - counter instance name cannot be greater than 127
+ if (result.Length > CounterInstanceNameMaxLength)
+ {
+ // Replacing the middle part with "[...]"
+ // For example: if path is c:\long_path\very_(Ax200)_long__path\perftest.exe and process ID is 1234 than the resulted instance name will be:
+ // c:\long_path\very_(AxM)[...](AxN)_long__path\perftest.exe[1234]
+ // while M and N are adjusted to make each part before and after the [...] = 61 (making the total = 61 + 5 + 61 = 127)
+ const string insertString = "[...]";
+ int firstPartLength = (CounterInstanceNameMaxLength - insertString.Length) / 2;
+ int lastPartLength = CounterInstanceNameMaxLength - firstPartLength - insertString.Length;
+ result = string.Format(null, "{0}{1}{2}",
+ result.Substring(0, firstPartLength),
+ insertString,
+ result.Substring(result.Length - lastPartLength, lastPartLength));
+
+ Debug.Assert(result.Length == CounterInstanceNameMaxLength,
+ string.Format(null, "wrong calculation of the instance name: expected {0}, actual: {1}", CounterInstanceNameMaxLength, result.Length));
+ }
+
+ return result;
+ }
+
+ [FileIOPermission(SecurityAction.Assert, Unrestricted = true)]
+ private static string? GetAssemblyName()
+ {
+ // First try GetEntryAssembly name, then AppDomain.FriendlyName.
+ Assembly? assembly = Assembly.GetEntryAssembly();
+ AssemblyName? name = assembly?.GetName();
+
+ return name?.Name;
+ }
+#endif
+ }
+}
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 c794cb0d2a..90a69b5670 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using Microsoft.Data.SqlClient.Diagnostics;
using System;
using System.Diagnostics.Tracing;
using System.Text;
@@ -9,78 +10,34 @@
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) { }
-
- #region not implemented for .Net core 2.1, .Net standard 2.0 and lower
- internal virtual void HardConnectRequest() { /*no-op*/ }
-
- internal virtual void HardDisconnectRequest() { /*no-op*/ }
-
- internal virtual void SoftConnectRequest() { /*no-op*/ }
-
- internal virtual void SoftDisconnectRequest() { /*no-op*/ }
-
- internal virtual void EnterNonPooledConnection() { /*no-op*/ }
-
- internal virtual void ExitNonPooledConnection() { /*no-op*/ }
-
- internal virtual void EnterPooledConnection() { /*no-op*/ }
-
- internal virtual void ExitPooledConnection() { /*no-op*/ }
-
- internal virtual void EnterActiveConnectionPoolGroup() { /*no-op*/ }
-
- internal virtual void ExitActiveConnectionPoolGroup() { /*no-op*/ }
-
- internal virtual void EnterInactiveConnectionPoolGroup() { /*no-op*/ }
-
- internal virtual void ExitInactiveConnectionPoolGroup() { /*no-op*/ }
-
- internal virtual void EnterActiveConnectionPool() { /*no-op*/ }
-
- internal virtual void ExitActiveConnectionPool() { /*no-op*/ }
-
- internal virtual void EnterInactiveConnectionPool() { /*no-op*/ }
-
- internal virtual void ExitInactiveConnectionPool() { /*no-op*/ }
-
- internal virtual void EnterActiveConnection() { /*no-op*/ }
-
- internal virtual void ExitActiveConnection() { /*no-op*/ }
-
- internal virtual void EnterFreeConnection() { /*no-op*/ }
-
- internal virtual void ExitFreeConnection() { /*no-op*/ }
-
- internal virtual void EnterStasisConnection() { /*no-op*/ }
-
- internal virtual void ExitStasisConnection() { /*no-op*/ }
-
- internal virtual void ReclaimedConnectionRequest() { /*no-op*/ }
- #endregion
- }
-
// Any changes to event writers might be considered as a breaking change.
// Other libraries such as OpenTelemetry and ApplicationInsight have based part of their code on BeginExecute and EndExecute arguments number.
[EventSource(Name = "Microsoft.Data.SqlClient.EventSource")]
- internal partial class SqlClientEventSource : SqlClientEventSourceBase
+ internal partial class SqlClientEventSource : EventSource
{
// Defines the singleton instance for the Resources ETW provider
- internal static readonly SqlClientEventSource Log = new();
+ public static readonly SqlClientEventSource Log = new();
+
+ // Provides access to metrics.
+ public static readonly SqlClientMetrics Metrics = new SqlClientMetrics(Log);
private SqlClientEventSource() { }
private const string NullStr = "null";
private const string SqlCommand_ClassName = nameof(SqlCommand);
+#if NET
+ protected override void OnEventCommand(EventCommandEventArgs command)
+ {
+ base.OnEventCommand(command);
+
+ if (command.Command == EventCommand.Enable)
+ {
+ Metrics.EnableEventCounters();
+ }
+ }
+#endif
+
#region Event IDs
// Initialized static Scope IDs
private static long s_nextScopeId = 0;
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
index bd5b6750f5..e3414ea7ee 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
@@ -249,8 +249,10 @@
+
+
+
-
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/MetricsTest.cs
similarity index 51%
rename from src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs
rename to src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/MetricsTest.cs
index 7a8e4bfe1a..4e90bbf6c7 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/MetricsTest.cs
@@ -9,18 +9,19 @@
namespace Microsoft.Data.SqlClient.ManualTesting.Tests
{
- ///
- /// This unit test is just valid for .NetCore 3.0 and above
- ///
- public class EventCounterTest
+ public class MetricsTest
{
- public EventCounterTest()
+#if NETFRAMEWORK
+ private readonly static TraceSwitch s_perfCtrSwitch = new TraceSwitch("ConnectionPoolPerformanceCounterDetail", "level of detail to track with connection pool performance counters");
+#endif
+
+ public MetricsTest()
{
ClearConnectionPools();
}
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
- public void EventCounter_HardConnectionsCounters_Functional()
+ public void NonPooledConnectionsCounters_Functional()
{
//create a non-pooled connection
var stringBuilder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { Pooling = false };
@@ -30,30 +31,39 @@ public void EventCounter_HardConnectionsCounters_Functional()
using (var conn = new SqlConnection(stringBuilder.ToString()))
{
- //initially we have no open physical connections
- Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
- SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
+ if (SupportsActiveConnectionCounters)
+ {
+ //initially we have no open physical connections
+ Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
+ SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
+ }
conn.Open();
//when the connection gets opened, the real physical connection appears
- Assert.Equal(ahc + 1, SqlClientEventSourceProps.ActiveHardConnections);
+ if (SupportsActiveConnectionCounters)
+ {
+ Assert.Equal(ahc + 1, SqlClientEventSourceProps.ActiveHardConnections);
+ Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
+ SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
+ }
Assert.Equal(npc + 1, SqlClientEventSourceProps.NonPooledConnections);
- Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
- SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
conn.Close();
//when the connection gets closed, the real physical connection is also closed
- Assert.Equal(ahc, SqlClientEventSourceProps.ActiveHardConnections);
+ if (SupportsActiveConnectionCounters)
+ {
+ Assert.Equal(ahc, SqlClientEventSourceProps.ActiveHardConnections);
+ Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
+ SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
+ }
Assert.Equal(npc, SqlClientEventSourceProps.NonPooledConnections);
- Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
- SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
}
}
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
- public void EventCounter_SoftConnectionsCounters_Functional()
+ public void PooledConnectionsCounters_Functional()
{
//create a pooled connection
var stringBuilder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { Pooling = true };
@@ -68,42 +78,57 @@ public void EventCounter_SoftConnectionsCounters_Functional()
using (var conn = new SqlConnection(stringBuilder.ToString()))
{
- //initially we have no open physical connections
- Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
- SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
- Assert.Equal(SqlClientEventSourceProps.ActiveSoftConnections,
- SqlClientEventSourceProps.SoftConnects - SqlClientEventSourceProps.SoftDisconnects);
+ if (SupportsActiveConnectionCounters)
+ {
+ //initially we have no open physical connections
+ Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
+ SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
+ Assert.Equal(SqlClientEventSourceProps.ActiveSoftConnections,
+ SqlClientEventSourceProps.SoftConnects - SqlClientEventSourceProps.SoftDisconnects);
+ }
conn.Open();
//when the connection gets opened, the real physical connection appears
//and the appropriate pooling infrastructure gets deployed
- Assert.Equal(ahc + 1, SqlClientEventSourceProps.ActiveHardConnections);
- Assert.Equal(asc + 1, SqlClientEventSourceProps.ActiveSoftConnections);
+ if (SupportsActiveConnectionCounters)
+ {
+ Assert.Equal(ahc + 1, SqlClientEventSourceProps.ActiveHardConnections);
+ Assert.Equal(asc + 1, SqlClientEventSourceProps.ActiveSoftConnections);
+ Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
+ SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
+ Assert.Equal(SqlClientEventSourceProps.ActiveSoftConnections,
+ SqlClientEventSourceProps.SoftConnects - SqlClientEventSourceProps.SoftDisconnects);
+ }
Assert.Equal(pc + 1, SqlClientEventSourceProps.PooledConnections);
Assert.Equal(npc, SqlClientEventSourceProps.NonPooledConnections);
Assert.Equal(acp + 1, SqlClientEventSourceProps.ActiveConnectionPools);
- Assert.Equal(ac + 1, SqlClientEventSourceProps.ActiveConnections);
- Assert.Equal(fc, SqlClientEventSourceProps.FreeConnections);
- Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
- SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
- Assert.Equal(SqlClientEventSourceProps.ActiveSoftConnections,
- SqlClientEventSourceProps.SoftConnects - SqlClientEventSourceProps.SoftDisconnects);
+ if (VerboseActiveConnectionCountersEnabled)
+ {
+ Assert.Equal(ac + 1, SqlClientEventSourceProps.ActiveConnections);
+ Assert.Equal(fc, SqlClientEventSourceProps.FreeConnections);
+ }
conn.Close();
//when the connection gets closed, the real physical connection gets returned to the pool
- Assert.Equal(ahc + 1, SqlClientEventSourceProps.ActiveHardConnections);
- Assert.Equal(asc, SqlClientEventSourceProps.ActiveSoftConnections);
+ if (SupportsActiveConnectionCounters)
+ {
+ Assert.Equal(ahc + 1, SqlClientEventSourceProps.ActiveHardConnections);
+ Assert.Equal(asc, SqlClientEventSourceProps.ActiveSoftConnections);
+ Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
+ SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
+ Assert.Equal(SqlClientEventSourceProps.ActiveSoftConnections,
+ SqlClientEventSourceProps.SoftConnects - SqlClientEventSourceProps.SoftDisconnects);
+ }
Assert.Equal(pc + 1, SqlClientEventSourceProps.PooledConnections);
Assert.Equal(npc, SqlClientEventSourceProps.NonPooledConnections);
Assert.Equal(acp + 1, SqlClientEventSourceProps.ActiveConnectionPools);
- Assert.Equal(ac, SqlClientEventSourceProps.ActiveConnections);
- Assert.Equal(fc + 1, SqlClientEventSourceProps.FreeConnections);
- Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
- SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
- Assert.Equal(SqlClientEventSourceProps.ActiveSoftConnections,
- SqlClientEventSourceProps.SoftConnects - SqlClientEventSourceProps.SoftDisconnects);
+ if (VerboseActiveConnectionCountersEnabled)
+ {
+ Assert.Equal(ac, SqlClientEventSourceProps.ActiveConnections);
+ Assert.Equal(fc + 1, SqlClientEventSourceProps.FreeConnections);
+ }
}
using (var conn2 = new SqlConnection(stringBuilder.ToString()))
@@ -111,22 +136,28 @@ public void EventCounter_SoftConnectionsCounters_Functional()
conn2.Open();
//the next open connection will reuse the underlying physical connection
- Assert.Equal(ahc + 1, SqlClientEventSourceProps.ActiveHardConnections);
- Assert.Equal(asc + 1, SqlClientEventSourceProps.ActiveSoftConnections);
+ if (SupportsActiveConnectionCounters)
+ {
+ Assert.Equal(ahc + 1, SqlClientEventSourceProps.ActiveHardConnections);
+ Assert.Equal(asc + 1, SqlClientEventSourceProps.ActiveSoftConnections);
+ Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
+ SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
+ Assert.Equal(SqlClientEventSourceProps.ActiveSoftConnections,
+ SqlClientEventSourceProps.SoftConnects - SqlClientEventSourceProps.SoftDisconnects);
+ }
Assert.Equal(pc + 1, SqlClientEventSourceProps.PooledConnections);
Assert.Equal(npc, SqlClientEventSourceProps.NonPooledConnections);
Assert.Equal(acp + 1, SqlClientEventSourceProps.ActiveConnectionPools);
- Assert.Equal(ac + 1, SqlClientEventSourceProps.ActiveConnections);
- Assert.Equal(fc, SqlClientEventSourceProps.FreeConnections);
- Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections,
- SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects);
- Assert.Equal(SqlClientEventSourceProps.ActiveSoftConnections,
- SqlClientEventSourceProps.SoftConnects - SqlClientEventSourceProps.SoftDisconnects);
+ if (VerboseActiveConnectionCountersEnabled)
+ {
+ Assert.Equal(ac + 1, SqlClientEventSourceProps.ActiveConnections);
+ Assert.Equal(fc, SqlClientEventSourceProps.FreeConnections);
+ }
}
}
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))]
- public void EventCounter_StasisCounters_Functional()
+ public void StasisCounters_Functional()
{
var stringBuilder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { Pooling = false, Enlist = false };
@@ -148,7 +179,7 @@ public void EventCounter_StasisCounters_Functional()
[ActiveIssue("https://github.com/dotnet/SqlClient/issues/3031")]
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
- public void EventCounter_ReclaimedConnectionsCounter_Functional()
+ public void ReclaimedConnectionsCounter_Functional()
{
// clean pools and pool groups
ClearConnectionPools();
@@ -180,7 +211,7 @@ public void EventCounter_ReclaimedConnectionsCounter_Functional()
}
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
- public void EventCounter_ConnectionPoolGroupsCounter_Functional()
+ public void ConnectionPoolGroupsCounter_Functional()
{
SqlConnection.ClearAllPools();
@@ -264,123 +295,139 @@ private static void PruneConnectionPoolGroups()
private static FieldInfo GetConnectionFactoryField()
{
+#if NET
FieldInfo connectionFactoryField =
typeof(SqlConnection).GetField("s_connectionFactory", BindingFlags.Static | BindingFlags.NonPublic);
+#else
+ FieldInfo connectionFactoryField =
+ typeof(SqlConnection).GetField("_connectionFactory", BindingFlags.Static | BindingFlags.NonPublic);
+#endif
Debug.Assert(connectionFactoryField != null);
return connectionFactoryField;
}
+
+ // Only the .NET Core build supports the active-hard-connections and active-soft-connects counters. The .NET Framework
+ // build doesn't have comparable performance counters.
+ private static bool SupportsActiveConnectionCounters =>
+#if NET
+ true;
+#else
+ false;
+#endif
+
+ private static bool VerboseActiveConnectionCountersEnabled =>
+ SupportsActiveConnectionCounters ||
+#if NET
+ true;
+#else
+ s_perfCtrSwitch.Level == TraceLevel.Verbose;
+#endif
}
internal static class SqlClientEventSourceProps
{
private static readonly object s_log;
- private static readonly FieldInfo _activeHardConnectionsCounter;
- private static readonly FieldInfo _hardConnectsCounter;
- private static readonly FieldInfo _hardDisconnectsCounter;
- private static readonly FieldInfo _activeSoftConnectionsCounter;
- private static readonly FieldInfo _softConnectsCounter;
- private static readonly FieldInfo _softDisconnectsCounter;
- private static readonly FieldInfo _nonPooledConnectionsCounter;
- private static readonly FieldInfo _pooledConnectionsCounter;
- private static readonly FieldInfo _activeConnectionPoolGroupsCounter;
- private static readonly FieldInfo _inactiveConnectionPoolGroupsCounter;
- private static readonly FieldInfo _activeConnectionPoolsCounter;
- private static readonly FieldInfo _inactiveConnectionPoolsCounter;
- private static readonly FieldInfo _activeConnectionsCounter;
- private static readonly FieldInfo _freeConnectionsCounter;
- private static readonly FieldInfo _stasisConnectionsCounter;
- private static readonly FieldInfo _reclaimedConnectionsCounter;
+ private static readonly Func s_getActiveHardConnections;
+ private static readonly Func s_getHardConnects;
+ private static readonly Func s_getHardDisconnects;
+ private static readonly Func s_getActiveSoftConnections;
+ private static readonly Func s_getSoftConnects;
+ private static readonly Func s_getSoftDisconnects;
+ private static readonly Func s_getNonPooledConnections;
+ private static readonly Func s_getPooledConnections;
+ private static readonly Func s_getActiveConnectionPoolGroups;
+ private static readonly Func s_getInactiveConnectionPoolGroups;
+ private static readonly Func s_getActiveConnectionPools;
+ private static readonly Func s_getInactiveConnectionPools;
+ private static readonly Func s_getActiveConnections;
+ private static readonly Func s_getFreeConnections;
+ private static readonly Func s_getStasisConnections;
+ private static readonly Func s_getReclaimedConnections;
static SqlClientEventSourceProps()
{
Type sqlClientEventSourceType =
Assembly.GetAssembly(typeof(SqlConnection))!.GetType("Microsoft.Data.SqlClient.SqlClientEventSource");
Debug.Assert(sqlClientEventSourceType != null);
- FieldInfo logField = sqlClientEventSourceType.GetField("Log", BindingFlags.Static | BindingFlags.NonPublic);
- Debug.Assert(logField != null);
- s_log = logField.GetValue(null);
-
- BindingFlags _bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
- _activeHardConnectionsCounter =
- sqlClientEventSourceType.GetField(nameof(_activeHardConnectionsCounter), _bindingFlags);
- Debug.Assert(_activeHardConnectionsCounter != null);
- _hardConnectsCounter =
- sqlClientEventSourceType.GetField(nameof(_hardConnectsCounter), _bindingFlags);
- Debug.Assert(_hardConnectsCounter != null);
- _hardDisconnectsCounter =
- sqlClientEventSourceType.GetField(nameof(_hardDisconnectsCounter), _bindingFlags);
- Debug.Assert(_hardDisconnectsCounter != null);
- _activeSoftConnectionsCounter =
- sqlClientEventSourceType.GetField(nameof(_activeSoftConnectionsCounter), _bindingFlags);
- Debug.Assert(_activeSoftConnectionsCounter != null);
- _softConnectsCounter =
- sqlClientEventSourceType.GetField(nameof(_softConnectsCounter), _bindingFlags);
- Debug.Assert(_softConnectsCounter != null);
- _softDisconnectsCounter =
- sqlClientEventSourceType.GetField(nameof(_softDisconnectsCounter), _bindingFlags);
- Debug.Assert(_softDisconnectsCounter != null);
- _nonPooledConnectionsCounter =
- sqlClientEventSourceType.GetField(nameof(_nonPooledConnectionsCounter), _bindingFlags);
- Debug.Assert(_nonPooledConnectionsCounter != null);
- _pooledConnectionsCounter =
- sqlClientEventSourceType.GetField(nameof(_pooledConnectionsCounter), _bindingFlags);
- Debug.Assert(_pooledConnectionsCounter != null);
- _activeConnectionPoolGroupsCounter =
- sqlClientEventSourceType.GetField(nameof(_activeConnectionPoolGroupsCounter), _bindingFlags);
- Debug.Assert(_activeConnectionPoolGroupsCounter != null);
- _inactiveConnectionPoolGroupsCounter =
- sqlClientEventSourceType.GetField(nameof(_inactiveConnectionPoolGroupsCounter), _bindingFlags);
- Debug.Assert(_inactiveConnectionPoolGroupsCounter != null);
- _activeConnectionPoolsCounter =
- sqlClientEventSourceType.GetField(nameof(_activeConnectionPoolsCounter), _bindingFlags);
- Debug.Assert(_activeConnectionPoolsCounter != null);
- _inactiveConnectionPoolsCounter =
- sqlClientEventSourceType.GetField(nameof(_inactiveConnectionPoolsCounter), _bindingFlags);
- Debug.Assert(_inactiveConnectionPoolsCounter != null);
- _activeConnectionsCounter =
- sqlClientEventSourceType.GetField(nameof(_activeConnectionsCounter), _bindingFlags);
- Debug.Assert(_activeConnectionsCounter != null);
- _freeConnectionsCounter =
- sqlClientEventSourceType.GetField(nameof(_freeConnectionsCounter), _bindingFlags);
- Debug.Assert(_freeConnectionsCounter != null);
- _stasisConnectionsCounter =
- sqlClientEventSourceType.GetField(nameof(_stasisConnectionsCounter), _bindingFlags);
- Debug.Assert(_stasisConnectionsCounter != null);
- _reclaimedConnectionsCounter =
- sqlClientEventSourceType.GetField(nameof(_reclaimedConnectionsCounter), _bindingFlags);
- Debug.Assert(_reclaimedConnectionsCounter != null);
+ FieldInfo metricsField = sqlClientEventSourceType.GetField("Metrics", BindingFlags.Static | BindingFlags.Public);
+ Debug.Assert(metricsField != null);
+ Type sqlClientMetricsType = metricsField.FieldType;
+ s_log = metricsField.GetValue(null);
+
+#if NETFRAMEWORK
+ Func notApplicableFunction = static () => -1;
+
+ // .NET Framework doesn't have performance counters for the number of hard and soft connections.
+ s_getActiveHardConnections = notApplicableFunction;
+ s_getActiveSoftConnections = notApplicableFunction;
+#endif
+ s_getActiveHardConnections = GenerateFieldGetter("_activeHardConnections");
+ s_getHardConnects = GenerateFieldGetter("_hardConnectsRate");
+ s_getHardDisconnects = GenerateFieldGetter("_hardDisconnectsRate");
+ s_getActiveSoftConnections = GenerateFieldGetter("_activeSoftConnections");
+ s_getSoftConnects = GenerateFieldGetter("_softConnectsRate");
+ s_getSoftDisconnects = GenerateFieldGetter("_softDisconnectsRate");
+ s_getNonPooledConnections = GenerateFieldGetter("_nonPooledConnections");
+ s_getPooledConnections = GenerateFieldGetter("_pooledConnections");
+ s_getActiveConnectionPoolGroups = GenerateFieldGetter("_activeConnectionPoolGroups");
+ s_getInactiveConnectionPoolGroups = GenerateFieldGetter("_inactiveConnectionPoolGroups");
+ s_getActiveConnectionPools = GenerateFieldGetter("_activeConnectionPools");
+ s_getInactiveConnectionPools = GenerateFieldGetter("_inactiveConnectionPools");
+ s_getActiveConnections = GenerateFieldGetter("_activeConnections");
+ s_getFreeConnections = GenerateFieldGetter("_freeConnections");
+ s_getStasisConnections = GenerateFieldGetter("_stasisConnections");
+ s_getReclaimedConnections = GenerateFieldGetter("_reclaimedConnections");
+
+#if NET
+ static Func GenerateFieldGetter(string fieldName)
+ {
+ FieldInfo counterField = s_log.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
+
+ Debug.Assert(counterField != null);
+ return () => (long)counterField.GetValue(s_log)!;
+ }
+#else
+ static Func GenerateFieldGetter(string fieldName)
+ {
+ FieldInfo counterField = s_log.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
+ Debug.Assert(counterField != null);
+
+ PerformanceCounter counter = counterField?.GetValue(s_log) as PerformanceCounter;
+ return () => counter is null ? -1 : counter.RawValue;
+ }
+#endif
}
- public static long ActiveHardConnections => (long)_activeHardConnectionsCounter.GetValue(s_log)!;
+ public static long ActiveHardConnections => s_getActiveHardConnections();
- public static long HardConnects => (long)_hardConnectsCounter.GetValue(s_log)!;
+ public static long HardConnects => s_getHardConnects();
- public static long HardDisconnects => (long)_hardDisconnectsCounter.GetValue(s_log)!;
+ public static long HardDisconnects => s_getHardDisconnects();
- public static long ActiveSoftConnections => (long)_activeSoftConnectionsCounter.GetValue(s_log)!;
+ public static long ActiveSoftConnections => s_getActiveSoftConnections();
- public static long SoftConnects => (long)_softConnectsCounter.GetValue(s_log)!;
+ public static long SoftConnects => s_getSoftConnects();
- public static long SoftDisconnects => (long)_softDisconnectsCounter.GetValue(s_log)!;
+ public static long SoftDisconnects => s_getSoftDisconnects();
- public static long NonPooledConnections => (long)_nonPooledConnectionsCounter.GetValue(s_log)!;
+ public static long NonPooledConnections => s_getNonPooledConnections();
- public static long PooledConnections => (long)_pooledConnectionsCounter.GetValue(s_log)!;
+ public static long PooledConnections => s_getPooledConnections();
- public static long ActiveConnectionPoolGroups => (long)_activeConnectionPoolGroupsCounter.GetValue(s_log)!;
+ public static long ActiveConnectionPoolGroups => s_getActiveConnectionPoolGroups();
- public static long InactiveConnectionPoolGroups => (long)_inactiveConnectionPoolGroupsCounter.GetValue(s_log)!;
+ public static long InactiveConnectionPoolGroups => s_getInactiveConnectionPoolGroups();
- public static long ActiveConnectionPools => (long)_activeConnectionPoolsCounter.GetValue(s_log)!;
+ public static long ActiveConnectionPools => s_getActiveConnectionPools();
- public static long InactiveConnectionPools => (long)_inactiveConnectionPoolsCounter.GetValue(s_log)!;
+ public static long InactiveConnectionPools => s_getInactiveConnectionPools();
- public static long ActiveConnections => (long)_activeConnectionsCounter.GetValue(s_log)!;
+ public static long ActiveConnections => s_getActiveConnections();
- public static long FreeConnections => (long)_freeConnectionsCounter.GetValue(s_log)!;
+ public static long FreeConnections => s_getFreeConnections();
- public static long StasisConnections => (long)_stasisConnectionsCounter.GetValue(s_log)!;
+ public static long StasisConnections => s_getStasisConnections();
- public static long ReclaimedConnections => (long)_reclaimedConnectionsCounter.GetValue(s_log)!;
+ public static long ReclaimedConnections => s_getReclaimedConnections();
}
}