Skip to content
This repository was archived by the owner on Dec 13, 2018. It is now read-only.

Commit 7c6a523

Browse files
authored
Add capture scopes flag (#921)
1 parent 937fccc commit 7c6a523

File tree

8 files changed

+159
-39
lines changed

8 files changed

+159
-39
lines changed

benchmarks/Logging.Performance/ScopesOverheadBenchmark.cs

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ public class ScopesOverheadBenchmark: LoggingBenchmarkBase
1414
[Params(true, false)]
1515
public bool HasISupportLoggingScopeLogger { get; set; } = false;
1616

17+
[Params(true, false)]
18+
public bool CaptureScopes { get; set; } = false;
19+
1720
// Baseline as this is the fastest way to do nothing
1821
[Benchmark(Baseline = true)]
1922
public void FilteredByLevel()
@@ -59,6 +62,8 @@ public void Setup()
5962
services.AddSingleton<ILoggerProvider, LoggerProvider<NoopLogger>>();
6063
}
6164

65+
services.Configure<LoggerFilterOptions>(options => options.CaptureScopes = CaptureScopes);
66+
6267
_logger = services.BuildServiceProvider().GetService<ILoggerFactory>().CreateLogger("Logger");
6368
}
6469

src/Microsoft.Extensions.Logging.Configuration/LoggerFilterConfigureOptions.cs

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ private void LoadDefaultConfigValues(LoggerFilterOptions options)
3030
return;
3131
}
3232

33+
options.CaptureScopes = _configuration.GetValue<bool>(nameof(options.CaptureScopes));
34+
3335
foreach (var configurationSection in _configuration.GetChildren())
3436
{
3537
if (configurationSection.Key.Equals(LogLevelKey, StringComparison.OrdinalIgnoreCase))

src/Microsoft.Extensions.Logging/Logger.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public LoggerInformation[] Loggers
3838
}
3939
}
4040

41+
public bool CaptureScopes { get; set; }
42+
4143
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
4244
{
4345
var loggers = Loggers;
@@ -124,7 +126,7 @@ public IDisposable BeginScope<TState>(TState state)
124126
{
125127
var loggers = Loggers;
126128

127-
if (loggers == null)
129+
if (loggers == null || !CaptureScopes)
128130
{
129131
return NullScope.Instance;
130132
}

src/Microsoft.Extensions.Logging/LoggerFactory.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ private void RefreshFilters(LoggerFilterOptions filterOptions)
5858
ApplyRules(loggerInformation, categoryName, 0, loggerInformation.Length);
5959

6060
logger.Value.Loggers = loggerInformation;
61+
logger.Value.CaptureScopes = filterOptions.CaptureScopes;
6162
}
6263
}
6364
}
@@ -75,7 +76,8 @@ public ILogger CreateLogger(string categoryName)
7576
{
7677
logger = new Logger(this)
7778
{
78-
Loggers = CreateLoggers(categoryName)
79+
Loggers = CreateLoggers(categoryName),
80+
CaptureScopes = _filterOptions.CaptureScopes
7981
};
8082
_loggers[categoryName] = logger;
8183
}

src/Microsoft.Extensions.Logging/LoggerFilterOptions.cs

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ namespace Microsoft.Extensions.Logging
77
{
88
public class LoggerFilterOptions
99
{
10+
/// <summary>
11+
/// Gets or sets value indicating whether logging scopes are being captured. Defaults to <c>true</c>
12+
/// </summary>
13+
public bool CaptureScopes { get; set; } = true;
14+
1015
/// <summary>
1116
/// Gets or sets the minimum level of log messages if none of the rules match.
1217
/// </summary>

test/Microsoft.Extensions.Logging.Test/LoggerFilterTest.cs

+7-37
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4-
using System;
54
using System.Collections.Generic;
6-
using System.IO;
75
using System.Linq;
86
using Microsoft.Extensions.Configuration;
9-
using Microsoft.Extensions.Configuration.Json;
107
using Microsoft.Extensions.DependencyInjection;
118
using Microsoft.Extensions.Logging.Testing;
129
using Microsoft.Extensions.Options;
@@ -28,7 +25,7 @@ public void ChangingConfigReloadsDefaultFilter()
2825
}
2926
}
3027
}";
31-
var config = CreateConfiguration(() => json);
28+
var config = TestConfiguration.Create(() => json);
3229
var loggerProvider = new TestLoggerProvider(new TestSink(), isEnabled: true);
3330

