Skip to content

Commit

Permalink
Updates to simple logging based on design meeting feedback
Browse files Browse the repository at this point in the history
#1199

* Stop exposing the interface in LogTo and replace with delegates overload.
* Rename SimpleLoggerFormatOptions to LogToOptions
  * Similar renaming across the internal implementation
  • Loading branch information
ajcvickers committed Dec 8, 2019
1 parent 9abd61d commit 347e823
Show file tree
Hide file tree
Showing 38 changed files with 294 additions and 237 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public static IServiceCollection AddEntityFrameworkDesignTimeServices(
.AddSingleton<IScaffoldingModelFactory, RelationalScaffoldingModelFactory>()
.AddSingleton<IScaffoldingTypeMapper, ScaffoldingTypeMapper>()
.AddSingleton<IValueConverterSelector, ValueConverterSelector>()
.AddSingleton<ISimpleLogger, NullSimpleLogger>()
.AddSingleton<ILogToLogger, NullLogToLogger>()
.AddTransient<MigrationsScaffolderDependencies>()
.AddTransient<IMigrationsScaffolder, MigrationsScaffolder>()
.AddTransient<ISnapshotModelProcessor, SnapshotModelProcessor>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2217,7 +2217,7 @@ private static TransactionEventData BroadcasstTransactionUsed(

if (simpleLogEnabled)
{
diagnostics.SimpleLogger.Log(eventData);
diagnostics.LogToLogger.Log(eventData);
}

return eventData;
Expand Down
99 changes: 54 additions & 45 deletions src/EFCore/DbContextOptionsBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Diagnostics.Internal;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Utilities;
Expand Down Expand Up @@ -113,26 +114,26 @@ public virtual DbContextOptionsBuilder UseLoggerFactory([CanBeNull] ILoggerFacto
/// </para>
/// <para>
/// This overload allows the minimum level of logging and the log formatting to be controlled.
/// Use the <see cref="LogTo(Action{string},IEnumerable{EventId},LogLevel,SimpleLoggerFormatOptions?)" />
/// Use the <see cref="LogTo(Action{string},IEnumerable{EventId},LogLevel,LogToOptions?)" />
/// overload to log only specific events.
/// Use the <see cref="LogTo(Action{string},IEnumerable{string},LogLevel,SimpleLoggerFormatOptions?)" />
/// Use the <see cref="LogTo(Action{string},IEnumerable{string},LogLevel,LogToOptions?)" />
/// overload to log only events in specific categories.
/// Use the <see cref="LogTo(Action{string},Func{EventId,LogLevel,bool},SimpleLoggerFormatOptions?)" />
/// Use the <see cref="LogTo(Action{string},Func{EventId,LogLevel,bool},LogToOptions?)" />
/// overload to use a custom filter for events.
/// Use the <see cref="LogTo(ISimpleLogger)" /> overload to log to a fully custom logger.
/// Use the <see cref="LogTo(Func{EventId,LogLevel,bool},Action{EventData})" /> overload to log to a fully custom logger.
/// </para>
/// </summary>
/// <param name="sink"> The sink to which log messages will be written. </param>
/// <param name="minimumLevel"> The minimum level of logging event to log. Defaults to <see cref="LogLevel.Debug" /> </param>
/// <param name="formatOptions">
/// Formatting options for log messages. Passing null (the default) means use <see cref="SimpleLoggerFormatOptions.DefaultWithLocalTime" />
/// <param name="options">
/// Formatting options for log messages. Passing null (the default) means use <see cref="LogToOptions.DefaultWithLocalTime" />
/// </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
public virtual DbContextOptionsBuilder LogTo(
[NotNull] Action<string> sink,
LogLevel minimumLevel = LogLevel.Debug,
SimpleLoggerFormatOptions? formatOptions = null)
=> LogTo(sink, (i, l) => l >= minimumLevel, formatOptions);
LogToOptions? options = null)
=> LogTo(sink, (i, l) => l >= minimumLevel, options);

/// <summary>
/// <para>
Expand All @@ -141,27 +142,27 @@ public virtual DbContextOptionsBuilder LogTo(
/// <see cref="CoreEventId.ContextInitialized" /> event to the console.
/// </para>
/// <para>
/// Use the <see cref="LogTo(Action{string},LogLevel,SimpleLoggerFormatOptions?)" /> overload for default logging of
/// Use the <see cref="LogTo(Action{string},LogLevel,LogToOptions?)" /> overload for default logging of
/// all events.
/// Use the <see cref="LogTo(Action{string},IEnumerable{string},LogLevel,SimpleLoggerFormatOptions?)" />
/// Use the <see cref="LogTo(Action{string},IEnumerable{string},LogLevel,LogToOptions?)" />
/// overload to log only events in specific categories.
/// Use the <see cref="LogTo(Action{string},Func{EventId,LogLevel,bool},SimpleLoggerFormatOptions?)" />
/// Use the <see cref="LogTo(Action{string},Func{EventId,LogLevel,bool},LogToOptions?)" />
/// overload to use a custom filter for events.
/// Use the <see cref="LogTo(ISimpleLogger)" /> overload to log to a fully custom logger.
/// Use the <see cref="LogTo(Func{EventId,LogLevel,bool},Action{EventData})" /> overload to log to a fully custom logger.
/// </para>
/// </summary>
/// <param name="sink"> The sink to which log messages will be written. </param>
/// <param name="events"> The <see cref="EventId" /> of each event to log. </param>
/// <param name="minimumLevel"> The minimum level of logging event to log. Defaults to <see cref="LogLevel.Debug" /> </param>
/// <param name="formatOptions">
/// Formatting options for log messages. Passing null (the default) means use <see cref="SimpleLoggerFormatOptions.DefaultWithLocalTime" />
/// <param name="options">
/// Formatting options for log messages. Passing null (the default) means use <see cref="LogToOptions.DefaultWithLocalTime" />
/// </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
public virtual DbContextOptionsBuilder LogTo(
[NotNull] Action<string> sink,
[NotNull] IEnumerable<EventId> events,
LogLevel minimumLevel = LogLevel.Debug,
SimpleLoggerFormatOptions? formatOptions = null)
LogToOptions? options = null)
{
Check.NotNull(events, nameof(events));

Expand All @@ -179,7 +180,7 @@ public virtual DbContextOptionsBuilder LogTo(
sink,
(eventId, level) => level >= minimumLevel
&& eventId == firstEvent,
formatOptions);
options);
}

if (eventsArray.Length < 6)
Expand All @@ -188,15 +189,15 @@ public virtual DbContextOptionsBuilder LogTo(
sink,
(eventId, level) => level >= minimumLevel
&& eventsArray.Contains(eventId),
formatOptions);
options);
}

