Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
using Microsoft.CodeAnalysis.Text;
using Microsoft.CommonLanguageServerProtocol.Framework;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Nerdbank.Streams;

namespace Microsoft.AspNetCore.Razor.Microbenchmarks.LanguageServer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal partial class RazorLanguageServer
/// </summary>
private sealed class LoggerFactoryWrapper(ILoggerFactory loggerFactory) : ILoggerFactory
{
private ILoggerFactory _loggerFactory = loggerFactory;
private readonly ILoggerFactory _loggerFactory = loggerFactory;

public void AddLoggerProvider(ILoggerProvider provider)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,35 @@ namespace Microsoft.CodeAnalysis.Razor.Logging;

internal abstract partial class AbstractLoggerFactory
{
private class AggregateLogger(ImmutableArray<ILogger> loggers) : ILogger
private sealed class LazyLogger(Lazy<ILoggerProvider, LoggerProviderMetadata> lazyProvider, string categoryName)
{
private ImmutableArray<ILogger> _loggers = loggers;
private readonly LoggerProviderMetadata _metadata = lazyProvider.Metadata;
private readonly Lazy<ILogger> _lazyLogger = new(() => lazyProvider.Value.CreateLogger(categoryName));

public ILogger Instance => _lazyLogger.Value;

public bool IsEnabled(LogLevel logLevel)
{
// If the ILoggerProvider's metadata has a minimum log level, we can use that
// rather than forcing the ILoggerProvider to be created.
if (_metadata.MinimumLogLevel is LogLevel minimumLogLevel)
{
return logLevel.IsAtLeast(minimumLogLevel);
}

return Instance.IsEnabled(logLevel);
}
}

private class AggregateLogger(ImmutableArray<LazyLogger> lazyLoggers) : ILogger
{
private ImmutableArray<LazyLogger> _lazyLoggers = lazyLoggers;

public bool IsEnabled(LogLevel logLevel)
{
foreach (var logger in _loggers)
foreach (var lazyLogger in _lazyLoggers)
{
if (logger.IsEnabled(logLevel))
if (lazyLogger.IsEnabled(logLevel))
{
return true;
}
Expand All @@ -27,18 +47,18 @@ public bool IsEnabled(LogLevel logLevel)

public void Log(LogLevel logLevel, string message, Exception? exception)
{
foreach (var logger in _loggers)
foreach (var lazyLogger in _lazyLoggers)
{
if (logger.IsEnabled(logLevel))
if (lazyLogger.IsEnabled(logLevel))
{
logger.Log(logLevel, message, exception);
lazyLogger.Instance.Log(logLevel, message, exception);
}
}
}

internal void AddLogger(ILogger logger)
internal void AddLogger(LazyLogger lazyLogger)
{
ImmutableInterlocked.Update(ref _loggers, (set, l) => set.Add(l), logger);
ImmutableInterlocked.Update(ref _lazyLoggers, (set, l) => set.Add(l), lazyLogger);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ namespace Microsoft.CodeAnalysis.Razor.Logging;

internal abstract partial class AbstractLoggerFactory : ILoggerFactory
{
private ImmutableArray<Lazy<ILoggerProvider, LoggerProviderMetadata>> _providers;
private ImmutableDictionary<string, AggregateLogger> _loggers;
private ImmutableArray<ILoggerProvider> _providers;

protected AbstractLoggerFactory(ImmutableArray<ILoggerProvider> providers)
: this(providers.SelectAsArray(p => new Lazy<ILoggerProvider, LoggerProviderMetadata>(() => p, LoggerProviderMetadata.Empty)))
{
}

protected AbstractLoggerFactory(ImmutableArray<Lazy<ILoggerProvider, LoggerProviderMetadata>> providers)
{
_providers = providers;
_loggers = ImmutableDictionary.Create<string, AggregateLogger>(StringComparer.OrdinalIgnoreCase);
Expand All @@ -29,24 +34,26 @@ public ILogger GetOrCreateLogger(string categoryName)
return logger;
}

using var loggers = new PooledArrayBuilder<ILogger>(_providers.Length);
using var lazyLoggers = new PooledArrayBuilder<LazyLogger>(_providers.Length);

foreach (var provider in _providers)
{
loggers.Add(provider.CreateLogger(categoryName));
lazyLoggers.Add(new(provider, categoryName));
}

var result = new AggregateLogger(loggers.DrainToImmutable());
var result = new AggregateLogger(lazyLoggers.DrainToImmutable());
return ImmutableInterlocked.AddOrUpdate(ref _loggers, categoryName, result, (k, v) => v);
}

public void AddLoggerProvider(ILoggerProvider provider)
{
if (ImmutableInterlocked.Update(ref _providers, (set, p) => set.Add(p), provider))
var lazyProvider = new Lazy<ILoggerProvider, LoggerProviderMetadata>(() => provider, LoggerProviderMetadata.Empty);

if (ImmutableInterlocked.Update(ref _providers, (set, p) => set.Add(p), lazyProvider))
{
foreach (var (category, logger) in _loggers)
foreach (var (categoryName, logger) in _loggers)
{
logger.AddLogger(provider.CreateLogger(category));
logger.AddLogger(new(lazyProvider, categoryName));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System.Collections.Generic;

namespace Microsoft.CodeAnalysis.Razor.Logging;

internal sealed class LoggerProviderMetadata
{
public static LoggerProviderMetadata Empty { get; } = new();

public LogLevel? MinimumLogLevel { get; }

private LoggerProviderMetadata()
{
}

public LoggerProviderMetadata(IDictionary<string, object> data)
: this()
{
MinimumLogLevel = data.TryGetValue(nameof(MinimumLogLevel), out var minimumLogLevel)
? (LogLevel?)minimumLogLevel
: null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,10 @@

namespace Microsoft.VisualStudio.Razor.LanguageClient.Logging;

internal sealed class RazorLogHubLogger : ILogger
internal sealed class RazorLogHubLogger(string categoryName, RazorLogHubTraceProvider traceProvider) : ILogger
{
private string _categoryName;
private RazorLogHubTraceProvider _traceProvider;

public RazorLogHubLogger(string categoryName, RazorLogHubTraceProvider traceProvider)
{
_categoryName = categoryName;
_traceProvider = traceProvider;
}
private readonly string _categoryName = categoryName;
private readonly RazorLogHubTraceProvider _traceProvider = traceProvider;

public bool IsEnabled(LogLevel logLevel)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,11 @@

namespace Microsoft.VisualStudio.Razor.LanguageClient.Logging;

[Export(typeof(ILoggerProvider))]
internal sealed class RazorLogHubLoggerProvider : ILoggerProvider
[ExportLoggerProvider]
[method: ImportingConstructor]
internal sealed class RazorLogHubLoggerProvider(RazorLogHubTraceProvider traceProvider) : ILoggerProvider
{
private readonly RazorLogHubTraceProvider _traceProvider;

[ImportingConstructor]
public RazorLogHubLoggerProvider(RazorLogHubTraceProvider traceProvider)
{
_traceProvider = traceProvider;
}
private readonly RazorLogHubTraceProvider _traceProvider = traceProvider;

public ILogger CreateLogger(string categoryName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Logging;
/// <summary>
/// An <see cref="ILoggerProvider"/> that logs any warnings or errors to the Visual Studio Activity Log.
/// </summary>
[Export(typeof(ILoggerProvider))]
[ExportLoggerProvider(minimumLogLevel: LogLevel.Warning)]
[method: ImportingConstructor]
internal sealed partial class ActivityLogLoggerProvider(RazorActivityLog activityLog) : ILoggerProvider
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System;
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis.Razor.Logging;

namespace Microsoft.VisualStudio.Razor.Logging;

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class)]
internal sealed class ExportLoggerProviderAttribute : ExportAttribute
{
public LogLevel? MinimumLogLevel { get; }

public ExportLoggerProviderAttribute()
: base(typeof(ILoggerProvider))
{
MinimumLogLevel = null;
}

public ExportLoggerProviderAttribute(LogLevel minimumLogLevel)
: base(typeof(ILoggerProvider))
{
MinimumLogLevel = minimumLogLevel;
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis.Razor.Logging;

namespace Microsoft.VisualStudio.Razor.Logging;

[Export(typeof(ILoggerProvider))]
[method: ImportingConstructor]
internal partial class MemoryLoggerProvider() : ILoggerProvider
[ExportLoggerProvider]
internal partial class MemoryLoggerProvider : ILoggerProvider
{
// How many messages will the buffer contain
private const int BufferSize = 5000;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

namespace Microsoft.VisualStudio.Razor.Logging;

[Export(typeof(ILoggerProvider))]
[ExportLoggerProvider]
[method: ImportingConstructor]
internal class OutputWindowLoggerProvider(
// Anything this class imports would have a circular dependency if they tried to log anything,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.Composition;
Expand All @@ -10,7 +11,7 @@ namespace Microsoft.VisualStudio.Razor.Logging;

[Export(typeof(ILoggerFactory))]
[method: ImportingConstructor]
internal sealed class VisualStudioLoggerFactory([ImportMany] IEnumerable<ILoggerProvider> providers)
internal sealed class VisualStudioLoggerFactory([ImportMany] IEnumerable<Lazy<ILoggerProvider, LoggerProviderMetadata>> providers)
: AbstractLoggerFactory(providers.ToImmutableArray())
{
}
3 changes: 2 additions & 1 deletion src/Razor/src/rzls/LoggerFactory.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Razor.Logging;

namespace Microsoft.AspNetCore.Razor.LanguageServer;

internal sealed class LoggerFactory(ImmutableArray<ILoggerProvider> providers)
internal sealed class LoggerFactory(ImmutableArray<Lazy<ILoggerProvider, LoggerProviderMetadata>> providers)
: AbstractLoggerFactory(providers)
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,21 +76,4 @@ public static TValue GetOrAdd<TKey, TValue>(
return value;
}
}

public static TValue GetValueOrDefault<TKey, TValue>(
this Dictionary<TKey, TValue> dictionary,
TKey key,
TValue defaultValue)
where TKey : notnull
{
if (dictionary.TryGetValue(key, out var existingValue))
{
return existingValue;
}
else
{
dictionary.Add(key, defaultValue);
return defaultValue;
}
}
}