3431
var factory = TestLoggerBuilder.Create(builder => builder
@@ -74,7 +71,7 @@ public void ChangingConfigFromUseConfigurationReloadsDefaultFilter()
7471
}
7572
}
7673
}";
77-
var config = CreateConfiguration(() => json);
74+
var config = TestConfiguration.Create(() => json);
7875
var loggerProvider = new TestLoggerProvider(new TestSink(), isEnabled: true);
7976
var factory = TestLoggerBuilder.Create(builder => builder
8077
.AddConfiguration(config.GetSection("Logging"))
@@ -121,7 +118,7 @@ public void CanFilterOnNamedProviders()
121118
}
122119
}
123120
}";
124-
var config = CreateConfiguration(() => json);
121+
var config = TestConfiguration.Create(() => json);
125122

126123
var loggerProvider = new TestLoggerProvider(new TestSink(), isEnabled: true);
127124
var factory = TestLoggerBuilder.Create(builder => builder
@@ -155,7 +152,7 @@ public void PreferFullNameOverDefaultForFiltering()
155152
}
156153
}
157154
}";
158-
var config = CreateConfiguration(() => json);
155+
var config = TestConfiguration.Create(() => json);
159156

160157
var loggerProvider = new TestLoggerProvider(new TestSink(), isEnabled: true);
161158
var factory = TestLoggerBuilder.Create(builder => builder
@@ -187,7 +184,7 @@ public void DefaultCategoryNameIsUsedIfNoneMatch()
187184
}
188185
}
189186
}";
190-
var config = CreateConfiguration(() => json);
187+
var config = TestConfiguration.Create(() => json);
191188

192189
var loggerProvider = new TestLoggerProvider(new TestSink(), isEnabled: true);
193190
var factory = TestLoggerBuilder.Create(builder => builder
@@ -315,7 +312,7 @@ public void ProviderLevelIsPreferredOverGlobalFilter()
315312
}
316313
}
317314
}";
318-
var config = CreateConfiguration(() => json);
315+
var config = TestConfiguration.Create(() => json);
319316
var loggerProvider = new TestLoggerProvider(new TestSink(), isEnabled: true);
320317

321318
var factory = TestLoggerBuilder.Create(builder => builder
@@ -426,7 +423,7 @@ public void DefaultCategoryIsCaseInsensitive()
426423
.Build())
427424
)
428425
.BuildServiceProvider();
429-
426+
430427
var options = serviceProvider.GetRequiredService<IOptions<LoggerFilterOptions>>();
431428

432429
Assert.Null(options.Value.Rules.Single().CategoryName);
@@ -584,32 +581,5 @@ public void FilterTest(LoggerFilterOptions options, (string category, LogLevel l
584581
("Category.Sub", LogLevel.Trace, true, false)
585582
},
586583
};
587-
588-
589-
internal ConfigurationRoot CreateConfiguration(Func<string> getJson)
590-
{
591-
var provider = new TestConfiguration(new JsonConfigurationSource { Optional = true }, getJson);
592-
return new ConfigurationRoot(new List<IConfigurationProvider> { provider });
593-
}
594-
595-
private class TestConfiguration : JsonConfigurationProvider
596-
{
597-
private Func<string> _json;
598-
public TestConfiguration(JsonConfigurationSource source, Func<string> json)
599-
: base(source)
600-
{
601-
_json = json;
602-
}
603-
604-
public override void Load()
605-
{
606-
var stream = new MemoryStream();
607-
var writer = new StreamWriter(stream);
608-
writer.Write(_json());
609-
writer.Flush();
610-
stream.Seek(0, SeekOrigin.Begin);
611-
Load(stream);
612-
}
613-
}
614584
}
615585
}

test/Microsoft.Extensions.Logging.Test/LoggerTest.cs

+97
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,103 @@ public void ScopesAreNotCreatedForDisabledLoggers()
149149
logger.Verify(l => l.BeginScope(It.IsAny<object>()), Times.Never);
150150
}
151151