var eventsHash = eventsArray.ToHashSet();
return LogTo(
sink,
(eventId, level) => level >= minimumLevel
&& eventsHash.Contains(eventId),
formatOptions);
options);
}

/// <summary>
Expand All @@ -206,27 +207,27 @@ public virtual DbContextOptionsBuilder LogTo(
/// events in the <see cref="DbLoggerCategory.Infrastructure" /> category.
/// </para>
/// <para>
/// Use the <see cref="LogTo(Action{string},LogLevel,SimpleLoggerFormatOptions?)" /> overload for default logging of
/// Use the <see cref="LogTo(Action{string},LogLevel,LogToOptions?)" /> overload for default logging of
/// all events.
/// Use the <see cref="LogTo(Action{string},IEnumerable{EventId},LogLevel,SimpleLoggerFormatOptions?)" />
/// Use the <see cref="LogTo(Action{string},IEnumerable{EventId},LogLevel,LogToOptions?)" />
/// overload to log only specific events.
/// Use the <see cref="LogTo(Action{string},Func{EventId,LogLevel,bool},SimpleLoggerFormatOptions?)" />
/// Use the <see cref="LogTo(Action{string},Func{EventId,LogLevel,bool},LogToOptions?)" />
/// overload to use a custom filter for events.
/// Use the <see cref="LogTo(ISimpleLogger)" /> overload to log to a fully custom logger.
/// Use the <see cref="LogTo(Func{EventId,LogLevel,bool},Action{EventData})" /> overload to log to a fully custom logger.
/// </para>
/// </summary>
/// <param name="sink"> The sink to which log messages will be written. </param>
/// <param name="categories"> The <see cref="DbLoggerCategory" /> of each event to log. </param>
/// <param name="minimumLevel"> The minimum level of logging event to log. Defaults to <see cref="LogLevel.Debug" /> </param>
/// <param name="formatOptions">
/// Formatting options for log messages. Passing null (the default) means use <see cref="SimpleLoggerFormatOptions.DefaultWithLocalTime" />
/// <param name="options">
/// Formatting options for log messages. Passing null (the default) means use <see cref="LogToOptions.DefaultWithLocalTime" />
/// </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
public virtual DbContextOptionsBuilder LogTo(
[NotNull] Action<string> sink,
[NotNull] IEnumerable<string> categories,
LogLevel minimumLevel = LogLevel.Debug,
SimpleLoggerFormatOptions? formatOptions = null)
LogToOptions? options = null)
{
Check.NotNull(categories, nameof(categories));

Expand Down Expand Up @@ -258,15 +259,15 @@ public virtual DbContextOptionsBuilder LogTo(

return false;
},
formatOptions);
options);
}

var singleCategory = categoriesArray[0];
return LogTo(
sink,
(eventId, level) => level >= minimumLevel
&& eventId.Name.StartsWith(singleCategory, StringComparison.OrdinalIgnoreCase),
formatOptions);
options);
}

