Skip to content

Commit 8680d88

Browse files
authored
Enable SqlClientDiagnosticListener in SqlCommand on .NET Framework (#3658)
1 parent 37a9c99 commit 8680d88

File tree

8 files changed

+75
-103
lines changed

8 files changed

+75
-103
lines changed

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.netcore.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,6 @@ public sealed partial class SqlCommand : DbCommand, ICloneable
5858
/// </summary>
5959
private static bool _forceRetryableEnclaveQueryExecutionExceptionDuringGenerateEnclavePackage = false;
6060
#endif
61-
62-
private static readonly SqlDiagnosticListener s_diagnosticListener = new SqlDiagnosticListener();
63-
private bool _parentOperationStarted = false;
64-
6561
internal static readonly Action<object> s_cancelIgnoreFailure = CancelIgnoreFailureCallback;
6662

6763
private _SqlRPC[] _rpcArrayOf1 = null; // Used for RPC executes

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommand.NonQuery.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,7 @@ public override int ExecuteNonQuery()
8484
// between entry into Execute* API and the thread obtaining the stateObject.
8585
_pendingCancel = false;
8686

87-
#if NET
8887
using var diagnosticScope = s_diagnosticListener.CreateCommandScope(this, _transaction);
89-
#endif
9088

9189
using var eventScope = TryEventScope.Create($"SqlCommand.ExecuteNonQuery | API | Object Id {ObjectID}");
9290
SqlClientEventSource.Log.TryCorrelationTraceEvent(
@@ -128,9 +126,7 @@ public override int ExecuteNonQuery()
128126
}
129127
catch (Exception ex)
130128
{
131-
#if NET
132129
diagnosticScope.SetException(ex);
133-
#endif
134130

135131
if (ex is SqlException sqlException)
136132
{
@@ -326,26 +322,20 @@ private void CleanupAfterExecuteNonQueryAsync(Task<int> task, TaskCompletionSour
326322
{
327323
Exception e = task.Exception?.InnerException;
328324

329-
#if NET
330325
s_diagnosticListener.WriteCommandError(operationId, this, _transaction, e);
331-
#endif
332326

333327
source.SetException(e);
334328
}
335329
else if (task.IsCanceled)
336330
{
337-
#if NET
338331
s_diagnosticListener.WriteCommandAfter(operationId, this, _transaction);
339-
#endif
340332

341333
source.SetCanceled();
342334
}
343335
else
344336
{
345337
// Task successful
346-
#if NET
347338
s_diagnosticListener.WriteCommandAfter(operationId, this, _transaction);
348-
#endif
349339

350340
source.SetResult(task.Result);
351341
}
@@ -652,11 +642,7 @@ private Task<int> InternalExecuteNonQueryAsync(CancellationToken cancellationTok
652642
$"Client Connection Id {_activeConnection?.ClientConnectionId}, " +
653643
$"Command Text '{CommandText}'");
654644

655-
#if NET
656645
Guid operationId = s_diagnosticListener.WriteCommandBefore(this, _transaction);
657-
#else
658-
Guid operationId = Guid.Empty;
659-
#endif
660646

661647
// Connection can be used as state in RegisterForConnectionCloseNotification continuation
662648
// to avoid an allocation so use it as the state value if possible but it can be changed if
@@ -715,9 +701,7 @@ private Task<int> InternalExecuteNonQueryAsync(CancellationToken cancellationTok
715701
}
716702
catch (Exception e)
717703
{
718-
#if NET
719704
s_diagnosticListener.WriteCommandError(operationId, this, _transaction, e);
720-
#endif
721705

722706
source.SetException(e);
723707
context.Dispose();

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommand.Reader.cs

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,8 @@ public SqlDataReader EndExecuteReader(IAsyncResult asyncResult)
109109
_pendingCancel = false;
110110

111111
// @TODO: Do we want to use a command scope here like nonquery and xml? or is operation id ok?
112-
#if NET
113112
Guid operationId = s_diagnosticListener.WriteCommandBefore(this, _transaction);
114113
Exception e = null;
115-
#endif
116114

117115
using var eventScope = TryEventScope.Create($"SqlCommand.ExecuteReader | API | Object Id {ObjectID}");
118116
// @TODO: Do we want to have a correlation trace event here like nonquery and xml?
@@ -136,9 +134,7 @@ public SqlDataReader EndExecuteReader(IAsyncResult asyncResult)
136134
// @TODO: CER Exception Handling was removed here (see GH#3581)
137135
catch (Exception ex)
138136
{
139-
#if NET
140137
e = ex;
141-
#endif
142138

143139
if (ex is SqlException sqlException)
144140
{
@@ -152,7 +148,6 @@ public SqlDataReader EndExecuteReader(IAsyncResult asyncResult)
152148
SqlStatistics.StopTimer(statistics);
153149
WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true);
154150

155-
#if NET
156151
if (e is not null)
157152
{
158153
s_diagnosticListener.WriteCommandError(operationId, this, _transaction, e);
@@ -161,7 +156,6 @@ public SqlDataReader EndExecuteReader(IAsyncResult asyncResult)
161156
{
162157
s_diagnosticListener.WriteCommandAfter(operationId, this, _transaction);
163158
}
164-
#endif
165159
}
166160
}
167161

@@ -573,23 +567,19 @@ private void CleanupExecuteReaderAsync(
573567
{
574568
Exception e = task.Exception.InnerException;
575569

576-
#if NET
577570
if (!_parentOperationStarted)
578571
{
579572
s_diagnosticListener.WriteCommandError(operationId, this, _transaction, e);
580573
}
581-
#endif
582574

583575
source.SetException(e);
584576
}
585577
else
586578
{
587-
#if NET
588579
if (!_parentOperationStarted)
589580
{
590581
s_diagnosticListener.WriteCommandAfter(operationId, this, _transaction);
591582
}
592-
#endif
593583

594584
if (task.IsCanceled)
595585
{
@@ -940,13 +930,7 @@ private Task<SqlDataReader> InternalExecuteReaderAsync(
940930
$"Client Connection Id {_activeConnection?.ClientConnectionId}, " +
941931
$"Command Text '{CommandText}'");
942932

943-
Guid operationId = Guid.Empty;
944-
#if NET
945-
if (!_parentOperationStarted)
946-
{
947-
operationId = s_diagnosticListener.WriteCommandBefore(this, _transaction);
948-
}
949-
#endif
933+
Guid operationId = !_parentOperationStarted ? s_diagnosticListener.WriteCommandBefore(this, _transaction) : Guid.Empty;
950934

951935
// Connection can be used as state in RegisterForConnectionCloseNotification
952936
// continuation to avoid an allocation so use it as the state value if possible, but it
@@ -1015,12 +999,10 @@ private Task<SqlDataReader> InternalExecuteReaderAsync(
1015999
}
10161000
catch (Exception e)
10171001
{
1018-
#if NET
10191002
if (!_parentOperationStarted)
10201003
{
10211004
s_diagnosticListener.WriteCommandError(operationId, this, _transaction, e);
10221005
}
1023-
#endif
10241006

10251007
source.SetException(e);
10261008
context?.Dispose();

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommand.Scalar.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ public override object ExecuteScalar()
2828
// between entry into Execute* API and the thread obtaining the stateObject.
2929
_pendingCancel = false;
3030

31-
#if NET
3231
using var diagnosticScope = s_diagnosticListener.CreateCommandScope(this, _transaction);
33-
#endif
3432

3533
using var eventScope = TryEventScope.Create($"SqlCommand.ExecuteScalar | API | Object Id {ObjectID}");
3634
SqlClientEventSource.Log.TryCorrelationTraceEvent(
@@ -60,9 +58,7 @@ public override object ExecuteScalar()
6058
}
6159
catch (Exception ex)
6260
{
63-
#if NET
6461
diagnosticScope.SetException(ex);
65-
#endif
6662

6763
if (ex is SqlException sqlException)
6864
{
@@ -233,10 +229,8 @@ private Task<object> ExecuteScalarAsyncInternal(CancellationToken cancellationTo
233229
$"Client Connection Id {_activeConnection?.ClientConnectionId}, " +
234230
$"Command Text '{CommandText}'");
235231

236-
#if NET
237232
Guid operationId = s_diagnosticListener.WriteCommandBefore(this, _transaction);
238233
_parentOperationStarted = true;
239-
#endif
240234

241235
// @TODO: Use continue with state? This would be a good candidate for rewriting async/await
242236
return ExecuteReaderAsync(cancellationToken).ContinueWith(executeTask =>
@@ -249,13 +243,11 @@ private Task<object> ExecuteScalarAsyncInternal(CancellationToken cancellationTo
249243
}
250244
else if (executeTask.IsFaulted)
251245
{
252-
#if NET
253246
s_diagnosticListener.WriteCommandError(
254247
operationId,
255248
this,
256249
_transaction,
257250
executeTask.Exception.InnerException);
258-
#endif
259251

260252
source.SetException(executeTask.Exception.InnerException);
261253
}
@@ -279,13 +271,11 @@ private Task<object> ExecuteScalarAsyncInternal(CancellationToken cancellationTo
279271
{
280272
reader.Dispose();
281273

282-
#if NET
283274
s_diagnosticListener.WriteCommandError(
284275
operationId,
285276
this,
286277
_transaction,
287278
readTask.Exception.InnerException);
288-
#endif
289279

290280
source.SetException(readTask.Exception.InnerException);
291281
}
@@ -316,17 +306,13 @@ private Task<object> ExecuteScalarAsyncInternal(CancellationToken cancellationTo
316306

317307
if (exception is not null)
318308
{
319-
#if NET
320309
s_diagnosticListener.WriteCommandError(operationId, this, _transaction, exception);
321-
#endif
322310

323311
source.SetException(exception);
324312
}
325313
else
326314
{
327-
#if NET
328315
s_diagnosticListener.WriteCommandAfter(operationId, this, _transaction);
329-
#endif
330316

331317
source.SetResult(result);
332318
}
@@ -341,9 +327,7 @@ private Task<object> ExecuteScalarAsyncInternal(CancellationToken cancellationTo
341327
TaskScheduler.Default);
342328
}
343329

344-
#if NET
345330
_parentOperationStarted = false;
346-
#endif
347331

348332
return source.Task;
349333
},

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommand.Xml.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,7 @@ public XmlReader ExecuteXmlReader()
8686
// between entry into Execute* API and the thread obtaining the stateObject.
8787
_pendingCancel = false;
8888

89-
#if NET
9089
using var diagnosticScope = s_diagnosticListener.CreateCommandScope(this, _transaction);
91-
#endif
9290

9391
using var eventScope = TryEventScope.Create($"SqlCommand.ExecuteXmlReader | API | Object Id {ObjectID}");
9492
SqlClientEventSource.Log.TryCorrelationTraceEvent(
@@ -116,9 +114,7 @@ public XmlReader ExecuteXmlReader()
116114
}
117115
catch (Exception ex)
118116
{
119-
#if NET
120117
diagnosticScope.SetException(ex);
121-
#endif
122118

123119
if (ex is SqlException sqlException)
124120
{
@@ -365,25 +361,19 @@ private void CleanupAfterExecuteXmlReaderAsync(
365361
{
366362
Exception e = task.Exception?.InnerException;
367363

368-
#if NET
369364
s_diagnosticListener.WriteCommandError(operationId, this, _transaction, e);
370-
#endif
371365

372366
source.SetException(e);
373367
}
374368
else if (task.IsCanceled)
375369
{
376-
#if NET
377370
s_diagnosticListener.WriteCommandAfter(operationId, this, _transaction);
378-
#endif
379371

380372
source.SetCanceled();
381373
}
382374
else
383375
{
384-
#if NET
385376
s_diagnosticListener.WriteCommandAfter(operationId, this, _transaction);
386-
#endif
387377

388378
source.SetResult(task.Result);
389379
}
@@ -475,11 +465,7 @@ private Task<XmlReader> InternalExecuteXmlReaderAsync(CancellationToken cancella
475465
$"Client Connection Id {_activeConnection?.ClientConnectionId}, " +
476466
$"Command Text '{CommandText}'");
477467

478-
#if NET
479468
Guid operationId = s_diagnosticListener.WriteCommandBefore(this, _transaction);
480-
#else
481-
Guid operationId = Guid.Empty;
482-
#endif
483469

484470
// Connection can be used as state in RegisterForConnectionCloseNotification continuation
485471
// to avoid an allocation so use it as the state value if possible but it can be changed if
@@ -547,9 +533,7 @@ private Task<XmlReader> InternalExecuteXmlReaderAsync(CancellationToken cancella
547533
}
548534
catch (Exception e)
549535
{
550-
#if NET
551536
s_diagnosticListener.WriteCommandError(operationId, this, _transaction, e);
552-
#endif
553537

554538
source.SetException(e);
555539
}

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommand.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@
1313
using System.Threading;
1414
using Microsoft.Data.Common;
1515
using Microsoft.Data.Sql;
16-
17-
#if NET
1816
using Microsoft.Data.SqlClient.Diagnostics;
19-
#endif
2017

2118
namespace Microsoft.Data.SqlClient
2219
{
@@ -55,6 +52,18 @@ public sealed partial class SqlCommand : DbCommand, ICloneable
5552
/// </summary>
5653
private static int _objectTypeCount = 0;
5754

55+
/// <summary>
56+
/// Static instance of the <see cref="SqlDiagnosticListener"/> used for capturing and emitting
57+
/// diagnostic events related to SqlCommand operations.
58+
/// </summary>
59+
private static readonly SqlDiagnosticListener s_diagnosticListener = new();
60+
61+
/// <summary>
62+
/// Prevents the completion events for ExecuteReader from being fired if ExecuteReader is being
63+
/// called as part of a parent operation (e.g. ExecuteScalar, or SqlBatch.ExecuteScalar.)
64+
/// </summary>
65+
private bool _parentOperationStarted = false;
66+
5867
/// <summary>
5968
/// Connection that will be used to process the current instance.
6069
/// </summary>
@@ -643,12 +652,8 @@ internal SqlStatistics Statistics
643652
{
644653
if (_activeConnection is not null)
645654
{
646-
#if NET
647655
bool isStatisticsEnabled = _activeConnection.StatisticsEnabled ||
648656
s_diagnosticListener.IsEnabled(SqlClientCommandAfter.Name);
649-
#else
650-
bool isStatisticsEnabled = _activeConnection.StatisticsEnabled;
651-
#endif
652657

653658
if (isStatisticsEnabled)
654659
{

0 commit comments

Comments
 (0)