152+
[Fact]
153+
public void ScopesAreNotCreatedWhenScopesAreDisabled()
154+
{
155+
var provider = new Mock<ILoggerProvider>();
156+
var logger = new Mock<ILogger>();
157+
158+
provider.Setup(loggerProvider => loggerProvider.CreateLogger(It.IsAny<string>()))
159+
.Returns(logger.Object);
160+
161+
var factory = TestLoggerBuilder.Create(
162+
builder => {
163+
builder.AddProvider(provider.Object);
164+
builder.Services.Configure<LoggerFilterOptions>(options => options.CaptureScopes = false);
165+
});
166+
167+
var newLogger = factory.CreateLogger("Logger");
168+
using (newLogger.BeginScope("Scope"))
169+
{
170+
}
171+
172+
provider.Verify(p => p.CreateLogger("Logger"), Times.Once);
173+
logger.Verify(l => l.BeginScope(It.IsAny<object>()), Times.Never);
174+
}
175+
176+
[Fact]
177+
public void ScopesAreNotCreatedInIScopeProviderWhenScopesAreDisabled()
178+
{
179+
var provider = new Mock<ILoggerProvider>();
180+
var logger = new Mock<ILogger>();
181+
182+
IExternalScopeProvider externalScopeProvider = null;
183+
184+
provider.Setup(loggerProvider => loggerProvider.CreateLogger(It.IsAny<string>()))
185+
.Returns(logger.Object);
186+
provider.As<ISupportExternalScope>().Setup(scope => scope.SetScopeProvider(It.IsAny<IExternalScopeProvider>()))
187+
.Callback((IExternalScopeProvider scopeProvider) => externalScopeProvider = scopeProvider);
188+
189+
var factory = TestLoggerBuilder.Create(
190+
builder => {
191+
builder.AddProvider(provider.Object);
192+
builder.Services.Configure<LoggerFilterOptions>(options => options.CaptureScopes = false);
193+
});
194+
195+
var newLogger = factory.CreateLogger("Logger");
196+
int scopeCount = 0;
197+
198+
using (newLogger.BeginScope("Scope"))
199+
{
200+
externalScopeProvider.ForEachScope<object>((_, __) => scopeCount ++, null);
201+
}
202+
203+
provider.Verify(p => p.CreateLogger("Logger"), Times.Once);
204+
logger.Verify(l => l.BeginScope(It.IsAny<object>()), Times.Never);
205+
Assert.Equal(0, scopeCount);
206+
}
207+
208+
[Fact]
209+
public void CaptureScopesIsReadFromConfiguration()
210+
{
211+
var provider = new Mock<ILoggerProvider>();
212+
var logger = new Mock<ILogger>();
213+
var json = @"{ ""CaptureScopes"": ""false"" }";
214+
215+
var config = TestConfiguration.Create(() => json);
216+
IExternalScopeProvider externalScopeProvider = null;
217+
218+
provider.Setup(loggerProvider => loggerProvider.CreateLogger(It.IsAny<string>()))
219+
.Returns(logger.Object);
220+
provider.As<ISupportExternalScope>().Setup(scope => scope.SetScopeProvider(It.IsAny<IExternalScopeProvider>()))
221+
.Callback((IExternalScopeProvider scopeProvider) => externalScopeProvider = scopeProvider);
222+
223+
var factory = TestLoggerBuilder.Create(
224+
builder => {
225+
builder.AddProvider(provider.Object);
226+
builder.AddConfiguration(config);
227+
});
228+
229+
var newLogger = factory.CreateLogger("Logger");
230+
int scopeCount = 0;
231+
232+
using (newLogger.BeginScope("Scope"))
233+
{
234+
externalScopeProvider.ForEachScope<object>((_, __) => scopeCount ++, null);
235+
Assert.Equal(0, scopeCount);
236+
}
237+
238+
json = @"{ ""CaptureScopes"": ""true"" }";
239+
config.Reload();
240+
241+
scopeCount = 0;
242+
using (newLogger.BeginScope("Scope"))
243+
{
244+
externalScopeProvider.ForEachScope<object>((_, __) => scopeCount ++, null);
245+
Assert.Equal(1, scopeCount);
246+
}
247+
}
248+
152249
private class CustomLoggerProvider : ILoggerProvider
153250
{
154251
private readonly string _providerName;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using Microsoft.Extensions.Configuration;
8+
using Microsoft.Extensions.Configuration.Json;
9+
10+
namespace Microsoft.Extensions.Logging.Test
11+
{
12+
internal class TestConfiguration : JsonConfigurationProvider
13+
{
14+
private Func<string> _json;
15+
public TestConfiguration(JsonConfigurationSource source, Func<string> json)
16+
: base(source)
17+
{
18+
_json = json;
19+
}
20+
21+
public override void Load()
22+
{
23+
var stream = new MemoryStream();
24+
var writer = new StreamWriter(stream);
25+
writer.Write(_json());
26+
writer.Flush();
27+
stream.Seek(0, SeekOrigin.Begin);
28+
Load(stream);
29+
}
30+
31+
public static ConfigurationRoot Create(Func<string> getJson)
32+
{
33+
var provider = new TestConfiguration(new JsonConfigurationSource { Optional = true }, getJson);
34+
return new ConfigurationRoot(new List<IConfigurationProvider> { provider });
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)