/// <summary>
Expand All @@ -275,55 +276,63 @@ public virtual DbContextOptionsBuilder LogTo(
/// log a message, or false to filter it out of the log.
/// </para>
/// <para>
/// Use the <see cref="LogTo(Action{string},LogLevel,SimpleLoggerFormatOptions?)" /> overload for default logging of
/// Use the <see cref="LogTo(Action{string},LogLevel,LogToOptions?)" /> overload for default logging of
/// all events.
/// Use the <see cref="LogTo(Action{string},IEnumerable{EventId},LogLevel,SimpleLoggerFormatOptions?)" />
/// Use the <see cref="LogTo(Action{string},IEnumerable{string},LogLevel,SimpleLoggerFormatOptions?)" />
/// Use the <see cref="LogTo(Action{string},IEnumerable{EventId},LogLevel,LogToOptions?)" />
/// Use the <see cref="LogTo(Action{string},IEnumerable{string},LogLevel,LogToOptions?)" />
/// overload to log only events in specific categories.
/// Use the <see cref="LogTo(ISimpleLogger)" /> overload to log to a fully custom logger.
/// Use the <see cref="LogTo(Func{EventId,LogLevel,bool},Action{EventData})" /> overload to log to a fully custom logger.
/// </para>
/// </summary>
/// <param name="sink"> The sink to which log messages will be written. </param>
/// <param name="filter"> Delegate that returns true to log the message or false to ignore it. </param>
/// <param name="formatOptions">
/// Formatting options for log messages. Passing null (the default) means use <see cref="SimpleLoggerFormatOptions.DefaultWithLocalTime" />
/// <param name="options">
/// Formatting options for log messages. Passing null (the default) means use <see cref="LogToOptions.DefaultWithLocalTime" />
/// </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
public virtual DbContextOptionsBuilder LogTo(
[NotNull] Action<string> sink,
[NotNull] Func<EventId, LogLevel, bool> filter,
SimpleLoggerFormatOptions? formatOptions = null)
LogToOptions? options = null)
{
Check.NotNull(sink, nameof(sink));
Check.NotNull(filter, nameof(filter));

return LogTo(new SimpleLogger(sink, filter, formatOptions ?? SimpleLoggerFormatOptions.DefaultWithLocalTime));
return LogTo(new FormattingLogToLogger(sink, filter, options ?? LogToOptions.DefaultWithLocalTime));
}

/// <summary>
/// <para>
/// Logs to the supplied <see cref="ISimpleLogger" /> implementation.
/// Logs events to a custom logger delegate filtered by a custom filter delegate. The filter should return true to
/// log a message, or false to filter it out of the log.
/// </para>
/// <para>
/// Use this method when the other overloads do not provide enough control over filtering and formatting of the output.
/// Use the <see cref="LogTo(Action{string},LogLevel,SimpleLoggerFormatOptions?)" /> overload for default logging of
/// Use the <see cref="LogTo(Action{string},LogLevel,LogToOptions?)" /> overload for default logging of
/// all events.
/// Use the <see cref="LogTo(Action{string},IEnumerable{EventId},LogLevel,SimpleLoggerFormatOptions?)" />
/// Use the <see cref="LogTo(Action{string},IEnumerable{string},LogLevel,SimpleLoggerFormatOptions?)" />
/// Use the <see cref="LogTo(Action{string},IEnumerable{EventId},LogLevel,LogToOptions?)" />
/// Use the <see cref="LogTo(Action{string},IEnumerable{string},LogLevel,LogToOptions?)" />
/// overload to log only events in specific categories.
/// Use the <see cref="LogTo(Action{string},Func{EventId,LogLevel,bool},SimpleLoggerFormatOptions?)" />
/// Use the <see cref="LogTo(Action{string},Func{EventId,LogLevel,bool},LogToOptions?)" />
/// overload to use a custom filter for events.
/// </para>
/// </summary>
/// <param name="simpleLogger"> The <see cref="ISimpleLogger" /> to use. </param>
/// <param name="filter"> Delegate that returns true to log the message or false to ignore it. </param>
/// <param name="logger"> Delegate called when there is a message to log. </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
public virtual DbContextOptionsBuilder LogTo([NotNull] ISimpleLogger simpleLogger)
// Filter comes first, logger second, otherwise it's hard to get the correct overload to resolve
public virtual DbContextOptionsBuilder LogTo(
[NotNull] Func<EventId, LogLevel, bool> filter,
[NotNull] Action<EventData> logger)
{
Check.NotNull(simpleLogger, nameof(simpleLogger));
Check.NotNull(logger, nameof(logger));
Check.NotNull(filter, nameof(filter));

return WithOption(e => e.WithSimpleLogger(simpleLogger));
return LogTo(new DelegatingLogToLogger(logger, filter));
}

private DbContextOptionsBuilder LogTo([NotNull] ILogToLogger logger)
=> WithOption(e => e.WithLogToLogger(logger));

/// <summary>
/// <para>
/// Enables detailed errors when handling of data value exceptions that occur during processing of store query results. Such errors
Expand Down
Loading

0 comments on commit 347e823

Please sign in to comment.