diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.Testing/Logging/FakeLogCollector.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.Testing/Logging/FakeLogCollector.cs index 376cc87be8c..73a34ac4333 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.Testing/Logging/FakeLogCollector.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.Testing/Logging/FakeLogCollector.cs @@ -129,6 +129,15 @@ internal void AddRecord(FakeLogRecord record) return; } + foreach (var condition in _options.CustomFilters) + { + if (!condition(record)) + { + // record was filtered out by a custom filter + return; + } + } + lock (_records) { _records.Add(record); diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.Testing/Logging/FakeLogCollectorOptions.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.Testing/Logging/FakeLogCollectorOptions.cs index be5476e685a..e164e16af37 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.Testing/Logging/FakeLogCollectorOptions.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.Testing/Logging/FakeLogCollectorOptions.cs @@ -3,7 +3,8 @@ using System; using System.Collections.Generic; -using Microsoft.Extensions.Logging; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Shared.DiagnosticIds; #pragma warning disable CA2227 // Collection properties should be read only @@ -34,6 +35,17 @@ public class FakeLogCollectorOptions /// public ISet FilteredLevels { get; set; } = new HashSet(); + /// + /// Gets or sets custom filters used to filter out records to be collected. + /// + /// Default is an empty array. + /// + /// Defaults to an empty array, which doesn't filter any records. + /// If not empty, only records for which the filter function returns will be collected by the fake logger. + /// + [Experimental(DiagnosticIds.Experiments.Telemetry)] + public IEnumerable> CustomFilters { get; set; } = Array.Empty>(); + /// /// Gets or sets a value indicating whether to collect records that are logged when the associated log level is currently disabled. /// diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.Testing.Tests/Logging/FakeLoggerTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.Testing.Tests/Logging/FakeLoggerTests.cs index 9ec81a36077..a13146a7a33 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.Testing.Tests/Logging/FakeLoggerTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.Testing.Tests/Logging/FakeLoggerTests.cs @@ -6,8 +6,6 @@ using System.Globalization; using System.Linq; using System.Threading; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Time.Testing; using Xunit; @@ -283,4 +281,59 @@ public void Scopes() Assert.Equal(42, (int)logger.LatestRecord.Scopes[0]!); Assert.Equal("Hello World", (string)logger.LatestRecord.Scopes[1]!); } + + [Fact] + public void FilterByCustomFilter() + { + const string NotIgnoredMessage1 = "Not ignored message 1"; + const string NotIgnoredMessage2 = "Not ignored message 2"; + const string IgnoredMessage = "Ignored message"; + + // Given + var options = new FakeLogCollectorOptions + { + CustomFilters = [ + r => !r.Message.Equals(IgnoredMessage, StringComparison.Ordinal), + ], + }; + + var collector = FakeLogCollector.Create(options); + var logger = new FakeLogger(collector); + + // When + logger.LogInformation(NotIgnoredMessage1); + logger.LogInformation(IgnoredMessage); + logger.LogError(IgnoredMessage); + logger.LogCritical(IgnoredMessage); + logger.LogError(NotIgnoredMessage2); + + var records = logger.Collector.GetSnapshot(); + + // Then + Assert.Equal(2, records.Count); + Assert.Equal(2, logger.Collector.Count); + + var firstLogRecordFromSnapshot = records[0]; + + Assert.Equal(NotIgnoredMessage1, firstLogRecordFromSnapshot.Message); + Assert.Equal(LogLevel.Information, firstLogRecordFromSnapshot.Level); + Assert.Null(firstLogRecordFromSnapshot.Exception); + Assert.Null(firstLogRecordFromSnapshot.Category); + Assert.True(firstLogRecordFromSnapshot.LevelEnabled); + Assert.Empty(firstLogRecordFromSnapshot.Scopes); + Assert.Equal(0, firstLogRecordFromSnapshot.Id.Id); + Assert.EndsWith($"info] {NotIgnoredMessage1}", firstLogRecordFromSnapshot.ToString()); + + var secondLogRecordFromSnapshot = records[1]; + Assert.Equal(NotIgnoredMessage2, secondLogRecordFromSnapshot.Message); + Assert.Equal(LogLevel.Error, secondLogRecordFromSnapshot.Level); + Assert.Null(secondLogRecordFromSnapshot.Exception); + Assert.Null(secondLogRecordFromSnapshot.Category); + Assert.Empty(secondLogRecordFromSnapshot.Scopes); + Assert.True(secondLogRecordFromSnapshot.LevelEnabled); + Assert.Equal(0, secondLogRecordFromSnapshot.Id.Id); + Assert.EndsWith($"error] {NotIgnoredMessage2}", secondLogRecordFromSnapshot.ToString()); + + Assert.Equivalent(secondLogRecordFromSnapshot, logger.LatestRecord); + } }