diff --git a/src/EFCore.Relational/Diagnostics/IRelationalCommandDiagnosticsLogger.cs b/src/EFCore.Relational/Diagnostics/IRelationalCommandDiagnosticsLogger.cs
new file mode 100644
index 00000000000..56737ad515a
--- /dev/null
+++ b/src/EFCore.Relational/Diagnostics/IRelationalCommandDiagnosticsLogger.cs
@@ -0,0 +1,407 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Data.Common;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore.Storage;
+
+namespace Microsoft.EntityFrameworkCore.Diagnostics
+{
+ ///
+ /// An with some extra functionality suited for high-performance logging.
+ ///
+ public interface IRelationalCommandDiagnosticsLogger : IDiagnosticsLogger
+ {
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The type of method that will be called on this command.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The time that execution began.
+ /// An intercepted result.
+ InterceptionResult CommandCreating(
+ IRelationalConnection connection,
+ DbCommandMethod commandMethod,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The type of method that will be called on this command.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The time that execution began.
+ /// The duration of the command creation.
+ /// An intercepted result.
+ DbCommand CommandCreated(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbCommandMethod commandMethod,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime,
+ TimeSpan duration);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The time that execution began.
+ /// An intercepted result.
+ InterceptionResult CommandReaderExecuting(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The time that execution began.
+ /// An intercepted result.
+ InterceptionResult CommandScalarExecuting(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The time that execution began.
+ /// An intercepted result.
+ InterceptionResult CommandNonQueryExecuting(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The time that execution began.
+ /// A to observe while waiting for the task to complete.
+ /// An intercepted result.
+ /// If the is canceled.
+ ValueTask> CommandReaderExecutingAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime,
+ CancellationToken cancellationToken = default);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The time that execution began.
+ /// A to observe while waiting for the task to complete.
+ /// An intercepted result.
+ /// If the is canceled.
+ ValueTask> CommandScalarExecutingAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime,
+ CancellationToken cancellationToken = default);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The time that execution began.
+ /// A to observe while waiting for the task to complete.
+ /// An intercepted result.
+ /// If the is canceled.
+ ValueTask> CommandNonQueryExecutingAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime,
+ CancellationToken cancellationToken = default);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The return value from the underlying method execution.
+ /// The time that execution began.
+ /// The duration of the command execution, not including consuming results.
+ /// The result of execution, which may have been modified by an interceptor.
+ DbDataReader CommandReaderExecuted(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DbDataReader methodResult,
+ DateTimeOffset startTime,
+ TimeSpan duration);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The return value from the underlying method execution.
+ /// The time that execution began.
+ /// The duration of the command execution, not including consuming results.
+ /// The result of execution, which may have been modified by an interceptor.
+ object? CommandScalarExecuted(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ object? methodResult,
+ DateTimeOffset startTime,
+ TimeSpan duration);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The return value from the underlying method execution.
+ /// The time that execution began.
+ /// The duration of the command execution, not including consuming results.
+ /// The result of execution, which may have been modified by an interceptor.
+ int CommandNonQueryExecuted(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ int methodResult,
+ DateTimeOffset startTime,
+ TimeSpan duration);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The return value from the underlying method execution.
+ /// The time that execution began.
+ /// The duration of the command execution, not including consuming results.
+ /// A to observe while waiting for the task to complete.
+ /// The result of execution, which may have been modified by an interceptor.
+ /// If the is canceled.
+ ValueTask CommandReaderExecutedAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DbDataReader methodResult,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ CancellationToken cancellationToken = default);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The return value from the underlying method execution.
+ /// The time that execution began.
+ /// The duration of the command execution, not including consuming results.
+ /// A to observe while waiting for the task to complete.
+ /// The result of execution, which may have been modified by an interceptor.
+ /// If the is canceled.
+ ValueTask CommandScalarExecutedAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ object? methodResult,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ CancellationToken cancellationToken = default);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The return value from the underlying method execution.
+ /// The time that execution began.
+ /// The duration of the command execution, not including consuming results.
+ /// A to observe while waiting for the task to complete.
+ /// The result of execution, which may have been modified by an interceptor.
+ /// If the is canceled.
+ ValueTask CommandNonQueryExecutedAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ int methodResult,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ CancellationToken cancellationToken = default);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// Represents the method that will be called to execute the command.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The exception that caused this failure.
+ /// The time that execution began.
+ /// The amount of time that passed until the exception was raised.
+ void CommandError(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ DbCommandMethod executeMethod,
+ Guid commandId,
+ Guid connectionId,
+ Exception exception,
+ DateTimeOffset startTime,
+ TimeSpan duration);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The currently being used, to null if not known.
+ /// Represents the method that will be called to execute the command.
+ /// The correlation ID associated with the given .
+ /// The correlation ID associated with the being used.
+ /// The exception that caused this failure.
+ /// The time that execution began.
+ /// The amount of time that passed until the exception was raised.
+ /// A to observe while waiting for the task to complete.
+ /// A representing the async operation.
+ /// If the is canceled.
+ Task CommandErrorAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ DbCommandMethod executeMethod,
+ Guid commandId,
+ Guid connectionId,
+ Exception exception,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ CancellationToken cancellationToken = default);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The database command object.
+ /// The data reader.
+ /// The correlation ID associated with the given .
+ /// The number of records in the database that were affected.
+ /// The number of records that were read.
+ /// The time that the operation was started.
+ /// The elapsed time from when the operation was started.
+ /// The result of execution, which may have been modified by an interceptor.
+ InterceptionResult DataReaderDisposing(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbDataReader dataReader,
+ Guid commandId,
+ int recordsAffected,
+ int readCount,
+ DateTimeOffset startTime,
+ TimeSpan duration);
+
+ ///
+ /// Whether or need
+ /// to be logged.
+ ///
+ bool ShouldLogCommandCreate(DateTimeOffset now);
+
+ ///
+ /// Whether or need
+ /// to be logged.
+ ///
+ bool ShouldLogCommandExecute(DateTimeOffset now);
+
+ ///
+ /// Whether needs to be logged.
+ ///
+ bool ShouldLogDataReaderDispose(DateTimeOffset now);
+
+ private bool ShouldLogParameterValues(DbCommand command)
+ => command.Parameters.Count > 0 && ShouldLogSensitiveData();
+ }
+}
diff --git a/src/EFCore.Relational/Diagnostics/IRelationalConnectionDiagnosticsLogger.cs b/src/EFCore.Relational/Diagnostics/IRelationalConnectionDiagnosticsLogger.cs
new file mode 100644
index 00000000000..a411452dc93
--- /dev/null
+++ b/src/EFCore.Relational/Diagnostics/IRelationalConnectionDiagnosticsLogger.cs
@@ -0,0 +1,154 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore.Storage;
+
+namespace Microsoft.EntityFrameworkCore.Diagnostics
+{
+ ///
+ /// An with some extra functionality suited for high-performance logging.
+ ///
+ public interface IRelationalConnectionDiagnosticsLogger : IDiagnosticsLogger
+ {
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The time that the operation was started.
+ /// The result of execution, which may have been modified by an interceptor.
+ InterceptionResult ConnectionOpening(
+ IRelationalConnection connection,
+ DateTimeOffset startTime);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The time that the operation was started.
+ /// A to observe while waiting for the task to complete.
+ /// A representing the async operation.
+ /// If the is canceled.
+ ValueTask ConnectionOpeningAsync(
+ IRelationalConnection connection,
+ DateTimeOffset startTime,
+ CancellationToken cancellationToken);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The time that the operation was started.
+ /// The amount of time before the connection was opened.
+ void ConnectionOpened(
+ IRelationalConnection connection,
+ DateTimeOffset startTime,
+ TimeSpan duration);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The time that the operation was started.
+ /// The amount of time before the connection was opened.
+ /// A to observe while waiting for the task to complete.
+ /// A representing the async operation.
+ /// If the is canceled.
+ Task ConnectionOpenedAsync(
+ IRelationalConnection connection,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ CancellationToken cancellationToken = default);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The time that the operation was started.
+ /// The result of execution, which may have been modified by an interceptor.
+ InterceptionResult ConnectionClosing(
+ IRelationalConnection connection,
+ DateTimeOffset startTime);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The time that the operation was started.
+ /// A representing the async operation.
+ ValueTask ConnectionClosingAsync(
+ IRelationalConnection connection,
+ DateTimeOffset startTime);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The time that the operation was started.
+ /// The amount of time before the connection was closed.
+ void ConnectionClosed(
+ IRelationalConnection connection,
+ DateTimeOffset startTime,
+ TimeSpan duration);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The time that the operation was started.
+ /// The amount of time before the connection was closed.
+ /// A representing the async operation.
+ Task ConnectionClosedAsync(
+ IRelationalConnection connection,
+ DateTimeOffset startTime,
+ TimeSpan duration);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The exception representing the error.
+ /// The time that the operation was started.
+ /// The elapsed time before the operation failed.
+ /// A flag indicating the exception is being handled and so it should be logged at Debug level.
+ void ConnectionError(
+ IRelationalConnection connection,
+ Exception exception,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ bool logErrorAsDebug);
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The connection.
+ /// The exception representing the error.
+ /// The time that the operation was started.
+ /// The elapsed time before the operation failed.
+ /// A flag indicating the exception is being handled and so it should be logged at Debug level.
+ /// A to observe while waiting for the task to complete.
+ /// A representing the async operation.
+ /// If the is canceled.
+ Task ConnectionErrorAsync(
+ IRelationalConnection connection,
+ Exception exception,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ bool logErrorAsDebug,
+ CancellationToken cancellationToken = default);
+
+ ///
+ /// Whether or need
+ /// to be logged.
+ ///
+ bool ShouldLogConnectionOpen(DateTimeOffset now);
+
+ ///
+ /// Whether or need
+ /// to be logged.
+ ///
+ bool ShouldLogConnectionClose(DateTimeOffset now);
+ }
+}
diff --git a/src/EFCore.Relational/Diagnostics/Internal/RelationalCommandDiagnosticsLogger.cs b/src/EFCore.Relational/Diagnostics/Internal/RelationalCommandDiagnosticsLogger.cs
new file mode 100644
index 00000000000..711e45c36d2
--- /dev/null
+++ b/src/EFCore.Relational/Diagnostics/Internal/RelationalCommandDiagnosticsLogger.cs
@@ -0,0 +1,1317 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Data;
+using System.Data.Common;
+using System.Diagnostics;
+using System.Globalization;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage;
+using Microsoft.EntityFrameworkCore.Storage.Internal;
+using Microsoft.Extensions.Logging;
+
+#pragma warning disable EF1001
+
+namespace Microsoft.EntityFrameworkCore.Diagnostics.Internal
+{
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public class RelationalCommandDiagnosticsLogger
+ : DiagnosticsLogger, IRelationalCommandDiagnosticsLogger
+ {
+ private DateTimeOffset _suppressCommandCreateExpiration;
+ private DateTimeOffset _suppressCommandExecuteExpiration;
+ private DateTimeOffset _suppressDataReaderDisposingExpiration;
+
+ private readonly TimeSpan _loggingConfigCacheTime;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public RelationalCommandDiagnosticsLogger(
+ ILoggerFactory loggerFactory,
+ ILoggingOptions loggingOptions,
+ DiagnosticSource diagnosticSource,
+ LoggingDefinitions loggingDefinitions,
+ IDbContextLogger contextLogger,
+ IDbContextOptions contextOptions,
+ IInterceptors? interceptors = null)
+ : base(loggerFactory, loggingOptions, diagnosticSource, loggingDefinitions, contextLogger, interceptors)
+ {
+ _loggingConfigCacheTime = contextOptions.FindExtension()?.LoggingConfigCacheTime ??
+ CoreOptionsExtension.DefaultLoggingConfigCacheTime;
+ }
+
+ #region CommandCreating
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual InterceptionResult CommandCreating(
+ IRelationalConnection connection,
+ DbCommandMethod commandMethod,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime)
+ {
+ _suppressCommandCreateExpiration = startTime + _loggingConfigCacheTime;
+
+ var definition = RelationalResources.LogCommandCreating(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandCreateExpiration = default;
+
+ definition.Log(this, commandMethod.ToString());
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandCreateExpiration = default;
+
+ var eventData = BroadcastCommandCreating(
+ connection.DbConnection,
+ context,
+ commandMethod,
+ commandId,
+ connectionId,
+ async: false,
+ startTime,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.CommandCreating(eventData, default);
+ }
+ }
+
+ return default;
+ }
+
+ private CommandCorrelatedEventData BroadcastCommandCreating(
+ DbConnection connection,
+ DbContext? context,
+ DbCommandMethod executeMethod,
+ Guid commandId,
+ Guid connectionId,
+ bool async,
+ DateTimeOffset startTime,
+ EventDefinition definition,
+ bool diagnosticSourceEnabled,
+ bool simpleLogEnabled)
+ {
+ var eventData = new CommandCorrelatedEventData(
+ definition,
+ CommandCreating,
+ connection,
+ context,
+ executeMethod,
+ commandId,
+ connectionId,
+ async,
+ startTime);
+
+ DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+
+ return eventData;
+
+ static string CommandCreating(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (CommandCorrelatedEventData)payload;
+ return d.GenerateMessage(p.ExecuteMethod.ToString());
+ }
+ }
+
+ #endregion CommandCreating
+
+ #region CommandCreated
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual DbCommand CommandCreated(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbCommandMethod commandMethod,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime,
+ TimeSpan duration)
+ {
+ var definition = RelationalResources.LogCommandCreated(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandCreateExpiration = default;
+
+ definition.Log(this, commandMethod.ToString(), (int)duration.TotalMilliseconds);
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandCreateExpiration = default;
+
+ var eventData = BroadcastCommandCreated(
+ connection.DbConnection,
+ command,
+ context,
+ commandMethod,
+ commandId,
+ connectionId,
+ async: false,
+ startTime,
+ duration,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.CommandCreated(eventData, command);
+ }
+ }
+
+ return command;
+ }
+
+ private CommandEndEventData BroadcastCommandCreated(
+ DbConnection connection,
+ DbCommand command,
+ DbContext? context,
+ DbCommandMethod executeMethod,
+ Guid commandId,
+ Guid connectionId,
+ bool async,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ EventDefinition definition,
+ bool diagnosticSourceEnabled,
+ bool simpleLogEnabled)
+ {
+ var eventData = new CommandEndEventData(
+ definition,
+ CommandCreated,
+ connection,
+ command,
+ context,
+ executeMethod,
+ commandId,
+ connectionId,
+ async,
+ false,
+ startTime,
+ duration);
+
+ DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+
+ return eventData;
+
+ static string CommandCreated(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (CommandEndEventData)payload;
+ return d.GenerateMessage(p.ExecuteMethod.ToString(), (int)p.Duration.TotalMilliseconds);
+ }
+ }
+
+ #endregion CommandCreated
+
+ #region CommandExecuting
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual InterceptionResult CommandReaderExecuting(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime)
+ {
+ _suppressCommandExecuteExpiration = startTime + _loggingConfigCacheTime;
+
+ var definition = RelationalResources.LogExecutingCommand(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ definition.Log(
+ this,
+ command.Parameters.FormatParameters(ShouldLogParameterValues(command)),
+ command.CommandType,
+ command.CommandTimeout,
+ Environment.NewLine,
+ command.CommandText.TrimEnd());
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ var eventData = BroadcastCommandExecuting(
+ connection.DbConnection,
+ command,
+ context,
+ DbCommandMethod.ExecuteReader,
+ commandId,
+ connectionId,
+ false,
+ startTime,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ReaderExecuting(command, eventData, default);
+ }
+ }
+
+ return default;
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual InterceptionResult CommandScalarExecuting(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime)
+ {
+ _suppressCommandExecuteExpiration = startTime + _loggingConfigCacheTime;
+
+ var definition = RelationalResources.LogExecutingCommand(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ definition.Log(
+ this,
+ command.Parameters.FormatParameters(ShouldLogParameterValues(command)),
+ command.CommandType,
+ command.CommandTimeout,
+ Environment.NewLine,
+ command.CommandText.TrimEnd());
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ var eventData = BroadcastCommandExecuting(
+ connection.DbConnection,
+ command,
+ context,
+ DbCommandMethod.ExecuteScalar,
+ commandId,
+ connectionId,
+ false,
+ startTime,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ScalarExecuting(command, eventData, default);
+ }
+ }
+
+ return default;
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual InterceptionResult CommandNonQueryExecuting(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime)
+ {
+ _suppressCommandExecuteExpiration = startTime + _loggingConfigCacheTime;
+
+ var definition = RelationalResources.LogExecutingCommand(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ definition.Log(
+ this,
+ command.Parameters.FormatParameters(ShouldLogParameterValues(command)),
+ command.CommandType,
+ command.CommandTimeout,
+ Environment.NewLine,
+ command.CommandText.TrimEnd());
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ var eventData = BroadcastCommandExecuting(
+ connection.DbConnection,
+ command,
+ context,
+ DbCommandMethod.ExecuteNonQuery,
+ commandId,
+ connectionId,
+ false,
+ startTime,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.NonQueryExecuting(command, eventData, default);
+ }
+ }
+
+ return default;
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual ValueTask> CommandReaderExecutingAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime,
+ CancellationToken cancellationToken = default)
+ {
+ _suppressCommandExecuteExpiration = startTime + _loggingConfigCacheTime;
+
+ var definition = RelationalResources.LogExecutingCommand(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ definition.Log(
+ this,
+ command.Parameters.FormatParameters(ShouldLogParameterValues(command)),
+ command.CommandType,
+ command.CommandTimeout,
+ Environment.NewLine,
+ command.CommandText.TrimEnd());
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ var eventData = BroadcastCommandExecuting(
+ connection.DbConnection,
+ command,
+ context,
+ DbCommandMethod.ExecuteReader,
+ commandId,
+ connectionId,
+ async: true,
+ startTime,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ReaderExecutingAsync(command, eventData, default, cancellationToken);
+ }
+ }
+
+ return default;
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual ValueTask> CommandScalarExecutingAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime,
+ CancellationToken cancellationToken = default)
+ {
+ _suppressCommandExecuteExpiration = startTime + _loggingConfigCacheTime;
+
+ var definition = RelationalResources.LogExecutingCommand(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ definition.Log(
+ this,
+ command.Parameters.FormatParameters(ShouldLogParameterValues(command)),
+ command.CommandType,
+ command.CommandTimeout,
+ Environment.NewLine,
+ command.CommandText.TrimEnd());
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ var eventData = BroadcastCommandExecuting(
+ connection.DbConnection,
+ command,
+ context,
+ DbCommandMethod.ExecuteScalar,
+ commandId,
+ connectionId,
+ async: true,
+ startTime,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ScalarExecutingAsync(command, eventData, default, cancellationToken);
+ }
+ }
+
+ return default;
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual ValueTask> CommandNonQueryExecutingAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DateTimeOffset startTime,
+ CancellationToken cancellationToken = default)
+ {
+ _suppressCommandExecuteExpiration = startTime + _loggingConfigCacheTime;
+
+ var definition = RelationalResources.LogExecutingCommand(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ definition.Log(
+ this,
+ command.Parameters.FormatParameters(ShouldLogParameterValues(command)),
+ command.CommandType,
+ command.CommandTimeout,
+ Environment.NewLine,
+ command.CommandText.TrimEnd());
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ var eventData = BroadcastCommandExecuting(
+ connection.DbConnection,
+ command,
+ context,
+ DbCommandMethod.ExecuteNonQuery,
+ commandId,
+ connectionId,
+ async: true,
+ startTime,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.NonQueryExecutingAsync(command, eventData, default, cancellationToken);
+ }
+ }
+
+ return default;
+ }
+
+ private CommandEventData BroadcastCommandExecuting(
+ DbConnection connection,
+ DbCommand command,
+ DbContext? context,
+ DbCommandMethod executeMethod,
+ Guid commandId,
+ Guid connectionId,
+ bool async,
+ DateTimeOffset startTime,
+ EventDefinition definition,
+ bool diagnosticSourceEnabled,
+ bool simpleLogEnabled)
+ {
+ var eventData = new CommandEventData(
+ definition,
+ CommandExecuting,
+ connection,
+ command,
+ context,
+ executeMethod,
+ commandId,
+ connectionId,
+ async,
+ ShouldLogParameterValues(command),
+ startTime);
+
+ DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+
+ return eventData;
+
+ static string CommandExecuting(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (CommandEventData)payload;
+ return d.GenerateMessage(
+ p.Command.Parameters.FormatParameters(p.LogParameterValues),
+ p.Command.CommandType,
+ p.Command.CommandTimeout,
+ Environment.NewLine,
+ p.Command.CommandText.TrimEnd());
+ }
+ }
+
+ #endregion CommandExecuting
+
+ #region CommandExecuted
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual DbDataReader CommandReaderExecuted(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DbDataReader methodResult,
+ DateTimeOffset startTime,
+ TimeSpan duration)
+ {
+ var definition = RelationalResources.LogExecutedCommand(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ definition.Log(
+ this,
+ string.Format(CultureInfo.InvariantCulture, "{0:N0}", duration.TotalMilliseconds),
+ command.Parameters.FormatParameters(ShouldLogParameterValues(command)),
+ command.CommandType,
+ command.CommandTimeout,
+ Environment.NewLine,
+ command.CommandText.TrimEnd());
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ var eventData = BroadcastCommandExecuted(
+ connection.DbConnection,
+ command,
+ context,
+ DbCommandMethod.ExecuteReader,
+ commandId,
+ connectionId,
+ methodResult,
+ async: false,
+ startTime,
+ duration,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ReaderExecuted(command, eventData, methodResult);
+ }
+ }
+
+ return methodResult;
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual object? CommandScalarExecuted(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ object? methodResult,
+ DateTimeOffset startTime,
+ TimeSpan duration)
+ {
+ var definition = RelationalResources.LogExecutedCommand(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ definition.Log(
+ this,
+ string.Format(CultureInfo.InvariantCulture, "{0:N0}", duration.TotalMilliseconds),
+ command.Parameters.FormatParameters(ShouldLogParameterValues(command)),
+ command.CommandType,
+ command.CommandTimeout,
+ Environment.NewLine,
+ command.CommandText.TrimEnd());
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ var eventData = BroadcastCommandExecuted(
+ connection.DbConnection,
+ command,
+ context,
+ DbCommandMethod.ExecuteScalar,
+ commandId,
+ connectionId,
+ methodResult,
+ async: false,
+ startTime,
+ duration,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ScalarExecuted(command, eventData, methodResult);
+ }
+ }
+
+ return methodResult;
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual int CommandNonQueryExecuted(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ int methodResult,
+ DateTimeOffset startTime,
+ TimeSpan duration)
+ {
+ var definition = RelationalResources.LogExecutedCommand(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ definition.Log(
+ this,
+ string.Format(CultureInfo.InvariantCulture, "{0:N0}", duration.TotalMilliseconds),
+ command.Parameters.FormatParameters(ShouldLogParameterValues(command)),
+ command.CommandType,
+ command.CommandTimeout,
+ Environment.NewLine,
+ command.CommandText.TrimEnd());
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ var eventData = BroadcastCommandExecuted(
+ connection.DbConnection,
+ command,
+ context,
+ DbCommandMethod.ExecuteNonQuery,
+ commandId,
+ connectionId,
+ methodResult,
+ async: false,
+ startTime,
+ duration,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.NonQueryExecuted(command, eventData, methodResult);
+ }
+ }
+
+ return methodResult;
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual ValueTask CommandReaderExecutedAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ DbDataReader methodResult,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ CancellationToken cancellationToken = default)
+ {
+ var definition = RelationalResources.LogExecutedCommand(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ definition.Log(
+ this,
+ string.Format(CultureInfo.InvariantCulture, "{0:N0}", duration.TotalMilliseconds),
+ command.Parameters.FormatParameters(ShouldLogParameterValues(command)),
+ command.CommandType,
+ command.CommandTimeout,
+ Environment.NewLine,
+ command.CommandText.TrimEnd());
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ var eventData = BroadcastCommandExecuted(
+ connection.DbConnection,
+ command,
+ context,
+ DbCommandMethod.ExecuteReader,
+ commandId,
+ connectionId,
+ methodResult,
+ async: true,
+ startTime,
+ duration,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ReaderExecutedAsync(command, eventData, methodResult, cancellationToken);
+ }
+ }
+
+ return new ValueTask(methodResult);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual ValueTask CommandScalarExecutedAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ object? methodResult,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ CancellationToken cancellationToken = default)
+ {
+ var definition = RelationalResources.LogExecutedCommand(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ definition.Log(
+ this,
+ string.Format(CultureInfo.InvariantCulture, "{0:N0}", duration.TotalMilliseconds),
+ command.Parameters.FormatParameters(ShouldLogParameterValues(command)),
+ command.CommandType,
+ command.CommandTimeout,
+ Environment.NewLine,
+ command.CommandText.TrimEnd());
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ var eventData = BroadcastCommandExecuted(
+ connection.DbConnection,
+ command,
+ context,
+ DbCommandMethod.ExecuteScalar,
+ commandId,
+ connectionId,
+ methodResult,
+ async: true,
+ startTime,
+ duration,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ScalarExecutedAsync(command, eventData, methodResult, cancellationToken);
+ }
+ }
+
+ return new ValueTask(methodResult);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual ValueTask CommandNonQueryExecutedAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ Guid commandId,
+ Guid connectionId,
+ int methodResult,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ CancellationToken cancellationToken = default)
+ {
+ var definition = RelationalResources.LogExecutedCommand(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ definition.Log(
+ this,
+ string.Format(CultureInfo.InvariantCulture, "{0:N0}", duration.TotalMilliseconds),
+ command.Parameters.FormatParameters(ShouldLogParameterValues(command)),
+ command.CommandType,
+ command.CommandTimeout,
+ Environment.NewLine,
+ command.CommandText.TrimEnd());
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCommandExecuteExpiration = default;
+
+ var eventData = BroadcastCommandExecuted(
+ connection.DbConnection,
+ command,
+ context,
+ DbCommandMethod.ExecuteNonQuery,
+ commandId,
+ connectionId,
+ methodResult,
+ async: true,
+ startTime,
+ duration,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.NonQueryExecutedAsync(command, eventData, methodResult, cancellationToken);
+ }
+ }
+
+ return new ValueTask(methodResult);
+ }
+
+ private CommandExecutedEventData BroadcastCommandExecuted(
+ DbConnection connection,
+ DbCommand command,
+ DbContext? context,
+ DbCommandMethod executeMethod,
+ Guid commandId,
+ Guid connectionId,
+ object? methodResult,
+ bool async,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ EventDefinition definition,
+ bool diagnosticSourceEnabled,
+ bool simpleLogEnabled)
+ {
+ var eventData = new CommandExecutedEventData(
+ definition,
+ CommandExecuted,
+ connection,
+ command,
+ context,
+ executeMethod,
+ commandId,
+ connectionId,
+ methodResult,
+ async,
+ ShouldLogParameterValues(command),
+ startTime,
+ duration);
+
+ DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+
+ return eventData;
+
+ static string CommandExecuted(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (CommandExecutedEventData)payload;
+ return d.GenerateMessage(
+ string.Format(CultureInfo.InvariantCulture, "{0:N0}", p.Duration.TotalMilliseconds),
+ p.Command.Parameters.FormatParameters(p.LogParameterValues),
+ p.Command.CommandType,
+ p.Command.CommandTimeout,
+ Environment.NewLine,
+ p.Command.CommandText.TrimEnd());
+ }
+ }
+
+ #endregion CommandExecuted
+
+ #region CommandError
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual void CommandError(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ DbCommandMethod executeMethod,
+ Guid commandId,
+ Guid connectionId,
+ Exception exception,
+ DateTimeOffset startTime,
+ TimeSpan duration)
+ {
+ var definition = RelationalResources.LogCommandFailed(this);
+
+ LogCommandError(command, duration, definition);
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ var eventData = BroadcastCommandError(
+ connection.DbConnection,
+ command,
+ context,
+ executeMethod,
+ commandId,
+ connectionId,
+ exception,
+ false,
+ startTime,
+ duration,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ interceptor?.CommandFailed(command, eventData);
+ }
+ }
+
+ private void LogCommandError(
+ DbCommand command,
+ TimeSpan duration,
+ EventDefinition definition)
+ {
+ if (ShouldLog(definition))
+ {
+ definition.Log(
+ this,
+ string.Format(CultureInfo.InvariantCulture, "{0:N0}", duration.TotalMilliseconds),
+ command.Parameters.FormatParameters(ShouldLogParameterValues(command)),
+ command.CommandType,
+ command.CommandTimeout,
+ Environment.NewLine,
+ command.CommandText.TrimEnd());
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual Task CommandErrorAsync(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbContext? context,
+ DbCommandMethod executeMethod,
+ Guid commandId,
+ Guid connectionId,
+ Exception exception,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ CancellationToken cancellationToken = default)
+ {
+ var definition = RelationalResources.LogCommandFailed(this);
+
+ LogCommandError(command, duration, definition);
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ var eventData = BroadcastCommandError(
+ connection.DbConnection,
+ command,
+ context,
+ executeMethod,
+ commandId,
+ connectionId,
+ exception,
+ true,
+ startTime,
+ duration,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.CommandFailedAsync(command, eventData, cancellationToken);
+ }
+ }
+
+ return Task.CompletedTask;
+ }
+
+ private CommandErrorEventData BroadcastCommandError(
+ DbConnection connection,
+ DbCommand command,
+ DbContext? context,
+ DbCommandMethod executeMethod,
+ Guid commandId,
+ Guid connectionId,
+ Exception exception,
+ bool async,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ EventDefinition definition,
+ bool diagnosticSourceEnabled,
+ bool simpleLogEnabled)
+ {
+ var eventData = new CommandErrorEventData(
+ definition,
+ CommandError,
+ connection,
+ command,
+ context,
+ executeMethod,
+ commandId,
+ connectionId,
+ exception,
+ async,
+ ShouldLogParameterValues(command),
+ startTime,
+ duration);
+
+ DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+
+ return eventData;
+
+ static string CommandError(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (CommandErrorEventData)payload;
+ return d.GenerateMessage(
+ string.Format(CultureInfo.InvariantCulture, "{0:N0}", p.Duration.TotalMilliseconds),
+ p.Command.Parameters.FormatParameters(p.LogParameterValues),
+ p.Command.CommandType,
+ p.Command.CommandTimeout,
+ Environment.NewLine,
+ p.Command.CommandText.TrimEnd());
+ }
+ }
+
+ #endregion CommandError
+
+ #region DataReaderDisposing
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual InterceptionResult DataReaderDisposing(
+ IRelationalConnection connection,
+ DbCommand command,
+ DbDataReader dataReader,
+ Guid commandId,
+ int recordsAffected,
+ int readCount,
+ DateTimeOffset startTime,
+ TimeSpan duration)
+ {
+ _suppressDataReaderDisposingExpiration = startTime + _loggingConfigCacheTime;
+
+ var definition = RelationalResources.LogDisposingDataReader(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressDataReaderDisposingExpiration = default;
+
+ definition.Log(this);
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressDataReaderDisposingExpiration = default;
+
+ var eventData = new DataReaderDisposingEventData(
+ definition,
+ (d, p) => ((EventDefinition)d).GenerateMessage(),
+ command,
+ dataReader,
+ connection.Context,
+ commandId,
+ connection.ConnectionId,
+ recordsAffected,
+ readCount,
+ startTime,
+ duration);
+
+ DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.DataReaderDisposing(command, eventData, default);
+ }
+ }
+
+ return default;
+ }
+
+ #endregion DataReaderDisposing
+
+ #region ShouldLog checks
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual bool ShouldLogCommandCreate(DateTimeOffset now)
+ => now > _suppressCommandCreateExpiration;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual bool ShouldLogCommandExecute(DateTimeOffset now)
+ => now > _suppressCommandExecuteExpiration;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual bool ShouldLogDataReaderDispose(DateTimeOffset now)
+ => now > _suppressDataReaderDisposingExpiration;
+
+ private bool ShouldLogParameterValues(DbCommand command)
+ => command.Parameters.Count > 0 && ShouldLogSensitiveData();
+
+ #endregion ShouldLog checks
+ }
+}
diff --git a/src/EFCore.Relational/Diagnostics/Internal/RelationalConnectionDiagnosticsLogger.cs b/src/EFCore.Relational/Diagnostics/Internal/RelationalConnectionDiagnosticsLogger.cs
new file mode 100644
index 00000000000..fc95cc34c14
--- /dev/null
+++ b/src/EFCore.Relational/Diagnostics/Internal/RelationalConnectionDiagnosticsLogger.cs
@@ -0,0 +1,679 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage;
+using Microsoft.Extensions.Logging;
+
+#pragma warning disable EF1001
+
+namespace Microsoft.EntityFrameworkCore.Diagnostics.Internal
+{
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public class RelationalConnectionDiagnosticsLogger
+ : DiagnosticsLogger, IRelationalConnectionDiagnosticsLogger
+ {
+ private DateTimeOffset _suppressOpenExpiration;
+ private DateTimeOffset _suppressCloseExpiration;
+
+ private readonly TimeSpan _loggingConfigCacheTime;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public RelationalConnectionDiagnosticsLogger(
+ ILoggerFactory loggerFactory,
+ ILoggingOptions loggingOptions,
+ DiagnosticSource diagnosticSource,
+ LoggingDefinitions loggingDefinitions,
+ IDbContextLogger contextLogger,
+ IDbContextOptions contextOptions,
+ IInterceptors? interceptors = null)
+ : base(loggerFactory, loggingOptions, diagnosticSource, loggingDefinitions, contextLogger, interceptors)
+ {
+ _loggingConfigCacheTime = contextOptions.FindExtension()?.LoggingConfigCacheTime ??
+ CoreOptionsExtension.DefaultLoggingConfigCacheTime;
+ }
+
+ #region ConnectionOpening
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual InterceptionResult ConnectionOpening(
+ IRelationalConnection connection,
+ DateTimeOffset startTime)
+ {
+ _suppressOpenExpiration = startTime + _loggingConfigCacheTime;
+
+ var definition = RelationalResources.LogOpeningConnection(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressOpenExpiration = default;
+
+ definition.Log(this, connection.DbConnection.Database, connection.DbConnection.DataSource);
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressOpenExpiration = default;
+
+ var eventData = BroadcastConnectionOpening(
+ connection,
+ startTime,
+ definition,
+ async: false,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ConnectionOpening(connection.DbConnection, eventData, default);
+ }
+ }
+
+ return default;
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual ValueTask ConnectionOpeningAsync(
+ IRelationalConnection connection,
+ DateTimeOffset startTime,
+ CancellationToken cancellationToken)
+ {
+ _suppressOpenExpiration = startTime + _loggingConfigCacheTime;
+
+ var definition = RelationalResources.LogOpeningConnection(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressOpenExpiration = default;
+
+ definition.Log(this, connection.DbConnection.Database, connection.DbConnection.DataSource);
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressOpenExpiration = default;
+
+ var eventData = BroadcastConnectionOpening(
+ connection,
+ startTime,
+ definition,
+ async: true,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ConnectionOpeningAsync(connection.DbConnection, eventData, default, cancellationToken);
+ }
+ }
+
+ return default;
+ }
+
+ private ConnectionEventData BroadcastConnectionOpening(
+ IRelationalConnection connection,
+ DateTimeOffset startTime,
+ EventDefinition definition,
+ bool async,
+ bool diagnosticSourceEnabled,
+ bool simpleLogEnabled)
+ {
+ var eventData = new ConnectionEventData(
+ definition,
+ ConnectionOpening,
+ connection.DbConnection,
+ connection.Context,
+ connection.ConnectionId,
+ async,
+ startTime);
+
+ DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+
+ return eventData;
+
+ static string ConnectionOpening(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (ConnectionEventData)payload;
+ return d.GenerateMessage(
+ p.Connection.Database,
+ p.Connection.DataSource);
+ }
+ }
+
+ #endregion ConnectionOpening
+
+ #region ConnectionOpened
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual void ConnectionOpened(
+ IRelationalConnection connection,
+ DateTimeOffset startTime,
+ TimeSpan duration)
+ {
+ var definition = RelationalResources.LogOpenedConnection(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressOpenExpiration = default;
+
+ definition.Log(this, connection.DbConnection.Database, connection.DbConnection.DataSource);
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressOpenExpiration = default;
+
+ var eventData = BroadcastConnectionOpened(
+ connection,
+ async: false,
+ startTime,
+ duration,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ interceptor?.ConnectionOpened(connection.DbConnection, eventData);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual Task ConnectionOpenedAsync(
+ IRelationalConnection connection,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ CancellationToken cancellationToken = default)
+ {
+ var definition = RelationalResources.LogOpenedConnection(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressOpenExpiration = default;
+
+ definition.Log(this, connection.DbConnection.Database, connection.DbConnection.DataSource);
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressOpenExpiration = default;
+
+ var eventData = BroadcastConnectionOpened(
+ connection,
+ async: true,
+ startTime,
+ duration,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ConnectionOpenedAsync(connection.DbConnection, eventData, cancellationToken);
+ }
+ }
+
+ return Task.CompletedTask;
+ }
+
+ private ConnectionEndEventData BroadcastConnectionOpened(
+ IRelationalConnection connection,
+ bool async,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ EventDefinition definition,
+ bool diagnosticSourceEnabled,
+ bool simpleLogEnabled)
+ {
+ var eventData = new ConnectionEndEventData(
+ definition,
+ ConnectionOpened,
+ connection.DbConnection,
+ connection.Context,
+ connection.ConnectionId,
+ async,
+ startTime,
+ duration);
+
+ DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+
+ return eventData;
+
+ static string ConnectionOpened(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (ConnectionEndEventData)payload;
+ return d.GenerateMessage(
+ p.Connection.Database,
+ p.Connection.DataSource);
+ }
+ }
+
+ #endregion ConnectionOpened
+
+ #region ConnectionClosing
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual InterceptionResult ConnectionClosing(
+ IRelationalConnection connection,
+ DateTimeOffset startTime)
+ {
+ _suppressCloseExpiration = startTime + _loggingConfigCacheTime;
+
+ var definition = RelationalResources.LogClosingConnection(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCloseExpiration = default;
+
+ definition.Log(this, connection.DbConnection.Database, connection.DbConnection.DataSource);
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCloseExpiration = default;
+
+ var eventData = BroadcastConnectionClosing(
+ connection,
+ startTime,
+ async: false,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ConnectionClosing(connection.DbConnection, eventData, default);
+ }
+ }
+
+ return default;
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual ValueTask ConnectionClosingAsync(
+ IRelationalConnection connection,
+ DateTimeOffset startTime)
+ {
+ _suppressCloseExpiration = startTime + _loggingConfigCacheTime;
+
+ var definition = RelationalResources.LogClosingConnection(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCloseExpiration = default;
+
+ definition.Log(this, connection.DbConnection.Database, connection.DbConnection.DataSource);
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCloseExpiration = default;
+
+ var eventData = BroadcastConnectionClosing(
+ connection,
+ startTime,
+ async: true,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ConnectionClosingAsync(connection.DbConnection, eventData, default);
+ }
+ }
+
+ return default;
+ }
+
+ private ConnectionEventData BroadcastConnectionClosing(
+ IRelationalConnection connection,
+ DateTimeOffset startTime,
+ bool async,
+ EventDefinition definition,
+ bool diagnosticSourceEnabled,
+ bool simpleLogEnabled)
+ {
+ var eventData = new ConnectionEventData(
+ definition,
+ ConnectionClosing,
+ connection.DbConnection,
+ connection.Context,
+ connection.ConnectionId,
+ async,
+ startTime);
+
+ DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+
+ return eventData;
+
+ static string ConnectionClosing(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (ConnectionEventData)payload;
+ return d.GenerateMessage(
+ p.Connection.Database,
+ p.Connection.DataSource);
+ }
+ }
+
+ #endregion ConnectionClosing
+
+ #region ConnectionClosed
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual void ConnectionClosed(
+ IRelationalConnection connection,
+ DateTimeOffset startTime,
+ TimeSpan duration)
+ {
+ var definition = RelationalResources.LogClosedConnection(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCloseExpiration = default;
+
+ definition.Log(this, connection.DbConnection.Database, connection.DbConnection.DataSource);
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCloseExpiration = default;
+
+ var eventData = BroadcastCollectionClosed(
+ connection,
+ startTime,
+ duration,
+ false,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ interceptor?.ConnectionClosed(connection.DbConnection, eventData);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual Task ConnectionClosedAsync(
+ IRelationalConnection connection,
+ DateTimeOffset startTime,
+ TimeSpan duration)
+ {
+ var definition = RelationalResources.LogClosedConnection(this);
+
+ if (ShouldLog(definition))
+ {
+ _suppressCloseExpiration = default;
+
+ definition.Log(this, connection.DbConnection.Database, connection.DbConnection.DataSource);
+ }
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ _suppressCloseExpiration = default;
+
+ var eventData = BroadcastCollectionClosed(
+ connection,
+ startTime,
+ duration,
+ async: true,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ConnectionClosedAsync(connection.DbConnection, eventData);
+ }
+ }
+
+ return Task.CompletedTask;
+ }
+
+ private ConnectionEndEventData BroadcastCollectionClosed(
+ IRelationalConnection connection,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ bool async,
+ EventDefinition definition,
+ bool diagnosticSourceEnabled,
+ bool simpleLogEnabled)
+ {
+ var eventData = new ConnectionEndEventData(
+ definition,
+ ConnectionClosed,
+ connection.DbConnection,
+ connection.Context,
+ connection.ConnectionId,
+ async,
+ startTime,
+ duration);
+
+ DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+
+ return eventData;
+
+ static string ConnectionClosed(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (ConnectionEndEventData)payload;
+ return d.GenerateMessage(
+ p.Connection.Database,
+ p.Connection.DataSource);
+ }
+ }
+
+ #endregion ConnectionClosed
+
+ #region ConnectionError
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual void ConnectionError(
+ IRelationalConnection connection,
+ Exception exception,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ bool logErrorAsDebug)
+ {
+ var definition = logErrorAsDebug
+ ? RelationalResources.LogConnectionErrorAsDebug(this)
+ : RelationalResources.LogConnectionError(this);
+
+ LogConnectionError(connection, definition);
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ var eventData = BroadcastConnectionError(
+ connection,
+ exception,
+ startTime,
+ duration,
+ false,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ interceptor?.ConnectionFailed(connection.DbConnection, eventData);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual Task ConnectionErrorAsync(
+ IRelationalConnection connection,
+ Exception exception,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ bool logErrorAsDebug,
+ CancellationToken cancellationToken = default)
+ {
+ var definition = logErrorAsDebug
+ ? RelationalResources.LogConnectionErrorAsDebug(this)
+ : RelationalResources.LogConnectionError(this);
+
+ LogConnectionError(connection, definition);
+
+ if (NeedsEventData(
+ definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ var eventData = BroadcastConnectionError(
+ connection,
+ exception,
+ startTime,
+ duration,
+ true,
+ definition,
+ diagnosticSourceEnabled,
+ simpleLogEnabled);
+
+ if (interceptor != null)
+ {
+ return interceptor.ConnectionFailedAsync(connection.DbConnection, eventData, cancellationToken);
+ }
+ }
+
+ return Task.CompletedTask;
+ }
+
+ private ConnectionErrorEventData BroadcastConnectionError(
+ IRelationalConnection connection,
+ Exception exception,
+ DateTimeOffset startTime,
+ TimeSpan duration,
+ bool async,
+ EventDefinition definition,
+ bool diagnosticSourceEnabled,
+ bool simpleLogEnabled)
+ {
+ var eventData = new ConnectionErrorEventData(
+ definition,
+ ConnectionError,
+ connection.DbConnection,
+ connection.Context,
+ connection.ConnectionId,
+ exception,
+ async,
+ startTime,
+ duration);
+
+ DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+
+ return eventData;
+
+ static string ConnectionError(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (ConnectionErrorEventData)payload;
+ return d.GenerateMessage(
+ p.Connection.Database,
+ p.Connection.DataSource);
+ }
+ }
+
+ private void LogConnectionError(
+ IRelationalConnection connection,
+ EventDefinition definition)
+ {
+ if (ShouldLog(definition))
+ {
+ definition.Log(this, connection.DbConnection.Database, connection.DbConnection.DataSource);
+ }
+ }
+
+ #endregion ConnectionError
+
+ #region ShouldLog checks
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual bool ShouldLogConnectionOpen(DateTimeOffset now)
+ => now > _suppressOpenExpiration;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual bool ShouldLogConnectionClose(DateTimeOffset now)
+ => now > _suppressCloseExpiration;
+
+ #endregion ShouldLog checks
+ }
+}
diff --git a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs
index 6d7d795432c..55146ed3e93 100644
--- a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs
+++ b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs
@@ -41,1806 +41,6 @@ namespace Microsoft.EntityFrameworkCore.Diagnostics
///
public static class RelationalLoggerExtensions
{
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The type of method that will be called on this command.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The time that execution began.
- /// An intercepted result.
- public static InterceptionResult CommandCreating(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommandMethod commandMethod,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- DateTimeOffset startTime)
- {
- var definition = RelationalResources.LogCommandCreating(diagnostics);
-
- LogCommandCreating(diagnostics, definition, commandMethod);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandCreating(
- diagnostics,
- connection.DbConnection,
- context,
- commandMethod,
- commandId,
- connectionId,
- false,
- startTime,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.CommandCreating(eventData, default);
- }
- }
-
- return default;
- }
-
- private static CommandCorrelatedEventData BroadcastCommandCreating(
- IDiagnosticsLogger diagnostics,
- DbConnection connection,
- DbContext? context,
- DbCommandMethod executeMethod,
- Guid commandId,
- Guid connectionId,
- bool async,
- DateTimeOffset startTime,
- EventDefinition definition,
- bool diagnosticSourceEnabled,
- bool simpleLogEnabled)
- {
- var eventData = new CommandCorrelatedEventData(
- definition,
- CommandCreating,
- connection,
- context,
- executeMethod,
- commandId,
- connectionId,
- async,
- startTime);
-
- diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
-
- return eventData;
- }
-
- private static void LogCommandCreating(
- IDiagnosticsLogger diagnostics,
- EventDefinition definition,
- DbCommandMethod commandMethod)
- {
- if (diagnostics.ShouldLog(definition))
- {
- definition.Log(diagnostics, commandMethod.ToString());
- }
- }
-
- private static string CommandCreating(EventDefinitionBase definition, EventData payload)
- {
- var d = (EventDefinition)definition;
- var p = (CommandCorrelatedEventData)payload;
- return d.GenerateMessage(p.ExecuteMethod.ToString());
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The type of method that will be called on this command.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The time that execution began.
- /// The duration of the command creation.
- /// An intercepted result.
- public static DbCommand CommandCreated(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbCommandMethod commandMethod,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- DateTimeOffset startTime,
- TimeSpan duration)
- {
- var definition = RelationalResources.LogCommandCreated(diagnostics);
-
- LogCommandCreated(diagnostics, definition, commandMethod, duration);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandCreated(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- commandMethod,
- commandId,
- connectionId,
- false,
- startTime,
- duration,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.CommandCreated(eventData, command);
- }
- }
-
- return command;
- }
-
- private static CommandEndEventData BroadcastCommandCreated(
- IDiagnosticsLogger diagnostics,
- DbConnection connection,
- DbCommand command,
- DbContext? context,
- DbCommandMethod executeMethod,
- Guid commandId,
- Guid connectionId,
- bool async,
- DateTimeOffset startTime,
- TimeSpan duration,
- EventDefinition definition,
- bool diagnosticSourceEnabled,
- bool simpleLogEnabled)
- {
- var eventData = new CommandEndEventData(
- definition,
- CommandCreated,
- connection,
- command,
- context,
- executeMethod,
- commandId,
- connectionId,
- async,
- false,
- startTime,
- duration);
-
- diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
-
- return eventData;
- }
-
- private static void LogCommandCreated(
- IDiagnosticsLogger diagnostics,
- EventDefinition definition,
- DbCommandMethod commandMethod,
- TimeSpan duration)
- {
- if (diagnostics.ShouldLog(definition))
- {
- definition.Log(diagnostics, commandMethod.ToString(), (int)duration.TotalMilliseconds);
- }
- }
-
- private static string CommandCreated(EventDefinitionBase definition, EventData payload)
- {
- var d = (EventDefinition)definition;
- var p = (CommandEndEventData)payload;
- return d.GenerateMessage(p.ExecuteMethod.ToString(), (int)p.Duration.TotalMilliseconds);
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The time that execution began.
- /// An intercepted result.
- public static InterceptionResult CommandReaderExecuting(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- DateTimeOffset startTime)
- {
- var definition = RelationalResources.LogExecutingCommand(diagnostics);
-
- LogCommandExecuting(diagnostics, command, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandExecuting(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- DbCommandMethod.ExecuteReader,
- commandId,
- connectionId,
- false,
- startTime,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ReaderExecuting(command, eventData, default);
- }
- }
-
- return default;
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The time that execution began.
- /// An intercepted result.
- public static InterceptionResult CommandScalarExecuting(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- DateTimeOffset startTime)
- {
- var definition = RelationalResources.LogExecutingCommand(diagnostics);
-
- LogCommandExecuting(diagnostics, command, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandExecuting(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- DbCommandMethod.ExecuteScalar,
- commandId,
- connectionId,
- false,
- startTime,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ScalarExecuting(command, eventData, default);
- }
- }
-
- return default;
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The time that execution began.
- /// An intercepted result.
- public static InterceptionResult CommandNonQueryExecuting(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- DateTimeOffset startTime)
- {
- var definition = RelationalResources.LogExecutingCommand(diagnostics);
-
- LogCommandExecuting(diagnostics, command, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandExecuting(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- DbCommandMethod.ExecuteNonQuery,
- commandId,
- connectionId,
- false,
- startTime,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.NonQueryExecuting(command, eventData, default);
- }
- }
-
- return default;
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The time that execution began.
- /// A to observe while waiting for the task to complete.
- /// An intercepted result.
- /// If the is canceled.
- public static ValueTask> CommandReaderExecutingAsync(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- DateTimeOffset startTime,
- CancellationToken cancellationToken = default)
- {
- var definition = RelationalResources.LogExecutingCommand(diagnostics);
-
- LogCommandExecuting(diagnostics, command, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandExecuting(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- DbCommandMethod.ExecuteReader,
- commandId,
- connectionId,
- true,
- startTime,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ReaderExecutingAsync(command, eventData, default, cancellationToken);
- }
- }
-
- return default;
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The time that execution began.
- /// A to observe while waiting for the task to complete.
- /// An intercepted result.
- /// If the is canceled.
- public static ValueTask> CommandScalarExecutingAsync(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- DateTimeOffset startTime,
- CancellationToken cancellationToken = default)
- {
- var definition = RelationalResources.LogExecutingCommand(diagnostics);
-
- LogCommandExecuting(diagnostics, command, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandExecuting(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- DbCommandMethod.ExecuteScalar,
- commandId,
- connectionId,
- true,
- startTime,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ScalarExecutingAsync(command, eventData, default, cancellationToken);
- }
- }
-
- return default;
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The time that execution began.
- /// A to observe while waiting for the task to complete.
- /// An intercepted result.
- /// If the is canceled.
- public static ValueTask> CommandNonQueryExecutingAsync(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- DateTimeOffset startTime,
- CancellationToken cancellationToken = default)
- {
- var definition = RelationalResources.LogExecutingCommand(diagnostics);
-
- LogCommandExecuting(diagnostics, command, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandExecuting(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- DbCommandMethod.ExecuteNonQuery,
- commandId,
- connectionId,
- true,
- startTime,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.NonQueryExecutingAsync(command, eventData, default, cancellationToken);
- }
- }
-
- return default;
- }
-
- private static CommandEventData BroadcastCommandExecuting(
- IDiagnosticsLogger diagnostics,
- DbConnection connection,
- DbCommand command,
- DbContext? context,
- DbCommandMethod executeMethod,
- Guid commandId,
- Guid connectionId,
- bool async,
- DateTimeOffset startTime,
- EventDefinition definition,
- bool diagnosticSourceEnabled,
- bool simpleLogEnabled)
- {
- var eventData = new CommandEventData(
- definition,
- CommandExecuting,
- connection,
- command,
- context,
- executeMethod,
- commandId,
- connectionId,
- async,
- ShouldLogParameterValues(diagnostics, command),
- startTime);
-
- diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
-
- return eventData;
- }
-
- private static void LogCommandExecuting(
- IDiagnosticsLogger diagnostics,
- DbCommand command,
- EventDefinition definition)
- {
- if (diagnostics.ShouldLog(definition))
- {
- definition.Log(
- diagnostics,
- command.Parameters.FormatParameters(ShouldLogParameterValues(diagnostics, command)),
- command.CommandType,
- command.CommandTimeout,
- Environment.NewLine,
- command.CommandText.TrimEnd());
- }
- }
-
- private static string CommandExecuting(EventDefinitionBase definition, EventData payload)
- {
- var d = (EventDefinition)definition;
- var p = (CommandEventData)payload;
- return d.GenerateMessage(
- p.Command.Parameters.FormatParameters(p.LogParameterValues),
- p.Command.CommandType,
- p.Command.CommandTimeout,
- Environment.NewLine,
- p.Command.CommandText.TrimEnd());
- }
-
- private static bool ShouldLogParameterValues(
- IDiagnosticsLogger diagnostics,
- DbCommand command)
- => command.Parameters.Count > 0
- && diagnostics.ShouldLogSensitiveData();
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The return value from the underlying method execution.
- /// The time that execution began.
- /// The duration of the command execution, not including consuming results.
- /// The result of execution, which may have been modified by an interceptor.
- public static DbDataReader CommandReaderExecuted(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- DbDataReader methodResult,
- DateTimeOffset startTime,
- TimeSpan duration)
- {
- var definition = RelationalResources.LogExecutedCommand(diagnostics);
-
- LogCommandExecuted(diagnostics, command, duration, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandExecuted(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- DbCommandMethod.ExecuteReader,
- commandId,
- connectionId,
- methodResult,
- false,
- startTime,
- duration,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ReaderExecuted(command, eventData, methodResult);
- }
- }
-
- return methodResult;
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The return value from the underlying method execution.
- /// The time that execution began.
- /// The duration of the command execution, not including consuming results.
- /// The result of execution, which may have been modified by an interceptor.
- public static object? CommandScalarExecuted(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- object? methodResult,
- DateTimeOffset startTime,
- TimeSpan duration)
- {
- var definition = RelationalResources.LogExecutedCommand(diagnostics);
-
- LogCommandExecuted(diagnostics, command, duration, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandExecuted(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- DbCommandMethod.ExecuteScalar,
- commandId,
- connectionId,
- methodResult,
- false,
- startTime,
- duration,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ScalarExecuted(command, eventData, methodResult);
- }
- }
-
- return methodResult;
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The return value from the underlying method execution.
- /// The time that execution began.
- /// The duration of the command execution, not including consuming results.
- /// The result of execution, which may have been modified by an interceptor.
- public static int CommandNonQueryExecuted(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- int methodResult,
- DateTimeOffset startTime,
- TimeSpan duration)
- {
- var definition = RelationalResources.LogExecutedCommand(diagnostics);
-
- LogCommandExecuted(diagnostics, command, duration, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandExecuted(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- DbCommandMethod.ExecuteNonQuery,
- commandId,
- connectionId,
- methodResult,
- false,
- startTime,
- duration,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.NonQueryExecuted(command, eventData, methodResult);
- }
- }
-
- return methodResult;
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The return value from the underlying method execution.
- /// The time that execution began.
- /// The duration of the command execution, not including consuming results.
- /// A to observe while waiting for the task to complete.
- /// The result of execution, which may have been modified by an interceptor.
- /// If the is canceled.
- public static ValueTask CommandReaderExecutedAsync(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- DbDataReader methodResult,
- DateTimeOffset startTime,
- TimeSpan duration,
- CancellationToken cancellationToken = default)
- {
- var definition = RelationalResources.LogExecutedCommand(diagnostics);
-
- LogCommandExecuted(diagnostics, command, duration, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandExecuted(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- DbCommandMethod.ExecuteReader,
- commandId,
- connectionId,
- methodResult,
- true,
- startTime,
- duration,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ReaderExecutedAsync(command, eventData, methodResult, cancellationToken);
- }
- }
-
- return new ValueTask(methodResult);
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The return value from the underlying method execution.
- /// The time that execution began.
- /// The duration of the command execution, not including consuming results.
- /// A to observe while waiting for the task to complete.
- /// The result of execution, which may have been modified by an interceptor.
- /// If the is canceled.
- public static ValueTask CommandScalarExecutedAsync(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- object? methodResult,
- DateTimeOffset startTime,
- TimeSpan duration,
- CancellationToken cancellationToken = default)
- {
- var definition = RelationalResources.LogExecutedCommand(diagnostics);
-
- LogCommandExecuted(diagnostics, command, duration, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandExecuted(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- DbCommandMethod.ExecuteScalar,
- commandId,
- connectionId,
- methodResult,
- true,
- startTime,
- duration,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ScalarExecutedAsync(command, eventData, methodResult, cancellationToken);
- }
- }
-
- return new ValueTask(methodResult);
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The return value from the underlying method execution.
- /// The time that execution began.
- /// The duration of the command execution, not including consuming results.
- /// A to observe while waiting for the task to complete.
- /// The result of execution, which may have been modified by an interceptor.
- /// If the is canceled.
- public static ValueTask CommandNonQueryExecutedAsync(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- Guid commandId,
- Guid connectionId,
- int methodResult,
- DateTimeOffset startTime,
- TimeSpan duration,
- CancellationToken cancellationToken = default)
- {
- var definition = RelationalResources.LogExecutedCommand(diagnostics);
-
- LogCommandExecuted(diagnostics, command, duration, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandExecuted(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- DbCommandMethod.ExecuteNonQuery,
- commandId,
- connectionId,
- methodResult,
- true,
- startTime,
- duration,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.NonQueryExecutedAsync(command, eventData, methodResult, cancellationToken);
- }
- }
-
- return new ValueTask(methodResult);
- }
-
- private static CommandExecutedEventData BroadcastCommandExecuted(
- IDiagnosticsLogger diagnostics,
- DbConnection connection,
- DbCommand command,
- DbContext? context,
- DbCommandMethod executeMethod,
- Guid commandId,
- Guid connectionId,
- object? methodResult,
- bool async,
- DateTimeOffset startTime,
- TimeSpan duration,
- EventDefinition definition,
- bool diagnosticSourceEnabled,
- bool simpleLogEnabled)
- {
- var eventData = new CommandExecutedEventData(
- definition,
- CommandExecuted,
- connection,
- command,
- context,
- executeMethod,
- commandId,
- connectionId,
- methodResult,
- async,
- ShouldLogParameterValues(diagnostics, command),
- startTime,
- duration);
-
- diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
-
- return eventData;
- }
-
- private static void LogCommandExecuted(
- IDiagnosticsLogger diagnostics,
- DbCommand command,
- TimeSpan duration,
- EventDefinition definition)
- {
- if (diagnostics.ShouldLog(definition))
- {
- definition.Log(
- diagnostics,
- string.Format(CultureInfo.InvariantCulture, "{0:N0}", duration.TotalMilliseconds),
- command.Parameters.FormatParameters(ShouldLogParameterValues(diagnostics, command)),
- command.CommandType,
- command.CommandTimeout,
- Environment.NewLine,
- command.CommandText.TrimEnd());
- }
- }
-
- private static string CommandExecuted(EventDefinitionBase definition, EventData payload)
- {
- var d = (EventDefinition)definition;
- var p = (CommandExecutedEventData)payload;
- return d.GenerateMessage(
- string.Format(CultureInfo.InvariantCulture, "{0:N0}", p.Duration.TotalMilliseconds),
- p.Command.Parameters.FormatParameters(p.LogParameterValues),
- p.Command.CommandType,
- p.Command.CommandTimeout,
- Environment.NewLine,
- p.Command.CommandText.TrimEnd());
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// Represents the method that will be called to execute the command.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The exception that caused this failure.
- /// The time that execution began.
- /// The amount of time that passed until the exception was raised.
- public static void CommandError(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- DbCommandMethod executeMethod,
- Guid commandId,
- Guid connectionId,
- Exception exception,
- DateTimeOffset startTime,
- TimeSpan duration)
- {
- var definition = RelationalResources.LogCommandFailed(diagnostics);
-
- LogCommandError(diagnostics, command, duration, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandError(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- executeMethod,
- commandId,
- connectionId,
- exception,
- false,
- startTime,
- duration,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- interceptor?.CommandFailed(command, eventData);
- }
- }
-
- private static void LogCommandError(
- IDiagnosticsLogger diagnostics,
- DbCommand command,
- TimeSpan duration,
- EventDefinition definition)
- {
- if (diagnostics.ShouldLog(definition))
- {
- definition.Log(
- diagnostics,
- string.Format(CultureInfo.InvariantCulture, "{0:N0}", duration.TotalMilliseconds),
- command.Parameters.FormatParameters(ShouldLogParameterValues(diagnostics, command)),
- command.CommandType,
- command.CommandTimeout,
- Environment.NewLine,
- command.CommandText.TrimEnd());
- }
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The currently being used, to null if not known.
- /// Represents the method that will be called to execute the command.
- /// The correlation ID associated with the given .
- /// The correlation ID associated with the being used.
- /// The exception that caused this failure.
- /// The time that execution began.
- /// The amount of time that passed until the exception was raised.
- /// A to observe while waiting for the task to complete.
- /// A representing the async operation.
- /// If the is canceled.
- public static Task CommandErrorAsync(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbContext? context,
- DbCommandMethod executeMethod,
- Guid commandId,
- Guid connectionId,
- Exception exception,
- DateTimeOffset startTime,
- TimeSpan duration,
- CancellationToken cancellationToken = default)
- {
- var definition = RelationalResources.LogCommandFailed(diagnostics);
-
- LogCommandError(diagnostics, command, duration, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCommandError(
- diagnostics,
- connection.DbConnection,
- command,
- context,
- executeMethod,
- commandId,
- connectionId,
- exception,
- true,
- startTime,
- duration,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.CommandFailedAsync(command, eventData, cancellationToken);
- }
- }
-
- return Task.CompletedTask;
- }
-
- private static CommandErrorEventData BroadcastCommandError(
- IDiagnosticsLogger diagnostics,
- DbConnection connection,
- DbCommand command,
- DbContext? context,
- DbCommandMethod executeMethod,
- Guid commandId,
- Guid connectionId,
- Exception exception,
- bool async,
- DateTimeOffset startTime,
- TimeSpan duration,
- EventDefinition definition,
- bool diagnosticSourceEnabled,
- bool simpleLogEnabled)
- {
- var eventData = new CommandErrorEventData(
- definition,
- CommandError,
- connection,
- command,
- context,
- executeMethod,
- commandId,
- connectionId,
- exception,
- async,
- ShouldLogParameterValues(diagnostics, command),
- startTime,
- duration);
-
- diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
-
- return eventData;
- }
-
- private static string CommandError(EventDefinitionBase definition, EventData payload)
- {
- var d = (EventDefinition)definition;
- var p = (CommandErrorEventData)payload;
- return d.GenerateMessage(
- string.Format(CultureInfo.InvariantCulture, "{0:N0}", p.Duration.TotalMilliseconds),
- p.Command.Parameters.FormatParameters(p.LogParameterValues),
- p.Command.CommandType,
- p.Command.CommandTimeout,
- Environment.NewLine,
- p.Command.CommandText.TrimEnd());
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The time that the operation was started.
- /// The result of execution, which may have been modified by an interceptor.
- public static InterceptionResult ConnectionOpening(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DateTimeOffset startTime)
- {
- var definition = RelationalResources.LogOpeningConnection(diagnostics);
-
- LogConnectionOpening(diagnostics, connection, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastConnectionOpening(
- diagnostics,
- connection,
- startTime,
- definition,
- false,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ConnectionOpening(connection.DbConnection, eventData, default);
- }
- }
-
- return default;
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The time that the operation was started.
- /// A to observe while waiting for the task to complete.
- /// A representing the async operation.
- /// If the is canceled.
- public static ValueTask ConnectionOpeningAsync(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DateTimeOffset startTime,
- CancellationToken cancellationToken)
- {
- var definition = RelationalResources.LogOpeningConnection(diagnostics);
-
- LogConnectionOpening(diagnostics, connection, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastConnectionOpening(
- diagnostics,
- connection,
- startTime,
- definition,
- true,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ConnectionOpeningAsync(connection.DbConnection, eventData, default, cancellationToken);
- }
- }
-
- return default;
- }
-
- private static void LogConnectionOpening(
- IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- EventDefinition definition)
- {
- if (diagnostics.ShouldLog(definition))
- {
- definition.Log(
- diagnostics,
- connection.DbConnection.Database, connection.DbConnection.DataSource);
- }
- }
-
- private static ConnectionEventData BroadcastConnectionOpening(
- IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DateTimeOffset startTime,
- EventDefinition definition,
- bool async,
- bool diagnosticSourceEnabled,
- bool simpleLogEnabled)
- {
- var eventData = new ConnectionEventData(
- definition,
- ConnectionOpening,
- connection.DbConnection,
- connection.Context,
- connection.ConnectionId,
- async,
- startTime);
-
- diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
-
- return eventData;
- }
-
- private static string ConnectionOpening(EventDefinitionBase definition, EventData payload)
- {
- var d = (EventDefinition)definition;
- var p = (ConnectionEventData)payload;
- return d.GenerateMessage(
- p.Connection.Database,
- p.Connection.DataSource);
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The time that the operation was started.
- /// The amount of time before the connection was opened.
- public static void ConnectionOpened(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DateTimeOffset startTime,
- TimeSpan duration)
- {
- var definition = RelationalResources.LogOpenedConnection(diagnostics);
-
- LogConnectionOpened(diagnostics, connection, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastConnectionOpened(
- diagnostics,
- connection,
- false,
- startTime,
- duration,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- interceptor?.ConnectionOpened(connection.DbConnection, eventData);
- }
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The time that the operation was started.
- /// The amount of time before the connection was opened.
- /// A to observe while waiting for the task to complete.
- /// A representing the async operation.
- /// If the is canceled.
- public static Task ConnectionOpenedAsync(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DateTimeOffset startTime,
- TimeSpan duration,
- CancellationToken cancellationToken = default)
- {
- var definition = RelationalResources.LogOpenedConnection(diagnostics);
-
- LogConnectionOpened(diagnostics, connection, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastConnectionOpened(
- diagnostics,
- connection,
- true,
- startTime,
- duration,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ConnectionOpenedAsync(connection.DbConnection, eventData, cancellationToken);
- }
- }
-
- return Task.CompletedTask;
- }
-
- private static ConnectionEndEventData BroadcastConnectionOpened(
- IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- bool async,
- DateTimeOffset startTime,
- TimeSpan duration,
- EventDefinition definition,
- bool diagnosticSourceEnabled,
- bool simpleLogEnabled)
- {
- var eventData = new ConnectionEndEventData(
- definition,
- ConnectionOpened,
- connection.DbConnection,
- connection.Context,
- connection.ConnectionId,
- async,
- startTime,
- duration);
-
- diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
-
- return eventData;
- }
-
- private static void LogConnectionOpened(
- IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- EventDefinition definition)
- {
- if (diagnostics.ShouldLog(definition))
- {
- definition.Log(
- diagnostics,
- connection.DbConnection.Database, connection.DbConnection.DataSource);
- }
- }
-
- private static string ConnectionOpened(EventDefinitionBase definition, EventData payload)
- {
- var d = (EventDefinition)definition;
- var p = (ConnectionEndEventData)payload;
- return d.GenerateMessage(
- p.Connection.Database,
- p.Connection.DataSource);
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The time that the operation was started.
- /// The result of execution, which may have been modified by an interceptor.
- public static InterceptionResult ConnectionClosing(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DateTimeOffset startTime)
- {
- var definition = RelationalResources.LogClosingConnection(diagnostics);
-
- LogConnectionClosing(diagnostics, connection, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastConnectionClosing(
- diagnostics,
- connection,
- startTime,
- false,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ConnectionClosing(connection.DbConnection, eventData, default);
- }
- }
-
- return default;
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The time that the operation was started.
- /// A representing the async operation.
- public static ValueTask ConnectionClosingAsync(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DateTimeOffset startTime)
- {
- var definition = RelationalResources.LogClosingConnection(diagnostics);
-
- LogConnectionClosing(diagnostics, connection, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastConnectionClosing(
- diagnostics,
- connection,
- startTime,
- true,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ConnectionClosingAsync(connection.DbConnection, eventData, default);
- }
- }
-
- return default;
- }
-
- private static ConnectionEventData BroadcastConnectionClosing(
- IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DateTimeOffset startTime,
- bool async,
- EventDefinition definition,
- bool diagnosticSourceEnabled,
- bool simpleLogEnabled)
- {
- var eventData = new ConnectionEventData(
- definition,
- ConnectionClosing,
- connection.DbConnection,
- connection.Context,
- connection.ConnectionId,
- async,
- startTime);
-
- diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
-
- return eventData;
- }
-
- private static void LogConnectionClosing(
- IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- EventDefinition definition)
- {
- if (diagnostics.ShouldLog(definition))
- {
- definition.Log(
- diagnostics,
- connection.DbConnection.Database, connection.DbConnection.DataSource);
- }
- }
-
- private static string ConnectionClosing(EventDefinitionBase definition, EventData payload)
- {
- var d = (EventDefinition)definition;
- var p = (ConnectionEventData)payload;
- return d.GenerateMessage(
- p.Connection.Database,
- p.Connection.DataSource);
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The time that the operation was started.
- /// The amount of time before the connection was closed.
- public static void ConnectionClosed(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DateTimeOffset startTime,
- TimeSpan duration)
- {
- var definition = RelationalResources.LogClosedConnection(diagnostics);
-
- LogConnectionClosed(diagnostics, connection, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCollectionClosed(
- diagnostics,
- connection,
- startTime,
- duration,
- false,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- interceptor?.ConnectionClosed(connection.DbConnection, eventData);
- }
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The time that the operation was started.
- /// The amount of time before the connection was closed.
- /// A representing the async operation.
- public static Task ConnectionClosedAsync(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DateTimeOffset startTime,
- TimeSpan duration)
- {
- var definition = RelationalResources.LogClosedConnection(diagnostics);
-
- LogConnectionClosed(diagnostics, connection, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastCollectionClosed(
- diagnostics,
- connection,
- startTime,
- duration,
- true,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ConnectionClosedAsync(connection.DbConnection, eventData);
- }
- }
-
- return Task.CompletedTask;
- }
-
- private static ConnectionEndEventData BroadcastCollectionClosed(
- IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DateTimeOffset startTime,
- TimeSpan duration,
- bool async,
- EventDefinition definition,
- bool diagnosticSourceEnabled,
- bool simpleLogEnabled)
- {
- var eventData = new ConnectionEndEventData(
- definition,
- ConnectionClosed,
- connection.DbConnection,
- connection.Context,
- connection.ConnectionId,
- async,
- startTime,
- duration);
-
- diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
-
- return eventData;
- }
-
- private static void LogConnectionClosed(
- IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- EventDefinition definition)
- {
- if (diagnostics.ShouldLog(definition))
- {
- definition.Log(
- diagnostics,
- connection.DbConnection.Database, connection.DbConnection.DataSource);
- }
- }
-
- private static string ConnectionClosed(EventDefinitionBase definition, EventData payload)
- {
- var d = (EventDefinition)definition;
- var p = (ConnectionEndEventData)payload;
- return d.GenerateMessage(
- p.Connection.Database,
- p.Connection.DataSource);
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The exception representing the error.
- /// The time that the operation was started.
- /// The elapsed time before the operation failed.
- /// A flag indicating the exception is being handled and so it should be logged at Debug level.
- public static void ConnectionError(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- Exception exception,
- DateTimeOffset startTime,
- TimeSpan duration,
- bool logErrorAsDebug)
- {
- var definition = logErrorAsDebug
- ? RelationalResources.LogConnectionErrorAsDebug(diagnostics)
- : RelationalResources.LogConnectionError(diagnostics);
-
- LogConnectionError(diagnostics, connection, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastConnectionError(
- diagnostics,
- connection,
- exception,
- startTime,
- duration,
- false,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- interceptor?.ConnectionFailed(connection.DbConnection, eventData);
- }
- }
-
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The exception representing the error.
- /// The time that the operation was started.
- /// The elapsed time before the operation failed.
- /// A flag indicating the exception is being handled and so it should be logged at Debug level.
- /// A to observe while waiting for the task to complete.
- /// A representing the async operation.
- /// If the is canceled.
- public static Task ConnectionErrorAsync(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- Exception exception,
- DateTimeOffset startTime,
- TimeSpan duration,
- bool logErrorAsDebug,
- CancellationToken cancellationToken = default)
- {
- var definition = logErrorAsDebug
- ? RelationalResources.LogConnectionErrorAsDebug(diagnostics)
- : RelationalResources.LogConnectionError(diagnostics);
-
- LogConnectionError(diagnostics, connection, definition);
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = BroadcastConnectionError(
- diagnostics,
- connection,
- exception,
- startTime,
- duration,
- true,
- definition,
- diagnosticSourceEnabled,
- simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.ConnectionFailedAsync(connection.DbConnection, eventData, cancellationToken);
- }
- }
-
- return Task.CompletedTask;
- }
-
- private static ConnectionErrorEventData BroadcastConnectionError(
- IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- Exception exception,
- DateTimeOffset startTime,
- TimeSpan duration,
- bool async,
- EventDefinition definition,
- bool diagnosticSourceEnabled,
- bool simpleLogEnabled)
- {
- var eventData = new ConnectionErrorEventData(
- definition,
- ConnectionError,
- connection.DbConnection,
- connection.Context,
- connection.ConnectionId,
- exception,
- async,
- startTime,
- duration);
-
- diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
-
- return eventData;
- }
-
- private static void LogConnectionError(
- IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- EventDefinition definition)
- {
- if (diagnostics.ShouldLog(definition))
- {
- definition.Log(
- diagnostics,
- connection.DbConnection.Database, connection.DbConnection.DataSource);
- }
- }
-
- private static string ConnectionError(EventDefinitionBase definition, EventData payload)
- {
- var d = (EventDefinition)definition;
- var p = (ConnectionErrorEventData)payload;
- return d.GenerateMessage(
- p.Connection.Database,
- p.Connection.DataSource);
- }
-
///
/// Logs for the event.
///
@@ -3785,64 +1985,6 @@ private static string ExplicitTransactionEnlisted(EventDefinitionBase definition
return d.GenerateMessage(p.Transaction.IsolationLevel.ToString("G"));
}
- ///
- /// Logs for the event.
- ///
- /// The diagnostics logger to use.
- /// The connection.
- /// The database command object.
- /// The data reader.
- /// The correlation ID associated with the given .
- /// The number of records in the database that were affected.
- /// The number of records that were read.
- /// The time that the operation was started.
- /// The elapsed time from when the operation was started.
- /// The result of execution, which may have been modified by an interceptor.
- public static InterceptionResult DataReaderDisposing(
- this IDiagnosticsLogger diagnostics,
- IRelationalConnection connection,
- DbCommand command,
- DbDataReader dataReader,
- Guid commandId,
- int recordsAffected,
- int readCount,
- DateTimeOffset startTime,
- TimeSpan duration)
- {
- var definition = RelationalResources.LogDisposingDataReader(diagnostics);
-
- if (diagnostics.ShouldLog(definition))
- {
- definition.Log(diagnostics);
- }
-
- if (diagnostics.NeedsEventData(
- definition, out var interceptor, out var diagnosticSourceEnabled, out var simpleLogEnabled))
- {
- var eventData = new DataReaderDisposingEventData(
- definition,
- (d, p) => ((EventDefinition)d).GenerateMessage(),
- command,
- dataReader,
- connection.Context,
- commandId,
- connection.ConnectionId,
- recordsAffected,
- readCount,
- startTime,
- duration);
-
- diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
-
- if (interceptor != null)
- {
- return interceptor.DataReaderDisposing(command, eventData, default);
- }
- }
-
- return default;
- }
-
///
/// Logs for the event.
///
diff --git a/src/EFCore.Relational/Infrastructure/EntityFrameworkRelationalServicesBuilder.cs b/src/EFCore.Relational/Infrastructure/EntityFrameworkRelationalServicesBuilder.cs
index 7cb0ce3a324..9e1cded2ba3 100644
--- a/src/EFCore.Relational/Infrastructure/EntityFrameworkRelationalServicesBuilder.cs
+++ b/src/EFCore.Relational/Infrastructure/EntityFrameworkRelationalServicesBuilder.cs
@@ -85,6 +85,10 @@ public static readonly IDictionary RelationalServi
{ typeof(IRelationalDatabaseCreator), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(IHistoryRepository), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(INamedConnectionStringResolver), new ServiceCharacteristics(ServiceLifetime.Scoped) },
+ { typeof(IRelationalConnectionDiagnosticsLogger), new ServiceCharacteristics(ServiceLifetime.Scoped) },
+ { typeof(IDiagnosticsLogger), new ServiceCharacteristics(ServiceLifetime.Scoped) },
+ { typeof(IRelationalCommandDiagnosticsLogger), new ServiceCharacteristics(ServiceLifetime.Scoped) },
+ { typeof(IDiagnosticsLogger), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(IInterceptor), new ServiceCharacteristics(ServiceLifetime.Scoped, multipleRegistrations: true) },
{
typeof(IRelationalTypeMappingSourcePlugin),
@@ -159,6 +163,10 @@ public override EntityFrameworkServicesBuilder TryAddCoreServices()
TryAdd();
TryAdd(p => p.GetRequiredService());
TryAdd();
+ TryAdd();
+ TryAdd>(p => p.GetRequiredService());
+ TryAdd();
+ TryAdd>(p => p.GetRequiredService());
TryAdd();
TryAdd();
TryAdd();
diff --git a/src/EFCore.Relational/Migrations/HistoryRepositoryDependencies.cs b/src/EFCore.Relational/Migrations/HistoryRepositoryDependencies.cs
index 72d20b8415f..bb3c33e2d19 100644
--- a/src/EFCore.Relational/Migrations/HistoryRepositoryDependencies.cs
+++ b/src/EFCore.Relational/Migrations/HistoryRepositoryDependencies.cs
@@ -85,7 +85,7 @@ public HistoryRepositoryDependencies(
ICurrentDbContext currentContext,
IModelRuntimeInitializer modelRuntimeInitializer,
IDiagnosticsLogger modelLogger,
- IDiagnosticsLogger commandLogger)
+ IRelationalCommandDiagnosticsLogger commandLogger)
{
Check.NotNull(databaseCreator, nameof(databaseCreator));
Check.NotNull(rawSqlCommandBuilder, nameof(rawSqlCommandBuilder));
@@ -188,6 +188,6 @@ public HistoryRepositoryDependencies(
///
/// The command logger
///
- public IDiagnosticsLogger CommandLogger { get; init; }
+ public IRelationalCommandDiagnosticsLogger CommandLogger { get; init; }
}
}
diff --git a/src/EFCore.Relational/Migrations/Internal/Migrator.cs b/src/EFCore.Relational/Migrations/Internal/Migrator.cs
index a9328dcbb68..549a7a3151d 100644
--- a/src/EFCore.Relational/Migrations/Internal/Migrator.cs
+++ b/src/EFCore.Relational/Migrations/Internal/Migrator.cs
@@ -43,7 +43,7 @@ public class Migrator : IMigrator
private readonly ICurrentDbContext _currentContext;
private readonly IModelRuntimeInitializer _modelRuntimeInitializer;
private readonly IDiagnosticsLogger _logger;
- private readonly IDiagnosticsLogger _commandLogger;
+ private readonly IRelationalCommandDiagnosticsLogger _commandLogger;
private readonly string _activeProvider;
///
@@ -64,7 +64,7 @@ public Migrator(
ICurrentDbContext currentContext,
IModelRuntimeInitializer modelRuntimeInitializer,
IDiagnosticsLogger logger,
- IDiagnosticsLogger commandLogger,
+ IRelationalCommandDiagnosticsLogger commandLogger,
IDatabaseProvider databaseProvider)
{
Check.NotNull(migrationsAssembly, nameof(migrationsAssembly));
diff --git a/src/EFCore.Relational/Migrations/MigrationCommand.cs b/src/EFCore.Relational/Migrations/MigrationCommand.cs
index 01418ef1a01..1abf7079451 100644
--- a/src/EFCore.Relational/Migrations/MigrationCommand.cs
+++ b/src/EFCore.Relational/Migrations/MigrationCommand.cs
@@ -29,7 +29,7 @@ public class MigrationCommand
public MigrationCommand(
IRelationalCommand relationalCommand,
DbContext? context,
- IDiagnosticsLogger logger,
+ IRelationalCommandDiagnosticsLogger logger,
bool transactionSuppressed = false)
{
Check.NotNull(relationalCommand, nameof(relationalCommand));
@@ -54,7 +54,7 @@ public virtual string CommandText
///
/// The associated command logger.
///
- public virtual IDiagnosticsLogger CommandLogger { get; }
+ public virtual IRelationalCommandDiagnosticsLogger CommandLogger { get; }
///
/// Executes the command and returns the number of rows affected.
diff --git a/src/EFCore.Relational/Migrations/MigrationsSqlGeneratorDependencies.cs b/src/EFCore.Relational/Migrations/MigrationsSqlGeneratorDependencies.cs
index bbfa97be1fa..c9b6eb489e7 100644
--- a/src/EFCore.Relational/Migrations/MigrationsSqlGeneratorDependencies.cs
+++ b/src/EFCore.Relational/Migrations/MigrationsSqlGeneratorDependencies.cs
@@ -62,7 +62,7 @@ public MigrationsSqlGeneratorDependencies(
IRelationalTypeMappingSource typeMappingSource,
ICurrentDbContext currentContext,
ILoggingOptions loggingOptions,
- IDiagnosticsLogger logger,
+ IRelationalCommandDiagnosticsLogger logger,
IDiagnosticsLogger migrationsLogger)
{
Check.NotNull(commandBuilderFactory, nameof(commandBuilderFactory));
@@ -117,7 +117,7 @@ public MigrationsSqlGeneratorDependencies(
///
/// The database command logger.
///
- public IDiagnosticsLogger Logger { get; init; }
+ public IRelationalCommandDiagnosticsLogger Logger { get; init; }
///
/// The database command logger.
diff --git a/src/EFCore.Relational/Query/RelationalQueryContext.cs b/src/EFCore.Relational/Query/RelationalQueryContext.cs
index 0b0e09d6163..e15686438e1 100644
--- a/src/EFCore.Relational/Query/RelationalQueryContext.cs
+++ b/src/EFCore.Relational/Query/RelationalQueryContext.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Data.Common;
+using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Utilities;
@@ -58,5 +59,11 @@ public virtual IRelationalQueryStringFactory RelationalQueryStringFactory
///
public virtual IRelationalConnection Connection
=> RelationalDependencies.RelationalConnection;
+
+ ///
+ /// The command logger to use while executing the query.
+ ///
+ public new virtual IRelationalCommandDiagnosticsLogger CommandLogger
+ => (IRelationalCommandDiagnosticsLogger)base.CommandLogger;
}
}
diff --git a/src/EFCore.Relational/Storage/IRelationalDatabaseFacadeDependencies.cs b/src/EFCore.Relational/Storage/IRelationalDatabaseFacadeDependencies.cs
index aa949d5bb02..31909e75503 100644
--- a/src/EFCore.Relational/Storage/IRelationalDatabaseFacadeDependencies.cs
+++ b/src/EFCore.Relational/Storage/IRelationalDatabaseFacadeDependencies.cs
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
@@ -32,5 +33,10 @@ public interface IRelationalDatabaseFacadeDependencies : IDatabaseFacadeDependen
/// The raw SQL command builder.
///
IRawSqlCommandBuilder RawSqlCommandBuilder { get; }
+
+ ///
+ /// A command logger.
+ ///
+ new IRelationalCommandDiagnosticsLogger CommandLogger { get; }
}
}
diff --git a/src/EFCore.Relational/Storage/Internal/RelationalDatabaseFacadeDependencies.cs b/src/EFCore.Relational/Storage/Internal/RelationalDatabaseFacadeDependencies.cs
index a76502d4e7c..bb7ed0718ff 100644
--- a/src/EFCore.Relational/Storage/Internal/RelationalDatabaseFacadeDependencies.cs
+++ b/src/EFCore.Relational/Storage/Internal/RelationalDatabaseFacadeDependencies.cs
@@ -26,7 +26,7 @@ public RelationalDatabaseFacadeDependencies(
IDatabaseCreator databaseCreator,
IExecutionStrategyFactory executionStrategyFactory,
IEnumerable databaseProviders,
- IDiagnosticsLogger commandLogger,
+ IRelationalCommandDiagnosticsLogger commandLogger,
IConcurrencyDetector concurrencyDetector,
IRelationalConnection relationalConnection,
IRawSqlCommandBuilder rawSqlCommandBuilder,
@@ -81,7 +81,9 @@ public RelationalDatabaseFacadeDependencies(
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual IDiagnosticsLogger CommandLogger { get; init; }
+ public virtual IRelationalCommandDiagnosticsLogger CommandLogger { get; init; }
+
+ IDiagnosticsLogger IDatabaseFacadeDependencies.CommandLogger => CommandLogger;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
diff --git a/src/EFCore.Relational/Storage/RelationalCommand.cs b/src/EFCore.Relational/Storage/RelationalCommand.cs
index 72e5809048a..7b711c1ecdc 100644
--- a/src/EFCore.Relational/Storage/RelationalCommand.cs
+++ b/src/EFCore.Relational/Storage/RelationalCommand.cs
@@ -79,38 +79,52 @@ public virtual int ExecuteNonQuery(RelationalCommandParameterObject parameterObj
{
var (connection, context, logger) = (parameterObject.Connection, parameterObject.Context, parameterObject.Logger);
- var commandId = Guid.NewGuid();
+ var startTime = DateTimeOffset.UtcNow;
+
+ var shouldLogCommandCreate = logger?.ShouldLogCommandCreate(startTime) == true;
+ var shouldLogCommandExecute = logger?.ShouldLogCommandExecute(startTime) == true;
+
+ // Guid.NewGuid is expensive, do it only if needed
+ var commandId = shouldLogCommandCreate || shouldLogCommandExecute ? Guid.NewGuid() : default;
+
var command = CreateDbCommand(parameterObject, commandId, DbCommandMethod.ExecuteNonQuery);
connection.Open();
- var startTime = DateTimeOffset.UtcNow;
- _stopwatch.Restart();
try
{
- var interceptionResult = logger?.CommandNonQueryExecuting(
- connection,
- command,
- context,
- commandId,
- connection.ConnectionId,
- startTime)
- ?? default;
+ if (shouldLogCommandExecute)
+ {
+ _stopwatch.Restart();
- var nonQueryResult = interceptionResult.HasResult
- ? interceptionResult.Result
- : command.ExecuteNonQuery();
+ var interceptionResult = logger?.CommandNonQueryExecuting(
+ connection,
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ startTime)
+ ?? default;
- return logger?.CommandNonQueryExecuted(
- connection,
- command,
- context,
- commandId,
- connection.ConnectionId,
- nonQueryResult,
- startTime,
- _stopwatch.Elapsed)
- ?? nonQueryResult;
+ var nonQueryResult = interceptionResult.HasResult
+ ? interceptionResult.Result
+ : command.ExecuteNonQuery();
+
+ return logger?.CommandNonQueryExecuted(
+ connection,
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ nonQueryResult,
+ startTime,
+ _stopwatch.Elapsed)
+ ?? nonQueryResult;
+ }
+ else
+ {
+ return command.ExecuteNonQuery();
+ }
}
catch (Exception exception)
{
@@ -133,24 +147,6 @@ public virtual int ExecuteNonQuery(RelationalCommandParameterObject parameterObj
}
}
- private static void CleanupCommand(
- DbCommand command,
- IRelationalConnection connection)
- {
- command.Parameters.Clear();
- command.Dispose();
- connection.Close();
- }
-
- private static async Task CleanupCommandAsync(
- DbCommand command,
- IRelationalConnection connection)
- {
- command.Parameters.Clear();
- await command.DisposeAsync().ConfigureAwait(false);
- await connection.CloseAsync().ConfigureAwait(false);
- }
-
///
/// Asynchronously executes the command with no results.
///
@@ -166,47 +162,61 @@ public virtual async Task ExecuteNonQueryAsync(
{
var (connection, context, logger) = (parameterObject.Connection, parameterObject.Context, parameterObject.Logger);
- var commandId = Guid.NewGuid();
+ var startTime = DateTimeOffset.UtcNow;
+
+ var shouldLogCommandCreate = logger?.ShouldLogCommandCreate(startTime) == true;
+ var shouldLogCommandExecute = logger?.ShouldLogCommandExecute(startTime) == true;
+
+ // Guid.NewGuid is expensive, do it only if needed
+ var commandId = shouldLogCommandCreate || shouldLogCommandExecute ? Guid.NewGuid() : default;
+
var command = CreateDbCommand(parameterObject, commandId, DbCommandMethod.ExecuteNonQuery);
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
- var startTime = DateTimeOffset.UtcNow;
- _stopwatch.Restart();
try
{
- var interceptionResult = logger == null
- ? default
- : await logger.CommandNonQueryExecutingAsync(
- connection,
- command,
- context,
- commandId,
- connection.ConnectionId,
- startTime,
- cancellationToken)
- .ConfigureAwait(false);
-
- var result = interceptionResult.HasResult
- ? interceptionResult.Result
- : await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
-
- if (logger != null)
+ if (shouldLogCommandExecute)
{
- result = await logger.CommandNonQueryExecutedAsync(
- connection,
- command,
- context,
- commandId,
- connection.ConnectionId,
- result,
- startTime,
- _stopwatch.Elapsed,
- cancellationToken)
- .ConfigureAwait(false);
+ _stopwatch.Restart();
+
+ var interceptionResult = logger == null
+ ? default
+ : await logger.CommandNonQueryExecutingAsync(
+ connection,
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ startTime,
+ cancellationToken)
+ .ConfigureAwait(false);
+
+ var result = interceptionResult.HasResult
+ ? interceptionResult.Result
+ : await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
+
+ if (logger != null)
+ {
+ result = await logger.CommandNonQueryExecutedAsync(
+ connection,
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ result,
+ startTime,
+ _stopwatch.Elapsed,
+ cancellationToken)
+ .ConfigureAwait(false);
+ }
+
+ return result;
+ }
+ else
+ {
+ return await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
}
-
- return result;
}
catch (Exception exception)
{
@@ -243,38 +253,52 @@ await logger.CommandErrorAsync(
{
var (connection, context, logger) = (parameterObject.Connection, parameterObject.Context, parameterObject.Logger);
- var commandId = Guid.NewGuid();
+ var startTime = DateTimeOffset.UtcNow;
+
+ var shouldLogCommandCreate = logger?.ShouldLogCommandCreate(startTime) == true;
+ var shouldLogCommandExecute = logger?.ShouldLogCommandExecute(startTime) == true;
+
+ // Guid.NewGuid is expensive, do it only if needed
+ var commandId = shouldLogCommandCreate || shouldLogCommandExecute ? Guid.NewGuid() : default;
+
var command = CreateDbCommand(parameterObject, commandId, DbCommandMethod.ExecuteScalar);
connection.Open();
- var startTime = DateTimeOffset.UtcNow;
- _stopwatch.Restart();
try
{
- var interceptionResult = logger?.CommandScalarExecuting(
- connection,
- command,
- context,
- commandId,
- connection.ConnectionId,
- startTime)
- ?? default;
+ if (shouldLogCommandExecute)
+ {
+ _stopwatch.Restart();
- var result = interceptionResult.HasResult
- ? interceptionResult.Result
- : command.ExecuteScalar();
+ var interceptionResult = logger?.CommandScalarExecuting(
+ connection,
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ startTime)
+ ?? default;
- return logger?.CommandScalarExecuted(
- connection,
- command,
- context,
- commandId,
- connection.ConnectionId,
- result,
- startTime,
- _stopwatch.Elapsed)
- ?? result;
+ var result = interceptionResult.HasResult
+ ? interceptionResult.Result
+ : command.ExecuteScalar();
+
+ return logger?.CommandScalarExecuted(
+ connection,
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ result,
+ startTime,
+ _stopwatch.Elapsed)
+ ?? result;
+ }
+ else
+ {
+ return command.ExecuteScalar();
+ }
}
catch (Exception exception)
{
@@ -312,47 +336,60 @@ await logger.CommandErrorAsync(
{
var (connection, context, logger) = (parameterObject.Connection, parameterObject.Context, parameterObject.Logger);
- var commandId = Guid.NewGuid();
+ var startTime = DateTimeOffset.UtcNow;
+
+ var shouldLogCommandCreate = logger?.ShouldLogCommandCreate(startTime) == true;
+ var shouldLogCommandExecute = logger?.ShouldLogCommandExecute(startTime) == true;
+
+ // Guid.NewGuid is expensive, do it only if needed
+ var commandId = shouldLogCommandCreate || shouldLogCommandExecute ? Guid.NewGuid() : default;
+
var command = CreateDbCommand(parameterObject, commandId, DbCommandMethod.ExecuteScalar);
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
- var startTime = DateTimeOffset.UtcNow;
- _stopwatch.Restart();
-
try
{
- var interceptionResult = logger == null
- ? default
- : await logger.CommandScalarExecutingAsync(
+ if (shouldLogCommandExecute)
+ {
+ _stopwatch.Restart();
+
+ var interceptionResult = logger == null
+ ? default
+ : await logger.CommandScalarExecutingAsync(
+ connection,
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ startTime,
+ cancellationToken)
+ .ConfigureAwait(false);
+
+ var result = interceptionResult.HasResult
+ ? interceptionResult.Result
+ : await command.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false);
+
+ if (logger != null)
+ {
+ result = await logger.CommandScalarExecutedAsync(
connection,
command,
context,
commandId,
connection.ConnectionId,
+ result,
startTime,
- cancellationToken)
- .ConfigureAwait(false);
-
- var result = interceptionResult.HasResult
- ? interceptionResult.Result
- : await command.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false);
+ _stopwatch.Elapsed,
+ cancellationToken).ConfigureAwait(false);
+ }
- if (logger != null)
+ return result;
+ }
+ else
{
- result = await logger.CommandScalarExecutedAsync(
- connection,
- command,
- context,
- commandId,
- connection.ConnectionId,
- result,
- startTime,
- _stopwatch.Elapsed,
- cancellationToken).ConfigureAwait(false);
+ return await command.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false);
}
-
- return result;
}
catch (Exception exception)
{
@@ -393,34 +430,40 @@ public virtual RelationalDataReader ExecuteReader(RelationalCommandParameterObje
var logger = parameterObject.Logger;
var detailedErrorsEnabled = parameterObject.DetailedErrorsEnabled;
- var commandId = Guid.NewGuid();
+ var startTime = DateTimeOffset.UtcNow;
+
+ var shouldLogCommandCreate = logger?.ShouldLogCommandCreate(startTime) == true;
+ var shouldLogCommandExecute = logger?.ShouldLogCommandExecute(startTime) == true;
+
+ // Guid.NewGuid is expensive, do it only if needed
+ var commandId = shouldLogCommandCreate || shouldLogCommandExecute ? Guid.NewGuid() : default;
+
var command = CreateDbCommand(parameterObject, commandId, DbCommandMethod.ExecuteReader);
connection.Open();
- var startTime = DateTimeOffset.UtcNow;
- _stopwatch.Restart();
-
var readerOpen = false;
DbDataReader reader;
+
try
{
- var interceptionResult = logger?.CommandReaderExecuting(
+ if (shouldLogCommandExecute)
+ {
+ _stopwatch.Restart();
+
+ var interceptionResult = logger!.CommandReaderExecuting(
connection,
command,
context,
commandId,
connection.ConnectionId,
- startTime)
- ?? default;
+ startTime);
- reader = interceptionResult.HasResult
- ? interceptionResult.Result
- : command.ExecuteReader();
+ reader = interceptionResult.HasResult
+ ? interceptionResult.Result
+ : command.ExecuteReader();
- if (logger != null)
- {
- reader = logger.CommandReaderExecuted(
+ reader = logger!.CommandReaderExecuted(
connection,
command,
context,
@@ -430,6 +473,10 @@ public virtual RelationalDataReader ExecuteReader(RelationalCommandParameterObje
startTime,
_stopwatch.Elapsed);
}
+ else
+ {
+ reader = command.ExecuteReader();
+ }
}
catch (Exception exception)
{
@@ -490,21 +537,28 @@ public virtual async Task ExecuteReaderAsync(
var logger = parameterObject.Logger;
var detailedErrorsEnabled = parameterObject.DetailedErrorsEnabled;
- var commandId = Guid.NewGuid();
+ var startTime = DateTimeOffset.UtcNow;
+
+ var shouldLogCommandCreate = logger?.ShouldLogCommandCreate(startTime) == true;
+ var shouldLogCommandExecute = logger?.ShouldLogCommandExecute(startTime) == true;
+
+ // Guid.NewGuid is expensive, do it only if needed
+ var commandId = shouldLogCommandCreate || shouldLogCommandExecute ? Guid.NewGuid() : default;
+
var command = CreateDbCommand(parameterObject, commandId, DbCommandMethod.ExecuteReader);
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
- var startTime = DateTimeOffset.UtcNow;
- _stopwatch.Restart();
-
var readerOpen = false;
DbDataReader reader;
+
try
{
- var interceptionResult = logger == null
- ? default
- : await logger.CommandReaderExecutingAsync(
+ if (shouldLogCommandExecute)
+ {
+ _stopwatch.Restart();
+
+ var interceptionResult = await logger!.CommandReaderExecutingAsync(
connection,
command,
context,
@@ -514,13 +568,11 @@ public virtual async Task ExecuteReaderAsync(
cancellationToken)
.ConfigureAwait(false);
- reader = interceptionResult.HasResult
- ? interceptionResult.Result
- : await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
+ reader = interceptionResult.HasResult
+ ? interceptionResult.Result
+ : await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
- if (logger != null)
- {
- reader = await logger.CommandReaderExecutedAsync(
+ reader = await logger!.CommandReaderExecutedAsync(
connection,
command,
context,
@@ -532,6 +584,10 @@ public virtual async Task ExecuteReaderAsync(
cancellationToken)
.ConfigureAwait(false);
}
+ else
+ {
+ reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
+ }
}
catch (Exception exception)
{
@@ -546,7 +602,7 @@ await logger.CommandErrorAsync(
connection.ConnectionId,
exception,
startTime,
- _stopwatch.Elapsed,
+ DateTimeOffset.UtcNow - startTime,
cancellationToken)
.ConfigureAwait(false);
}
@@ -603,20 +659,27 @@ public virtual DbCommand CreateDbCommand(
var connectionId = connection.ConnectionId;
var startTime = DateTimeOffset.UtcNow;
- _stopwatch.Restart();
-
- var interceptionResult = logger?.CommandCreating(connection, commandMethod, context, commandId, connectionId, startTime)
- ?? default;
- var command = interceptionResult.HasResult
- ? interceptionResult.Result
- : connection.DbConnection.CreateCommand();
+ DbCommand command;
- if (logger != null)
+ if (logger?.ShouldLogCommandCreate(startTime) == true)
{
+ _stopwatch.Restart();
+
+ var interceptionResult = logger.CommandCreating(
+ connection, commandMethod, context, commandId, connectionId, startTime);
+
+ command = interceptionResult.HasResult
+ ? interceptionResult.Result
+ : connection.DbConnection.CreateCommand();
+
command = logger.CommandCreated(
connection, command, commandMethod, context, commandId, connectionId, startTime, _stopwatch.Elapsed);
}
+ else
+ {
+ command = connection.DbConnection.CreateCommand();
+ }
command.CommandText = CommandText;
@@ -649,6 +712,24 @@ public virtual DbCommand CreateDbCommand(
return command;
}
+ private static void CleanupCommand(
+ DbCommand command,
+ IRelationalConnection connection)
+ {
+ command.Parameters.Clear();
+ command.Dispose();
+ connection.Close();
+ }
+
+ private static async Task CleanupCommandAsync(
+ DbCommand command,
+ IRelationalConnection connection)
+ {
+ command.Parameters.Clear();
+ await command.DisposeAsync().ConfigureAwait(false);
+ await connection.CloseAsync().ConfigureAwait(false);
+ }
+
///
///
/// Creates a new to be used by and
diff --git a/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs b/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs
index bc5765cb770..011e74c849e 100644
--- a/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs
+++ b/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs
@@ -37,7 +37,7 @@ public RelationalCommandParameterObject(
IReadOnlyDictionary? parameterValues,
IReadOnlyList? readerColumns,
DbContext? context,
- IDiagnosticsLogger? logger)
+ IRelationalCommandDiagnosticsLogger? logger)
: this(connection, parameterValues, readerColumns, context, logger, detailedErrorsEnabled: false)
{
}
@@ -62,7 +62,7 @@ public RelationalCommandParameterObject(
IReadOnlyDictionary? parameterValues,
IReadOnlyList? readerColumns,
DbContext? context,
- IDiagnosticsLogger? logger,
+ IRelationalCommandDiagnosticsLogger? logger,
bool detailedErrorsEnabled)
{
Check.NotNull(connection, nameof(connection));
@@ -98,7 +98,7 @@ public RelationalCommandParameterObject(
///
/// A logger, or if no logger is available.
///
- public IDiagnosticsLogger? Logger { get; }
+ public IRelationalCommandDiagnosticsLogger? Logger { get; }
///
/// A value indicating if detailed errors are enabled.
diff --git a/src/EFCore.Relational/Storage/RelationalConnection.cs b/src/EFCore.Relational/Storage/RelationalConnection.cs
index 78519aab6db..6dc5f252b7e 100644
--- a/src/EFCore.Relational/Storage/RelationalConnection.cs
+++ b/src/EFCore.Relational/Storage/RelationalConnection.cs
@@ -690,23 +690,32 @@ private void ClearTransactions(bool clearAmbient)
private void OpenInternal(bool errorsExpected)
{
+ var logger = Dependencies.ConnectionLogger;
var startTime = DateTimeOffset.UtcNow;
- _stopwatch.Restart();
-
- var interceptionResult = Dependencies.ConnectionLogger.ConnectionOpening(this, startTime);
try
{
- if (!interceptionResult.IsSuppressed)
+ if (logger.ShouldLogConnectionOpen(startTime))
+ {
+ _stopwatch.Restart();
+
+ var interceptionResult = logger.ConnectionOpening(this, startTime);
+
+ if (!interceptionResult.IsSuppressed)
+ {
+ OpenDbConnection(errorsExpected);
+ }
+
+ logger.ConnectionOpened(this, startTime, _stopwatch.Elapsed);
+ }
+ else
{
OpenDbConnection(errorsExpected);
}
-
- Dependencies.ConnectionLogger.ConnectionOpened(this, startTime, _stopwatch.Elapsed);
}
catch (Exception e)
{
- Dependencies.ConnectionLogger.ConnectionError(this, e, startTime, _stopwatch.Elapsed, errorsExpected);
+ logger.ConnectionError(this, e, startTime, _stopwatch.Elapsed, errorsExpected);
throw;
}
@@ -727,30 +736,37 @@ protected virtual void OpenDbConnection(bool errorsExpected)
private async Task OpenInternalAsync(bool errorsExpected, CancellationToken cancellationToken)
{
+ var logger = Dependencies.ConnectionLogger;
var startTime = DateTimeOffset.UtcNow;
- _stopwatch.Restart();
-
- var interceptionResult
- = await Dependencies.ConnectionLogger.ConnectionOpeningAsync(this, startTime, cancellationToken)
- .ConfigureAwait(false);
try
{
- if (!interceptionResult.IsSuppressed)
+ if (logger.ShouldLogConnectionOpen(startTime))
+ {
+ _stopwatch.Restart();
+
+ var interceptionResult
+ = await logger.ConnectionOpeningAsync(this, startTime, cancellationToken).ConfigureAwait(false);
+
+ if (!interceptionResult.IsSuppressed)
+ {
+ await OpenDbConnectionAsync(errorsExpected, cancellationToken).ConfigureAwait(false);
+ }
+
+ await logger.ConnectionOpenedAsync(this, startTime, _stopwatch.Elapsed, cancellationToken).ConfigureAwait(false);
+ }
+ else
{
await OpenDbConnectionAsync(errorsExpected, cancellationToken).ConfigureAwait(false);
}
-
- await Dependencies.ConnectionLogger.ConnectionOpenedAsync(this, startTime, _stopwatch.Elapsed, cancellationToken)
- .ConfigureAwait(false);
}
catch (Exception e)
{
- await Dependencies.ConnectionLogger.ConnectionErrorAsync(
+ await logger.ConnectionErrorAsync(
this,
e,
startTime,
- _stopwatch.Elapsed,
+ DateTimeOffset.UtcNow - startTime,
errorsExpected,
cancellationToken)
.ConfigureAwait(false);
@@ -842,21 +858,30 @@ public virtual bool Close()
if (DbConnectionState != ConnectionState.Closed)
{
+ var logger = Dependencies.ConnectionLogger;
var startTime = DateTimeOffset.UtcNow;
- _stopwatch.Restart();
-
- var interceptionResult = Dependencies.ConnectionLogger.ConnectionClosing(this, startTime);
try
{
- if (!interceptionResult.IsSuppressed)
+ if (logger.ShouldLogConnectionClose(startTime))
{
- CloseDbConnection();
+ _stopwatch.Restart();
+
+ var interceptionResult = Dependencies.ConnectionLogger.ConnectionClosing(this, startTime);
+
+ if (!interceptionResult.IsSuppressed)
+ {
+ CloseDbConnection();
+ }
+
+ Dependencies.ConnectionLogger.ConnectionClosed(this, startTime, _stopwatch.Elapsed);
+ }
+ else
+ {
+ CloseDbConnectionAsync();
}
wasClosed = true;
-
- Dependencies.ConnectionLogger.ConnectionClosed(this, startTime, _stopwatch.Elapsed);
}
catch (Exception e)
{
@@ -901,26 +926,32 @@ public virtual async Task CloseAsync()
if (DbConnectionState != ConnectionState.Closed)
{
+ var logger = Dependencies.ConnectionLogger;
var startTime = DateTimeOffset.UtcNow;
- _stopwatch.Restart();
-
- var interceptionResult = await Dependencies.ConnectionLogger.ConnectionClosingAsync(this, startTime)
- .ConfigureAwait(false);
try
{
- if (!interceptionResult.IsSuppressed)
+ if (logger.ShouldLogConnectionClose(startTime))
+ {
+ _stopwatch.Restart();
+
+ var interceptionResult = await Dependencies.ConnectionLogger.ConnectionClosingAsync(this, startTime)
+ .ConfigureAwait(false);
+
+ if (!interceptionResult.IsSuppressed)
+ {
+ await CloseDbConnectionAsync().ConfigureAwait(false);
+ }
+
+ await Dependencies.ConnectionLogger.ConnectionClosedAsync(this, startTime, _stopwatch.Elapsed)
+ .ConfigureAwait(false);
+ }
+ else
{
await CloseDbConnectionAsync().ConfigureAwait(false);
}
wasClosed = true;
-
- await Dependencies.ConnectionLogger.ConnectionClosedAsync(
- this,
- startTime,
- _stopwatch.Elapsed)
- .ConfigureAwait(false);
}
catch (Exception e)
{
@@ -928,7 +959,7 @@ await Dependencies.ConnectionLogger.ConnectionErrorAsync(
this,
e,
startTime,
- _stopwatch.Elapsed,
+ DateTimeOffset.UtcNow - startTime,
false)
.ConfigureAwait(false);
diff --git a/src/EFCore.Relational/Storage/RelationalConnectionDependencies.cs b/src/EFCore.Relational/Storage/RelationalConnectionDependencies.cs
index 610a6d69e03..74ec95d9a59 100644
--- a/src/EFCore.Relational/Storage/RelationalConnectionDependencies.cs
+++ b/src/EFCore.Relational/Storage/RelationalConnectionDependencies.cs
@@ -57,7 +57,7 @@ public sealed record RelationalConnectionDependencies
public RelationalConnectionDependencies(
IDbContextOptions contextOptions,
IDiagnosticsLogger transactionLogger,
- IDiagnosticsLogger connectionLogger,
+ IRelationalConnectionDiagnosticsLogger connectionLogger,
INamedConnectionStringResolver connectionStringResolver,
IRelationalTransactionFactory relationalTransactionFactory,
ICurrentDbContext currentContext,
@@ -93,7 +93,7 @@ public RelationalConnectionDependencies(
///
/// The logger to which connection messages will be written.
///
- public IDiagnosticsLogger ConnectionLogger { get; init; }
+ public IRelationalConnectionDiagnosticsLogger ConnectionLogger { get; init; }
///
/// A service for resolving a connection string from a name.
diff --git a/src/EFCore.Relational/Storage/RelationalDataReader.cs b/src/EFCore.Relational/Storage/RelationalDataReader.cs
index d60d5b20d50..199d7effe3c 100644
--- a/src/EFCore.Relational/Storage/RelationalDataReader.cs
+++ b/src/EFCore.Relational/Storage/RelationalDataReader.cs
@@ -28,7 +28,7 @@ public class RelationalDataReader : IDisposable, IAsyncDisposable
private DbCommand _command = default!;
private DbDataReader _reader = default!;
private Guid _commandId;
- private IDiagnosticsLogger? _logger;
+ private IRelationalCommandDiagnosticsLogger? _logger;
private DateTimeOffset _startTime;
private readonly Stopwatch _stopwatch = new();
@@ -36,6 +36,8 @@ public class RelationalDataReader : IDisposable, IAsyncDisposable
private bool _disposed;
+ private static readonly TimeSpan _oneSecond = TimeSpan.FromSeconds(1);
+
///
/// Initializes a new instance of the class.
///
@@ -60,7 +62,7 @@ public virtual void Initialize(
DbCommand command,
DbDataReader reader,
Guid commandId,
- IDiagnosticsLogger? logger)
+ IRelationalCommandDiagnosticsLogger? logger)
{
Check.NotNull(command, nameof(command));
Check.NotNull(reader, nameof(reader));
@@ -70,8 +72,8 @@ public virtual void Initialize(
_reader = reader;
_commandId = commandId;
_logger = logger;
- _startTime = DateTimeOffset.UtcNow;
_disposed = false;
+ _startTime = DateTimeOffset.UtcNow;
_stopwatch.Restart();
}
@@ -122,7 +124,7 @@ public virtual void Dispose()
{
_reader.Close(); // can throw
- if (_logger != null)
+ if (_logger?.ShouldLogDataReaderDispose(DateTimeOffset.UtcNow) == true)
{
interceptionResult = _logger.DataReaderDisposing(
_relationalConnection,
@@ -162,7 +164,7 @@ public virtual async ValueTask DisposeAsync()
{
await _reader.CloseAsync().ConfigureAwait(false); // can throw
- if (_logger != null)
+ if (_logger?.ShouldLogDataReaderDispose(DateTimeOffset.UtcNow) == true)
{
interceptionResult = _logger.DataReaderDisposing(
_relationalConnection,
diff --git a/src/EFCore.Relational/Storage/RelationalDatabaseCreatorDependencies.cs b/src/EFCore.Relational/Storage/RelationalDatabaseCreatorDependencies.cs
index 1661fb465bb..b3f669cc8a3 100644
--- a/src/EFCore.Relational/Storage/RelationalDatabaseCreatorDependencies.cs
+++ b/src/EFCore.Relational/Storage/RelationalDatabaseCreatorDependencies.cs
@@ -71,7 +71,7 @@ public RelationalDatabaseCreatorDependencies(
ISqlGenerationHelper sqlGenerationHelper,
IExecutionStrategyFactory executionStrategyFactory,
ICurrentDbContext currentContext,
- IDiagnosticsLogger commandLogger)
+ IRelationalCommandDiagnosticsLogger commandLogger)
{
Check.NotNull(model, nameof(model));
Check.NotNull(connection, nameof(connection));
@@ -135,7 +135,7 @@ public RelationalDatabaseCreatorDependencies(
///
/// The command logger.
///
- public IDiagnosticsLogger CommandLogger { get; init; }
+ public IRelationalCommandDiagnosticsLogger CommandLogger { get; init; }
///