Reorganize source code in preparation to move into aspnet/Extensions

Prior to reorganization, this source code was found in f7d8e4e053
This commit is contained in:
Nate McMaster 2018-11-06 16:58:30 -08:00
parent 08375cd15c
commit fc4e64de38
12 changed files with 139 additions and 12 deletions

View File

@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging.AzureAppServices;
using Microsoft.Extensions.Logging.AzureAppServices.Internal;
using Microsoft.Extensions.Logging.Configuration;
using Microsoft.Extensions.Options;
using static Microsoft.Extensions.DependencyInjection.ServiceDescriptor;
@ -55,6 +56,7 @@ namespace Microsoft.Extensions.Logging
services.AddSingleton<IConfigureOptions<AzureFileLoggerOptions>>(new FileLoggerConfigureOptions(config, context));
services.AddSingleton<IOptionsChangeTokenSource<AzureFileLoggerOptions>>(
new ConfigurationChangeTokenSource<AzureFileLoggerOptions>(config));
LoggerProviderOptions.RegisterProviderOptions<AzureFileLoggerOptions, FileLoggerProvider>(builder.Services);
}
if (addedBlobLogger)
@ -63,6 +65,7 @@ namespace Microsoft.Extensions.Logging
services.AddSingleton<IConfigureOptions<AzureBlobLoggerOptions>>(new BlobLoggerConfigureOptions(config, context));
services.AddSingleton<IOptionsChangeTokenSource<AzureBlobLoggerOptions>>(
new ConfigurationChangeTokenSource<AzureBlobLoggerOptions>(config));
LoggerProviderOptions.RegisterProviderOptions<AzureBlobLoggerOptions, BlobLoggerProvider>(builder.Services);
}
return builder;

View File

@ -51,8 +51,9 @@ namespace Microsoft.Extensions.Logging.AzureAppServices
}
/// <summary>
/// Gets or sets a strictly positive value representing the maximum retained file count or null for no limit.
/// Defaults to <c>2</c>.
/// Gets or sets a string representing the prefix of the file name used to store the logging information.
/// The current date, in the format YYYYMMDD will be added after the given value.
/// Defaults to <c>diagnostics-</c>.
/// </summary>
public string FileName
{
@ -69,4 +70,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices
internal string LogDirectory { get; set; }
}
}
}

View File

@ -40,7 +40,22 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal
builder.Append(logLevel.ToString());
builder.Append("] ");
builder.Append(_category);
builder.Append(": ");
var scopeProvider = _provider.ScopeProvider;
if (scopeProvider != null)
{
scopeProvider.ForEachScope((scope, stringBuilder) =>
{
stringBuilder.Append(" => ").Append(scope);
}, builder);
builder.AppendLine(":");
}
else
{
builder.Append(": ");
}
builder.AppendLine(formatter(state, exception));
if (exception != null)

View File

@ -66,5 +66,11 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal
/// Gets or sets value indicating if logger accepts and queues writes.
/// </summary>
public bool IsEnabled { get; set; }
/// <summary>
/// Gets or sets a value indicating whether scopes should be included in the message.
/// Defaults to <c>false</c>.
/// </summary>
public bool IncludeScopes { get; set; } = false;
}
}

View File

