diff --git a/src/MySqlConnector/Core/DiagnosticListenerExtensions.cs b/src/MySqlConnector/Core/DiagnosticListenerExtensions.cs
new file mode 100644
index 000000000..e4c44c4e0
--- /dev/null
+++ b/src/MySqlConnector/Core/DiagnosticListenerExtensions.cs
@@ -0,0 +1,325 @@
+using System;
+using System.Data;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using MySql.Data.MySqlClient;
+
+namespace MySqlConnector.Core
+{
+ ///
+ /// Extension methods on the DiagnosticListener class to log MySqlCommand data
+ ///
+ internal static class DiagnosticListenerExtensions
+ {
+ // Diagnostics listeners name
+ public const string CommandListenerName = "MySqlConnector.Command";
+ public const string ConnectionListenerName = "MySqlConnector.Connection";
+ public const string TransactionListenerName = "MySqlConnector.Transaction";
+
+ // Command listener events name
+ public const string WriteStart = nameof(WriteStart);
+ public const string WriteStop = nameof(WriteStop);
+ public const string WriteError = nameof(WriteError);
+
+ // Connection listener events name
+ public const string WriteOpenStart = nameof(WriteOpenStart);
+ public const string WriteOpenStop = nameof(WriteOpenStop);
+ public const string WriteOpenError = nameof(WriteOpenError);
+ public const string WriteCloseStart = nameof(WriteCloseStart);
+ public const string WriteCloseStop = nameof(WriteCloseStop);
+ public const string WriteCloseError = nameof(WriteCloseError);
+
+ // Transaction listener events name
+ public const string WriteCommitStart = nameof(WriteCommitStart);
+ public const string WriteCommitStop = nameof(WriteCommitStop);
+ public const string WriteCommitError = nameof(WriteCommitError);
+ public const string WriteRollbackStart = nameof(WriteRollbackStart);
+ public const string WriteRollbackStop = nameof(WriteRollbackStop);
+ public const string WriteRollbackError = nameof(WriteRollbackError);
+
+ public static Guid WriteCommandStart(this DiagnosticListener @this, MySqlCommand sqlCommand, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteStart))
+ {
+ Guid operationId = Guid.NewGuid();
+
+ @this.Write(
+ WriteStart,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ Command = sqlCommand
+ });
+
+ return operationId;
+ }
+ else
+ return Guid.Empty;
+ }
+
+ public static void WriteCommandStop(this DiagnosticListener @this, Guid operationId, MySqlCommand sqlCommand, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteStop))
+ {
+ @this.Write(
+ WriteStop,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ Command = sqlCommand,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+ }
+ }
+
+ public static void WriteCommandError(this DiagnosticListener @this, Guid operationId, MySqlCommand sqlCommand, Exception ex, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteError))
+ {
+ @this.Write(
+ WriteError,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ Command = sqlCommand,
+ Exception = ex,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+ }
+ }
+
+ public static Guid WriteConnectionOpenStart(this DiagnosticListener @this, MySqlConnection sqlConnection, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteOpenStart))
+ {
+ Guid operationId = Guid.NewGuid();
+
+ @this.Write(
+ WriteOpenStart,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ Connection = sqlConnection,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+
+ return operationId;
+ }
+ else
+ return Guid.Empty;
+ }
+
+ public static void WriteConnectionOpenStop(this DiagnosticListener @this, Guid operationId, MySqlConnection sqlConnection, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteOpenStop))
+ {
+ @this.Write(
+ WriteOpenStop,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ Connection = sqlConnection,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+ }
+ }
+
+ public static void WriteConnectionOpenError(this DiagnosticListener @this, Guid operationId, MySqlConnection sqlConnection, Exception ex, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteOpenError))
+ {
+ @this.Write(
+ WriteOpenError,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ Connection = sqlConnection,
+ Exception = ex,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+ }
+ }
+
+ public static Guid WriteConnectionCloseStart(this DiagnosticListener @this, MySqlConnection sqlConnection, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteCloseStart))
+ {
+ Guid operationId = Guid.NewGuid();
+
+ @this.Write(
+ WriteCloseStart,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ Connection = sqlConnection,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+
+ return operationId;
+ }
+ else
+ return Guid.Empty;
+ }
+
+ public static void WriteConnectionCloseStop(this DiagnosticListener @this, Guid operationId, string clientConnectionId, MySqlConnection sqlConnection, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteCloseStop))
+ {
+ @this.Write(
+ WriteCloseStop,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ ConnectionId = clientConnectionId,
+ Connection = sqlConnection,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+ }
+ }
+
+ public static void WriteConnectionCloseError(this DiagnosticListener @this, Guid operationId, string clientConnectionId, MySqlConnection sqlConnection, Exception ex, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteCloseError))
+ {
+ @this.Write(
+ WriteCloseError,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ ConnectionId = clientConnectionId,
+ Connection = sqlConnection,
+ Exception = ex,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+ }
+ }
+
+ public static Guid WriteTransactionCommitStart(this DiagnosticListener @this, IsolationLevel isolationLevel, MySqlConnection connection, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteCommitStart))
+ {
+ Guid operationId = Guid.NewGuid();
+
+ @this.Write(
+ WriteCommitStart,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ IsolationLevel = isolationLevel,
+ Connection = connection,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+
+ return operationId;
+ }
+ else
+ return Guid.Empty;
+ }
+
+ public static void WriteTransactionCommitStop(this DiagnosticListener @this, Guid operationId, IsolationLevel isolationLevel, MySqlConnection connection, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteCommitStop))
+ {
+ @this.Write(
+ WriteCommitStop,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ IsolationLevel = isolationLevel,
+ Connection = connection,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+ }
+ }
+
+ public static void WriteTransactionCommitError(this DiagnosticListener @this, Guid operationId, IsolationLevel isolationLevel, MySqlConnection connection, Exception ex, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteCommitError))
+ {
+ @this.Write(
+ WriteCommitError,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ IsolationLevel = isolationLevel,
+ Connection = connection,
+ Exception = ex,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+ }
+ }
+
+ public static Guid WriteTransactionRollbackStart(this DiagnosticListener @this, IsolationLevel isolationLevel, MySqlConnection connection, string transactionName, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteRollbackStart))
+ {
+ Guid operationId = Guid.NewGuid();
+
+ @this.Write(
+ WriteRollbackStart,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ IsolationLevel = isolationLevel,
+ Connection = connection,
+ TransactionName = transactionName,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+
+ return operationId;
+ }
+ else
+ return Guid.Empty;
+ }
+
+ public static void WriteTransactionRollbackStop(this DiagnosticListener @this, Guid operationId, IsolationLevel isolationLevel, MySqlConnection connection, string transactionName, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteRollbackStop))
+ {
+ @this.Write(
+ WriteRollbackStop,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ IsolationLevel = isolationLevel,
+ Connection = connection,
+ TransactionName = transactionName,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+ }
+ }
+
+ public static void WriteTransactionRollbackError(this DiagnosticListener @this, Guid operationId, IsolationLevel isolationLevel, MySqlConnection connection, string transactionName, Exception ex, [CallerMemberName] string operation = "")
+ {
+ if (@this.IsEnabled(WriteRollbackError))
+ {
+ @this.Write(
+ WriteRollbackError,
+ new
+ {
+ OperationId = operationId,
+ Operation = operation,
+ IsolationLevel = isolationLevel,
+ Connection = connection,
+ TransactionName = transactionName,
+ Exception = ex,
+ Timestamp = Stopwatch.GetTimestamp()
+ });
+ }
+ }
+ }
+}
diff --git a/src/MySqlConnector/Core/TextCommandExecutor.cs b/src/MySqlConnector/Core/TextCommandExecutor.cs
index f59362bf0..9651af3fd 100644
--- a/src/MySqlConnector/Core/TextCommandExecutor.cs
+++ b/src/MySqlConnector/Core/TextCommandExecutor.cs
@@ -1,6 +1,7 @@
using System;
using System.Data;
using System.Data.Common;
+using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Threading;
@@ -23,37 +24,77 @@ internal TextCommandExecutor(MySqlCommand command)
public virtual async Task ExecuteNonQueryAsync(string commandText, MySqlParameterCollection parameterCollection,
IOBehavior ioBehavior, CancellationToken cancellationToken)
{
- using (var reader = (MySqlDataReader) await ExecuteReaderAsync(commandText, parameterCollection, CommandBehavior.Default, ioBehavior, cancellationToken).ConfigureAwait(false))
+ Exception e = default;
+ var operationId = s_diagnosticListener.WriteCommandStart(m_command);
+
+ try
{
- do
+ using (var reader = (MySqlDataReader) await ExecuteReaderAsync(commandText, parameterCollection,
+ CommandBehavior.Default, ioBehavior, cancellationToken).ConfigureAwait(false))
{
- while (await reader.ReadAsync(ioBehavior, cancellationToken).ConfigureAwait(false))
+ do
{
- }
- } while (await reader.NextResultAsync(ioBehavior, cancellationToken).ConfigureAwait(false));
- return reader.RecordsAffected;
+ while (await reader.ReadAsync(ioBehavior, cancellationToken).ConfigureAwait(false))
+ {
+ }
+ } while (await reader.NextResultAsync(ioBehavior, cancellationToken).ConfigureAwait(false));
+
+ return reader.RecordsAffected;
+ }
+ }
+ catch (Exception ex)
+ {
+ e = ex;
+ throw;
+ }
+ finally
+ {
+ if (e != null)
+ s_diagnosticListener.WriteCommandError(operationId, m_command, e);
+ else
+ s_diagnosticListener.WriteCommandStop(operationId, m_command);
}
}
public virtual async Task