Skip to content

Commit b4bdfe0

Browse files
Add export attribute to allow logger providers to optionally provider minimum log level
1 parent 414d4fe commit b4bdfe0

File tree

13 files changed

+105
-44
lines changed

13 files changed

+105
-44
lines changed

src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorLanguageServerBenchmarkBase.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
using Microsoft.CodeAnalysis.Text;
2020
using Microsoft.CommonLanguageServerProtocol.Framework;
2121
using Microsoft.Extensions.DependencyInjection;
22-
using Microsoft.VisualStudio.LanguageServer.Protocol;
2322
using Nerdbank.Streams;
2423

2524
namespace Microsoft.AspNetCore.Razor.Microbenchmarks.LanguageServer;
@@ -108,7 +107,7 @@ public Task<TResponse> SendRequestAsync<TParams, TResponse>(string method, TPara
108107
}
109108
}
110109

111-
internal class NoopLoggerFactory() : AbstractLoggerFactory([new(() => new NoopLoggerProvider())]);
110+
internal class NoopLoggerFactory() : AbstractLoggerFactory([new NoopLoggerProvider()]);
112111

113112
internal class NoopLoggerProvider : ILoggerProvider
114113
{

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Logging/AbstractLoggerFactory.AggregateLogger.cs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,35 @@ namespace Microsoft.CodeAnalysis.Razor.Logging;
88

99
internal abstract partial class AbstractLoggerFactory
1010
{
11-
private class AggregateLogger(ImmutableArray<Lazy<ILogger>> lazyLoggers) : ILogger
11+
private sealed class LazyLogger(Lazy<ILoggerProvider, LoggerProviderMetadata> lazyProvider, string categoryName)
1212
{
13-
private ImmutableArray<Lazy<ILogger>> _lazyLoggers = lazyLoggers;
13+
private readonly LoggerProviderMetadata _metadata = lazyProvider.Metadata;
14+
private readonly Lazy<ILogger> _lazyLogger = new(() => lazyProvider.Value.CreateLogger(categoryName));
15+
16+
public ILogger Instance => _lazyLogger.Value;
17+
18+
public bool IsEnabled(LogLevel logLevel)
19+
{
20+
// If the ILoggerProvider's metadata has a minimum log level, we can use that
21+
// rather than forcing the ILoggerProvider to be created.
22+
if (_metadata.MinimumLogLevel is LogLevel minimumLogLevel)
23+
{
24+
return logLevel.IsAtLeast(minimumLogLevel);
25+
}
26+
27+
return Instance.IsEnabled(logLevel);
28+
}
29+
}
30+
31+
private class AggregateLogger(ImmutableArray<LazyLogger> lazyLoggers) : ILogger
32+
{
33+
private ImmutableArray<LazyLogger> _lazyLoggers = lazyLoggers;
1434

1535
public bool IsEnabled(LogLevel logLevel)
1636
{
1737
foreach (var lazyLogger in _lazyLoggers)
1838
{
19-
if (lazyLogger.Value.IsEnabled(logLevel))
39+
if (lazyLogger.IsEnabled(logLevel))
2040
{
2141
return true;
2242
}
@@ -29,16 +49,14 @@ public void Log(LogLevel logLevel, string message, Exception? exception)
2949
{
3050
foreach (var lazyLogger in _lazyLoggers)
3151
{
32-
var logger = lazyLogger.Value;
33-
34-
if (logger.IsEnabled(logLevel))
52+
if (lazyLogger.IsEnabled(logLevel))
3553
{
36-
logger.Log(logLevel, message, exception);
54+
lazyLogger.Instance.Log(logLevel, message, exception);
3755
}
3856
}
3957
}
4058

41-
internal void AddLogger(Lazy<ILogger> lazyLogger)
59+
internal void AddLogger(LazyLogger lazyLogger)
4260
{
4361
ImmutableInterlocked.Update(ref _lazyLoggers, (set, l) => set.Add(l), lazyLogger);
4462
}

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Logging/AbstractLoggerFactory.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,15 @@ namespace Microsoft.CodeAnalysis.Razor.Logging;
1313

1414
internal abstract partial class AbstractLoggerFactory : ILoggerFactory
1515
{
16-
private ImmutableArray<Lazy<ILoggerProvider>> _providers;
16+
private ImmutableArray<Lazy<ILoggerProvider, LoggerProviderMetadata>> _providers;
1717
private ImmutableDictionary<string, AggregateLogger> _loggers;
1818

19-
protected AbstractLoggerFactory(ImmutableArray<Lazy<ILoggerProvider>> providers)
19+
protected AbstractLoggerFactory(ImmutableArray<ILoggerProvider> providers)
20+
: this(providers.SelectAsArray(p => new Lazy<ILoggerProvider, LoggerProviderMetadata>(() => p, LoggerProviderMetadata.Empty)))
21+
{
22+
}
23+
24+
protected AbstractLoggerFactory(ImmutableArray<Lazy<ILoggerProvider, LoggerProviderMetadata>> providers)
2025
{
2126
_providers = providers;
2227
_loggers = ImmutableDictionary.Create<string, AggregateLogger>(StringComparer.OrdinalIgnoreCase);
@@ -29,11 +34,11 @@ public ILogger GetOrCreateLogger(string categoryName)
2934
return logger;
3035
}
3136

32-
using var lazyLoggers = new PooledArrayBuilder<Lazy<ILogger>>(_providers.Length);
37+
using var lazyLoggers = new PooledArrayBuilder<LazyLogger>(_providers.Length);
3338

3439
foreach (var provider in _providers)
3540
{
36-
lazyLoggers.Add(new(() => provider.Value.CreateLogger(categoryName)));
41+
lazyLoggers.Add(new(provider, categoryName));
3742
}
3843

3944
var result = new AggregateLogger(lazyLoggers.DrainToImmutable());
@@ -42,13 +47,13 @@ public ILogger GetOrCreateLogger(string categoryName)
4247

4348
public void AddLoggerProvider(ILoggerProvider provider)
4449
{
45-
var lazyProvider = new Lazy<ILoggerProvider>(() => provider);
50+
var lazyProvider = new Lazy<ILoggerProvider, LoggerProviderMetadata>(() => provider, LoggerProviderMetadata.Empty);
4651

4752
if (ImmutableInterlocked.Update(ref _providers, (set, p) => set.Add(p), lazyProvider))
4853
{
49-
foreach (var (category, logger) in _loggers)
54+
foreach (var (categoryName, logger) in _loggers)
5055
{
51-
logger.AddLogger(new(() => provider.CreateLogger(category)));
56+
logger.AddLogger(new(lazyProvider, categoryName));
5257
}
5358
}
5459
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT license. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
6+
namespace Microsoft.CodeAnalysis.Razor.Logging;
7+
8+
internal sealed class LoggerProviderMetadata
9+
{
10+
public static LoggerProviderMetadata Empty { get; } = new();
11+
12+
public LogLevel? MinimumLogLevel { get; }
13+
14+
private LoggerProviderMetadata()
15+
{
16+
}
17+
18+
public LoggerProviderMetadata(IDictionary<string, object> data)
19+
: this()
20+
{
21+
MinimumLogLevel = data.TryGetValue(nameof(MinimumLogLevel), out var minimumLogLevel)
22+
? (LogLevel?)minimumLogLevel
23+
: null;
24+
}
25+
}

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Logging/RazorLogHubLogger.cs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,10 @@
99

1010
namespace Microsoft.VisualStudio.Razor.LanguageClient.Logging;
1111

12-
internal sealed class RazorLogHubLogger : ILogger
12+
internal sealed class RazorLogHubLogger(string categoryName, RazorLogHubTraceProvider traceProvider) : ILogger
1313
{
14-
private string _categoryName;
15-
private RazorLogHubTraceProvider _traceProvider;
16-
17-
public RazorLogHubLogger(string categoryName, RazorLogHubTraceProvider traceProvider)
18-
{
19-
_categoryName = categoryName;
20-
_traceProvider = traceProvider;
21-
}
14+
private readonly string _categoryName = categoryName;
15+
private readonly RazorLogHubTraceProvider _traceProvider = traceProvider;
2216

2317
public bool IsEnabled(LogLevel logLevel)
2418
{

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Logging/RazorLogHubLoggerProvider.cs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,11 @@
77

88
namespace Microsoft.VisualStudio.Razor.LanguageClient.Logging;
99

10-
[Export(typeof(ILoggerProvider))]
11-
internal sealed class RazorLogHubLoggerProvider : ILoggerProvider
10+
[ExportLoggerProvider]
11+
[method: ImportingConstructor]
12+
internal sealed class RazorLogHubLoggerProvider(RazorLogHubTraceProvider traceProvider) : ILoggerProvider
1213
{
13-
private readonly RazorLogHubTraceProvider _traceProvider;
14-
15-
[ImportingConstructor]
16-
public RazorLogHubLoggerProvider(RazorLogHubTraceProvider traceProvider)
17-
{
18-
_traceProvider = traceProvider;
19-
}
14+
private readonly RazorLogHubTraceProvider _traceProvider = traceProvider;
2015

2116
public ILogger CreateLogger(string categoryName)
2217
{

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Logging/ActivityLogLoggerProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Logging;
1010
/// <summary>
1111
/// An <see cref="ILoggerProvider"/> that logs any warnings or errors to the Visual Studio Activity Log.
1212
/// </summary>
13-
[Export(typeof(ILoggerProvider))]
13+
[ExportLoggerProvider(minimumLogLevel: LogLevel.Warning)]
1414
[method: ImportingConstructor]
1515
internal sealed partial class ActivityLogLoggerProvider(RazorActivityLog activityLog) : ILoggerProvider
1616
{
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT license. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.ComponentModel.Composition;
6+
using Microsoft.CodeAnalysis.Razor.Logging;
7+
8+
namespace Microsoft.VisualStudio.Razor.Logging;
9+
10+
[MetadataAttribute]
11+
[AttributeUsage(AttributeTargets.Class)]
12+
internal sealed class ExportLoggerProviderAttribute : ExportAttribute
13+
{
14+
public LogLevel? MinimumLogLevel { get; }
15+
16+
public ExportLoggerProviderAttribute()
17+
: base(typeof(ILoggerProvider))
18+
{
19+
MinimumLogLevel = null;
20+
}
21+
22+
public ExportLoggerProviderAttribute(LogLevel minimumLogLevel)
23+
: base(typeof(ILoggerProvider))
24+
{
25+
MinimumLogLevel = minimumLogLevel;
26+
}
27+
}

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Logging/MemoryLoggerProvider.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the MIT license. See License.txt in the project root for license information.
33

4-
using System.ComponentModel.Composition;
54
using Microsoft.CodeAnalysis.Razor.Logging;
65

76
namespace Microsoft.VisualStudio.Razor.Logging;
87

9-
[Export(typeof(ILoggerProvider))]
10-
[method: ImportingConstructor]
11-
internal partial class MemoryLoggerProvider() : ILoggerProvider
8+
[ExportLoggerProvider]
9+
internal partial class MemoryLoggerProvider : ILoggerProvider
1210
{
1311
// How many messages will the buffer contain
1412
private const int BufferSize = 5000;

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Logging/OutputWindowLoggerProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
namespace Microsoft.VisualStudio.Razor.Logging;
1616

17-
[Export(typeof(ILoggerProvider))]
17+
[ExportLoggerProvider]
1818
[method: ImportingConstructor]
1919
internal class OutputWindowLoggerProvider(
2020
// Anything this class imports would have a circular dependency if they tried to log anything,

0 commit comments

Comments
 (0)