@ -10,7 +10,7 @@ using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.Logging.AzureAppServices.Internal
{
public abstract class BatchingLoggerProvider: ILoggerProvider
public abstract class BatchingLoggerProvider: ILoggerProvider, ISupportExternalScope
{
private readonly List<LogMessage> _currentBatch = new List<LogMessage>();
private readonly TimeSpan _interval;
@ -22,6 +22,11 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal
private Task _outputTask;
private CancellationTokenSource _cancellationTokenSource;
private bool _includeScopes;
private IExternalScopeProvider _scopeProvider;
internal IExternalScopeProvider ScopeProvider => _includeScopes ? _scopeProvider : null;
protected BatchingLoggerProvider(IOptionsMonitor<BatchingLoggerOptions> options)
{
// NOTE: Only IsEnabled is monitored
@ -50,6 +55,8 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal
{
var oldIsEnabled = IsEnabled;
IsEnabled = options.IsEnabled;
_includeScopes = options.IncludeScopes;
if (oldIsEnabled != IsEnabled)
{
if (IsEnabled)
@ -159,5 +166,10 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal
{
return new BatchingLogger(this, categoryName);
}
void ISupportExternalScope.SetScopeProvider(IExternalScopeProvider scopeProvider)
{
_scopeProvider = scopeProvider;
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging.AzureAppServices.Internal;
@ -13,8 +14,9 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test
{
public class BatchingLoggerProviderTests
{
DateTimeOffset _timestampOne = new DateTimeOffset(2016, 05, 04, 03, 02, 01, TimeSpan.Zero);
string _nl = Environment.NewLine;
private DateTimeOffset _timestampOne = new DateTimeOffset(2016, 05, 04, 03, 02, 01, TimeSpan.Zero);
private string _nl = Environment.NewLine;
private Regex _timeStampRegex = new Regex(@"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3} .\d{2}:\d{2} ");
[Fact]
public async Task LogsInIntervals()
@ -34,6 +36,33 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test
Assert.Equal("2016-05-04 04:02:01.000 +00:00 [Error] Cat: Error message" + _nl, provider.Batches[0][1].Message);
}
[Fact]
public async Task IncludesScopes()
{
var provider = new TestBatchingLoggingProvider(includeScopes: true);
var factory = new LoggerFactory(new [] { provider });
var logger = factory.CreateLogger("Cat");
await provider.IntervalControl.Pause;
using (logger.BeginScope("Scope"))
{
using (logger.BeginScope("Scope2"))
{
logger.Log(LogLevel.Information, 0, "Info message", null, (state, ex) => state);
}
}
provider.IntervalControl.Resume();
await provider.IntervalControl.Pause;
Assert.Matches(_timeStampRegex, provider.Batches[0][0].Message);
Assert.EndsWith(
" [Information] Cat => Scope => Scope2:" + _nl +
"Info message" + _nl,
provider.Batches[0][0].Message);
}
[Fact]
public async Task RespectsBatchSize()
{
@ -85,13 +114,14 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test
public List<LogMessage[]> Batches { get; } = new List<LogMessage[]>();
public ManualIntervalControl IntervalControl { get; } = new ManualIntervalControl();
public TestBatchingLoggingProvider(TimeSpan? interval = null, int? maxBatchSize = null, int? maxQueueSize = null)
public TestBatchingLoggingProvider(TimeSpan? interval = null, int? maxBatchSize = null, int? maxQueueSize = null, bool includeScopes = false)
: base(new OptionsWrapperMonitor<BatchingLoggerOptions>(new BatchingLoggerOptions
{
FlushPeriod = interval ?? TimeSpan.FromSeconds(1),
BatchSize = maxBatchSize,
BackgroundQueueSize = maxQueueSize,
IsEnabled = true
IsEnabled = true,
IncludeScopes = includeScopes
}))
{
}

View File

@ -5,6 +5,10 @@ namespace Microsoft.Extensions.Logging.Testing
{
public interface ITestSink
{
event Action<WriteContext> MessageLogged;
event Action<BeginScopeContext> ScopeStarted;
Func<WriteContext, bool> WriteEnabled { get; set; }
Func<BeginScopeContext, bool> BeginEnabled { get; set; }

View File

@ -51,7 +51,9 @@ namespace Microsoft.Extensions.Logging.Testing
TestOutputHelper = testOutputHelper;
var classType = GetType();
var logLevelAttribute = methodInfo.GetCustomAttribute<LogLevelAttribute>();
var logLevelAttribute = methodInfo.GetCustomAttribute<LogLevelAttribute>()
?? methodInfo.DeclaringType.GetCustomAttribute<LogLevelAttribute>()
?? methodInfo.DeclaringType.Assembly.GetCustomAttribute<LogLevelAttribute>();
var testName = testMethodArguments.Aggregate(methodInfo.Name, (a, b) => $"{a}-{(b ?? "null")}");
var useShortClassName = methodInfo.DeclaringType.GetCustomAttribute<ShortClassNameAttribute>()

View File

@ -30,12 +30,17 @@ namespace Microsoft.Extensions.Logging.Testing
public IProducerConsumerCollection<WriteContext> Writes { get => _writes; set => _writes = new ConcurrentQueue<WriteContext>(value); }
public event Action<WriteContext> MessageLogged;
public event Action<BeginScopeContext> ScopeStarted;
public void Write(WriteContext context)
{
if (WriteEnabled == null || WriteEnabled(context))
{
_writes.Enqueue(context);
}
MessageLogged?.Invoke(context);
}
public void Begin(BeginScopeContext context)
@ -44,6 +49,7 @@ namespace Microsoft.Extensions.Logging.Testing
{
_scopes.Enqueue(context);
}
ScopeStarted?.Invoke(context);
}
public static bool EnableWithTypeName<T>(WriteContext context)

View File

@ -5,7 +5,7 @@ using System;
namespace Microsoft.Extensions.Logging.Testing
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false)]
public class LogLevelAttribute : Attribute
{
public LogLevelAttribute(LogLevel logLevel)

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.DependencyInjection;
@ -9,6 +10,7 @@ using Xunit.Abstractions;
namespace Microsoft.Extensions.Logging.Testing.Tests
{
[LogLevel(LogLevel.Debug)]
[ShortClassName]
public class LoggedTestXunitTests : TestLoggedTest
{
@ -75,7 +77,7 @@ namespace Microsoft.Extensions.Logging.Testing.Tests
[Fact]
[LogLevel(LogLevel.Information)]
public void LoggedFactFilteredByLogLevel()
public void LoggedFactFilteredByMethodLogLevel()
{
Logger.LogInformation("Information");
Logger.LogDebug("Debug");
@ -85,6 +87,17 @@ namespace Microsoft.Extensions.Logging.Testing.Tests
Assert.Equal("Information", message.Formatter(message.State, null));
}
[Fact]
public void LoggedFactFilteredByClassLogLevel()
{
Logger.LogDebug("Debug");
Logger.LogTrace("Trace");
var message = Assert.Single(TestSink.Writes);
Assert.Equal(LogLevel.Debug, message.LogLevel);
Assert.Equal("Debug", message.Formatter(message.State, null));
}
[Theory]
[InlineData("Hello world")]
[LogLevel(LogLevel.Information)]
@ -129,6 +142,37 @@ namespace Microsoft.Extensions.Logging.Testing.Tests
{
Assert.True(SetupInvoked);
}
[Fact]
public void MessageWrittenEventInvoked()
{
WriteContext context = null;
TestSink.MessageLogged += ctx => context = ctx;
Logger.LogInformation("Information");
Assert.Equal(TestSink.Writes.Single(), context);
}
[Fact]
public void ScopeStartedEventInvoked()
{
BeginScopeContext context = null;
TestSink.ScopeStarted += ctx => context = ctx;
using (Logger.BeginScope("Scope")) {}
Assert.Equal(TestSink.Scopes.Single(), context);
}
}
public class LoggedTestXunitLogLevelTests : LoggedTest
{
[Fact]
public void LoggedFactFilteredByAssemblyLogLevel()
{
Logger.LogTrace("Trace");
var message = Assert.Single(TestSink.Writes);
Assert.Equal(LogLevel.Trace, message.LogLevel);
Assert.Equal("Trace", message.Formatter(message.State, null));
}
}
public class LoggedTestXunitInitializationTests : TestLoggedTest

View File

@ -0,0 +1,4 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
[assembly: LogLevel(LogLevel.Trace)]