From 018907bec0eedae04669aec564e737b0e459eb33 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 6 Nov 2018 13:11:45 -0800 Subject: [PATCH 01/44] Reorganize source code in preparation to move into aspnet/Extensions Prior to reorganization, this source code was found in https://github.com/aspnet/Logging/tree/8270c545224e8734d7297e54edef5c584ee82f01 --- .../Directory.Build.props | 7 + .../AzureAppServicesDiagnosticsSettings.cs | 161 ++ ...AzureAppServicesLoggerFactoryExtensions.cs | 189 +++ .../src/AzureBlobLoggerOptions.cs | 44 + .../src/AzureFileLoggerOptions.cs | 72 + .../Internal/BatchLoggerConfigureOptions.cs | 36 + .../src/Internal/BatchingLogger.cs | 59 + .../src/Internal/BatchingLoggerOptions.cs | 69 + .../src/Internal/BatchingLoggerProvider.cs | 163 ++ .../Internal/BlobAppendReferenceWrapper.cs | 96 ++ .../Internal/BlobLoggerConfigureOptions.cs | 29 + .../src/Internal/BlobLoggerProvider.cs | 91 ++ .../ConfigurationBasedLevelSwitcher.cs | 50 + .../Internal/FileLoggerConfigureOptions.cs | 26 + .../src/Internal/FileLoggerProvider.cs | 81 + .../src/Internal/ForwardingLoggerProvider.cs | 25 + .../src/Internal/ICloudAppendBlob.cs | 22 + .../src/Internal/IWebAppContext.cs | 31 + .../src/Internal/LogMessage.cs | 13 + .../src/Internal/SiteConfigurationProvider.cs | 22 + .../src/Internal/WebAppContext.cs | 33 + ...Extensions.Logging.AzureAppServices.csproj | 18 + .../src/Properties/AssemblyInfo.cs | 7 + .../src/baseline.netcore.json | 368 +++++ .../test/AzureAppendBlobTests.cs | 186 +++ .../test/AzureBlobSinkTests.cs | 98 ++ ...reDiagnosticsConfigurationProviderTests.cs | 70 + .../test/BatchingLoggerProviderTests.cs | 111 ++ .../test/ConfigureOptionsTests.cs | 71 + .../test/FileLoggerTests.cs | 122 ++ .../test/LoggerBuilderExtensionsTests.cs | 69 + .../test/ManualIntervalControl.cs | 30 + ...ions.Logging.AzureAppServices.Tests.csproj | 12 + .../test/OptionsWrapperMonitor.cs | 25 + .../test/TestBlobSink.cs | 30 + .../test/TestFileLoggerProvider.cs | 36 + .../test/WebConfigurationLevelSwitchTests.cs | 40 + .../Logging.Testing/src/AssemblyTestLog.cs | 305 ++++ .../Logging.Testing/src/BeginScopeContext.cs | 12 + src/Logging/Logging.Testing/src/ITestSink.cs | 20 + .../Logging.Testing/src/LogValuesAssert.cs | 80 + src/Logging/Logging.Testing/src/LoggedTest.cs | 45 + ...icrosoft.Extensions.Logging.Testing.csproj | 26 + .../src/Properties/AssemblyInfo.cs | 6 + .../src/ShortClassNameAttribute.cs | 12 + src/Logging/Logging.Testing/src/TestLogger.cs | 76 + .../Logging.Testing/src/TestLoggerFactory.cs | 32 + .../Logging.Testing/src/TestLoggerOfT.cs | 37 + .../Logging.Testing/src/TestLoggerProvider.cs | 24 + src/Logging/Logging.Testing/src/TestSink.cs | 59 + .../Logging.Testing/src/WriteContext.cs | 32 + .../src/Xunit/LogLevelAttribute.cs | 18 + .../Xunit/LoggedConditionalFactDiscoverer.cs | 28 + .../LoggedConditionalTheoryDiscoverer.cs | 41 + .../src/Xunit/LoggedFactDiscoverer.cs | 18 + .../src/Xunit/LoggedTestAssemblyRunner.cs | 31 + .../src/Xunit/LoggedTestCase.cs | 36 + .../src/Xunit/LoggedTestCaseRunner.cs | 42 + .../src/Xunit/LoggedTestClassRunner.cs | 36 + .../src/Xunit/LoggedTestCollectionRunner.cs | 33 + .../src/Xunit/LoggedTestFramework.cs | 26 + .../Xunit/LoggedTestFrameworkDiscoverer.cs | 80 + .../src/Xunit/LoggedTestFrameworkExecutor.cs | 26 + .../src/Xunit/LoggedTestInvoker.cs | 100 ++ .../src/Xunit/LoggedTestMethodRunner.cs | 36 + .../src/Xunit/LoggedTestRunner.cs | 33 + .../src/Xunit/LoggedTheoryDiscoverer.cs | 29 + .../src/Xunit/LoggedTheoryTestCase.cs | 35 + .../src/Xunit/LoggedTheoryTestCaseRunner.cs | 41 + .../src/XunitLoggerFactoryExtensions.cs | 37 + .../src/XunitLoggerProvider.cs | 116 ++ .../Logging.Testing/src/baseline.netcore.json | 1321 +++++++++++++++++ ...Microsoft.Extensions.Logging.Testing.props | 8 + .../test/AssemblyTestLogTests.cs | 207 +++ .../test/LogValuesAssertTest.cs | 221 +++ .../test/LoggedTestXunitTests.cs | 142 ++ ...ft.Extensions.Logging.Testing.Tests.csproj | 13 + .../test/TestTestOutputHelper.cs | 36 + .../test/XunitLoggerProviderTest.cs | 87 ++ 79 files changed, 6255 insertions(+) create mode 100644 src/Logging/Logging.AzureAppServices/Directory.Build.props create mode 100644 src/Logging/Logging.AzureAppServices/src/AzureAppServicesDiagnosticsSettings.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/BatchLoggerConfigureOptions.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/BatchingLogger.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/BlobAppendReferenceWrapper.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerConfigureOptions.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerProvider.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/ConfigurationBasedLevelSwitcher.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerConfigureOptions.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerProvider.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/ForwardingLoggerProvider.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/ICloudAppendBlob.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/IWebAppContext.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/LogMessage.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/SiteConfigurationProvider.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/WebAppContext.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj create mode 100644 src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/baseline.netcore.json create mode 100644 src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs create mode 100644 src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs create mode 100644 src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs create mode 100644 src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs create mode 100644 src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs create mode 100644 src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs create mode 100644 src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs create mode 100644 src/Logging/Logging.AzureAppServices/test/ManualIntervalControl.cs create mode 100644 src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj create mode 100644 src/Logging/Logging.AzureAppServices/test/OptionsWrapperMonitor.cs create mode 100644 src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs create mode 100644 src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs create mode 100644 src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs create mode 100644 src/Logging/Logging.Testing/src/AssemblyTestLog.cs create mode 100644 src/Logging/Logging.Testing/src/BeginScopeContext.cs create mode 100644 src/Logging/Logging.Testing/src/ITestSink.cs create mode 100644 src/Logging/Logging.Testing/src/LogValuesAssert.cs create mode 100644 src/Logging/Logging.Testing/src/LoggedTest.cs create mode 100644 src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj create mode 100644 src/Logging/Logging.Testing/src/Properties/AssemblyInfo.cs create mode 100644 src/Logging/Logging.Testing/src/ShortClassNameAttribute.cs create mode 100644 src/Logging/Logging.Testing/src/TestLogger.cs create mode 100644 src/Logging/Logging.Testing/src/TestLoggerFactory.cs create mode 100644 src/Logging/Logging.Testing/src/TestLoggerOfT.cs create mode 100644 src/Logging/Logging.Testing/src/TestLoggerProvider.cs create mode 100644 src/Logging/Logging.Testing/src/TestSink.cs create mode 100644 src/Logging/Logging.Testing/src/WriteContext.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LogLevelAttribute.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedFactDiscoverer.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestAssemblyRunner.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestCase.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestCaseRunner.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestClassRunner.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestCollectionRunner.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestFramework.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkExecutor.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestMethodRunner.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTheoryDiscoverer.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCase.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCaseRunner.cs create mode 100644 src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs create mode 100644 src/Logging/Logging.Testing/src/XunitLoggerProvider.cs create mode 100644 src/Logging/Logging.Testing/src/baseline.netcore.json create mode 100644 src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props create mode 100644 src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs create mode 100644 src/Logging/Logging.Testing/test/LogValuesAssertTest.cs create mode 100644 src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs create mode 100644 src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj create mode 100644 src/Logging/Logging.Testing/test/TestTestOutputHelper.cs create mode 100644 src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs diff --git a/src/Logging/Logging.AzureAppServices/Directory.Build.props b/src/Logging/Logging.AzureAppServices/Directory.Build.props new file mode 100644 index 0000000000..f25c1d90ce --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/Directory.Build.props @@ -0,0 +1,7 @@ + + + + + true + + diff --git a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesDiagnosticsSettings.cs b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesDiagnosticsSettings.cs new file mode 100644 index 0000000000..f48480c70f --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesDiagnosticsSettings.cs @@ -0,0 +1,161 @@ +// 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; + +namespace Microsoft.Extensions.Logging.AzureAppServices +{ + /// + /// Settings for Azure diagnostics logging. + /// + public class AzureAppServicesDiagnosticsSettings + { + private TimeSpan _blobCommitPeriod = TimeSpan.FromSeconds(5); + private int _blobBatchSize = 32; + private string _outputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"; + private int _retainedFileCountLimit = 2; + private int _fileSizeLimit = 10 * 1024 * 1024; + private string _blobName = "applicationLog.txt"; + private TimeSpan? _fileFlushPeriod = TimeSpan.FromSeconds(1); + private int _backgroundQueueSize; + + /// + /// Gets or sets a strictly positive value representing the maximum log size in bytes. + /// Once the log is full, no more messages will be appended. + /// Defaults to 10MB. + /// + public int FileSizeLimit + { + get { return _fileSizeLimit; } + set + { + if (value <= 0) + { + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(FileSizeLimit)} must be positive."); + } + _fileSizeLimit = value; + } + } + + /// + /// Gets or sets a strictly positive value representing the maximum retained file count. + /// Defaults to 2. + /// + public int RetainedFileCountLimit + { + get { return _retainedFileCountLimit; } + set + { + if (value <= 0) + { + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(RetainedFileCountLimit)} must be positive."); + } + _retainedFileCountLimit = value; + } + } + + /// + /// Gets or sets a message template describing the output messages. + /// Defaults to "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}". + /// + public string OutputTemplate + { + get { return _outputTemplate; } + set + { + if (string.IsNullOrEmpty(value)) + { + throw new ArgumentException(nameof(value), $"{nameof(OutputTemplate)} must be non-empty string."); + } + _outputTemplate = value; + } + } + + /// + /// Gets or sets a maximum number of events to include in a single blob append batch. + /// Defaults to 32. + /// + public int BlobBatchSize + { + get { return _blobBatchSize; } + set + { + if (value <= 0) + { + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(BlobBatchSize)} must be positive."); + } + _blobBatchSize = value; + } + } + + /// + /// Gets or sets a time to wait between checking for blob log batches. + /// Defaults to 5 seconds. + /// + public TimeSpan BlobCommitPeriod + { + get { return _blobCommitPeriod; } + set + { + if (value < TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(BlobCommitPeriod)} must be positive."); + } + _blobCommitPeriod = value; + } + } + + /// + /// Gets or sets the last section of log blob name. + /// Defaults to "applicationLog.txt". + /// + public string BlobName + { + get { return _blobName; } + set + { + if (string.IsNullOrEmpty(value)) + { + throw new ArgumentException(nameof(value), $"{nameof(BlobName)} must be non-empty string."); + } + _blobName = value; + } + } + + /// + /// Gets or sets the maximum size of the background log message queue or 0 for no limit. + /// After maximum queue size is reached log event sink would start blocking. + /// Defaults to 0. + /// + public int BackgroundQueueSize + { + get { return _backgroundQueueSize; } + set + { + if (value < 0) + { + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(BackgroundQueueSize)} must be non-negative."); + } + _backgroundQueueSize = value; + } + } + + /// + /// Gets or sets the period after which logs will be flushed to disk or + /// null if auto flushing is not required. + /// Defaults to 1 second. + /// + public TimeSpan? FileFlushPeriod + { + get { return _fileFlushPeriod; } + set + { + if (value < TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(FileFlushPeriod)} must be positive."); + } + _fileFlushPeriod = value; + } + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs new file mode 100644 index 0000000000..7970133d38 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs @@ -0,0 +1,189 @@ +// 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 Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Logging.AzureAppServices; +using Microsoft.Extensions.Logging.AzureAppServices.Internal; +using Microsoft.Extensions.Options; +using static Microsoft.Extensions.DependencyInjection.ServiceDescriptor; + +namespace Microsoft.Extensions.Logging +{ + /// + /// Extension methods for adding Azure diagnostics logger. + /// + public static class AzureAppServicesLoggerFactoryExtensions + { + /// + /// Adds an Azure Web Apps diagnostics logger. + /// + /// The extension method argument + public static ILoggingBuilder AddAzureWebAppDiagnostics(this ILoggingBuilder builder) + { + var context = WebAppContext.Default; + + // Only add the provider if we're in Azure WebApp. That cannot change once the apps started + return AddAzureWebAppDiagnostics(builder, context); + } + + internal static ILoggingBuilder AddAzureWebAppDiagnostics(this ILoggingBuilder builder, IWebAppContext context) + { + if (!context.IsRunningInAzureWebApp) + { + return builder; + } + + var config = SiteConfigurationProvider.GetAzureLoggingConfiguration(context); + var services = builder.Services; + + var addedFileLogger = TryAddEnumerable(services, Singleton()); + var addedBlobLogger = TryAddEnumerable(services, Singleton()); + + if (addedFileLogger || addedBlobLogger) + { + services.AddSingleton(context); + services.AddSingleton>( + new ConfigurationChangeTokenSource(config)); + } + + if (addedFileLogger) + { + services.AddSingleton>(CreateFileFilterConfigureOptions(config)); + services.AddSingleton>(new FileLoggerConfigureOptions(config, context)); + services.AddSingleton>( + new ConfigurationChangeTokenSource(config)); + } + + if (addedBlobLogger) + { + services.AddSingleton>(CreateBlobFilterConfigureOptions(config)); + services.AddSingleton>(new BlobLoggerConfigureOptions(config, context)); + services.AddSingleton>( + new ConfigurationChangeTokenSource(config)); + } + + return builder; + } + + private static bool TryAddEnumerable(IServiceCollection collection, ServiceDescriptor descriptor) + { + var beforeCount = collection.Count; + collection.TryAddEnumerable(descriptor); + return beforeCount != collection.Count; + } + + private static ConfigurationBasedLevelSwitcher CreateBlobFilterConfigureOptions(IConfiguration config) + { + return new ConfigurationBasedLevelSwitcher( + configuration: config, + provider: typeof(BlobLoggerProvider), + levelKey: "AzureBlobTraceLevel"); + } + + private static ConfigurationBasedLevelSwitcher CreateFileFilterConfigureOptions(IConfiguration config) + { + return new ConfigurationBasedLevelSwitcher( + configuration: config, + provider: typeof(FileLoggerProvider), + levelKey: "AzureDriveTraceLevel"); + } + + /// + /// Adds an Azure Web Apps diagnostics logger. + /// + /// The extension method argument + public static ILoggerFactory AddAzureWebAppDiagnostics(this ILoggerFactory factory) + { + return AddAzureWebAppDiagnostics(factory, new AzureAppServicesDiagnosticsSettings()); + } + + /// + /// Adds an Azure Web Apps diagnostics logger. + /// + /// The extension method argument + /// The setting object to configure loggers. + public static ILoggerFactory AddAzureWebAppDiagnostics(this ILoggerFactory factory, AzureAppServicesDiagnosticsSettings settings) + { + var context = WebAppContext.Default; + if (!context.IsRunningInAzureWebApp) + { + return factory; + } + + var config = SiteConfigurationProvider.GetAzureLoggingConfiguration(context); + + // Only add the provider if we're in Azure WebApp. That cannot change once the apps started + var fileOptions = new OptionsMonitor( + new OptionsFactory( + new IConfigureOptions[] + { + new FileLoggerConfigureOptions(config, context), + new ConfigureOptions(options => + { + options.FileSizeLimit = settings.FileSizeLimit; + options.RetainedFileCountLimit = settings.RetainedFileCountLimit; + options.BackgroundQueueSize = settings.BackgroundQueueSize == 0 ? (int?) null : settings.BackgroundQueueSize; + + if (settings.FileFlushPeriod != null) + { + options.FlushPeriod = settings.FileFlushPeriod.Value; + } + }) + }, + new IPostConfigureOptions[0] + ), + new[] + { + new ConfigurationChangeTokenSource(config) + }, + new OptionsCache() + ); + + var blobOptions = new OptionsMonitor( + new OptionsFactory( + new IConfigureOptions[] { + new BlobLoggerConfigureOptions(config, context), + new ConfigureOptions(options => + { + options.BlobName = settings.BlobName; + options.FlushPeriod = settings.BlobCommitPeriod; + options.BatchSize = settings.BlobBatchSize; + options.BackgroundQueueSize = settings.BackgroundQueueSize == 0 ? (int?) null : settings.BackgroundQueueSize; + }) + }, + new IPostConfigureOptions[0] + ), + new[] + { + new ConfigurationChangeTokenSource(config) + }, + new OptionsCache() + ); + + var filterOptions = new OptionsMonitor( + new OptionsFactory( + new[] + { + CreateFileFilterConfigureOptions(config), + CreateBlobFilterConfigureOptions(config) + }, + new IPostConfigureOptions[0]), + new [] { new ConfigurationChangeTokenSource(config) }, + new OptionsCache()); + + factory.AddProvider(new ForwardingLoggerProvider( + new LoggerFactory( + new ILoggerProvider[] + { + new FileLoggerProvider(fileOptions), + new BlobLoggerProvider(blobOptions) + }, + filterOptions + ) + )); + return factory; + } + } +} diff --git a/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs new file mode 100644 index 0000000000..eb466f4bb9 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs @@ -0,0 +1,44 @@ +// 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; +using Microsoft.Extensions.Logging.AzureAppServices.Internal; + +namespace Microsoft.Extensions.Logging.AzureAppServices +{ + /// + /// Options for Azure diagnostics blob logging. + /// + public class AzureBlobLoggerOptions: BatchingLoggerOptions + { + public AzureBlobLoggerOptions() + { + BatchSize = 32; + } + + private string _blobName = "applicationLog.txt"; + + /// + /// Gets or sets the last section of log blob name. + /// Defaults to "applicationLog.txt". + /// + public string BlobName + { + get { return _blobName; } + set + { + if (string.IsNullOrEmpty(value)) + { + throw new ArgumentException(nameof(value), $"{nameof(BlobName)} must be non-empty string."); + } + _blobName = value; + } + } + + internal string ContainerUrl { get; set; } + + internal string ApplicationName { get; set; } + + internal string ApplicationInstanceId { get; set; } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs new file mode 100644 index 0000000000..47795d9954 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs @@ -0,0 +1,72 @@ +// 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; +using Microsoft.Extensions.Logging.AzureAppServices.Internal; + +namespace Microsoft.Extensions.Logging.AzureAppServices +{ + /// + /// Options for Azure diagnostics file logging. + /// + public class AzureFileLoggerOptions: BatchingLoggerOptions + { + private int? _fileSizeLimit = 10 * 1024 * 1024; + private int? _retainedFileCountLimit = 2; + private string _fileName = "diagnostics-"; + + /// + /// Gets or sets a strictly positive value representing the maximum log size in bytes or null for no limit. + /// Once the log is full, no more messages will be appended. + /// Defaults to 10MB. + /// + public int? FileSizeLimit + { + get { return _fileSizeLimit; } + set + { + if (value <= 0) + { + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(FileSizeLimit)} must be positive."); + } + _fileSizeLimit = value; + } + } + + /// + /// Gets or sets a strictly positive value representing the maximum retained file count or null for no limit. + /// Defaults to 2. + /// + public int? RetainedFileCountLimit + { + get { return _retainedFileCountLimit; } + set + { + if (value <= 0) + { + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(RetainedFileCountLimit)} must be positive."); + } + _retainedFileCountLimit = value; + } + } + + /// + /// Gets or sets a strictly positive value representing the maximum retained file count or null for no limit. + /// Defaults to 2. + /// + public string FileName + { + get { return _fileName; } + set + { + if (string.IsNullOrEmpty(value)) + { + throw new ArgumentException(nameof(value)); + } + _fileName = value; + } + } + + internal string LogDirectory { get; set; } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchLoggerConfigureOptions.cs b/src/Logging/Logging.AzureAppServices/src/Internal/BatchLoggerConfigureOptions.cs new file mode 100644 index 0000000000..3982193dd8 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/BatchLoggerConfigureOptions.cs @@ -0,0 +1,36 @@ +// 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 Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + public class BatchLoggerConfigureOptions : IConfigureOptions + { + private readonly IConfiguration _configuration; + private readonly string _isEnabledKey; + + public BatchLoggerConfigureOptions(IConfiguration configuration, string isEnabledKey) + { + _configuration = configuration; + _isEnabledKey = isEnabledKey; + } + + public void Configure(BatchingLoggerOptions options) + { + options.IsEnabled = TextToBoolean(_configuration.GetSection(_isEnabledKey)?.Value); + } + + private static bool TextToBoolean(string text) + { + if (string.IsNullOrEmpty(text) || + !bool.TryParse(text, out var result)) + { + result = false; + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLogger.cs b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLogger.cs new file mode 100644 index 0000000000..2cfb26582f --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLogger.cs @@ -0,0 +1,59 @@ +// 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; +using System.Text; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + public class BatchingLogger : ILogger + { + private readonly BatchingLoggerProvider _provider; + private readonly string _category; + + public BatchingLogger(BatchingLoggerProvider loggerProvider, string categoryName) + { + _provider = loggerProvider; + _category = categoryName; + } + + public IDisposable BeginScope(TState state) + { + return null; + } + + public bool IsEnabled(LogLevel logLevel) + { + return _provider.IsEnabled; + } + + public void Log(DateTimeOffset timestamp, LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + if (!IsEnabled(logLevel)) + { + return; + } + + var builder = new StringBuilder(); + builder.Append(timestamp.ToString("yyyy-MM-dd HH:mm:ss.fff zzz")); + builder.Append(" ["); + builder.Append(logLevel.ToString()); + builder.Append("] "); + builder.Append(_category); + builder.Append(": "); + builder.AppendLine(formatter(state, exception)); + + if (exception != null) + { + builder.AppendLine(exception.ToString()); + } + + _provider.AddMessage(timestamp, builder.ToString()); + } + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + Log(DateTimeOffset.Now, logLevel, eventId, state, exception, formatter); + } + } +} diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs new file mode 100644 index 0000000000..ccdf75e561 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs @@ -0,0 +1,69 @@ +// 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; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + public class BatchingLoggerOptions + { + private int? _batchSize = 32; + private int? _backgroundQueueSize; + private TimeSpan _flushPeriod = TimeSpan.FromSeconds(1); + + /// + /// Gets or sets the period after which logs will be flushed to the store. + /// + public TimeSpan FlushPeriod + { + get { return _flushPeriod; } + set + { + if (value <= TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(FlushPeriod)} must be positive."); + } + _flushPeriod = value; + } + } + + /// + /// Gets or sets the maximum size of the background log message queue or null for no limit. + /// After maximum queue size is reached log event sink would start blocking. + /// Defaults to null. + /// + public int? BackgroundQueueSize + { + get { return _backgroundQueueSize; } + set + { + if (value < 0) + { + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(BackgroundQueueSize)} must be non-negative."); + } + _backgroundQueueSize = value; + } + } + + /// + /// Gets or sets a maximum number of events to include in a single batch or null for no limit. + /// + public int? BatchSize + { + get { return _batchSize; } + set + { + if (value <= 0) + { + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(BatchSize)} must be positive."); + } + _batchSize = value; + } + } + + /// + /// Gets or sets value indicating if logger accepts and queues writes. + /// + public bool IsEnabled { get; set; } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs new file mode 100644 index 0000000000..79720c5531 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs @@ -0,0 +1,163 @@ +// 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; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + public abstract class BatchingLoggerProvider: ILoggerProvider + { + private readonly List _currentBatch = new List(); + private readonly TimeSpan _interval; + private readonly int? _queueSize; + private readonly int? _batchSize; + private readonly IDisposable _optionsChangeToken; + + private BlockingCollection _messageQueue; + private Task _outputTask; + private CancellationTokenSource _cancellationTokenSource; + + protected BatchingLoggerProvider(IOptionsMonitor options) + { + // NOTE: Only IsEnabled is monitored + + var loggerOptions = options.CurrentValue; + if (loggerOptions.BatchSize <= 0) + { + throw new ArgumentOutOfRangeException(nameof(loggerOptions.BatchSize), $"{nameof(loggerOptions.BatchSize)} must be a positive number."); + } + if (loggerOptions.FlushPeriod <= TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException(nameof(loggerOptions.FlushPeriod), $"{nameof(loggerOptions.FlushPeriod)} must be longer than zero."); + } + + _interval = loggerOptions.FlushPeriod; + _batchSize = loggerOptions.BatchSize; + _queueSize = loggerOptions.BackgroundQueueSize; + + _optionsChangeToken = options.OnChange(UpdateOptions); + UpdateOptions(options.CurrentValue); + } + + public bool IsEnabled { get; private set; } + + private void UpdateOptions(BatchingLoggerOptions options) + { + var oldIsEnabled = IsEnabled; + IsEnabled = options.IsEnabled; + if (oldIsEnabled != IsEnabled) + { + if (IsEnabled) + { + Start(); + } + else + { + Stop(); + } + } + + } + + protected abstract Task WriteMessagesAsync(IEnumerable messages, CancellationToken token); + + private async Task ProcessLogQueue(object state) + { + while (!_cancellationTokenSource.IsCancellationRequested) + { + var limit = _batchSize ?? int.MaxValue; + + while (limit > 0 && _messageQueue.TryTake(out var message)) + { + _currentBatch.Add(message); + limit--; + } + + if (_currentBatch.Count > 0) + { + try + { + await WriteMessagesAsync(_currentBatch, _cancellationTokenSource.Token); + } + catch + { + // ignored + } + + _currentBatch.Clear(); + } + + await IntervalAsync(_interval, _cancellationTokenSource.Token); + } + } + + protected virtual Task IntervalAsync(TimeSpan interval, CancellationToken cancellationToken) + { + return Task.Delay(interval, cancellationToken); + } + + internal void AddMessage(DateTimeOffset timestamp, string message) + { + if (!_messageQueue.IsAddingCompleted) + { + try + { + _messageQueue.Add(new LogMessage { Message = message, Timestamp = timestamp }, _cancellationTokenSource.Token); + } + catch + { + //cancellation token canceled or CompleteAdding called + } + } + } + + private void Start() + { + _messageQueue = _queueSize == null ? + new BlockingCollection(new ConcurrentQueue()) : + new BlockingCollection(new ConcurrentQueue(), _queueSize.Value); + + _cancellationTokenSource = new CancellationTokenSource(); + _outputTask = Task.Factory.StartNew( + ProcessLogQueue, + null, + TaskCreationOptions.LongRunning); + } + + private void Stop() + { + _cancellationTokenSource.Cancel(); + _messageQueue.CompleteAdding(); + + try + { + _outputTask.Wait(_interval); + } + catch (TaskCanceledException) + { + } + catch (AggregateException ex) when (ex.InnerExceptions.Count == 1 && ex.InnerExceptions[0] is TaskCanceledException) + { + } + } + + public void Dispose() + { + _optionsChangeToken?.Dispose(); + if (IsEnabled) + { + Stop(); + } + } + + public ILogger CreateLogger(string categoryName) + { + return new BatchingLogger(this, categoryName); + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BlobAppendReferenceWrapper.cs b/src/Logging/Logging.AzureAppServices/src/Internal/BlobAppendReferenceWrapper.cs new file mode 100644 index 0000000000..e0702275cb --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/BlobAppendReferenceWrapper.cs @@ -0,0 +1,96 @@ +// 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; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + /// + public class BlobAppendReferenceWrapper : ICloudAppendBlob + { + private readonly Uri _fullUri; + private readonly HttpClient _client; + private readonly Uri _appendUri; + + public BlobAppendReferenceWrapper(string containerUrl, string name, HttpClient client) + { + var uriBuilder = new UriBuilder(containerUrl); + uriBuilder.Path += "/" + name; + _fullUri = uriBuilder.Uri; + + AppendBlockQuery(uriBuilder); + _appendUri = uriBuilder.Uri; + _client = client; + } + + /// + public async Task AppendAsync(ArraySegment data, CancellationToken cancellationToken) + { + Task AppendDataAsync() + { + var message = new HttpRequestMessage(HttpMethod.Put, _appendUri) + { + Content = new ByteArrayContent(data.Array, data.Offset, data.Count) + }; + AddCommonHeaders(message); + + return _client.SendAsync(message, cancellationToken); + } + + var response = await AppendDataAsync(); + + if (response.StatusCode == HttpStatusCode.NotFound) + { + // If no blob exists try creating it + var message = new HttpRequestMessage(HttpMethod.Put, _fullUri) + { + // Set Content-Length to 0 to create "Append Blob" + Content = new ByteArrayContent(Array.Empty()), + Headers = + { + { "If-None-Match", "*" } + } + }; + + AddCommonHeaders(message); + + response = await _client.SendAsync(message, cancellationToken); + + // If result is 2** or 412 try to append again + if (response.IsSuccessStatusCode || + response.StatusCode == HttpStatusCode.PreconditionFailed) + { + // Retry sending data after blob creation + response = await AppendDataAsync(); + } + } + + response.EnsureSuccessStatusCode(); + } + + private static void AddCommonHeaders(HttpRequestMessage message) + { + message.Headers.Add("x-ms-blob-type", "AppendBlob"); + message.Headers.Add("x-ms-version", "2016-05-31"); + message.Headers.Date = DateTimeOffset.UtcNow; + } + + private static void AppendBlockQuery(UriBuilder uriBuilder) + { + // See https://msdn.microsoft.com/en-us/library/system.uribuilder.query.aspx for: + // Note: Do not append a string directly to Query property. + // If the length of Query is greater than 1, retrieve the property value + // as a string, remove the leading question mark, append the new query string, + // and set the property with the combined string. + var queryToAppend = "comp=appendblock"; + if (uriBuilder.Query != null && uriBuilder.Query.Length > 1) + uriBuilder.Query = uriBuilder.Query.Substring(1) + "&" + queryToAppend; + else + uriBuilder.Query = queryToAppend; + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerConfigureOptions.cs b/src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerConfigureOptions.cs new file mode 100644 index 0000000000..25ea1b6af6 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerConfigureOptions.cs @@ -0,0 +1,29 @@ +// 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 Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + public class BlobLoggerConfigureOptions : BatchLoggerConfigureOptions, IConfigureOptions + { + private readonly IConfiguration _configuration; + private readonly IWebAppContext _context; + + public BlobLoggerConfigureOptions(IConfiguration configuration, IWebAppContext context) + : base(configuration, "AzureBlobEnabled") + { + _configuration = configuration; + _context = context; + } + + public void Configure(AzureBlobLoggerOptions options) + { + base.Configure(options); + options.ContainerUrl = _configuration.GetSection("APPSETTING_DIAGNOSTICS_AZUREBLOBCONTAINERSASURL")?.Value; + options.ApplicationName = _context.SiteName; + options.ApplicationInstanceId = _context.SiteInstanceId; + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerProvider.cs new file mode 100644 index 0000000000..96c98fa455 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerProvider.cs @@ -0,0 +1,91 @@ +// 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; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + /// + /// The implementation that stores messages by appending them to Azure Blob in batches. + /// + [ProviderAlias("AzureAppServicesBlob")] + public class BlobLoggerProvider : BatchingLoggerProvider + { + private readonly string _appName; + private readonly string _fileName; + private readonly Func _blobReferenceFactory; + private readonly HttpClient _httpClient; + + /// + /// Creates a new instance of + /// + /// + public BlobLoggerProvider(IOptionsMonitor options) + : this(options, null) + { + _blobReferenceFactory = name => new BlobAppendReferenceWrapper( + options.CurrentValue.ContainerUrl, + name, + _httpClient); + } + + /// + /// Creates a new instance of + /// + /// The container to store logs to. + /// + public BlobLoggerProvider( + IOptionsMonitor options, + Func blobReferenceFactory) : + base(options) + { + var value = options.CurrentValue; + _appName = value.ApplicationName; + _fileName = value.ApplicationInstanceId + "_" + value.BlobName; + _blobReferenceFactory = blobReferenceFactory; + _httpClient = new HttpClient(); + } + + protected override async Task WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) + { + var eventGroups = messages.GroupBy(GetBlobKey); + foreach (var eventGroup in eventGroups) + { + var key = eventGroup.Key; + var blobName = $"{_appName}/{key.Year}/{key.Month:00}/{key.Day:00}/{key.Hour:00}/{_fileName}"; + + var blob = _blobReferenceFactory(blobName); + + using (var stream = new MemoryStream()) + using (var writer = new StreamWriter(stream)) + { + foreach (var logEvent in eventGroup) + { + writer.Write(logEvent.Message); + } + + await writer.FlushAsync(); + var tryGetBuffer = stream.TryGetBuffer(out var buffer); + Debug.Assert(tryGetBuffer); + await blob.AppendAsync(buffer, cancellationToken); + } + } + } + + private (int Year, int Month, int Day, int Hour) GetBlobKey(LogMessage e) + { + return (e.Timestamp.Year, + e.Timestamp.Month, + e.Timestamp.Day, + e.Timestamp.Hour); + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/ConfigurationBasedLevelSwitcher.cs b/src/Logging/Logging.AzureAppServices/src/Internal/ConfigurationBasedLevelSwitcher.cs new file mode 100644 index 0000000000..388a4ed54e --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/ConfigurationBasedLevelSwitcher.cs @@ -0,0 +1,50 @@ +// 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; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + public class ConfigurationBasedLevelSwitcher: IConfigureOptions + { + private readonly IConfiguration _configuration; + private readonly Type _provider; + private readonly string _levelKey; + + public ConfigurationBasedLevelSwitcher(IConfiguration configuration, Type provider, string levelKey) + { + _configuration = configuration; + _provider = provider; + _levelKey = levelKey; + } + + public void Configure(LoggerFilterOptions options) + { + options.Rules.Add(new LoggerFilterRule(_provider.FullName, null, GetLogLevel(), null)); + } + + private LogLevel GetLogLevel() + { + return TextToLogLevel(_configuration.GetSection(_levelKey)?.Value); + } + + private static LogLevel TextToLogLevel(string text) + { + switch (text?.ToUpperInvariant()) + { + case "ERROR": + return LogLevel.Error; + case "WARNING": + return LogLevel.Warning; + case "INFORMATION": + return LogLevel.Information; + case "VERBOSE": + return LogLevel.Trace; + default: + return LogLevel.None; + } + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerConfigureOptions.cs b/src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerConfigureOptions.cs new file mode 100644 index 0000000000..00037bca87 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerConfigureOptions.cs @@ -0,0 +1,26 @@ +// 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.IO; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + public class FileLoggerConfigureOptions : BatchLoggerConfigureOptions, IConfigureOptions + { + private readonly IWebAppContext _context; + + public FileLoggerConfigureOptions(IConfiguration configuration, IWebAppContext context) + : base(configuration, "AzureDriveEnabled") + { + _context = context; + } + + public void Configure(AzureFileLoggerOptions options) + { + base.Configure(options); + options.LogDirectory = Path.Combine(_context.HomeFolder, "LogFiles", "Application"); + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerProvider.cs new file mode 100644 index 0000000000..154f609225 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerProvider.cs @@ -0,0 +1,81 @@ +// 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.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + [ProviderAlias("AzureAppServicesFile")] + public class FileLoggerProvider : BatchingLoggerProvider + { + private readonly string _path; + private readonly string _fileName; + private readonly int? _maxFileSize; + private readonly int? _maxRetainedFiles; + + public FileLoggerProvider(IOptionsMonitor options) : base(options) + { + var loggerOptions = options.CurrentValue; + _path = loggerOptions.LogDirectory; + _fileName = loggerOptions.FileName; + _maxFileSize = loggerOptions.FileSizeLimit; + _maxRetainedFiles = loggerOptions.RetainedFileCountLimit; + } + + protected override async Task WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) + { + Directory.CreateDirectory(_path); + + foreach (var group in messages.GroupBy(GetGrouping)) + { + var fullName = GetFullName(group.Key); + var fileInfo = new FileInfo(fullName); + if (_maxFileSize > 0 && fileInfo.Exists && fileInfo.Length > _maxFileSize) + { + return; + } + + using (var streamWriter = File.AppendText(fullName)) + { + foreach (var item in group) + { + await streamWriter.WriteAsync(item.Message); + } + } + } + + RollFiles(); + } + + private string GetFullName((int Year, int Month, int Day) group) + { + return Path.Combine(_path, $"{_fileName}{group.Year:0000}{group.Month:00}{group.Day:00}.txt"); + } + + public (int Year, int Month, int Day) GetGrouping(LogMessage message) + { + return (message.Timestamp.Year, message.Timestamp.Month, message.Timestamp.Day); + } + + protected void RollFiles() + { + if (_maxRetainedFiles > 0) + { + var files = new DirectoryInfo(_path) + .GetFiles(_fileName + "*") + .OrderByDescending(f => f.Name) + .Skip(_maxRetainedFiles.Value); + + foreach (var item in files) + { + item.Delete(); + } + } + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/ForwardingLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/Internal/ForwardingLoggerProvider.cs new file mode 100644 index 0000000000..0474f0ba9e --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/ForwardingLoggerProvider.cs @@ -0,0 +1,25 @@ +// 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. + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + internal class ForwardingLoggerProvider : ILoggerProvider + { + private readonly ILoggerFactory _loggerFactory; + + public ForwardingLoggerProvider(ILoggerFactory loggerFactory) + { + _loggerFactory = loggerFactory; + } + + public void Dispose() + { + _loggerFactory.Dispose(); + } + + public ILogger CreateLogger(string categoryName) + { + return _loggerFactory.CreateLogger(categoryName); + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/ICloudAppendBlob.cs b/src/Logging/Logging.AzureAppServices/src/Internal/ICloudAppendBlob.cs new file mode 100644 index 0000000000..ccca525090 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/ICloudAppendBlob.cs @@ -0,0 +1,22 @@ +// 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; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + /// + /// Represents an append blob, a type of blob where blocks of data are always committed to the end of the blob. + /// + public interface ICloudAppendBlob + { + /// + /// Initiates an asynchronous operation to open a stream for writing to the blob. + /// + /// A object of type that represents the asynchronous operation. + Task AppendAsync(ArraySegment data, CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/IWebAppContext.cs b/src/Logging/Logging.AzureAppServices/src/Internal/IWebAppContext.cs new file mode 100644 index 0000000000..21e2982192 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/IWebAppContext.cs @@ -0,0 +1,31 @@ +// 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. + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + /// + /// Represents an Azure WebApp context + /// + public interface IWebAppContext + { + /// + /// Gets the path to the home folder if running in Azure WebApp + /// + string HomeFolder { get; } + + /// + /// Gets the name of site if running in Azure WebApp + /// + string SiteName { get; } + + /// + /// Gets the id of site if running in Azure WebApp + /// + string SiteInstanceId { get; } + + /// + /// Gets a value indicating whether or new we're in an Azure WebApp + /// + bool IsRunningInAzureWebApp { get; } + } +} diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/LogMessage.cs b/src/Logging/Logging.AzureAppServices/src/Internal/LogMessage.cs new file mode 100644 index 0000000000..b330f4dda7 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/LogMessage.cs @@ -0,0 +1,13 @@ +// 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; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + public struct LogMessage + { + public DateTimeOffset Timestamp { get; set; } + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/SiteConfigurationProvider.cs b/src/Logging/Logging.AzureAppServices/src/Internal/SiteConfigurationProvider.cs new file mode 100644 index 0000000000..b7aa39de2c --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/SiteConfigurationProvider.cs @@ -0,0 +1,22 @@ +// 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.IO; +using Microsoft.Extensions.Configuration; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + public class SiteConfigurationProvider + { + public static IConfiguration GetAzureLoggingConfiguration(IWebAppContext context) + { + var settingsFolder = Path.Combine(context.HomeFolder, "site", "diagnostics"); + var settingsFile = Path.Combine(settingsFolder, "settings.json"); + + return new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddJsonFile(settingsFile, optional: true, reloadOnChange: true) + .Build(); + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/WebAppContext.cs b/src/Logging/Logging.AzureAppServices/src/Internal/WebAppContext.cs new file mode 100644 index 0000000000..774020afdb --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Internal/WebAppContext.cs @@ -0,0 +1,33 @@ +// 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; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +{ + /// + /// Represents the default implementation of . + /// + public class WebAppContext : IWebAppContext + { + /// + /// Gets the default instance of the WebApp context. + /// + public static WebAppContext Default { get; } = new WebAppContext(); + + private WebAppContext() { } + + /// + public string HomeFolder { get; } = Environment.GetEnvironmentVariable("HOME"); + + /// + public string SiteName { get; } = Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME"); + + /// + public string SiteInstanceId { get; } = Environment.GetEnvironmentVariable("WEBSITE_INSTANCE_ID"); + + /// + public bool IsRunningInAzureWebApp => !string.IsNullOrEmpty(HomeFolder) && + !string.IsNullOrEmpty(SiteName); + } +} diff --git a/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj b/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj new file mode 100644 index 0000000000..d6eb186122 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj @@ -0,0 +1,18 @@ + + + + Logger implementation to support Azure App Services 'Diagnostics logs' and 'Log stream' features. + netstandard2.0 + $(NoWarn);CS1591 + + + + + + + + + + + + diff --git a/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs b/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..85c4d7c575 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs @@ -0,0 +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.Runtime.CompilerServices; + + +[assembly: InternalsVisibleTo("Microsoft.Extensions.Logging.AzureAppServices.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Logging/Logging.AzureAppServices/src/baseline.netcore.json b/src/Logging/Logging.AzureAppServices/src/baseline.netcore.json new file mode 100644 index 0000000000..f9b148ceae --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/baseline.netcore.json @@ -0,0 +1,368 @@ +{ + "AssemblyIdentity": "Microsoft.Extensions.Logging.AzureAppServices, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.Extensions.Logging.AzureAppServicesLoggerFactoryExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AddAzureWebAppDiagnostics", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.Extensions.Logging.ILoggingBuilder" + } + ], + "ReturnType": "Microsoft.Extensions.Logging.ILoggingBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddAzureWebAppDiagnostics", + "Parameters": [ + { + "Name": "factory", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + } + ], + "ReturnType": "Microsoft.Extensions.Logging.ILoggerFactory", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddAzureWebAppDiagnostics", + "Parameters": [ + { + "Name": "factory", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "settings", + "Type": "Microsoft.Extensions.Logging.AzureAppServices.AzureAppServicesDiagnosticsSettings" + } + ], + "ReturnType": "Microsoft.Extensions.Logging.ILoggerFactory", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.AzureAppServices.AzureAppServicesDiagnosticsSettings", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_FileSizeLimit", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_FileSizeLimit", + "Parameters": [ + { + "Name": "value", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_RetainedFileCountLimit", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_RetainedFileCountLimit", + "Parameters": [ + { + "Name": "value", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_OutputTemplate", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_OutputTemplate", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_BlobBatchSize", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_BlobBatchSize", + "Parameters": [ + { + "Name": "value", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_BlobCommitPeriod", + "Parameters": [], + "ReturnType": "System.TimeSpan", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_BlobCommitPeriod", + "Parameters": [ + { + "Name": "value", + "Type": "System.TimeSpan" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_BlobName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_BlobName", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_BackgroundQueueSize", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_BackgroundQueueSize", + "Parameters": [ + { + "Name": "value", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_FileFlushPeriod", + "Parameters": [], + "ReturnType": "System.Nullable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_FileFlushPeriod", + "Parameters": [ + { + "Name": "value", + "Type": "System.Nullable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.AzureAppServices.AzureBlobLoggerOptions", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.Extensions.Logging.AzureAppServices.Internal.BatchingLoggerOptions", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_BlobName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_BlobName", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.AzureAppServices.AzureFileLoggerOptions", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.Extensions.Logging.AzureAppServices.Internal.BatchingLoggerOptions", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_FileSizeLimit", + "Parameters": [], + "ReturnType": "System.Nullable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_FileSizeLimit", + "Parameters": [ + { + "Name": "value", + "Type": "System.Nullable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_RetainedFileCountLimit", + "Parameters": [], + "ReturnType": "System.Nullable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_RetainedFileCountLimit", + "Parameters": [ + { + "Name": "value", + "Type": "System.Nullable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_FileName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_FileName", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs b/src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs new file mode 100644 index 0000000000..e9fe0b65b1 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs @@ -0,0 +1,186 @@ +// 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; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging.AzureAppServices.Internal; +using Xunit; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Test +{ + public class AzureAppendBlobTests + { + public string _containerUrl = "https://host/container?query=1"; + public string _blobName = "blob/path"; + + [Fact] + public async Task SendsDataAsStream() + { + var testMessageHandler = new TestMessageHandler(async message => + { + Assert.Equal(HttpMethod.Put, message.Method); + Assert.Equal("https://host/container/blob/path?query=1&comp=appendblock", message.RequestUri.ToString()); + Assert.Equal(new byte[] { 0, 2, 3 }, await message.Content.ReadAsByteArrayAsync()); + AssertDefaultHeaders(message); + + return new HttpResponseMessage(HttpStatusCode.OK); + }); + + var blob = new BlobAppendReferenceWrapper(_containerUrl, _blobName, new HttpClient(testMessageHandler)); + await blob.AppendAsync(new ArraySegment(new byte[] { 0, 2, 3 }), CancellationToken.None); + } + + private static void AssertDefaultHeaders(HttpRequestMessage message) + { + Assert.Equal(new[] {"AppendBlob"}, message.Headers.GetValues("x-ms-blob-type")); + Assert.Equal(new[] {"2016-05-31"}, message.Headers.GetValues("x-ms-version")); + Assert.NotNull(message.Headers.Date); + } + + [Theory] + [InlineData(HttpStatusCode.Created)] + [InlineData(HttpStatusCode.PreconditionFailed)] + public async Task CreatesBlobIfNotExist(HttpStatusCode createStatusCode) + { + var stage = 0; + var testMessageHandler = new TestMessageHandler(async message => + { + // First PUT request + if (stage == 0) + { + Assert.Equal(HttpMethod.Put, message.Method); + Assert.Equal("https://host/container/blob/path?query=1&comp=appendblock", message.RequestUri.ToString()); + Assert.Equal(new byte[] { 0, 2, 3 }, await message.Content.ReadAsByteArrayAsync()); + Assert.Equal(3, message.Content.Headers.ContentLength); + + AssertDefaultHeaders(message); + + stage++; + return new HttpResponseMessage(HttpStatusCode.NotFound); + } + // Create request + if (stage == 1) + { + Assert.Equal(HttpMethod.Put, message.Method); + Assert.Equal("https://host/container/blob/path?query=1", message.RequestUri.ToString()); + Assert.Equal(0, message.Content.Headers.ContentLength); + Assert.Equal(new[] { "*" }, message.Headers.GetValues("If-None-Match")); + + AssertDefaultHeaders(message); + + stage++; + return new HttpResponseMessage(createStatusCode); + } + // First PUT request + if (stage == 2) + { + Assert.Equal(HttpMethod.Put, message.Method); + Assert.Equal("https://host/container/blob/path?query=1&comp=appendblock", message.RequestUri.ToString()); + Assert.Equal(new byte[] { 0, 2, 3 }, await message.Content.ReadAsByteArrayAsync()); + Assert.Equal(3, message.Content.Headers.ContentLength); + + AssertDefaultHeaders(message); + + stage++; + return new HttpResponseMessage(HttpStatusCode.Created); + } + throw new NotImplementedException(); + }); + + var blob = new BlobAppendReferenceWrapper(_containerUrl, _blobName, new HttpClient(testMessageHandler)); + await blob.AppendAsync(new ArraySegment(new byte[] { 0, 2, 3 }), CancellationToken.None); + + Assert.Equal(3, stage); + } + + [Fact] + public async Task ThrowsForUnknownStatus() + { + var stage = 0; + var testMessageHandler = new TestMessageHandler(async message => + { + // First PUT request + if (stage == 0) + { + Assert.Equal(HttpMethod.Put, message.Method); + Assert.Equal("https://host/container/blob/path?query=1&comp=appendblock", message.RequestUri.ToString()); + Assert.Equal(new byte[] { 0, 2, 3 }, await message.Content.ReadAsByteArrayAsync()); + Assert.Equal(3, message.Content.Headers.ContentLength); + + AssertDefaultHeaders(message); + + stage++; + return new HttpResponseMessage(HttpStatusCode.InternalServerError); + } + + throw new NotImplementedException(); + }); + + var blob = new BlobAppendReferenceWrapper(_containerUrl, _blobName, new HttpClient(testMessageHandler)); + await Assert.ThrowsAsync(() => blob.AppendAsync(new ArraySegment(new byte[] { 0, 2, 3 }), CancellationToken.None)); + + Assert.Equal(1, stage); + } + + [Fact] + public async Task ThrowsForUnknownStatusDuringCreation() + { + var stage = 0; + var testMessageHandler = new TestMessageHandler(async message => + { + // First PUT request + if (stage == 0) + { + Assert.Equal(HttpMethod.Put, message.Method); + Assert.Equal("https://host/container/blob/path?query=1&comp=appendblock", message.RequestUri.ToString()); + Assert.Equal(new byte[] { 0, 2, 3 }, await message.Content.ReadAsByteArrayAsync()); + Assert.Equal(3, message.Content.Headers.ContentLength); + + AssertDefaultHeaders(message); + + stage++; + return new HttpResponseMessage(HttpStatusCode.NotFound); + } + // Create request + if (stage == 1) + { + Assert.Equal(HttpMethod.Put, message.Method); + Assert.Equal("https://host/container/blob/path?query=1", message.RequestUri.ToString()); + Assert.Equal(0, message.Content.Headers.ContentLength); + Assert.Equal(new[] { "*" }, message.Headers.GetValues("If-None-Match")); + + AssertDefaultHeaders(message); + + stage++; + return new HttpResponseMessage(HttpStatusCode.InternalServerError); + } + + throw new NotImplementedException(); + }); + + var blob = new BlobAppendReferenceWrapper(_containerUrl, _blobName, new HttpClient(testMessageHandler)); + await Assert.ThrowsAsync(() => blob.AppendAsync(new ArraySegment(new byte[] { 0, 2, 3 }), CancellationToken.None)); + + Assert.Equal(2, stage); + } + + + private class TestMessageHandler : HttpMessageHandler + { + private readonly Func> _callback; + + public TestMessageHandler(Func> callback) + { + _callback = callback; + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + return await _callback(request); + } + } + } +} diff --git a/src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs b/src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs new file mode 100644 index 0000000000..a1ee0e97d3 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs @@ -0,0 +1,98 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Moq; +using Xunit; +using Microsoft.Extensions.Logging.AzureAppServices.Internal; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Test +{ + public class AzureBlobSinkTests + { + DateTimeOffset _timestampOne = new DateTimeOffset(2016, 05, 04, 03, 02, 01, TimeSpan.Zero); + + [Fact] + public async Task WritesMessagesInBatches() + { + var blob = new Mock(); + var buffers = new List(); + blob.Setup(b => b.AppendAsync(It.IsAny>(), It.IsAny())) + .Callback((ArraySegment s, CancellationToken ct) => buffers.Add(ToArray(s))) + .Returns(Task.CompletedTask); + + var sink = new TestBlobSink(name => blob.Object); + var logger = (BatchingLogger)sink.CreateLogger("Cat"); + + await sink.IntervalControl.Pause; + + for (int i = 0; i < 5; i++) + { + logger.Log(_timestampOne, LogLevel.Information, 0, "Text " + i, null, (state, ex) => state); + } + + sink.IntervalControl.Resume(); + await sink.IntervalControl.Pause; + + Assert.Single(buffers); + Assert.Equal( + "2016-05-04 03:02:01.000 +00:00 [Information] Cat: Text 0" + Environment.NewLine + + "2016-05-04 03:02:01.000 +00:00 [Information] Cat: Text 1" + Environment.NewLine + + "2016-05-04 03:02:01.000 +00:00 [Information] Cat: Text 2" + Environment.NewLine + + "2016-05-04 03:02:01.000 +00:00 [Information] Cat: Text 3" + Environment.NewLine + + "2016-05-04 03:02:01.000 +00:00 [Information] Cat: Text 4" + Environment.NewLine, + Encoding.UTF8.GetString(buffers[0])); + } + + [Fact] + public async Task GroupsByHour() + { + var blob = new Mock(); + var buffers = new List(); + var names = new List(); + + blob.Setup(b => b.AppendAsync(It.IsAny>(), It.IsAny())) + .Callback((ArraySegment s, CancellationToken ct) => buffers.Add(ToArray(s))) + .Returns(Task.CompletedTask); + + var sink = new TestBlobSink(name => + { + names.Add(name); + return blob.Object; + }); + var logger = (BatchingLogger)sink.CreateLogger("Cat"); + + await sink.IntervalControl.Pause; + + var startDate = _timestampOne; + for (int i = 0; i < 3; i++) + { + logger.Log(startDate, LogLevel.Information, 0, "Text " + i, null, (state, ex) => state); + + startDate = startDate.AddHours(1); + } + + sink.IntervalControl.Resume(); + await sink.IntervalControl.Pause; + + Assert.Equal(3, buffers.Count); + + Assert.Equal("appname/2016/05/04/03/42_filename", names[0]); + Assert.Equal("appname/2016/05/04/04/42_filename", names[1]); + Assert.Equal("appname/2016/05/04/05/42_filename", names[2]); + } + + private byte[] ToArray(ArraySegment inputStream) + { + return inputStream.Array + .Skip(inputStream.Offset) + .Take(inputStream.Count) + .ToArray(); + } + } +} diff --git a/src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs b/src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs new file mode 100644 index 0000000000..51ba07f12b --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs @@ -0,0 +1,70 @@ +// 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; +using System.IO; +using Microsoft.Extensions.Logging.AzureAppServices.Internal; +using Moq; +using Xunit; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Test +{ + public class AzureDiagnosticsConfigurationProviderTests + { + [Fact] + public void NoConfigFile() + { + var tempFolder = Path.Combine(Path.GetTempPath(), "AzureWebAppLoggerThisFolderShouldNotExist"); + + var contextMock = new Mock(); + contextMock.SetupGet(c => c.HomeFolder) + .Returns(tempFolder); + + var config = SiteConfigurationProvider.GetAzureLoggingConfiguration(contextMock.Object); + + Assert.NotNull(config); + } + + [Fact] + public void ReadsSettingsFileAndEnvironment() + { + var tempFolder = Path.Combine(Path.GetTempPath(), "WebAppLoggerConfigurationDisabledInSettingsFile"); + + try + { + var settingsFolder = Path.Combine(tempFolder, "site", "diagnostics"); + var settingsFile = Path.Combine(settingsFolder, "settings.json"); + + if (!Directory.Exists(settingsFolder)) + { + Directory.CreateDirectory(settingsFolder); + } + Environment.SetEnvironmentVariable("RANDOM_ENVIRONMENT_VARIABLE", "USEFUL_VALUE"); + File.WriteAllText(settingsFile, @"{ ""key"":""test value"" }"); + + var contextMock = new Mock(); + contextMock.SetupGet(c => c.HomeFolder) + .Returns(tempFolder); + + var config = SiteConfigurationProvider.GetAzureLoggingConfiguration(contextMock.Object); + + Assert.Equal("test value", config["key"]); + Assert.Equal("USEFUL_VALUE", config["RANDOM_ENVIRONMENT_VARIABLE"]); + } + finally + { + if (Directory.Exists(tempFolder)) + { + try + { + Directory.Delete(tempFolder, recursive: true); + } + catch + { + // Don't break the test if temp folder deletion fails. + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs b/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs new file mode 100644 index 0000000000..42cefe99df --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs @@ -0,0 +1,111 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging.AzureAppServices.Internal; +using Xunit; + +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; + + [Fact] + public async Task LogsInIntervals() + { + var provider = new TestBatchingLoggingProvider(); + var logger = (BatchingLogger)provider.CreateLogger("Cat"); + + await provider.IntervalControl.Pause; + + logger.Log(_timestampOne, LogLevel.Information, 0, "Info message", null, (state, ex) => state); + logger.Log(_timestampOne.AddHours(1), LogLevel.Error, 0, "Error message", null, (state, ex) => state); + + provider.IntervalControl.Resume(); + await provider.IntervalControl.Pause; + + Assert.Equal("2016-05-04 03:02:01.000 +00:00 [Information] Cat: Info message" + _nl, provider.Batches[0][0].Message); + 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 RespectsBatchSize() + { + var provider = new TestBatchingLoggingProvider(maxBatchSize: 1); + var logger = (BatchingLogger)provider.CreateLogger("Cat"); + + await provider.IntervalControl.Pause; + + logger.Log(_timestampOne, LogLevel.Information, 0, "Info message", null, (state, ex) => state); + logger.Log(_timestampOne.AddHours(1), LogLevel.Error, 0, "Error message", null, (state, ex) => state); + + provider.IntervalControl.Resume(); + await provider.IntervalControl.Pause; + + Assert.Single(provider.Batches); + Assert.Single(provider.Batches[0]); + Assert.Equal("2016-05-04 03:02:01.000 +00:00 [Information] Cat: Info message" + _nl, provider.Batches[0][0].Message); + + provider.IntervalControl.Resume(); + await provider.IntervalControl.Pause; + + Assert.Equal(2, provider.Batches.Count); + Assert.Single(provider.Batches[1]); + + Assert.Equal("2016-05-04 04:02:01.000 +00:00 [Error] Cat: Error message" + _nl, provider.Batches[1][0].Message); + } + + [Fact] + public async Task BlocksWhenReachingMaxQueue() + { + var provider = new TestBatchingLoggingProvider(maxQueueSize: 1); + var logger = (BatchingLogger)provider.CreateLogger("Cat"); + + await provider.IntervalControl.Pause; + + logger.Log(_timestampOne, LogLevel.Information, 0, "Info message", null, (state, ex) => state); + var task = Task.Run(() => logger.Log(_timestampOne.AddHours(1), LogLevel.Error, 0, "Error message", null, (state, ex) => state)); + + Assert.False(task.Wait(1000)); + + provider.IntervalControl.Resume(); + await provider.IntervalControl.Pause; + + Assert.True(task.Wait(1000)); + } + + private class TestBatchingLoggingProvider: BatchingLoggerProvider + { + public List Batches { get; } = new List(); + public ManualIntervalControl IntervalControl { get; } = new ManualIntervalControl(); + + public TestBatchingLoggingProvider(TimeSpan? interval = null, int? maxBatchSize = null, int? maxQueueSize = null) + : base(new OptionsWrapperMonitor(new BatchingLoggerOptions + { + FlushPeriod = interval ?? TimeSpan.FromSeconds(1), + BatchSize = maxBatchSize, + BackgroundQueueSize = maxQueueSize, + IsEnabled = true + })) + { + } + + protected override Task WriteMessagesAsync(IEnumerable messages, CancellationToken token) + { + Batches.Add(messages.ToArray()); + return Task.CompletedTask; + } + + protected override Task IntervalAsync(TimeSpan interval, CancellationToken cancellationToken) + { + return IntervalControl.IntervalAsync(); + } + } + } +} diff --git a/src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs b/src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs new file mode 100644 index 0000000000..077ebd726a --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs @@ -0,0 +1,71 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging.AzureAppServices.Internal; +using Moq; +using Xunit; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Test +{ + public class ConfigureOptionsTests + { + [Theory] + [InlineData(true)] + [InlineData(false)] + [InlineData(null)] + public void InitializesIsEnabled(bool? enabled) + { + var configuration = new ConfigurationBuilder().AddInMemoryCollection(new[] + { + new KeyValuePair("IsEnabledKey", Convert.ToString(enabled)) + }).Build(); + + var options = new BatchingLoggerOptions(); + new BatchLoggerConfigureOptions(configuration, "IsEnabledKey").Configure(options); + + Assert.Equal(enabled ?? false, options.IsEnabled); + } + + [Fact] + public void InitializesLogDirectory() + { + var configuration = new ConfigurationBuilder().AddInMemoryCollection(new[] + { + new KeyValuePair("APPSETTING_DIAGNOSTICS_AZUREBLOBCONTAINERSASURL", "http://container/url") + }).Build(); + + var contextMock = new Mock(); + contextMock.SetupGet(c => c.HomeFolder).Returns("Home"); + + var options = new AzureFileLoggerOptions(); + new FileLoggerConfigureOptions(configuration, contextMock.Object).Configure(options); + + Assert.Equal(Path.Combine("Home", "LogFiles", "Application"), options.LogDirectory); + } + + [Fact] + public void InitializesBlobUriSiteInstanceAndName() + { + var configuration = new ConfigurationBuilder().AddInMemoryCollection(new [] + { + new KeyValuePair("APPSETTING_DIAGNOSTICS_AZUREBLOBCONTAINERSASURL", "http://container/url") + }).Build(); + + var contextMock = new Mock(); + contextMock.SetupGet(c => c.HomeFolder).Returns("Home"); + contextMock.SetupGet(c => c.SiteInstanceId).Returns("InstanceId"); + contextMock.SetupGet(c => c.SiteName).Returns("Name"); + + var options = new AzureBlobLoggerOptions(); + new BlobLoggerConfigureOptions(configuration, contextMock.Object).Configure(options); + + Assert.Equal("http://container/url", options.ContainerUrl); + Assert.Equal("InstanceId", options.ApplicationInstanceId); + Assert.Equal("Name", options.ApplicationName); + } + } +} diff --git a/src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs b/src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs new file mode 100644 index 0000000000..ea838b93cf --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs @@ -0,0 +1,122 @@ +// 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; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging.AzureAppServices.Internal; +using Xunit; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Test +{ + public class FileLoggerTests: IDisposable + { + DateTimeOffset _timestampOne = new DateTimeOffset(2016, 05, 04, 03, 02, 01, TimeSpan.Zero); + + public FileLoggerTests() + { + TempPath = Path.GetTempFileName() + "_"; + } + + public string TempPath { get; } + + public void Dispose() + { + try + { + if (Directory.Exists(TempPath)) + { + Directory.Delete(TempPath, true); + } + } + catch + { + // ignored + } + } + + [Fact] + public async Task WritesToTextFile() + { + var provider = new TestFileLoggerProvider(TempPath); + var logger = (BatchingLogger)provider.CreateLogger("Cat"); + + await provider.IntervalControl.Pause; + + logger.Log(_timestampOne, LogLevel.Information, 0, "Info message", null, (state, ex) => state); + logger.Log(_timestampOne.AddHours(1), LogLevel.Error, 0, "Error message", null, (state, ex) => state); + + provider.IntervalControl.Resume(); + await provider.IntervalControl.Pause; + + Assert.Equal( + "2016-05-04 03:02:01.000 +00:00 [Information] Cat: Info message" + Environment.NewLine + + "2016-05-04 04:02:01.000 +00:00 [Error] Cat: Error message" + Environment.NewLine, + File.ReadAllText(Path.Combine(TempPath, "LogFile.20160504.txt"))); + } + + [Fact] + public async Task RollsTextFile() + { + var provider = new TestFileLoggerProvider(TempPath); + var logger = (BatchingLogger)provider.CreateLogger("Cat"); + + await provider.IntervalControl.Pause; + + logger.Log(_timestampOne, LogLevel.Information, 0, "Info message", null, (state, ex) => state); + logger.Log(_timestampOne.AddDays(1), LogLevel.Error, 0, "Error message", null, (state, ex) => state); + + provider.IntervalControl.Resume(); + await provider.IntervalControl.Pause; + + Assert.Equal( + "2016-05-04 03:02:01.000 +00:00 [Information] Cat: Info message" + Environment.NewLine, + File.ReadAllText(Path.Combine(TempPath, "LogFile.20160504.txt"))); + + Assert.Equal( + "2016-05-05 03:02:01.000 +00:00 [Error] Cat: Error message" + Environment.NewLine, + File.ReadAllText(Path.Combine(TempPath, "LogFile.20160505.txt"))); + } + + [Fact] + public async Task RespectsMaxFileCount() + { + Directory.CreateDirectory(TempPath); + File.WriteAllText(Path.Combine(TempPath, "randomFile.txt"), "Text"); + + var provider = new TestFileLoggerProvider(TempPath, maxRetainedFiles: 5); + var logger = (BatchingLogger)provider.CreateLogger("Cat"); + + await provider.IntervalControl.Pause; + var timestamp = _timestampOne; + + for (int i = 0; i < 10; i++) + { + logger.Log(timestamp, LogLevel.Information, 0, "Info message", null, (state, ex) => state); + logger.Log(timestamp.AddHours(1), LogLevel.Error, 0, "Error message", null, (state, ex) => state); + + timestamp = timestamp.AddDays(1); + } + + provider.IntervalControl.Resume(); + await provider.IntervalControl.Pause; + + var actualFiles = new DirectoryInfo(TempPath) + .GetFiles() + .Select(f => f.Name) + .OrderBy(f => f) + .ToArray(); + + Assert.Equal(6, actualFiles.Length); + Assert.Equal(new[] { + "LogFile.20160509.txt", + "LogFile.20160510.txt", + "LogFile.20160511.txt", + "LogFile.20160512.txt", + "LogFile.20160513.txt", + "randomFile.txt" + }, actualFiles); + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs b/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs new file mode 100644 index 0000000000..ddf38d0137 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs @@ -0,0 +1,69 @@ +// 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 Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging.AzureAppServices.Internal; +using Microsoft.Extensions.Options; +using Moq; +using Xunit; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Test +{ + public class LoggerBuilderExtensionsTests + { + private IWebAppContext _appContext; + + public LoggerBuilderExtensionsTests() + { + var contextMock = new Mock(); + contextMock.SetupGet(c => c.IsRunningInAzureWebApp).Returns(true); + contextMock.SetupGet(c => c.HomeFolder).Returns("."); + _appContext = contextMock.Object; + } + + [Fact] + public void BuilderExtensionAddsSingleSetOfServicesWhenCalledTwice() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(builder => builder.AddAzureWebAppDiagnostics(_appContext)); + var count = serviceCollection.Count; + + Assert.NotEqual(0, count); + + serviceCollection.AddLogging(builder => builder.AddAzureWebAppDiagnostics(_appContext)); + + Assert.Equal(count, serviceCollection.Count); + } + + [Fact] + public void BuilderExtensionAddsConfigurationChangeTokenSource() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(builder => builder.AddConfiguration(new ConfigurationBuilder().Build())); + + // Tracking for main configuration + Assert.Equal(1, serviceCollection.Count(d => d.ServiceType == typeof(IOptionsChangeTokenSource))); + + serviceCollection.AddLogging(builder => builder.AddAzureWebAppDiagnostics(_appContext)); + + // Make sure we add another config change token for azure diagnostic configuration + Assert.Equal(2, serviceCollection.Count(d => d.ServiceType == typeof(IOptionsChangeTokenSource))); + } + + [Fact] + public void BuilderExtensionAddsIConfigureOptions() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(builder => builder.AddConfiguration(new ConfigurationBuilder().Build())); + + // Tracking for main configuration + Assert.Equal(2, serviceCollection.Count(d => d.ServiceType == typeof(IConfigureOptions))); + + serviceCollection.AddLogging(builder => builder.AddAzureWebAppDiagnostics(_appContext)); + + Assert.Equal(4, serviceCollection.Count(d => d.ServiceType == typeof(IConfigureOptions))); + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/test/ManualIntervalControl.cs b/src/Logging/Logging.AzureAppServices/test/ManualIntervalControl.cs new file mode 100644 index 0000000000..0ce87f65dc --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/test/ManualIntervalControl.cs @@ -0,0 +1,30 @@ +// 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.Threading.Tasks; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Test +{ + internal class ManualIntervalControl + { + + private TaskCompletionSource _pauseCompletionSource = new TaskCompletionSource(); + private TaskCompletionSource _resumeCompletionSource; + + public Task Pause => _pauseCompletionSource.Task; + + public void Resume() + { + _pauseCompletionSource = new TaskCompletionSource(); + _resumeCompletionSource.SetResult(null); + } + + public async Task IntervalAsync() + { + _resumeCompletionSource = new TaskCompletionSource(); + _pauseCompletionSource.SetResult(null); + + await _resumeCompletionSource.Task; + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj b/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj new file mode 100644 index 0000000000..e89ce311d8 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj @@ -0,0 +1,12 @@ + + + + $(StandardTestTfms) + + + + + + + + diff --git a/src/Logging/Logging.AzureAppServices/test/OptionsWrapperMonitor.cs b/src/Logging/Logging.AzureAppServices/test/OptionsWrapperMonitor.cs new file mode 100644 index 0000000000..32da949cdb --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/test/OptionsWrapperMonitor.cs @@ -0,0 +1,25 @@ +// 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; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Test +{ + internal class OptionsWrapperMonitor : IOptionsMonitor + { + public OptionsWrapperMonitor(T currentValue) + { + CurrentValue = currentValue; + } + + public IDisposable OnChange(Action listener) + { + return null; + } + + public T Get(string name) => CurrentValue; + + public T CurrentValue { get; } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs b/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs new file mode 100644 index 0000000000..df9665e44e --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs @@ -0,0 +1,30 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging.AzureAppServices.Internal; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Test +{ + internal class TestBlobSink : BlobLoggerProvider + { + internal ManualIntervalControl IntervalControl { get; } = new ManualIntervalControl(); + + public TestBlobSink(Func blobReferenceFactory) : base( + new OptionsWrapperMonitor(new AzureBlobLoggerOptions() + { + ApplicationInstanceId = "42", + ApplicationName = "appname", + BlobName = "filename", + IsEnabled = true + }), + blobReferenceFactory) + { + } + + protected override Task IntervalAsync(TimeSpan interval, CancellationToken cancellationToken) + { + return IntervalControl.IntervalAsync(); + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs new file mode 100644 index 0000000000..4b0b87c4e4 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs @@ -0,0 +1,36 @@ +// 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; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging.AzureAppServices.Internal; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Test +{ + internal class TestFileLoggerProvider : FileLoggerProvider + { + internal ManualIntervalControl IntervalControl { get; } = new ManualIntervalControl(); + + public TestFileLoggerProvider( + string path, + string fileName = "LogFile.", + int maxFileSize = 32_000, + int maxRetainedFiles = 100) + : base(new OptionsWrapperMonitor(new AzureFileLoggerOptions() + { + LogDirectory = path, + FileName = fileName, + FileSizeLimit = maxFileSize, + RetainedFileCountLimit = maxRetainedFiles, + IsEnabled = true + })) + { + } + + protected override Task IntervalAsync(TimeSpan interval, CancellationToken cancellationToken) + { + return IntervalControl.IntervalAsync(); + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs b/src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs new file mode 100644 index 0000000000..afb5dc037f --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs @@ -0,0 +1,40 @@ +// 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.Collections.Generic; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging.AzureAppServices.Internal; +using Xunit; + +namespace Microsoft.Extensions.Logging.AzureAppServices.Test +{ + public class WebConfigurationLevelSwitchTests + { + [Theory] + [InlineData("Error", LogLevel.Error)] + [InlineData("Warning", LogLevel.Warning)] + [InlineData("Information", LogLevel.Information)] + [InlineData("Verbose", LogLevel.Trace)] + [InlineData("ABCD", LogLevel.None)] + public void AddsRuleWithCorrectLevel(string levelValue, LogLevel expectedLevel) + { + var configuration = new ConfigurationBuilder().AddInMemoryCollection( + new[] + { + new KeyValuePair("levelKey", levelValue), + }) + .Build(); + + var levelSwitcher = new ConfigurationBasedLevelSwitcher(configuration, typeof(TestFileLoggerProvider), "levelKey"); + + var filterConfiguration = new LoggerFilterOptions(); + levelSwitcher.Configure(filterConfiguration); + + Assert.Equal(1, filterConfiguration.Rules.Count); + + var rule = filterConfiguration.Rules[0]; + Assert.Equal(typeof(TestFileLoggerProvider).FullName, rule.ProviderName); + Assert.Equal(expectedLevel, rule.LogLevel); + } + } +} diff --git a/src/Logging/Logging.Testing/src/AssemblyTestLog.cs b/src/Logging/Logging.Testing/src/AssemblyTestLog.cs new file mode 100644 index 0000000000..97a67b11fa --- /dev/null +++ b/src/Logging/Logging.Testing/src/AssemblyTestLog.cs @@ -0,0 +1,305 @@ +// 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; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Serilog; +using Serilog.Extensions.Logging; +using Xunit.Abstractions; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class AssemblyTestLog : IDisposable + { + public static readonly string OutputDirectoryEnvironmentVariableName = "ASPNETCORE_TEST_LOG_DIR"; + private static readonly string MaxPathLengthEnvironmentVariableName = "ASPNETCORE_TEST_LOG_MAXPATH"; + private static readonly string LogFileExtension = ".log"; + private static readonly int MaxPathLength = GetMaxPathLength(); + private static char[] InvalidFileChars = new char[] + { + '\"', '<', '>', '|', '\0', + (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10, + (char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17, (char)18, (char)19, (char)20, + (char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30, + (char)31, ':', '*', '?', '\\', '/', ' ', (char)127 + }; + + private static readonly object _lock = new object(); + private static readonly Dictionary _logs = new Dictionary(); + + private readonly ILoggerFactory _globalLoggerFactory; + private readonly ILogger _globalLogger; + private readonly string _baseDirectory; + private readonly string _assemblyName; + private readonly IServiceProvider _serviceProvider; + + private static int GetMaxPathLength() + { + var maxPathString = Environment.GetEnvironmentVariable(MaxPathLengthEnvironmentVariableName); + var defaultMaxPath = 245; + return string.IsNullOrEmpty(maxPathString) ? defaultMaxPath : int.Parse(maxPathString); + } + + private AssemblyTestLog(ILoggerFactory globalLoggerFactory, ILogger globalLogger, string baseDirectory, string assemblyName, IServiceProvider serviceProvider) + { + _globalLoggerFactory = globalLoggerFactory; + _globalLogger = globalLogger; + _baseDirectory = baseDirectory; + _assemblyName = assemblyName; + _serviceProvider = serviceProvider; + } + + public IDisposable StartTestLog(ITestOutputHelper output, string className, out ILoggerFactory loggerFactory, [CallerMemberName] string testName = null) => + StartTestLog(output, className, out loggerFactory, LogLevel.Debug, testName); + + public IDisposable StartTestLog(ITestOutputHelper output, string className, out ILoggerFactory loggerFactory, LogLevel minLogLevel, [CallerMemberName] string testName = null) => + StartTestLog(output, className, out loggerFactory, minLogLevel, out var _, testName); + + internal IDisposable StartTestLog(ITestOutputHelper output, string className, out ILoggerFactory loggerFactory, LogLevel minLogLevel, out string resolvedTestName, [CallerMemberName] string testName = null) + { + var serviceProvider = CreateLoggerServices(output, className, minLogLevel, out resolvedTestName, testName); + var factory = serviceProvider.GetRequiredService(); + loggerFactory = factory; + var logger = loggerFactory.CreateLogger("TestLifetime"); + + var stopwatch = Stopwatch.StartNew(); + + var scope = logger.BeginScope("Test: {testName}", testName); + + _globalLogger.LogInformation("Starting test {testName}", testName); + logger.LogInformation("Starting test {testName}", testName); + + return new Disposable(() => + { + stopwatch.Stop(); + _globalLogger.LogInformation("Finished test {testName} in {duration}s", testName, stopwatch.Elapsed.TotalSeconds); + logger.LogInformation("Finished test {testName} in {duration}s", testName, stopwatch.Elapsed.TotalSeconds); + scope.Dispose(); + factory.Dispose(); + (serviceProvider as IDisposable)?.Dispose(); + }); + } + + public ILoggerFactory CreateLoggerFactory(ITestOutputHelper output, string className, [CallerMemberName] string testName = null) => + CreateLoggerFactory(output, className, LogLevel.Trace, testName); + + public ILoggerFactory CreateLoggerFactory(ITestOutputHelper output, string className, LogLevel minLogLevel, [CallerMemberName] string testName = null) + { + return CreateLoggerServices(output, className, minLogLevel, out var _, testName).GetRequiredService(); + } + + public IServiceProvider CreateLoggerServices(ITestOutputHelper output, string className, LogLevel minLogLevel, out string normalizedTestName, [CallerMemberName] string testName = null) + { + normalizedTestName = string.Empty; + + // Try to shorten the class name using the assembly name + if (className.StartsWith(_assemblyName + ".")) + { + className = className.Substring(_assemblyName.Length + 1); + } + + SerilogLoggerProvider serilogLoggerProvider = null; + if (!string.IsNullOrEmpty(_baseDirectory)) + { + var testOutputDirectory = Path.Combine(GetAssemblyBaseDirectory(_assemblyName, _baseDirectory), className); + testName = RemoveIllegalFileChars(testName); + + if (testOutputDirectory.Length + testName.Length + LogFileExtension.Length >= MaxPathLength) + { + _globalLogger.LogWarning($"Test name {testName} is too long. Please shorten test name."); + + // Shorten the test name by removing the middle portion of the testname + var testNameLength = MaxPathLength - testOutputDirectory.Length - LogFileExtension.Length; + + if (testNameLength <= 0) + { + throw new InvalidOperationException("Output file path could not be constructed due to max path length restrictions. Please shorten test assembly, class or method names."); + } + + testName = testName.Substring(0, testNameLength / 2) + testName.Substring(testName.Length - testNameLength / 2, testNameLength / 2); + + _globalLogger.LogWarning($"To prevent long paths test name was shortened to {testName}."); + } + + var testOutputFile = Path.Combine(testOutputDirectory, $"{testName}{LogFileExtension}"); + + if (File.Exists(testOutputFile)) + { + _globalLogger.LogWarning($"Output log file {testOutputFile} already exists. Please try to keep log file names unique."); + + for (var i = 0; i < 1000; i++) + { + testOutputFile = Path.Combine(testOutputDirectory, $"{testName}.{i}{LogFileExtension}"); + + if (!File.Exists(testOutputFile)) + { + _globalLogger.LogWarning($"To resolve log file collision, the enumerated file {testOutputFile} will be used."); + testName = $"{testName}.{i}"; + break; + } + } + } + + normalizedTestName = testName; + serilogLoggerProvider = ConfigureFileLogging(testOutputFile); + } + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(builder => + { + builder.SetMinimumLevel(minLogLevel); + + if (output != null) + { + builder.AddXunit(output, minLogLevel); + } + + if (serilogLoggerProvider != null) + { + // Use a factory so that the container will dispose it + builder.Services.AddSingleton(_ => serilogLoggerProvider); + } + }); + + return serviceCollection.BuildServiceProvider(); + } + + public static AssemblyTestLog Create(string assemblyName, string baseDirectory) + { + SerilogLoggerProvider serilogLoggerProvider = null; + var globalLogDirectory = GetAssemblyBaseDirectory(assemblyName, baseDirectory); + if (!string.IsNullOrEmpty(globalLogDirectory)) + { + var globalLogFileName = Path.Combine(globalLogDirectory, "global.log"); + serilogLoggerProvider = ConfigureFileLogging(globalLogFileName); + } + + var serviceCollection = new ServiceCollection(); + + serviceCollection.AddLogging(builder => + { + // Global logging, when it's written, is expected to be outputted. So set the log level to minimum. + builder.SetMinimumLevel(LogLevel.Trace); + + if (serilogLoggerProvider != null) + { + // Use a factory so that the container will dispose it + builder.Services.AddSingleton(_ => serilogLoggerProvider); + } + }); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + var loggerFactory = serviceProvider.GetRequiredService(); + + var logger = loggerFactory.CreateLogger("GlobalTestLog"); + logger.LogInformation($"Global Test Logging initialized. Set the '{OutputDirectoryEnvironmentVariableName}' Environment Variable in order to create log files on disk."); + return new AssemblyTestLog(loggerFactory, logger, baseDirectory, assemblyName, serviceProvider); + } + + public static AssemblyTestLog ForAssembly(Assembly assembly) + { + lock (_lock) + { + if (!_logs.TryGetValue(assembly, out var log)) + { + var assemblyName = assembly.GetName().Name; + var baseDirectory = Environment.GetEnvironmentVariable(OutputDirectoryEnvironmentVariableName); + log = Create(assemblyName, baseDirectory); + _logs[assembly] = log; + + // Try to clear previous logs + var assemblyBaseDirectory = GetAssemblyBaseDirectory(assemblyName, baseDirectory); + if (Directory.Exists(assemblyBaseDirectory)) + { + try + { + Directory.Delete(assemblyBaseDirectory, recursive: true); + } + catch {} + } + } + return log; + } + } + + private static string GetAssemblyBaseDirectory(string assemblyName, string baseDirectory) + { + if (!string.IsNullOrEmpty(baseDirectory)) + { + return Path.Combine(baseDirectory, assemblyName, RuntimeInformation.FrameworkDescription.TrimStart('.')); + } + return string.Empty; + } + + private static SerilogLoggerProvider ConfigureFileLogging(string fileName) + { + var dir = Path.GetDirectoryName(fileName); + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + + if (File.Exists(fileName)) + { + File.Delete(fileName); + } + + var serilogger = new LoggerConfiguration() + .Enrich.FromLogContext() + .MinimumLevel.Verbose() + .WriteTo.File(fileName, outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{SourceContext}] [{Level}] {Message}{NewLine}{Exception}", flushToDiskInterval: TimeSpan.FromSeconds(1), shared: true) + .CreateLogger(); + return new SerilogLoggerProvider(serilogger, dispose: true); + } + + private static string RemoveIllegalFileChars(string s) + { + var sb = new StringBuilder(); + + foreach (var c in s) + { + if (InvalidFileChars.Contains(c)) + { + if (sb.Length > 0 && sb[sb.Length - 1] != '_') + { + sb.Append('_'); + } + } + else + { + sb.Append(c); + } + } + return sb.ToString(); + } + + public void Dispose() + { + (_serviceProvider as IDisposable)?.Dispose(); + _globalLoggerFactory.Dispose(); + } + + private class Disposable : IDisposable + { + private Action _action; + + public Disposable(Action action) + { + _action = action; + } + + public void Dispose() + { + _action(); + } + } + } +} diff --git a/src/Logging/Logging.Testing/src/BeginScopeContext.cs b/src/Logging/Logging.Testing/src/BeginScopeContext.cs new file mode 100644 index 0000000000..b432f1ad7d --- /dev/null +++ b/src/Logging/Logging.Testing/src/BeginScopeContext.cs @@ -0,0 +1,12 @@ +// 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. + +namespace Microsoft.Extensions.Logging.Testing +{ + public class BeginScopeContext + { + public object Scope { get; set; } + + public string LoggerName { get; set; } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.Testing/src/ITestSink.cs b/src/Logging/Logging.Testing/src/ITestSink.cs new file mode 100644 index 0000000000..bd2d1955ae --- /dev/null +++ b/src/Logging/Logging.Testing/src/ITestSink.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Concurrent; + +namespace Microsoft.Extensions.Logging.Testing +{ + public interface ITestSink + { + Func WriteEnabled { get; set; } + + Func BeginEnabled { get; set; } + + IProducerConsumerCollection Scopes { get; set; } + + IProducerConsumerCollection Writes { get; set; } + + void Write(WriteContext context); + + void Begin(BeginScopeContext context); + } +} diff --git a/src/Logging/Logging.Testing/src/LogValuesAssert.cs b/src/Logging/Logging.Testing/src/LogValuesAssert.cs new file mode 100644 index 0000000000..ea769e68e2 --- /dev/null +++ b/src/Logging/Logging.Testing/src/LogValuesAssert.cs @@ -0,0 +1,80 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public static class LogValuesAssert + { + /// + /// Asserts that the given key and value are present in the actual values. + /// + /// The key of the item to be found. + /// The value of the item to be found. + /// The actual values. + public static void Contains( + string key, + object value, + IEnumerable> actualValues) + { + Contains(new[] { new KeyValuePair(key, value) }, actualValues); + } + + /// + /// Asserts that all the expected values are present in the actual values by ignoring + /// the order of values. + /// + /// Expected subset of values + /// Actual set of values + public static void Contains( + IEnumerable> expectedValues, + IEnumerable> actualValues) + { + if (expectedValues == null) + { + throw new ArgumentNullException(nameof(expectedValues)); + } + + if (actualValues == null) + { + throw new ArgumentNullException(nameof(actualValues)); + } + + var comparer = new LogValueComparer(); + + foreach (var expectedPair in expectedValues) + { + if (!actualValues.Contains(expectedPair, comparer)) + { + throw new EqualException( + expected: GetString(expectedValues), + actual: GetString(actualValues)); + } + } + } + + private static string GetString(IEnumerable> logValues) + { + return string.Join(",", logValues.Select(kvp => $"[{kvp.Key} {kvp.Value}]")); + } + + private class LogValueComparer : IEqualityComparer> + { + public bool Equals(KeyValuePair x, KeyValuePair y) + { + return string.Equals(x.Key, y.Key) && object.Equals(x.Value, y.Value); + } + + public int GetHashCode(KeyValuePair obj) + { + // We are never going to put this KeyValuePair in a hash table, + // so this is ok. + throw new NotImplementedException(); + } + } + } +} diff --git a/src/Logging/Logging.Testing/src/LoggedTest.cs b/src/Logging/Logging.Testing/src/LoggedTest.cs new file mode 100644 index 0000000000..58fcc1fb3e --- /dev/null +++ b/src/Logging/Logging.Testing/src/LoggedTest.cs @@ -0,0 +1,45 @@ +// 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; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.Extensions.DependencyInjection; +using Xunit.Abstractions; + +namespace Microsoft.Extensions.Logging.Testing +{ + public abstract class LoggedTest + { + // Obsolete but keeping for back compat + public LoggedTest(ITestOutputHelper output = null) + { + TestOutputHelper = output; + } + + // Internal for testing + internal string ResolvedTestMethodName { get; set; } + + // Internal for testing + internal string ResolvedTestClassName { get; set; } + + public ILogger Logger { get; set; } + + public ILoggerFactory LoggerFactory { get; set; } + + public ITestOutputHelper TestOutputHelper { get; set; } + + public ITestSink TestSink { get; set; } + + public void AddTestLogging(IServiceCollection services) => services.AddSingleton(LoggerFactory); + + public IDisposable StartLog(out ILoggerFactory loggerFactory, [CallerMemberName] string testName = null) => StartLog(out loggerFactory, LogLevel.Information, testName); + + public IDisposable StartLog(out ILoggerFactory loggerFactory, LogLevel minLogLevel, [CallerMemberName] string testName = null) + { + return AssemblyTestLog.ForAssembly(GetType().GetTypeInfo().Assembly).StartTestLog(TestOutputHelper, GetType().FullName, out loggerFactory, minLogLevel, testName); + } + + public virtual void AdditionalSetup() { } + } +} diff --git a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj new file mode 100644 index 0000000000..22a1db0243 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj @@ -0,0 +1,26 @@ + + + + Helpers for writing tests that use Microsoft.Extensions.Logging. Contains null implementations of the abstractions that do nothing, as well as test implementations that are observable. + netstandard2.0;net461 + $(NoWarn);CS1591 + $(PackageTags);testing + false + + + + + + + + + + + + + + + + + + diff --git a/src/Logging/Logging.Testing/src/Properties/AssemblyInfo.cs b/src/Logging/Logging.Testing/src/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..a5cc6c1da7 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// 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.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.Logging.Testing.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Logging/Logging.Testing/src/ShortClassNameAttribute.cs b/src/Logging/Logging.Testing/src/ShortClassNameAttribute.cs new file mode 100644 index 0000000000..bd30718814 --- /dev/null +++ b/src/Logging/Logging.Testing/src/ShortClassNameAttribute.cs @@ -0,0 +1,12 @@ +// 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; + +namespace Microsoft.Extensions.Logging.Testing +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false)] + public class ShortClassNameAttribute : Attribute + { + } +} diff --git a/src/Logging/Logging.Testing/src/TestLogger.cs b/src/Logging/Logging.Testing/src/TestLogger.cs new file mode 100644 index 0000000000..f7a73dfa6a --- /dev/null +++ b/src/Logging/Logging.Testing/src/TestLogger.cs @@ -0,0 +1,76 @@ +// 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; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class TestLogger : ILogger + { + private object _scope; + private readonly ITestSink _sink; + private readonly string _name; + private readonly Func _filter; + + public TestLogger(string name, ITestSink sink, bool enabled) + : this(name, sink, _ => enabled) + { + } + + public TestLogger(string name, ITestSink sink, Func filter) + { + _sink = sink; + _name = name; + _filter = filter; + } + + public string Name { get; set; } + + public IDisposable BeginScope(TState state) + { + _scope = state; + + _sink.Begin(new BeginScopeContext() + { + LoggerName = _name, + Scope = state, + }); + + return TestDisposable.Instance; + } + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + if (!IsEnabled(logLevel)) + { + return; + } + + _sink.Write(new WriteContext() + { + LogLevel = logLevel, + EventId = eventId, + State = state, + Exception = exception, + Formatter = (s, e) => formatter((TState)s, e), + LoggerName = _name, + Scope = _scope + }); + } + + public bool IsEnabled(LogLevel logLevel) + { + return logLevel != LogLevel.None && _filter(logLevel); + } + + private class TestDisposable : IDisposable + { + public static readonly TestDisposable Instance = new TestDisposable(); + + public void Dispose() + { + // intentionally does nothing + } + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.Testing/src/TestLoggerFactory.cs b/src/Logging/Logging.Testing/src/TestLoggerFactory.cs new file mode 100644 index 0000000000..b0513fed66 --- /dev/null +++ b/src/Logging/Logging.Testing/src/TestLoggerFactory.cs @@ -0,0 +1,32 @@ +// 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; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class TestLoggerFactory : ILoggerFactory + { + private readonly ITestSink _sink; + private readonly bool _enabled; + + public TestLoggerFactory(ITestSink sink, bool enabled) + { + _sink = sink; + _enabled = enabled; + } + + public ILogger CreateLogger(string name) + { + return new TestLogger(name, _sink, _enabled); + } + + public void AddProvider(ILoggerProvider provider) + { + } + + public void Dispose() + { + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.Testing/src/TestLoggerOfT.cs b/src/Logging/Logging.Testing/src/TestLoggerOfT.cs new file mode 100644 index 0000000000..b54870eb87 --- /dev/null +++ b/src/Logging/Logging.Testing/src/TestLoggerOfT.cs @@ -0,0 +1,37 @@ +// 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; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class TestLogger : ILogger + { + private readonly ILogger _logger; + + public TestLogger(TestLoggerFactory factory) + { + _logger = factory.CreateLogger(); + } + + public IDisposable BeginScope(TState state) + { + return _logger.BeginScope(state); + } + + public bool IsEnabled(LogLevel logLevel) + { + return _logger.IsEnabled(logLevel); + } + + public void Log( + LogLevel logLevel, + EventId eventId, + TState state, + Exception exception, + Func formatter) + { + _logger.Log(logLevel, eventId, state, exception, formatter); + } + } +} diff --git a/src/Logging/Logging.Testing/src/TestLoggerProvider.cs b/src/Logging/Logging.Testing/src/TestLoggerProvider.cs new file mode 100644 index 0000000000..758ff32492 --- /dev/null +++ b/src/Logging/Logging.Testing/src/TestLoggerProvider.cs @@ -0,0 +1,24 @@ +// 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. + +namespace Microsoft.Extensions.Logging.Testing +{ + public class TestLoggerProvider : ILoggerProvider + { + private readonly ITestSink _sink; + + public TestLoggerProvider(ITestSink sink) + { + _sink = sink; + } + + public ILogger CreateLogger(string categoryName) + { + return new TestLogger(categoryName, _sink, enabled: true); + } + + public void Dispose() + { + } + } +} diff --git a/src/Logging/Logging.Testing/src/TestSink.cs b/src/Logging/Logging.Testing/src/TestSink.cs new file mode 100644 index 0000000000..f67cab5648 --- /dev/null +++ b/src/Logging/Logging.Testing/src/TestSink.cs @@ -0,0 +1,59 @@ +// 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; +using System.Collections.Concurrent; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class TestSink : ITestSink + { + private ConcurrentQueue _scopes; + private ConcurrentQueue _writes; + + public TestSink( + Func writeEnabled = null, + Func beginEnabled = null) + { + WriteEnabled = writeEnabled; + BeginEnabled = beginEnabled; + + _scopes = new ConcurrentQueue(); + _writes = new ConcurrentQueue(); + } + + public Func WriteEnabled { get; set; } + + public Func BeginEnabled { get; set; } + + public IProducerConsumerCollection Scopes { get => _scopes; set => _scopes = new ConcurrentQueue(value); } + + public IProducerConsumerCollection Writes { get => _writes; set => _writes = new ConcurrentQueue(value); } + + public void Write(WriteContext context) + { + if (WriteEnabled == null || WriteEnabled(context)) + { + _writes.Enqueue(context); + } + } + + public void Begin(BeginScopeContext context) + { + if (BeginEnabled == null || BeginEnabled(context)) + { + _scopes.Enqueue(context); + } + } + + public static bool EnableWithTypeName(WriteContext context) + { + return context.LoggerName.Equals(typeof(T).FullName); + } + + public static bool EnableWithTypeName(BeginScopeContext context) + { + return context.LoggerName.Equals(typeof(T).FullName); + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.Testing/src/WriteContext.cs b/src/Logging/Logging.Testing/src/WriteContext.cs new file mode 100644 index 0000000000..661538e4c5 --- /dev/null +++ b/src/Logging/Logging.Testing/src/WriteContext.cs @@ -0,0 +1,32 @@ +// 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; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class WriteContext + { + public LogLevel LogLevel { get; set; } + + public EventId EventId { get; set; } + + public object State { get; set; } + + public Exception Exception { get; set; } + + public Func Formatter { get; set; } + + public object Scope { get; set; } + + public string LoggerName { get; set; } + + public string Message + { + get + { + return Formatter(State, Exception); + } + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.Testing/src/Xunit/LogLevelAttribute.cs b/src/Logging/Logging.Testing/src/Xunit/LogLevelAttribute.cs new file mode 100644 index 0000000000..9f6f621374 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LogLevelAttribute.cs @@ -0,0 +1,18 @@ +// 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; + +namespace Microsoft.Extensions.Logging.Testing +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class LogLevelAttribute : Attribute + { + public LogLevelAttribute(LogLevel logLevel) + { + LogLevel = logLevel; + } + + public LogLevel LogLevel { get; } + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs new file mode 100644 index 0000000000..ebb9ecf92e --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs @@ -0,0 +1,28 @@ +// 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 Microsoft.AspNetCore.Testing.xunit; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedConditionalFactDiscoverer : LoggedFactDiscoverer + { + private readonly IMessageSink _diagnosticMessageSink; + + public LoggedConditionalFactDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink) + { + _diagnosticMessageSink = diagnosticMessageSink; + } + + protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) + { + var skipReason = testMethod.EvaluateSkipConditions(); + return skipReason != null + ? new SkippedTestCase(skipReason, _diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod) + : base.CreateTestCase(discoveryOptions, testMethod, factAttribute); + } + + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs new file mode 100644 index 0000000000..da5685bbfc --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs @@ -0,0 +1,41 @@ +// 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.Collections.Generic; +using Microsoft.AspNetCore.Testing.xunit; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedConditionalTheoryDiscoverer : LoggedTheoryDiscoverer + { + public LoggedConditionalTheoryDiscoverer(IMessageSink diagnosticMessageSink) + : base(diagnosticMessageSink) + { + } + + protected override IEnumerable CreateTestCasesForTheory( + ITestFrameworkDiscoveryOptions discoveryOptions, + ITestMethod testMethod, + IAttributeInfo theoryAttribute) + { + var skipReason = testMethod.EvaluateSkipConditions(); + return skipReason != null + ? new[] { new SkippedTestCase(skipReason, DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod) } + : base.CreateTestCasesForTheory(discoveryOptions, testMethod, theoryAttribute); + } + + protected override IEnumerable CreateTestCasesForDataRow( + ITestFrameworkDiscoveryOptions discoveryOptions, + ITestMethod testMethod, IAttributeInfo theoryAttribute, + object[] dataRow) + { + var skipReason = testMethod.EvaluateSkipConditions(); + return skipReason != null + ? base.CreateTestCasesForSkippedDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow, skipReason) + : base.CreateTestCasesForDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow); + } + + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedFactDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedFactDiscoverer.cs new file mode 100644 index 0000000000..c52d99c822 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedFactDiscoverer.cs @@ -0,0 +1,18 @@ +// 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 Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedFactDiscoverer : FactDiscoverer + { + public LoggedFactDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink) + { + } + + protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) + => new LoggedTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod); + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestAssemblyRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestAssemblyRunner.cs new file mode 100644 index 0000000000..39dff8fce7 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestAssemblyRunner.cs @@ -0,0 +1,31 @@ +// 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.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTestAssemblyRunner : XunitTestAssemblyRunner + { + public LoggedTestAssemblyRunner( + ITestAssembly testAssembly, + IEnumerable testCases, + IMessageSink diagnosticMessageSink, + IMessageSink executionMessageSink, + ITestFrameworkExecutionOptions executionOptions) + : base(testAssembly, testCases, diagnosticMessageSink, executionMessageSink, executionOptions) + { + } + + protected override Task RunTestCollectionAsync( + IMessageBus messageBus, + ITestCollection testCollection, + IEnumerable testCases, + CancellationTokenSource cancellationTokenSource) + => new LoggedTestCollectionRunner(testCollection, testCases, DiagnosticMessageSink, messageBus, TestCaseOrderer, new ExceptionAggregator(Aggregator), cancellationTokenSource).RunAsync(); + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestCase.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestCase.cs new file mode 100644 index 0000000000..b8d3684c18 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestCase.cs @@ -0,0 +1,36 @@ +// 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; +using System.Threading; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTestCase : XunitTestCase + { + [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] + public LoggedTestCase() : base() + { + } + + public LoggedTestCase( + IMessageSink diagnosticMessageSink, + TestMethodDisplay defaultMethodDisplay, + ITestMethod testMethod, + object[] testMethodArguments = null) + : base(diagnosticMessageSink, defaultMethodDisplay, testMethod, testMethodArguments) + { + } + + public override Task RunAsync( + IMessageSink diagnosticMessageSink, + IMessageBus messageBus, + object[] constructorArguments, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + => new LoggedTestCaseRunner(this, DisplayName, SkipReason, constructorArguments, TestMethodArguments, messageBus, aggregator, cancellationTokenSource).RunAsync(); + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestCaseRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestCaseRunner.cs new file mode 100644 index 0000000000..20cde6144e --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestCaseRunner.cs @@ -0,0 +1,42 @@ +// 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; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTestCaseRunner : XunitTestCaseRunner + { + public LoggedTestCaseRunner( + IXunitTestCase testCase, + string displayName, + string skipReason, + object[] constructorArguments, + object[] testMethodArguments, + IMessageBus messageBus, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + : base(testCase, displayName, skipReason, constructorArguments, testMethodArguments, messageBus, aggregator, cancellationTokenSource) + { + } + + protected override XunitTestRunner CreateTestRunner( + ITest test, + IMessageBus messageBus, + Type testClass, + object[] constructorArguments, + MethodInfo testMethod, + object[] testMethodArguments, + string skipReason, + IReadOnlyList beforeAfterAttributes, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + => new LoggedTestRunner(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, + skipReason, beforeAfterAttributes, new ExceptionAggregator(aggregator), cancellationTokenSource); + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestClassRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestClassRunner.cs new file mode 100644 index 0000000000..e7c30264e6 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestClassRunner.cs @@ -0,0 +1,36 @@ +// 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; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTestClassRunner : XunitTestClassRunner + { + public LoggedTestClassRunner( + ITestClass testClass, + IReflectionTypeInfo @class, + IEnumerable testCases, + IMessageSink diagnosticMessageSink, + IMessageBus messageBus, + ITestCaseOrderer testCaseOrderer, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource, + IDictionary collectionFixtureMappings) + : base(testClass, @class, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource, collectionFixtureMappings) + { + } + + protected override Task RunTestMethodAsync( + ITestMethod testMethod, + IReflectionMethodInfo method, + IEnumerable testCases, + object[] constructorArguments) + => new LoggedTestMethodRunner(testMethod, Class, method, testCases, DiagnosticMessageSink, MessageBus, new ExceptionAggregator(Aggregator), CancellationTokenSource, constructorArguments).RunAsync(); + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestCollectionRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestCollectionRunner.cs new file mode 100644 index 0000000000..c3713d4245 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestCollectionRunner.cs @@ -0,0 +1,33 @@ +// 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.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTestCollectionRunner : XunitTestCollectionRunner + { + private readonly IMessageSink _diagnosticMessageSink; + + public LoggedTestCollectionRunner( + ITestCollection testCollection, + IEnumerable testCases, + IMessageSink diagnosticMessageSink, + IMessageBus messageBus, + ITestCaseOrderer testCaseOrderer, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + : base(testCollection, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource) + { + // Base class doesn't expose this, so capture it here. + _diagnosticMessageSink = diagnosticMessageSink; + } + + protected override Task RunTestClassAsync(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable testCases) + => new LoggedTestClassRunner(testClass, @class, testCases, _diagnosticMessageSink, MessageBus, TestCaseOrderer, new ExceptionAggregator(Aggregator), CancellationTokenSource, CollectionFixtureMappings).RunAsync(); + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFramework.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFramework.cs new file mode 100644 index 0000000000..dc5737d32b --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFramework.cs @@ -0,0 +1,26 @@ +// 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.Reflection; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTestFramework : XunitTestFramework + { + public LoggedTestFramework(IMessageSink messageSink) : base(messageSink) + { + } + + protected override ITestFrameworkDiscoverer CreateDiscoverer(IAssemblyInfo assemblyInfo) + { + return new LoggedTestFrameworkDiscoverer(assemblyInfo, SourceInformationProvider, DiagnosticMessageSink); + } + + protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName) + { + return new LoggedTestFrameworkExecutor(assemblyName, SourceInformationProvider, DiagnosticMessageSink); + } + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs new file mode 100644 index 0000000000..bc02355c87 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs @@ -0,0 +1,80 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Testing.xunit; +using Xunit; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTestFrameworkDiscoverer : XunitTestFrameworkDiscoverer + { + private IDictionary Discoverers { get; } + + public LoggedTestFrameworkDiscoverer( + IAssemblyInfo assemblyInfo, + ISourceInformationProvider sourceProvider, + IMessageSink diagnosticMessageSink, + IXunitTestCollectionFactory collectionFactory = null) + : base(assemblyInfo, sourceProvider, diagnosticMessageSink, collectionFactory) + { + Discoverers = new Dictionary() + { + { typeof(ConditionalTheoryAttribute), new LoggedConditionalTheoryDiscoverer(diagnosticMessageSink) }, + { typeof(ConditionalFactAttribute), new LoggedConditionalFactDiscoverer(diagnosticMessageSink) }, + { typeof(TheoryAttribute), new LoggedTheoryDiscoverer(diagnosticMessageSink) }, + { typeof(FactAttribute), new LoggedFactDiscoverer(diagnosticMessageSink) } + }; + } + + protected override bool FindTestsForMethod( + ITestMethod testMethod, + bool includeSourceInformation, + IMessageBus messageBus, + ITestFrameworkDiscoveryOptions discoveryOptions) + { + if (typeof(LoggedTest).IsAssignableFrom(testMethod.TestClass.Class.ToRuntimeType())) + { + var factAttributes = testMethod.Method.GetCustomAttributes(typeof(FactAttribute)); + if (factAttributes.Count() > 1) + { + var message = $"Test method '{testMethod.TestClass.Class.Name}.{testMethod.Method.Name}' has multiple [Fact]-derived attributes"; + var testCase = new ExecutionErrorTestCase(DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod, testMethod, message); + return ReportDiscoveredTestCase(testCase, includeSourceInformation, messageBus); + } + + var factAttribute = factAttributes.FirstOrDefault(); + if (factAttribute == null) + { + return true; + } + + var factAttributeType = (factAttribute as IReflectionAttributeInfo)?.Attribute.GetType(); + if (!Discoverers.TryGetValue(factAttributeType, out var discoverer)) + { + return base.FindTestsForMethod(testMethod, includeSourceInformation, messageBus, discoveryOptions); + } + else + { + foreach (var testCase in discoverer.Discover(discoveryOptions, testMethod, factAttribute)) + { + if (!ReportDiscoveredTestCase(testCase, includeSourceInformation, messageBus)) + { + return false; + } + } + + return true; + } + } + else + { + return base.FindTestsForMethod(testMethod, includeSourceInformation, messageBus, discoveryOptions); + } + } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkExecutor.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkExecutor.cs new file mode 100644 index 0000000000..ece623fa7a --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkExecutor.cs @@ -0,0 +1,26 @@ +// 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.Collections.Generic; +using System.Reflection; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTestFrameworkExecutor : XunitTestFrameworkExecutor + { + public LoggedTestFrameworkExecutor(AssemblyName assemblyName, ISourceInformationProvider sourceInformationProvider, IMessageSink diagnosticMessageSink) + : base(assemblyName, sourceInformationProvider, diagnosticMessageSink) + { + } + + protected override async void RunTestCases(IEnumerable testCases, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions) + { + using (var assemblyRunner = new LoggedTestAssemblyRunner(TestAssembly, testCases, DiagnosticMessageSink, executionMessageSink, executionOptions)) + { + await assemblyRunner.RunAsync(); + } + } + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs new file mode 100644 index 0000000000..09fe03c2b7 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs @@ -0,0 +1,100 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTestInvoker : XunitTestInvoker + { + private TestOutputHelper _output; + + public LoggedTestInvoker( + ITest test, + IMessageBus messageBus, + Type testClass, + object[] constructorArguments, + MethodInfo testMethod, + object[] testMethodArguments, + IReadOnlyList beforeAfterAttributes, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + : base(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, beforeAfterAttributes, aggregator, cancellationTokenSource) + { + } + + protected override Task BeforeTestMethodInvokedAsync() + { + if (_output != null) + { + _output.Initialize(MessageBus, Test); + } + + return base.BeforeTestMethodInvokedAsync(); + } + + protected override async Task AfterTestMethodInvokedAsync() + { + await base.AfterTestMethodInvokedAsync(); + + if (_output != null) + { + _output.Uninitialize(); + } + } + + protected override object CreateTestClass() + { + var testClass = base.CreateTestClass(); + + if (testClass is LoggedTest loggedTestClass) + { + var classType = loggedTestClass.GetType(); + var logLevelAttribute = TestMethod.GetCustomAttribute() as LogLevelAttribute; + var testName = TestMethodArguments.Aggregate(TestMethod.Name, (a, b) => $"{a}-{(b ?? "null")}"); + + // Try resolving ITestOutputHelper from constructor arguments + loggedTestClass.TestOutputHelper = ConstructorArguments?.SingleOrDefault(a => typeof(ITestOutputHelper).IsAssignableFrom(a.GetType())) as ITestOutputHelper; + + var useShortClassName = TestMethod.DeclaringType.GetCustomAttribute() + ?? TestMethod.DeclaringType.Assembly.GetCustomAttribute(); + var resolvedClassName = useShortClassName == null ? classType.FullName : classType.Name; + // None resolved so create a new one and retain a reference to it for initialization/uninitialization + if (loggedTestClass.TestOutputHelper == null) + { + loggedTestClass.TestOutputHelper = _output = new TestOutputHelper(); + } + + AssemblyTestLog + .ForAssembly(classType.GetTypeInfo().Assembly) + .StartTestLog( + loggedTestClass.TestOutputHelper, + resolvedClassName, + out var loggerFactory, + logLevelAttribute?.LogLevel ?? LogLevel.Trace, + out var resolvedTestName, + testName); + + // internal for testing + loggedTestClass.ResolvedTestMethodName = resolvedTestName; + loggedTestClass.ResolvedTestClassName = resolvedClassName; + + loggedTestClass.LoggerFactory = loggerFactory; + loggedTestClass.Logger = loggerFactory.CreateLogger(classType); + loggedTestClass.TestSink = new TestSink(); + loggerFactory.AddProvider(new TestLoggerProvider(loggedTestClass.TestSink)); + + loggedTestClass.AdditionalSetup(); + } + + return testClass; + } + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestMethodRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestMethodRunner.cs new file mode 100644 index 0000000000..2ba2988257 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestMethodRunner.cs @@ -0,0 +1,36 @@ +// 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.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTestMethodRunner : XunitTestMethodRunner + { + private IMessageSink DiagnosticMessageSink { get; } + private object[] ConstructorArguments { get; } + + public LoggedTestMethodRunner( + ITestMethod testMethod, + IReflectionTypeInfo @class, + IReflectionMethodInfo method, + IEnumerable testCases, + IMessageSink diagnosticMessageSink, + IMessageBus messageBus, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource, + object[] constructorArguments) + : base(testMethod, @class, method, testCases, diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource, constructorArguments) + { + DiagnosticMessageSink = diagnosticMessageSink; + ConstructorArguments = constructorArguments; + } + + protected override Task RunTestCaseAsync(IXunitTestCase testCase) + => testCase.RunAsync(DiagnosticMessageSink, MessageBus, ConstructorArguments, new ExceptionAggregator(Aggregator), CancellationTokenSource); + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs new file mode 100644 index 0000000000..07ad0978d2 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs @@ -0,0 +1,33 @@ +// 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; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTestRunner : XunitTestRunner + { + public LoggedTestRunner( + ITest test, + IMessageBus messageBus, + Type testClass, + object[] constructorArguments, + MethodInfo testMethod, object[] + testMethodArguments, string skipReason, + IReadOnlyList beforeAfterAttributes, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + : base(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, skipReason, beforeAfterAttributes, aggregator, cancellationTokenSource) + { + } + + protected override Task InvokeTestMethodAsync(ExceptionAggregator aggregator) + => new LoggedTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, aggregator, CancellationTokenSource).RunAsync(); + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryDiscoverer.cs new file mode 100644 index 0000000000..535099c690 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryDiscoverer.cs @@ -0,0 +1,29 @@ +// 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.Collections.Generic; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTheoryDiscoverer : TheoryDiscoverer + { + public LoggedTheoryDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink) + { + } + + protected override IEnumerable CreateTestCasesForDataRow( + ITestFrameworkDiscoveryOptions discoveryOptions, + ITestMethod testMethod, + IAttributeInfo theoryAttribute, + object[] dataRow) + => new[] { new LoggedTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod, dataRow) }; + + protected override IEnumerable CreateTestCasesForTheory( + ITestFrameworkDiscoveryOptions discoveryOptions, + ITestMethod testMethod, + IAttributeInfo theoryAttribute) + => new[] { new LoggedTheoryTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod) }; + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCase.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCase.cs new file mode 100644 index 0000000000..db78f093c2 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCase.cs @@ -0,0 +1,35 @@ +// 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; +using System.Threading; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTheoryTestCase : XunitTheoryTestCase + { + [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] + public LoggedTheoryTestCase() : base() + { + } + + public LoggedTheoryTestCase( + IMessageSink diagnosticMessageSink, + TestMethodDisplay defaultMethodDisplay, + ITestMethod testMethod) + : base(diagnosticMessageSink, defaultMethodDisplay, testMethod) + { + } + + public override Task RunAsync( + IMessageSink diagnosticMessageSink, + IMessageBus messageBus, + object[] constructorArguments, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + => new LoggedTheoryTestCaseRunner(this, DisplayName, SkipReason, constructorArguments, diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource).RunAsync(); + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCaseRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCaseRunner.cs new file mode 100644 index 0000000000..f1f92e1dcd --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCaseRunner.cs @@ -0,0 +1,41 @@ +// 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; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTheoryTestCaseRunner : XunitTheoryTestCaseRunner + { + public LoggedTheoryTestCaseRunner( + IXunitTestCase testCase, + string displayName, + string skipReason, + object[] constructorArguments, + IMessageSink diagnosticMessageSink, + IMessageBus messageBus, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + : base(testCase, displayName, skipReason, constructorArguments, diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource) + { + } + + protected override XunitTestRunner CreateTestRunner( + ITest test, + IMessageBus messageBus, + Type testClass, + object[] constructorArguments, + MethodInfo testMethod, + object[] testMethodArguments, + string skipReason, + IReadOnlyList beforeAfterAttributes, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + => new LoggedTestRunner(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, skipReason, beforeAfterAttributes, new ExceptionAggregator(aggregator), cancellationTokenSource); + } +} diff --git a/src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs b/src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs new file mode 100644 index 0000000000..498ef39c35 --- /dev/null +++ b/src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs @@ -0,0 +1,37 @@ +// 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; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging.Testing; +using Xunit.Abstractions; + +namespace Microsoft.Extensions.Logging +{ + public static class XunitLoggerFactoryExtensions + { + public static ILoggingBuilder AddXunit(this ILoggingBuilder builder, ITestOutputHelper output) + { + builder.Services.AddSingleton(new XunitLoggerProvider(output)); + return builder; + } + + public static ILoggingBuilder AddXunit(this ILoggingBuilder builder, ITestOutputHelper output, LogLevel minLevel) + { + builder.Services.AddSingleton(new XunitLoggerProvider(output, minLevel)); + return builder; + } + + public static ILoggerFactory AddXunit(this ILoggerFactory loggerFactory, ITestOutputHelper output) + { + loggerFactory.AddProvider(new XunitLoggerProvider(output)); + return loggerFactory; + } + + public static ILoggerFactory AddXunit(this ILoggerFactory loggerFactory, ITestOutputHelper output, LogLevel minLevel) + { + loggerFactory.AddProvider(new XunitLoggerProvider(output, minLevel)); + return loggerFactory; + } + } +} diff --git a/src/Logging/Logging.Testing/src/XunitLoggerProvider.cs b/src/Logging/Logging.Testing/src/XunitLoggerProvider.cs new file mode 100644 index 0000000000..60ca147a30 --- /dev/null +++ b/src/Logging/Logging.Testing/src/XunitLoggerProvider.cs @@ -0,0 +1,116 @@ +// 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; +using System.Linq; +using System.Text; +using Xunit.Abstractions; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class XunitLoggerProvider : ILoggerProvider + { + private readonly ITestOutputHelper _output; + private readonly LogLevel _minLevel; + + public XunitLoggerProvider(ITestOutputHelper output) + : this(output, LogLevel.Trace) + { + } + + public XunitLoggerProvider(ITestOutputHelper output, LogLevel minLevel) + { + _output = output; + _minLevel = minLevel; + } + + public ILogger CreateLogger(string categoryName) + { + return new XunitLogger(_output, categoryName, _minLevel); + } + + public void Dispose() + { + } + } + + public class XunitLogger : ILogger + { + private static readonly string[] NewLineChars = new[] { Environment.NewLine }; + private readonly string _category; + private readonly LogLevel _minLogLevel; + private readonly ITestOutputHelper _output; + + public XunitLogger(ITestOutputHelper output, string category, LogLevel minLogLevel) + { + _minLogLevel = minLogLevel; + _category = category; + _output = output; + } + + public void Log( + LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + if (!IsEnabled(logLevel)) + { + return; + } + + // Buffer the message into a single string in order to avoid shearing the message when running across multiple threads. + var messageBuilder = new StringBuilder(); + + var timestamp = DateTime.Now.ToString("s"); + var firstLinePrefix = $"| [{timestamp}] {_category} {logLevel}: "; + var lines = formatter(state, exception).Split(NewLineChars, StringSplitOptions.RemoveEmptyEntries); + messageBuilder.AppendLine(firstLinePrefix + lines.FirstOrDefault() ?? string.Empty); + + var additionalLinePrefix = "|" + new string(' ', firstLinePrefix.Length - 1); + foreach (var line in lines.Skip(1)) + { + messageBuilder.AppendLine(additionalLinePrefix + line); + } + + if (exception != null) + { + lines = exception.ToString().Split(NewLineChars, StringSplitOptions.RemoveEmptyEntries); + additionalLinePrefix = "| "; + foreach (var line in lines) + { + messageBuilder.AppendLine(additionalLinePrefix + line); + } + } + + // Remove the last line-break, because ITestOutputHelper only has WriteLine. + var message = messageBuilder.ToString(); + if (message.EndsWith(Environment.NewLine)) + { + message = message.Substring(0, message.Length - Environment.NewLine.Length); + } + + try + { + _output.WriteLine(message); + } + catch (Exception) + { + // We could fail because we're on a background thread and our captured ITestOutputHelper is + // busted (if the test "completed" before the background thread fired). + // So, ignore this. There isn't really anything we can do but hope the + // caller has additional loggers registered + } + } + + public bool IsEnabled(LogLevel logLevel) + => logLevel >= _minLogLevel; + + public IDisposable BeginScope(TState state) + => new NullScope(); + + private class NullScope : IDisposable + { + public void Dispose() + { + } + } + } +} diff --git a/src/Logging/Logging.Testing/src/baseline.netcore.json b/src/Logging/Logging.Testing/src/baseline.netcore.json new file mode 100644 index 0000000000..95ba2ad582 --- /dev/null +++ b/src/Logging/Logging.Testing/src/baseline.netcore.json @@ -0,0 +1,1321 @@ +{ + "AssemblyIdentity": "Microsoft.Extensions.Logging.Testing, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.Extensions.Logging.XunitLoggerFactoryExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AddXunit", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.Extensions.Logging.ILoggingBuilder" + }, + { + "Name": "output", + "Type": "Xunit.Abstractions.ITestOutputHelper" + } + ], + "ReturnType": "Microsoft.Extensions.Logging.ILoggingBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddXunit", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.Extensions.Logging.ILoggingBuilder" + }, + { + "Name": "output", + "Type": "Xunit.Abstractions.ITestOutputHelper" + }, + { + "Name": "minLevel", + "Type": "Microsoft.Extensions.Logging.LogLevel" + } + ], + "ReturnType": "Microsoft.Extensions.Logging.ILoggingBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddXunit", + "Parameters": [ + { + "Name": "loggerFactory", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "output", + "Type": "Xunit.Abstractions.ITestOutputHelper" + } + ], + "ReturnType": "Microsoft.Extensions.Logging.ILoggerFactory", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddXunit", + "Parameters": [ + { + "Name": "loggerFactory", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "output", + "Type": "Xunit.Abstractions.ITestOutputHelper" + }, + { + "Name": "minLevel", + "Type": "Microsoft.Extensions.Logging.LogLevel" + } + ], + "ReturnType": "Microsoft.Extensions.Logging.ILoggerFactory", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.Testing.AssemblyTestLog", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "System.IDisposable" + ], + "Members": [ + { + "Kind": "Method", + "Name": "StartTestLog", + "Parameters": [ + { + "Name": "output", + "Type": "Xunit.Abstractions.ITestOutputHelper" + }, + { + "Name": "className", + "Type": "System.String" + }, + { + "Name": "loggerFactory", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory", + "Direction": "Out" + }, + { + "Name": "testName", + "Type": "System.String", + "DefaultValue": "null" + } + ], + "ReturnType": "System.IDisposable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "CreateLoggerFactory", + "Parameters": [ + { + "Name": "output", + "Type": "Xunit.Abstractions.ITestOutputHelper" + }, + { + "Name": "className", + "Type": "System.String" + }, + { + "Name": "testName", + "Type": "System.String", + "DefaultValue": "null" + } + ], + "ReturnType": "Microsoft.Extensions.Logging.ILoggerFactory", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Create", + "Parameters": [ + { + "Name": "assemblyName", + "Type": "System.String" + }, + { + "Name": "baseDirectory", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.Extensions.Logging.Testing.AssemblyTestLog", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ForAssembly", + "Parameters": [ + { + "Name": "assembly", + "Type": "System.Reflection.Assembly" + } + ], + "ReturnType": "Microsoft.Extensions.Logging.Testing.AssemblyTestLog", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Dispose", + "Parameters": [], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "System.IDisposable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "OutputDirectoryEnvironmentVariableName", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.Testing.BeginScopeContext", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Scope", + "Parameters": [], + "ReturnType": "System.Object", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Scope", + "Parameters": [ + { + "Name": "value", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_LoggerName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_LoggerName", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.Testing.ITestSink", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_WriteEnabled", + "Parameters": [], + "ReturnType": "System.Func", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_WriteEnabled", + "Parameters": [ + { + "Name": "value", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_BeginEnabled", + "Parameters": [], + "ReturnType": "System.Func", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_BeginEnabled", + "Parameters": [ + { + "Name": "value", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Scopes", + "Parameters": [], + "ReturnType": "System.Collections.Generic.List", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Scopes", + "Parameters": [ + { + "Name": "value", + "Type": "System.Collections.Generic.List" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Writes", + "Parameters": [], + "ReturnType": "System.Collections.Generic.List", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Writes", + "Parameters": [ + { + "Name": "value", + "Type": "System.Collections.Generic.List" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Write", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.Extensions.Logging.Testing.WriteContext" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Begin", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.Extensions.Logging.Testing.BeginScopeContext" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.Testing.LoggedTest", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "StartLog", + "Parameters": [ + { + "Name": "loggerFactory", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory", + "Direction": "Out" + }, + { + "Name": "testName", + "Type": "System.String", + "DefaultValue": "null" + } + ], + "ReturnType": "System.IDisposable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "output", + "Type": "Xunit.Abstractions.ITestOutputHelper" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.Testing.LogValuesAssert", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Contains", + "Parameters": [ + { + "Name": "key", + "Type": "System.String" + }, + { + "Name": "value", + "Type": "System.Object" + }, + { + "Name": "actualValues", + "Type": "System.Collections.Generic.IEnumerable>" + } + ], + "ReturnType": "System.Void", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Contains", + "Parameters": [ + { + "Name": "expectedValues", + "Type": "System.Collections.Generic.IEnumerable>" + }, + { + "Name": "actualValues", + "Type": "System.Collections.Generic.IEnumerable>" + } + ], + "ReturnType": "System.Void", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.Testing.TestLogger", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Logging.ILogger" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_Name", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Name", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "BeginScope", + "Parameters": [ + { + "Name": "state", + "Type": "T0" + } + ], + "ReturnType": "System.IDisposable", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TState", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Log", + "Parameters": [ + { + "Name": "logLevel", + "Type": "Microsoft.Extensions.Logging.LogLevel" + }, + { + "Name": "eventId", + "Type": "Microsoft.Extensions.Logging.EventId" + }, + { + "Name": "state", + "Type": "T0" + }, + { + "Name": "exception", + "Type": "System.Exception" + }, + { + "Name": "formatter", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TState", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "IsEnabled", + "Parameters": [ + { + "Name": "logLevel", + "Type": "Microsoft.Extensions.Logging.LogLevel" + } + ], + "ReturnType": "System.Boolean", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "name", + "Type": "System.String" + }, + { + "Name": "sink", + "Type": "Microsoft.Extensions.Logging.Testing.ITestSink" + }, + { + "Name": "enabled", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "name", + "Type": "System.String" + }, + { + "Name": "sink", + "Type": "Microsoft.Extensions.Logging.Testing.ITestSink" + }, + { + "Name": "filter", + "Type": "System.Func" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.Testing.TestLoggerFactory", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Logging.ILoggerFactory" + ], + "Members": [ + { + "Kind": "Method", + "Name": "CreateLogger", + "Parameters": [ + { + "Name": "name", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.Extensions.Logging.ILogger", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.ILoggerFactory", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddProvider", + "Parameters": [ + { + "Name": "provider", + "Type": "Microsoft.Extensions.Logging.ILoggerProvider" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.ILoggerFactory", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "sink", + "Type": "Microsoft.Extensions.Logging.Testing.ITestSink" + }, + { + "Name": "enabled", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.Testing.TestLogger", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Logging.ILogger" + ], + "Members": [ + { + "Kind": "Method", + "Name": "BeginScope", + "Parameters": [ + { + "Name": "state", + "Type": "T0" + } + ], + "ReturnType": "System.IDisposable", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TState", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "IsEnabled", + "Parameters": [ + { + "Name": "logLevel", + "Type": "Microsoft.Extensions.Logging.LogLevel" + } + ], + "ReturnType": "System.Boolean", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Log", + "Parameters": [ + { + "Name": "logLevel", + "Type": "Microsoft.Extensions.Logging.LogLevel" + }, + { + "Name": "eventId", + "Type": "Microsoft.Extensions.Logging.EventId" + }, + { + "Name": "state", + "Type": "T0" + }, + { + "Name": "exception", + "Type": "System.Exception" + }, + { + "Name": "formatter", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TState", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "factory", + "Type": "Microsoft.Extensions.Logging.Testing.TestLoggerFactory" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [ + { + "ParameterName": "T", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Name": "Microsoft.Extensions.Logging.Testing.TestSink", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Logging.Testing.ITestSink" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_WriteEnabled", + "Parameters": [], + "ReturnType": "System.Func", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_WriteEnabled", + "Parameters": [ + { + "Name": "value", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_BeginEnabled", + "Parameters": [], + "ReturnType": "System.Func", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_BeginEnabled", + "Parameters": [ + { + "Name": "value", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Scopes", + "Parameters": [], + "ReturnType": "System.Collections.Generic.List", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Scopes", + "Parameters": [ + { + "Name": "value", + "Type": "System.Collections.Generic.List" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Writes", + "Parameters": [], + "ReturnType": "System.Collections.Generic.List", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Writes", + "Parameters": [ + { + "Name": "value", + "Type": "System.Collections.Generic.List" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Write", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.Extensions.Logging.Testing.WriteContext" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Begin", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.Extensions.Logging.Testing.BeginScopeContext" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "EnableWithTypeName", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.Extensions.Logging.Testing.WriteContext" + } + ], + "ReturnType": "System.Boolean", + "Static": true, + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "T", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "EnableWithTypeName", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.Extensions.Logging.Testing.BeginScopeContext" + } + ], + "ReturnType": "System.Boolean", + "Static": true, + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "T", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "writeEnabled", + "Type": "System.Func", + "DefaultValue": "null" + }, + { + "Name": "beginEnabled", + "Type": "System.Func", + "DefaultValue": "null" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.Testing.WriteContext", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_LogLevel", + "Parameters": [], + "ReturnType": "Microsoft.Extensions.Logging.LogLevel", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_LogLevel", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.Extensions.Logging.LogLevel" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_EventId", + "Parameters": [], + "ReturnType": "Microsoft.Extensions.Logging.EventId", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_EventId", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.Extensions.Logging.EventId" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_State", + "Parameters": [], + "ReturnType": "System.Object", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_State", + "Parameters": [ + { + "Name": "value", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Exception", + "Parameters": [], + "ReturnType": "System.Exception", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Exception", + "Parameters": [ + { + "Name": "value", + "Type": "System.Exception" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Formatter", + "Parameters": [], + "ReturnType": "System.Func", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Formatter", + "Parameters": [ + { + "Name": "value", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Scope", + "Parameters": [], + "ReturnType": "System.Object", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Scope", + "Parameters": [ + { + "Name": "value", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_LoggerName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_LoggerName", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.Testing.XunitLoggerProvider", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Logging.ILoggerProvider" + ], + "Members": [ + { + "Kind": "Method", + "Name": "CreateLogger", + "Parameters": [ + { + "Name": "categoryName", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.Extensions.Logging.ILogger", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.ILoggerProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "output", + "Type": "Xunit.Abstractions.ITestOutputHelper" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "output", + "Type": "Xunit.Abstractions.ITestOutputHelper" + }, + { + "Name": "minLevel", + "Type": "Microsoft.Extensions.Logging.LogLevel" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.Logging.Testing.XunitLogger", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Logging.ILogger" + ], + "Members": [ + { + "Kind": "Method", + "Name": "Log", + "Parameters": [ + { + "Name": "logLevel", + "Type": "Microsoft.Extensions.Logging.LogLevel" + }, + { + "Name": "eventId", + "Type": "Microsoft.Extensions.Logging.EventId" + }, + { + "Name": "state", + "Type": "T0" + }, + { + "Name": "exception", + "Type": "System.Exception" + }, + { + "Name": "formatter", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TState", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "IsEnabled", + "Parameters": [ + { + "Name": "logLevel", + "Type": "Microsoft.Extensions.Logging.LogLevel" + } + ], + "ReturnType": "System.Boolean", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "BeginScope", + "Parameters": [ + { + "Name": "state", + "Type": "T0" + } + ], + "ReturnType": "System.IDisposable", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TState", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "output", + "Type": "Xunit.Abstractions.ITestOutputHelper" + }, + { + "Name": "category", + "Type": "System.String" + }, + { + "Name": "minLogLevel", + "Type": "Microsoft.Extensions.Logging.LogLevel" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props b/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props new file mode 100644 index 0000000000..f98e3e13b5 --- /dev/null +++ b/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props @@ -0,0 +1,8 @@ + + + + <_Parameter1>Microsoft.Extensions.Logging.Testing.LoggedTestFramework + <_Parameter2>Microsoft.Extensions.Logging.Testing + + + \ No newline at end of file diff --git a/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs b/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs new file mode 100644 index 0000000000..0efadb4367 --- /dev/null +++ b/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs @@ -0,0 +1,207 @@ +// 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; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Extensions.Logging.Testing.Tests +{ + public class AssemblyTestLogTests : LoggedTest + { + private static readonly Assembly ThisAssembly = typeof(AssemblyTestLog).GetTypeInfo().Assembly; + + [Fact] + public void FullClassNameUsedWhenShortClassNameAttributeNotSpecified() + { + Assert.Equal(GetType().FullName, ResolvedTestClassName); + } + + [Fact] + public void ForAssembly_ReturnsSameInstanceForSameAssembly() + { + Assert.Same( + AssemblyTestLog.ForAssembly(ThisAssembly), + AssemblyTestLog.ForAssembly(ThisAssembly)); + } + + [Fact] + public void TestLogWritesToITestOutputHelper() + { + var output = new TestTestOutputHelper(); + var assemblyLog = AssemblyTestLog.Create("NonExistant.Test.Assembly", baseDirectory: null); + + using (assemblyLog.StartTestLog(output, "NonExistant.Test.Class", out var loggerFactory)) + { + var logger = loggerFactory.CreateLogger("TestLogger"); + logger.LogInformation("Information!"); + + // Trace is disabled by default + logger.LogTrace("Trace!"); + } + + Assert.Equal(@"[TIMESTAMP] TestLifetime Information: Starting test TestLogWritesToITestOutputHelper +[TIMESTAMP] TestLogger Information: Information! +[TIMESTAMP] TestLifetime Information: Finished test TestLogWritesToITestOutputHelper in DURATION +", MakeConsistent(output.Output), ignoreLineEndingDifferences: true); + } + + [Fact] + private Task TestLogEscapesIllegalFileNames() => + RunTestLogFunctionalTest((tempDir) => + { + var illegalTestName = "Testing-https://localhost:5000"; + var escapedTestName = "Testing-https_localhost_5000"; + using (var testAssemblyLog = AssemblyTestLog.Create("FakeTestAssembly", baseDirectory: tempDir)) + using (testAssemblyLog.StartTestLog(output: null, className: "FakeTestAssembly.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, resolvedTestName: out var resolvedTestname, testName: illegalTestName)) + { + Assert.Equal(escapedTestName, resolvedTestname); + } + }); + + [Fact] + public Task TestLogWritesToGlobalLogFile() => + RunTestLogFunctionalTest((tempDir) => + { + // Because this test writes to a file, it is a functional test and should be logged + // but it's also testing the test logging facility. So this is pretty meta ;) + var logger = LoggerFactory.CreateLogger("Test"); + + using (var testAssemblyLog = AssemblyTestLog.Create("FakeTestAssembly", tempDir)) + { + logger.LogInformation("Created test log in {baseDirectory}", tempDir); + + using (testAssemblyLog.StartTestLog(output: null, className: "FakeTestAssembly.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, testName: "FakeTestName")) + { + var testLogger = testLoggerFactory.CreateLogger("TestLogger"); + testLogger.LogInformation("Information!"); + testLogger.LogTrace("Trace!"); + } + } + + logger.LogInformation("Finished test log in {baseDirectory}", tempDir); + + var globalLogPath = Path.Combine(tempDir, "FakeTestAssembly", RuntimeInformation.FrameworkDescription.TrimStart('.'), "global.log"); + var testLog = Path.Combine(tempDir, "FakeTestAssembly", RuntimeInformation.FrameworkDescription.TrimStart('.'), "FakeTestClass", $"FakeTestName.log"); + + Assert.True(File.Exists(globalLogPath), $"Expected global log file {globalLogPath} to exist"); + Assert.True(File.Exists(testLog), $"Expected test log file {testLog} to exist"); + + var globalLogContent = MakeConsistent(File.ReadAllText(globalLogPath)); + var testLogContent = MakeConsistent(File.ReadAllText(testLog)); + + Assert.Equal(@"[GlobalTestLog] [Information] Global Test Logging initialized. Set the 'ASPNETCORE_TEST_LOG_DIR' Environment Variable in order to create log files on disk. +[GlobalTestLog] [Information] Starting test ""FakeTestName"" +[GlobalTestLog] [Information] Finished test ""FakeTestName"" in DURATION +", globalLogContent, ignoreLineEndingDifferences: true); + Assert.Equal(@"[TestLifetime] [Information] Starting test ""FakeTestName"" +[TestLogger] [Information] Information! +[TestLogger] [Verbose] Trace! +[TestLifetime] [Information] Finished test ""FakeTestName"" in DURATION +", testLogContent, ignoreLineEndingDifferences: true); + }); + + [Fact] + public Task TestLogTruncatesTestNameToAvoidLongPaths() => + RunTestLogFunctionalTest((tempDir) => + { + var longTestName = new string('0', 50) + new string('1', 50) + new string('2', 50) + new string('3', 50) + new string('4', 50); + var logger = LoggerFactory.CreateLogger("Test"); + using (var testAssemblyLog = AssemblyTestLog.Create("FakeTestAssembly", tempDir)) + { + logger.LogInformation("Created test log in {baseDirectory}", tempDir); + + using (testAssemblyLog.StartTestLog(output: null, className: "FakeTestAssembly.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, testName: longTestName)) + { + testLoggerFactory.CreateLogger("TestLogger").LogInformation("Information!"); + } + } + logger.LogInformation("Finished test log in {baseDirectory}", tempDir); + + var testLogFiles = new DirectoryInfo(Path.Combine(tempDir, "FakeTestAssembly", RuntimeInformation.FrameworkDescription.TrimStart('.'), "FakeTestClass")).EnumerateFiles(); + var testLog = Assert.Single(testLogFiles); + var testFileName = Path.GetFileNameWithoutExtension(testLog.Name); + + // The first half of the file comes from the beginning of the test name passed to the logger + Assert.Equal(longTestName.Substring(0, testFileName.Length / 2), testFileName.Substring(0, testFileName.Length / 2)); + // The last half of the file comes from the ending of the test name passed to the logger + Assert.Equal(longTestName.Substring(longTestName.Length - testFileName.Length / 2, testFileName.Length / 2), testFileName.Substring(testFileName.Length - testFileName.Length / 2, testFileName.Length / 2)); + }); + + [Fact] + public Task TestLogEnumerateFilenamesToAvoidCollisions() => + RunTestLogFunctionalTest((tempDir) => + { + var logger = LoggerFactory.CreateLogger("Test"); + using (var testAssemblyLog = AssemblyTestLog.Create("FakeTestAssembly", tempDir)) + { + logger.LogInformation("Created test log in {baseDirectory}", tempDir); + + for (var i = 0; i < 10; i++) + { + using (testAssemblyLog.StartTestLog(output: null, className: "FakeTestAssembly.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, testName: "FakeTestName")) + { + testLoggerFactory.CreateLogger("TestLogger").LogInformation("Information!"); + } + } + } + logger.LogInformation("Finished test log in {baseDirectory}", tempDir); + + // The first log file exists + Assert.True(File.Exists(Path.Combine(tempDir, "FakeTestAssembly", RuntimeInformation.FrameworkDescription.TrimStart('.'), "FakeTestClass", $"FakeTestName.log"))); + + // Subsequent files exist + for (var i = 0; i < 9; i++) + { + Assert.True(File.Exists(Path.Combine(tempDir, "FakeTestAssembly", RuntimeInformation.FrameworkDescription.TrimStart('.'), "FakeTestClass", $"FakeTestName.{i}.log"))); + } + }); + + private static readonly Regex TimestampRegex = new Regex(@"\d+-\d+-\d+T\d+:\d+:\d+"); + private static readonly Regex DurationRegex = new Regex(@"[^ ]+s$"); + + private async Task RunTestLogFunctionalTest(Action action, [CallerMemberName] string testName = null) + { + var tempDir = Path.Combine(Path.GetTempPath(), $"TestLogging_{Guid.NewGuid().ToString("N")}"); + try + { + action(tempDir); + } + finally + { + if (Directory.Exists(tempDir)) + { + try + { + Directory.Delete(tempDir, recursive: true); + } + catch + { + await Task.Delay(100); + Directory.Delete(tempDir, recursive: true); + } + } + } + } + + private static string MakeConsistent(string input) + { + return string.Join(Environment.NewLine, input.Split(new[] { Environment.NewLine }, StringSplitOptions.None) + .Select(line => + { + var strippedPrefix = line.IndexOf("[") >= 0 ? line.Substring(line.IndexOf("[")) : line; + + var strippedDuration = + DurationRegex.Replace(strippedPrefix, "DURATION"); + var strippedTimestamp = TimestampRegex.Replace(strippedDuration, "TIMESTAMP"); + return strippedTimestamp; + })); + } + } +} diff --git a/src/Logging/Logging.Testing/test/LogValuesAssertTest.cs b/src/Logging/Logging.Testing/test/LogValuesAssertTest.cs new file mode 100644 index 0000000000..b5e1d98738 --- /dev/null +++ b/src/Logging/Logging.Testing/test/LogValuesAssertTest.cs @@ -0,0 +1,221 @@ +// 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.Collections.Generic; +using System.Linq; +using Xunit; +using Xunit.Sdk; + +namespace Microsoft.Extensions.Logging.Testing.Tests +{ + public class LogValuesAssertTest + { + public static TheoryData< + IEnumerable>, + IEnumerable>> ExpectedValues_SubsetOf_ActualValuesData + { + get + { + return new TheoryData< + IEnumerable>, + IEnumerable>>() + { + { + new KeyValuePair[] { }, + new KeyValuePair[] { } + }, + { + // subset + new KeyValuePair[] { }, + new[] + { + new KeyValuePair("RouteValue", "Failure"), + new KeyValuePair("RouteKey", "id") + } + }, + { + // subset + new[] + { + new KeyValuePair("RouteValue", "Failure"), + new KeyValuePair("RouteKey", "id") + }, + new[] + { + new KeyValuePair("RouteValue", "Failure"), + new KeyValuePair("RouteKey", "id"), + new KeyValuePair("RouteConstraint", "Something") + } + }, + { + // equal number of values + new[] + { + new KeyValuePair("RouteValue", "Failure"), + new KeyValuePair("RouteKey", "id") + }, + new[] + { + new KeyValuePair("RouteValue", "Failure"), + new KeyValuePair("RouteKey", "id"), + } + } + }; + } + } + + [Theory] + [MemberData(nameof(ExpectedValues_SubsetOf_ActualValuesData))] + public void Asserts_Success_ExpectedValues_SubsetOf_ActualValues( + IEnumerable> expectedValues, + IEnumerable> actualValues) + { + // Act && Assert + LogValuesAssert.Contains(expectedValues, actualValues); + } + + public static TheoryData< + IEnumerable>, + IEnumerable>> ExpectedValues_MoreThan_ActualValuesData + { + get + { + return new TheoryData< + IEnumerable>, + IEnumerable>>() + { + { + new[] + { + new KeyValuePair("RouteValue", "Failure"), + new KeyValuePair("RouteKey", "id") + }, + new KeyValuePair[] { } + }, + { + new[] + { + new KeyValuePair("RouteValue", "Failure"), + new KeyValuePair("RouteKey", "id"), + new KeyValuePair("RouteConstraint", "Something") + }, + new[] + { + new KeyValuePair("RouteValue", "Failure"), + new KeyValuePair("RouteKey", "id") + } + } + }; + } + } + + [Theory] + [MemberData(nameof(ExpectedValues_MoreThan_ActualValuesData))] + public void Asserts_Failure_ExpectedValues_MoreThan_ActualValues( + IEnumerable> expectedValues, + IEnumerable> actualValues) + { + // Act && Assert + var equalException = Assert.Throws( + () => LogValuesAssert.Contains(expectedValues, actualValues)); + + Assert.Equal(GetString(expectedValues), equalException.Expected); + Assert.Equal(GetString(actualValues), equalException.Actual); + } + + [Fact] + public void Asserts_Success_IgnoringOrderOfItems() + { + // Arrange + var expectedLogValues = new[] + { + new KeyValuePair("RouteConstraint", "Something"), + new KeyValuePair("RouteValue", "Failure"), + new KeyValuePair("RouteKey", "id") + }; + var actualLogValues = new[] + { + new KeyValuePair("RouteKey", "id"), + new KeyValuePair("RouteConstraint", "Something"), + new KeyValuePair("RouteValue", "Failure"), + }; + + // Act && Assert + LogValuesAssert.Contains(expectedLogValues, actualLogValues); + } + + [Fact] + public void Asserts_Success_OnSpecifiedKeyAndValue() + { + // Arrange + var actualLogValues = new[] + { + new KeyValuePair("RouteConstraint", "Something"), + new KeyValuePair("RouteKey", "id"), + new KeyValuePair("RouteValue", "Failure"), + }; + + // Act && Assert + LogValuesAssert.Contains("RouteKey", "id", actualLogValues); + } + + public static TheoryData< + IEnumerable>, + IEnumerable>> CaseSensitivityComparisionData + { + get + { + return new TheoryData< + IEnumerable>, + IEnumerable>>() + { + { + new[] + { + new KeyValuePair("RouteKey", "id"), + new KeyValuePair("RouteValue", "Failure"), + }, + new[] + { + new KeyValuePair("ROUTEKEY", "id"), + new KeyValuePair("RouteValue", "Failure"), + } + }, + { + new[] + { + new KeyValuePair("RouteKey", "id"), + new KeyValuePair("RouteValue", "Failure"), + }, + new[] + { + new KeyValuePair("RouteKey", "id"), + new KeyValuePair("RouteValue", "FAILURE"), + } + } + }; + } + } + + [Theory] + [MemberData(nameof(CaseSensitivityComparisionData))] + public void DefaultComparer_Performs_CaseSensitiveComparision( + IEnumerable> expectedValues, + IEnumerable> actualValues) + { + // Act && Assert + var equalException = Assert.Throws( + () => LogValuesAssert.Contains(expectedValues, actualValues)); + + Assert.Equal(GetString(expectedValues), equalException.Expected); + Assert.Equal(GetString(actualValues), equalException.Actual); + } + + private string GetString(IEnumerable> logValues) + { + return logValues == null ? + "Null" : + string.Join(",", logValues.Select(kvp => $"[{kvp.Key} {kvp.Value}]")); + } + } +} diff --git a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs new file mode 100644 index 0000000000..31fd6d631f --- /dev/null +++ b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs @@ -0,0 +1,142 @@ +// 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 Microsoft.AspNetCore.Testing.xunit; +using Microsoft.Extensions.DependencyInjection; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.Extensions.Logging.Testing.Tests +{ + [ShortClassName] + public class LoggedTestXunitTests : TestLoggedTest + { + private readonly ITestOutputHelper _output; + + public LoggedTestXunitTests(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void ShortClassNameUsedWhenShortClassNameAttributeSpecified() + { + Assert.Equal(GetType().Name, ResolvedTestClassName); + } + + [Fact] + public void LoggedTestTestOutputHelperSameInstanceAsInjectedConstructorArg() + { + Assert.Same(_output, TestOutputHelper); + } + + [Fact] + public void LoggedFactInitializesLoggedTestProperties() + { + Assert.NotNull(Logger); + Assert.NotNull(LoggerFactory); + Assert.NotNull(TestSink); + Assert.NotNull(TestOutputHelper); + } + + [Theory] + [InlineData("Hello world")] + public void LoggedTheoryInitializesLoggedTestProperties(string argument) + { + Assert.NotNull(Logger); + Assert.NotNull(LoggerFactory); + Assert.NotNull(TestSink); + Assert.NotNull(TestOutputHelper); + // Use the test argument + Assert.NotNull(argument); + } + + [ConditionalFact] + public void ConditionalLoggedFactGetsInitializedLoggerFactory() + { + Assert.NotNull(Logger); + Assert.NotNull(LoggerFactory); + Assert.NotNull(TestSink); + Assert.NotNull(TestOutputHelper); + } + + [ConditionalTheory] + [InlineData("Hello world")] + public void LoggedConditionalTheoryInitializesLoggedTestProperties(string argument) + { + Assert.NotNull(Logger); + Assert.NotNull(LoggerFactory); + Assert.NotNull(TestSink); + Assert.NotNull(TestOutputHelper); + // Use the test argument + Assert.NotNull(argument); + } + + [Fact] + [LogLevel(LogLevel.Information)] + public void LoggedFactFilteredByLogLevel() + { + Logger.LogInformation("Information"); + Logger.LogDebug("Debug"); + + var message = Assert.Single(TestSink.Writes); + Assert.Equal(LogLevel.Information, message.LogLevel); + Assert.Equal("Information", message.Formatter(message.State, null)); + } + + [Theory] + [InlineData("Hello world")] + [LogLevel(LogLevel.Information)] + public void LoggedTheoryFilteredByLogLevel(string argument) + { + Logger.LogInformation("Information"); + Logger.LogDebug("Debug"); + + var message = Assert.Single(TestSink.Writes); + Assert.Equal(LogLevel.Information, message.LogLevel); + Assert.Equal("Information", message.Formatter(message.State, null)); + + // Use the test argument + Assert.NotNull(argument); + } + + [Fact] + public void AddTestLoggingUpdatedWhenLoggerFactoryIsSet() + { + var loggerFactory = new LoggerFactory(); + var serviceCollection = new ServiceCollection(); + + LoggerFactory = loggerFactory; + AddTestLogging(serviceCollection); + + Assert.Same(loggerFactory, serviceCollection.BuildServiceProvider().GetRequiredService()); + } + + [ConditionalTheory] + [EnvironmentVariableSkipCondition("ASPNETCORE_TEST_LOG_DIR", "")] // The test name is only generated when logging is enabled via the environment variable + [InlineData(null)] + public void LoggedTheoryNullArgumentsAreEscaped(string argument) + { + Assert.NotNull(LoggerFactory); + Assert.Equal($"{nameof(LoggedTheoryNullArgumentsAreEscaped)}_null", ResolvedTestMethodName); + // Use the test argument + Assert.Null(argument); + } + + [Fact] + public void AdditionalSetupInvoked() + { + Assert.True(SetupInvoked); + } + } + + public class TestLoggedTest : LoggedTest + { + public bool SetupInvoked { get; private set; } = false; + + public override void AdditionalSetup() + { + SetupInvoked = true; + } + } +} diff --git a/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj b/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj new file mode 100644 index 0000000000..7d2170b241 --- /dev/null +++ b/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj @@ -0,0 +1,13 @@ + + + + + $(StandardTestTfms) + + + + + + + + diff --git a/src/Logging/Logging.Testing/test/TestTestOutputHelper.cs b/src/Logging/Logging.Testing/test/TestTestOutputHelper.cs new file mode 100644 index 0000000000..7043fe4ed2 --- /dev/null +++ b/src/Logging/Logging.Testing/test/TestTestOutputHelper.cs @@ -0,0 +1,36 @@ +// 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; +using System.Text; +using Xunit.Abstractions; + +namespace Microsoft.Extensions.Logging.Testing.Tests +{ + public class TestTestOutputHelper : ITestOutputHelper + { + private StringBuilder _output = new StringBuilder(); + + public bool Throw { get; set; } + + public string Output => _output.ToString(); + + public void WriteLine(string message) + { + if (Throw) + { + throw new Exception("Boom!"); + } + _output.AppendLine(message); + } + + public void WriteLine(string format, params object[] args) + { + if (Throw) + { + throw new Exception("Boom!"); + } + _output.AppendLine(string.Format(format, args)); + } + } +} diff --git a/src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs b/src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs new file mode 100644 index 0000000000..9720e15a09 --- /dev/null +++ b/src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs @@ -0,0 +1,87 @@ +// 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; +using System.Text.RegularExpressions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging.Test; +using Xunit; + +namespace Microsoft.Extensions.Logging.Testing.Tests +{ + public class XunitLoggerProviderTest + { + [Fact] + public void LoggerProviderWritesToTestOutputHelper() + { + var testTestOutputHelper = new TestTestOutputHelper(); + + var loggerFactory = TestLoggerBuilder.Create(builder => builder + .SetMinimumLevel(LogLevel.Trace) + .AddXunit(testTestOutputHelper)); + + var logger = loggerFactory.CreateLogger("TestCategory"); + logger.LogInformation("This is some great information"); + logger.LogTrace("This is some unimportant information"); + + var expectedOutput = + "| [TIMESTAMP] TestCategory Information: This is some great information" + Environment.NewLine + + "| [TIMESTAMP] TestCategory Trace: This is some unimportant information" + Environment.NewLine; + + Assert.Equal(expectedOutput, MakeConsistent(testTestOutputHelper.Output)); + } + + [Fact] + public void LoggerProviderDoesNotWriteLogMessagesBelowMinimumLevel() + { + var testTestOutputHelper = new TestTestOutputHelper(); + var loggerFactory = TestLoggerBuilder.Create(builder => builder + .AddXunit(testTestOutputHelper, LogLevel.Warning)); + + var logger = loggerFactory.CreateLogger("TestCategory"); + logger.LogInformation("This is some great information"); + logger.LogError("This is a bad error"); + + Assert.Equal("| [TIMESTAMP] TestCategory Error: This is a bad error" + Environment.NewLine, MakeConsistent(testTestOutputHelper.Output)); + } + + [Fact] + public void LoggerProviderPrependsPrefixToEachLine() + { + var testTestOutputHelper = new TestTestOutputHelper(); + var loggerFactory = TestLoggerBuilder.Create(builder => builder + .AddXunit(testTestOutputHelper)); + + var logger = loggerFactory.CreateLogger("TestCategory"); + logger.LogInformation("This is a" + Environment.NewLine + "multi-line" + Environment.NewLine + "message"); + + // The lines after the first one are indented more because the indentation was calculated based on the timestamp's actual length. + var expectedOutput = + "| [TIMESTAMP] TestCategory Information: This is a" + Environment.NewLine + + "| multi-line" + Environment.NewLine + + "| message" + Environment.NewLine; + + Assert.Equal(expectedOutput, MakeConsistent(testTestOutputHelper.Output)); + } + + [Fact] + public void LoggerProviderDoesNotThrowIfOutputHelperThrows() + { + var testTestOutputHelper = new TestTestOutputHelper(); + var loggerFactory = TestLoggerBuilder.Create(builder => builder + + .AddXunit(testTestOutputHelper)); + + testTestOutputHelper.Throw = true; + + var logger = loggerFactory.CreateLogger("TestCategory"); + logger.LogInformation("This is a" + Environment.NewLine + "multi-line" + Environment.NewLine + "message"); + + Assert.Equal(0, testTestOutputHelper.Output.Length); + } + + private static readonly Regex TimestampRegex = new Regex(@"\d+-\d+-\d+T\d+:\d+:\d+"); + + private string MakeConsistent(string input) => TimestampRegex.Replace(input, "TIMESTAMP"); + } +} From 08375cd15ce4e2fc4beb8b741eae3a5d1c462d40 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 6 Nov 2018 15:28:23 -0800 Subject: [PATCH 02/44] Reorganize source code in preparation to move into aspnet/Extensions Prior to reorganization, this source code was found in https://github.com/aspnet/Logging/tree/5381f42ded1f41a3b0960bba799aed53da411401 --- .../AzureAppServicesDiagnosticsSettings.cs | 1 + ...AzureAppServicesLoggerFactoryExtensions.cs | 3 + .../src/AzureBlobLoggerOptions.cs | 5 - .../src/Internal/BatchingLoggerOptions.cs | 7 +- .../Logging.Testing/src/AssemblyTestLog.cs | 119 +++++++++++------- src/Logging/Logging.Testing/src/LoggedTest.cs | 45 ------- .../src/LoggedTest/ILoggedTest.cs | 23 ++++ .../src/LoggedTest/LoggedTest.cs | 24 ++++ .../src/LoggedTest/LoggedTestBase.cs | 82 ++++++++++++ .../Logging.Testing/src/RetryContext.cs | 18 +++ .../src/TestFrameworkFileLoggerAttribute.cs | 20 +++ .../LoggedConditionalTheoryDiscoverer.cs | 14 +++ .../Xunit/LoggedTestFrameworkDiscoverer.cs | 2 +- .../src/Xunit/LoggedTestInvoker.cs | 81 ++++-------- .../src/Xunit/LoggedTestRunner.cs | 99 ++++++++++++++- .../src/Xunit/RetryTestAttribute.cs | 68 ++++++++++ .../src/XunitLoggerFactoryExtensions.cs | 12 ++ .../src/XunitLoggerProvider.cs | 16 ++- ...Microsoft.Extensions.Logging.Testing.props | 27 +++- .../test/AssemblyTestLogTests.cs | 71 ++++++----- .../test/LoggedTestXunitRetryTests.cs | 101 +++++++++++++++ .../test/LoggedTestXunitTests.cs | 20 ++- 22 files changed, 661 insertions(+), 197 deletions(-) delete mode 100644 src/Logging/Logging.Testing/src/LoggedTest.cs create mode 100644 src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs create mode 100644 src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs create mode 100644 src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs create mode 100644 src/Logging/Logging.Testing/src/RetryContext.cs create mode 100644 src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs create mode 100644 src/Logging/Logging.Testing/src/Xunit/RetryTestAttribute.cs create mode 100644 src/Logging/Logging.Testing/test/LoggedTestXunitRetryTests.cs diff --git a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesDiagnosticsSettings.cs b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesDiagnosticsSettings.cs index f48480c70f..f93538218f 100644 --- a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesDiagnosticsSettings.cs +++ b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesDiagnosticsSettings.cs @@ -8,6 +8,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices /// /// Settings for Azure diagnostics logging. /// + [Obsolete("This type is obsolete and will be removed in a future version. The recommended alternative is AzureBlobLoggerOptions.")] public class AzureAppServicesDiagnosticsSettings { private TimeSpan _blobCommitPeriod = TimeSpan.FromSeconds(5); diff --git a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs index 7970133d38..a0e73027fb 100644 --- a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs +++ b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs @@ -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; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -94,6 +95,7 @@ namespace Microsoft.Extensions.Logging /// Adds an Azure Web Apps diagnostics logger. /// /// The extension method argument + [Obsolete("This method is obsolete and will be removed in a future version. The recommended alternative is AddAzureWebAppDiagnostics(this ILoggingBuilder builder).")] public static ILoggerFactory AddAzureWebAppDiagnostics(this ILoggerFactory factory) { return AddAzureWebAppDiagnostics(factory, new AzureAppServicesDiagnosticsSettings()); @@ -104,6 +106,7 @@ namespace Microsoft.Extensions.Logging /// /// The extension method argument /// The setting object to configure loggers. + [Obsolete("This method is obsolete and will be removed in a future version. The recommended alternative is AddAzureWebAppDiagnostics(this ILoggingBuilder builder).")] public static ILoggerFactory AddAzureWebAppDiagnostics(this ILoggerFactory factory, AzureAppServicesDiagnosticsSettings settings) { var context = WebAppContext.Default; diff --git a/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs index eb466f4bb9..2f1285f8ac 100644 --- a/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs @@ -11,11 +11,6 @@ namespace Microsoft.Extensions.Logging.AzureAppServices /// public class AzureBlobLoggerOptions: BatchingLoggerOptions { - public AzureBlobLoggerOptions() - { - BatchSize = 32; - } - private string _blobName = "applicationLog.txt"; /// diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs index ccdf75e561..fbbb5cfd08 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs @@ -7,8 +7,8 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal { public class BatchingLoggerOptions { - private int? _batchSize = 32; - private int? _backgroundQueueSize; + private int? _batchSize; + private int? _backgroundQueueSize = 1000; private TimeSpan _flushPeriod = TimeSpan.FromSeconds(1); /// @@ -30,7 +30,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal /// /// Gets or sets the maximum size of the background log message queue or null for no limit. /// After maximum queue size is reached log event sink would start blocking. - /// Defaults to null. + /// Defaults to 1000. /// public int? BackgroundQueueSize { @@ -48,6 +48,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal /// /// Gets or sets a maximum number of events to include in a single batch or null for no limit. /// + /// Defaults to null. public int? BatchSize { get { return _batchSize; } diff --git a/src/Logging/Logging.Testing/src/AssemblyTestLog.cs b/src/Logging/Logging.Testing/src/AssemblyTestLog.cs index 97a67b11fa..e84df52554 100644 --- a/src/Logging/Logging.Testing/src/AssemblyTestLog.cs +++ b/src/Logging/Logging.Testing/src/AssemblyTestLog.cs @@ -8,10 +8,11 @@ using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Text; using Microsoft.Extensions.DependencyInjection; using Serilog; +using Serilog.Core; +using Serilog.Events; using Serilog.Extensions.Logging; using Xunit.Abstractions; @@ -19,7 +20,6 @@ namespace Microsoft.Extensions.Logging.Testing { public class AssemblyTestLog : IDisposable { - public static readonly string OutputDirectoryEnvironmentVariableName = "ASPNETCORE_TEST_LOG_DIR"; private static readonly string MaxPathLengthEnvironmentVariableName = "ASPNETCORE_TEST_LOG_MAXPATH"; private static readonly string LogFileExtension = ".log"; private static readonly int MaxPathLength = GetMaxPathLength(); @@ -38,7 +38,7 @@ namespace Microsoft.Extensions.Logging.Testing private readonly ILoggerFactory _globalLoggerFactory; private readonly ILogger _globalLogger; private readonly string _baseDirectory; - private readonly string _assemblyName; + private readonly Assembly _assembly; private readonly IServiceProvider _serviceProvider; private static int GetMaxPathLength() @@ -48,12 +48,12 @@ namespace Microsoft.Extensions.Logging.Testing return string.IsNullOrEmpty(maxPathString) ? defaultMaxPath : int.Parse(maxPathString); } - private AssemblyTestLog(ILoggerFactory globalLoggerFactory, ILogger globalLogger, string baseDirectory, string assemblyName, IServiceProvider serviceProvider) + private AssemblyTestLog(ILoggerFactory globalLoggerFactory, ILogger globalLogger, string baseDirectory, Assembly assembly, IServiceProvider serviceProvider) { _globalLoggerFactory = globalLoggerFactory; _globalLogger = globalLogger; _baseDirectory = baseDirectory; - _assemblyName = assemblyName; + _assembly = assembly; _serviceProvider = serviceProvider; } @@ -61,11 +61,12 @@ namespace Microsoft.Extensions.Logging.Testing StartTestLog(output, className, out loggerFactory, LogLevel.Debug, testName); public IDisposable StartTestLog(ITestOutputHelper output, string className, out ILoggerFactory loggerFactory, LogLevel minLogLevel, [CallerMemberName] string testName = null) => - StartTestLog(output, className, out loggerFactory, minLogLevel, out var _, testName); + StartTestLog(output, className, out loggerFactory, minLogLevel, out var _, out var _, testName); - internal IDisposable StartTestLog(ITestOutputHelper output, string className, out ILoggerFactory loggerFactory, LogLevel minLogLevel, out string resolvedTestName, [CallerMemberName] string testName = null) + internal IDisposable StartTestLog(ITestOutputHelper output, string className, out ILoggerFactory loggerFactory, LogLevel minLogLevel, out string resolvedTestName, out string logOutputDirectory, [CallerMemberName] string testName = null) { - var serviceProvider = CreateLoggerServices(output, className, minLogLevel, out resolvedTestName, testName); + var logStart = DateTimeOffset.UtcNow; + var serviceProvider = CreateLoggerServices(output, className, minLogLevel, out resolvedTestName, out logOutputDirectory, testName, logStart); var factory = serviceProvider.GetRequiredService(); loggerFactory = factory; var logger = loggerFactory.CreateLogger("TestLifetime"); @@ -75,7 +76,7 @@ namespace Microsoft.Extensions.Logging.Testing var scope = logger.BeginScope("Test: {testName}", testName); _globalLogger.LogInformation("Starting test {testName}", testName); - logger.LogInformation("Starting test {testName}", testName); + logger.LogInformation("Starting test {testName} at {logStart}", testName, logStart.ToString("s")); return new Disposable(() => { @@ -88,36 +89,39 @@ namespace Microsoft.Extensions.Logging.Testing }); } - public ILoggerFactory CreateLoggerFactory(ITestOutputHelper output, string className, [CallerMemberName] string testName = null) => - CreateLoggerFactory(output, className, LogLevel.Trace, testName); + public ILoggerFactory CreateLoggerFactory(ITestOutputHelper output, string className, [CallerMemberName] string testName = null, DateTimeOffset? logStart = null) + => CreateLoggerFactory(output, className, LogLevel.Trace, testName, logStart); - public ILoggerFactory CreateLoggerFactory(ITestOutputHelper output, string className, LogLevel minLogLevel, [CallerMemberName] string testName = null) - { - return CreateLoggerServices(output, className, minLogLevel, out var _, testName).GetRequiredService(); - } + public ILoggerFactory CreateLoggerFactory(ITestOutputHelper output, string className, LogLevel minLogLevel, [CallerMemberName] string testName = null, DateTimeOffset? logStart = null) + => CreateLoggerServices(output, className, minLogLevel, out var _, out var _, testName, logStart).GetRequiredService(); - public IServiceProvider CreateLoggerServices(ITestOutputHelper output, string className, LogLevel minLogLevel, out string normalizedTestName, [CallerMemberName] string testName = null) + public IServiceProvider CreateLoggerServices(ITestOutputHelper output, string className, LogLevel minLogLevel, out string normalizedTestName, [CallerMemberName] string testName = null, DateTimeOffset? logStart = null) + => CreateLoggerServices(output, className, minLogLevel, out normalizedTestName, out var _, testName, logStart); + + public IServiceProvider CreateLoggerServices(ITestOutputHelper output, string className, LogLevel minLogLevel, out string normalizedTestName, out string logOutputDirectory, [CallerMemberName] string testName = null, DateTimeOffset? logStart = null) { normalizedTestName = string.Empty; + logOutputDirectory = string.Empty; + var assemblyName = _assembly.GetName().Name; // Try to shorten the class name using the assembly name - if (className.StartsWith(_assemblyName + ".")) + if (className.StartsWith(assemblyName + ".")) { - className = className.Substring(_assemblyName.Length + 1); + className = className.Substring(assemblyName.Length + 1); } SerilogLoggerProvider serilogLoggerProvider = null; if (!string.IsNullOrEmpty(_baseDirectory)) { - var testOutputDirectory = Path.Combine(GetAssemblyBaseDirectory(_assemblyName, _baseDirectory), className); + logOutputDirectory = Path.Combine(GetAssemblyBaseDirectory(_baseDirectory, _assembly), className); testName = RemoveIllegalFileChars(testName); - if (testOutputDirectory.Length + testName.Length + LogFileExtension.Length >= MaxPathLength) + if (logOutputDirectory.Length + testName.Length + LogFileExtension.Length >= MaxPathLength) { _globalLogger.LogWarning($"Test name {testName} is too long. Please shorten test name."); // Shorten the test name by removing the middle portion of the testname - var testNameLength = MaxPathLength - testOutputDirectory.Length - LogFileExtension.Length; + var testNameLength = MaxPathLength - logOutputDirectory.Length - LogFileExtension.Length; if (testNameLength <= 0) { @@ -129,7 +133,7 @@ namespace Microsoft.Extensions.Logging.Testing _globalLogger.LogWarning($"To prevent long paths test name was shortened to {testName}."); } - var testOutputFile = Path.Combine(testOutputDirectory, $"{testName}{LogFileExtension}"); + var testOutputFile = Path.Combine(logOutputDirectory, $"{testName}{LogFileExtension}"); if (File.Exists(testOutputFile)) { @@ -137,7 +141,7 @@ namespace Microsoft.Extensions.Logging.Testing for (var i = 0; i < 1000; i++) { - testOutputFile = Path.Combine(testOutputDirectory, $"{testName}.{i}{LogFileExtension}"); + testOutputFile = Path.Combine(logOutputDirectory, $"{testName}.{i}{LogFileExtension}"); if (!File.Exists(testOutputFile)) { @@ -149,7 +153,7 @@ namespace Microsoft.Extensions.Logging.Testing } normalizedTestName = testName; - serilogLoggerProvider = ConfigureFileLogging(testOutputFile); + serilogLoggerProvider = ConfigureFileLogging(testOutputFile, logStart); } var serviceCollection = new ServiceCollection(); @@ -159,7 +163,7 @@ namespace Microsoft.Extensions.Logging.Testing if (output != null) { - builder.AddXunit(output, minLogLevel); + builder.AddXunit(output, minLogLevel, logStart); } if (serilogLoggerProvider != null) @@ -172,14 +176,19 @@ namespace Microsoft.Extensions.Logging.Testing return serviceCollection.BuildServiceProvider(); } + // For back compat public static AssemblyTestLog Create(string assemblyName, string baseDirectory) + => Create(Assembly.Load(new AssemblyName(assemblyName)), baseDirectory); + + public static AssemblyTestLog Create(Assembly assembly, string baseDirectory) { + var logStart = DateTimeOffset.UtcNow; SerilogLoggerProvider serilogLoggerProvider = null; - var globalLogDirectory = GetAssemblyBaseDirectory(assemblyName, baseDirectory); + var globalLogDirectory = GetAssemblyBaseDirectory(baseDirectory, assembly); if (!string.IsNullOrEmpty(globalLogDirectory)) { var globalLogFileName = Path.Combine(globalLogDirectory, "global.log"); - serilogLoggerProvider = ConfigureFileLogging(globalLogFileName); + serilogLoggerProvider = ConfigureFileLogging(globalLogFileName, logStart); } var serviceCollection = new ServiceCollection(); @@ -200,8 +209,11 @@ namespace Microsoft.Extensions.Logging.Testing var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger("GlobalTestLog"); - logger.LogInformation($"Global Test Logging initialized. Set the '{OutputDirectoryEnvironmentVariableName}' Environment Variable in order to create log files on disk."); - return new AssemblyTestLog(loggerFactory, logger, baseDirectory, assemblyName, serviceProvider); + logger.LogInformation("Global Test Logging initialized at {logStart}. " + + "Configure the output directory via 'LoggingTestingFileLoggingDirectory' MSBuild property " + + "or set 'LoggingTestingDisableFileLogging' to 'true' to disable file logging.", + logStart.ToString("s")); + return new AssemblyTestLog(loggerFactory, logger, baseDirectory, assembly, serviceProvider); } public static AssemblyTestLog ForAssembly(Assembly assembly) @@ -210,13 +222,13 @@ namespace Microsoft.Extensions.Logging.Testing { if (!_logs.TryGetValue(assembly, out var log)) { - var assemblyName = assembly.GetName().Name; - var baseDirectory = Environment.GetEnvironmentVariable(OutputDirectoryEnvironmentVariableName); - log = Create(assemblyName, baseDirectory); + var baseDirectory = GetFileLoggerAttribute(assembly).BaseDirectory; + + log = Create(assembly, baseDirectory); _logs[assembly] = log; // Try to clear previous logs - var assemblyBaseDirectory = GetAssemblyBaseDirectory(assemblyName, baseDirectory); + var assemblyBaseDirectory = GetAssemblyBaseDirectory(baseDirectory, assembly); if (Directory.Exists(assemblyBaseDirectory)) { try @@ -230,16 +242,18 @@ namespace Microsoft.Extensions.Logging.Testing } } - private static string GetAssemblyBaseDirectory(string assemblyName, string baseDirectory) - { - if (!string.IsNullOrEmpty(baseDirectory)) - { - return Path.Combine(baseDirectory, assemblyName, RuntimeInformation.FrameworkDescription.TrimStart('.')); - } - return string.Empty; - } + private static string GetAssemblyBaseDirectory(string baseDirectory, Assembly assembly) + => string.IsNullOrEmpty(baseDirectory) + ? string.Empty + : Path.Combine(baseDirectory, assembly.GetName().Name, GetFileLoggerAttribute(assembly).TFM); - private static SerilogLoggerProvider ConfigureFileLogging(string fileName) + private static TestFrameworkFileLoggerAttribute GetFileLoggerAttribute(Assembly assembly) + => assembly.GetCustomAttribute() + ?? throw new InvalidOperationException($"No {nameof(TestFrameworkFileLoggerAttribute)} found on the assembly {assembly.GetName().Name}. " + + "The attribute is added via msbuild properties of the Microsoft.Extensions.Logging.Testing. " + + "Please ensure the msbuild property is imported or a direct reference to Microsoft.Extensions.Logging.Testing is added."); + + private static SerilogLoggerProvider ConfigureFileLogging(string fileName, DateTimeOffset? logStart) { var dir = Path.GetDirectoryName(fileName); if (!Directory.Exists(dir)) @@ -254,8 +268,9 @@ namespace Microsoft.Extensions.Logging.Testing var serilogger = new LoggerConfiguration() .Enrich.FromLogContext() + .Enrich.With(new AssemblyLogTimestampOffsetEnricher(logStart)) .MinimumLevel.Verbose() - .WriteTo.File(fileName, outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{SourceContext}] [{Level}] {Message}{NewLine}{Exception}", flushToDiskInterval: TimeSpan.FromSeconds(1), shared: true) + .WriteTo.File(fileName, outputTemplate: "[{TimestampOffset}] [{SourceContext}] [{Level}] {Message:l}{NewLine}{Exception}", flushToDiskInterval: TimeSpan.FromSeconds(1), shared: true) .CreateLogger(); return new SerilogLoggerProvider(serilogger, dispose: true); } @@ -287,6 +302,24 @@ namespace Microsoft.Extensions.Logging.Testing _globalLoggerFactory.Dispose(); } + private class AssemblyLogTimestampOffsetEnricher : ILogEventEnricher + { + private DateTimeOffset? _logStart; + + public AssemblyLogTimestampOffsetEnricher(DateTimeOffset? logStart) + { + _logStart = logStart; + } + + public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) + => logEvent.AddPropertyIfAbsent( + propertyFactory.CreateProperty( + "TimestampOffset", + _logStart.HasValue + ? $"{(DateTimeOffset.UtcNow - _logStart.Value).TotalSeconds.ToString("N3")}s" + : DateTimeOffset.UtcNow.ToString("s"))); + } + private class Disposable : IDisposable { private Action _action; diff --git a/src/Logging/Logging.Testing/src/LoggedTest.cs b/src/Logging/Logging.Testing/src/LoggedTest.cs deleted file mode 100644 index 58fcc1fb3e..0000000000 --- a/src/Logging/Logging.Testing/src/LoggedTest.cs +++ /dev/null @@ -1,45 +0,0 @@ -// 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; -using System.Reflection; -using System.Runtime.CompilerServices; -using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; - -namespace Microsoft.Extensions.Logging.Testing -{ - public abstract class LoggedTest - { - // Obsolete but keeping for back compat - public LoggedTest(ITestOutputHelper output = null) - { - TestOutputHelper = output; - } - - // Internal for testing - internal string ResolvedTestMethodName { get; set; } - - // Internal for testing - internal string ResolvedTestClassName { get; set; } - - public ILogger Logger { get; set; } - - public ILoggerFactory LoggerFactory { get; set; } - - public ITestOutputHelper TestOutputHelper { get; set; } - - public ITestSink TestSink { get; set; } - - public void AddTestLogging(IServiceCollection services) => services.AddSingleton(LoggerFactory); - - public IDisposable StartLog(out ILoggerFactory loggerFactory, [CallerMemberName] string testName = null) => StartLog(out loggerFactory, LogLevel.Information, testName); - - public IDisposable StartLog(out ILoggerFactory loggerFactory, LogLevel minLogLevel, [CallerMemberName] string testName = null) - { - return AssemblyTestLog.ForAssembly(GetType().GetTypeInfo().Assembly).StartTestLog(TestOutputHelper, GetType().FullName, out loggerFactory, minLogLevel, testName); - } - - public virtual void AdditionalSetup() { } - } -} diff --git a/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs b/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs new file mode 100644 index 0000000000..a563cbdaf9 --- /dev/null +++ b/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs @@ -0,0 +1,23 @@ +// 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; +using System.Reflection; +using Xunit.Abstractions; + +namespace Microsoft.Extensions.Logging.Testing +{ + public interface ILoggedTest : IDisposable + { + ILogger Logger { get; } + + ILoggerFactory LoggerFactory { get; } + + ITestOutputHelper TestOutputHelper { get; } + + // For back compat + IDisposable StartLog(out ILoggerFactory loggerFactory, LogLevel minLogLevel, string testName); + + void Initialize(MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper); + } +} diff --git a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs new file mode 100644 index 0000000000..64a9adec06 --- /dev/null +++ b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs @@ -0,0 +1,24 @@ +// 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.Reflection; +using Xunit.Abstractions; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTest : LoggedTestBase + { + // Obsolete but keeping for back compat + public LoggedTest(ITestOutputHelper output = null) : base (output) { } + + public ITestSink TestSink { get; set; } + + public override void Initialize(MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) + { + base.Initialize(methodInfo, testMethodArguments, testOutputHelper); + + TestSink = new TestSink(); + LoggerFactory.AddProvider(new TestLoggerProvider(TestSink)); + } + } +} diff --git a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs new file mode 100644 index 0000000000..f714a632a4 --- /dev/null +++ b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs @@ -0,0 +1,82 @@ +// 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; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.Extensions.DependencyInjection; +using Xunit.Abstractions; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class LoggedTestBase : ILoggedTest + { + private IDisposable _testLog; + + // Obsolete but keeping for back compat + public LoggedTestBase(ITestOutputHelper output = null) + { + TestOutputHelper = output; + } + + // Internal for testing + internal string ResolvedTestClassName { get; set; } + + internal RetryContext RetryContext { get; set; } + + public string ResolvedLogOutputDirectory { get; set; } + + public string ResolvedTestMethodName { get; set; } + + public ILogger Logger { get; set; } + + public ILoggerFactory LoggerFactory { get; set; } + + public ITestOutputHelper TestOutputHelper { get; set; } + + public void AddTestLogging(IServiceCollection services) => services.AddSingleton(LoggerFactory); + + // For back compat + public IDisposable StartLog(out ILoggerFactory loggerFactory, [CallerMemberName] string testName = null) => StartLog(out loggerFactory, LogLevel.Debug, testName); + + // For back compat + public IDisposable StartLog(out ILoggerFactory loggerFactory, LogLevel minLogLevel, [CallerMemberName] string testName = null) + { + return AssemblyTestLog.ForAssembly(GetType().GetTypeInfo().Assembly).StartTestLog(TestOutputHelper, GetType().FullName, out loggerFactory, minLogLevel, testName); + } + + public virtual void Initialize(MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) + { + TestOutputHelper = testOutputHelper; + + var classType = GetType(); + var logLevelAttribute = methodInfo.GetCustomAttribute(); + var testName = testMethodArguments.Aggregate(methodInfo.Name, (a, b) => $"{a}-{(b ?? "null")}"); + + var useShortClassName = methodInfo.DeclaringType.GetCustomAttribute() + ?? methodInfo.DeclaringType.Assembly.GetCustomAttribute(); + // internal for testing + ResolvedTestClassName = useShortClassName == null ? classType.FullName : classType.Name; + + _testLog = AssemblyTestLog + .ForAssembly(classType.GetTypeInfo().Assembly) + .StartTestLog( + TestOutputHelper, + ResolvedTestClassName, + out var loggerFactory, + logLevelAttribute?.LogLevel ?? LogLevel.Debug, + out var resolvedTestName, + out var logOutputDirectory, + testName); + + ResolvedLogOutputDirectory = logOutputDirectory; + ResolvedTestMethodName = resolvedTestName; + + LoggerFactory = loggerFactory; + Logger = loggerFactory.CreateLogger(classType); + } + + public virtual void Dispose() => _testLog.Dispose(); + } +} diff --git a/src/Logging/Logging.Testing/src/RetryContext.cs b/src/Logging/Logging.Testing/src/RetryContext.cs new file mode 100644 index 0000000000..2a774cfd3e --- /dev/null +++ b/src/Logging/Logging.Testing/src/RetryContext.cs @@ -0,0 +1,18 @@ +// 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; + +namespace Microsoft.Extensions.Logging.Testing +{ + public class RetryContext + { + internal int Limit { get; set; } + + internal object TestClassInstance { get; set; } + + internal string Reason { get; set; } + + internal int CurrentIteration { get; set; } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs b/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs new file mode 100644 index 0000000000..32d8f30584 --- /dev/null +++ b/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs @@ -0,0 +1,20 @@ +// 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; + +namespace Microsoft.Extensions.Logging.Testing +{ + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] + public class TestFrameworkFileLoggerAttribute : Attribute + { + public TestFrameworkFileLoggerAttribute(string tfm, string baseDirectory = null) + { + TFM = tfm; + BaseDirectory = baseDirectory; + } + + public string TFM { get; } + public string BaseDirectory { get; } + } +} \ No newline at end of file diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs index da5685bbfc..d239b1147c 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs @@ -32,6 +32,20 @@ namespace Microsoft.Extensions.Logging.Testing object[] dataRow) { var skipReason = testMethod.EvaluateSkipConditions(); + if (skipReason == null && dataRow?.Length > 0) + { + var obj = dataRow[0]; + if (obj != null) + { + var type = obj.GetType(); + var property = type.GetProperty("Skip"); + if (property != null && property.PropertyType.Equals(typeof(string))) + { + skipReason = property.GetValue(obj) as string; + } + } + } + return skipReason != null ? base.CreateTestCasesForSkippedDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow, skipReason) : base.CreateTestCasesForDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow); diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs index bc02355c87..4b1668ce95 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs @@ -37,7 +37,7 @@ namespace Microsoft.Extensions.Logging.Testing IMessageBus messageBus, ITestFrameworkDiscoveryOptions discoveryOptions) { - if (typeof(LoggedTest).IsAssignableFrom(testMethod.TestClass.Class.ToRuntimeType())) + if (typeof(ILoggedTest).IsAssignableFrom(testMethod.TestClass.Class.ToRuntimeType())) { var factAttributes = testMethod.Method.GetCustomAttributes(typeof(FactAttribute)); if (factAttributes.Count() > 1) diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs index 09fe03c2b7..708db37105 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading; -using System.Threading.Tasks; using Xunit.Abstractions; using Xunit.Sdk; @@ -14,7 +13,8 @@ namespace Microsoft.Extensions.Logging.Testing { public class LoggedTestInvoker : XunitTestInvoker { - private TestOutputHelper _output; + private readonly ITestOutputHelper _output; + private readonly RetryContext _retryContext; public LoggedTestInvoker( ITest test, @@ -25,73 +25,40 @@ namespace Microsoft.Extensions.Logging.Testing object[] testMethodArguments, IReadOnlyList beforeAfterAttributes, ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) + CancellationTokenSource cancellationTokenSource, + ITestOutputHelper output, + RetryContext retryContext) : base(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, beforeAfterAttributes, aggregator, cancellationTokenSource) { - } - - protected override Task BeforeTestMethodInvokedAsync() - { - if (_output != null) - { - _output.Initialize(MessageBus, Test); - } - - return base.BeforeTestMethodInvokedAsync(); - } - - protected override async Task AfterTestMethodInvokedAsync() - { - await base.AfterTestMethodInvokedAsync(); - - if (_output != null) - { - _output.Uninitialize(); - } + _output = output; + _retryContext = retryContext; } protected override object CreateTestClass() { var testClass = base.CreateTestClass(); - if (testClass is LoggedTest loggedTestClass) + (testClass as ILoggedTest).Initialize( + TestMethod, + TestMethodArguments, + _output ?? ConstructorArguments.SingleOrDefault(a => typeof(ITestOutputHelper).IsAssignableFrom(a.GetType())) as ITestOutputHelper); + + if (testClass is LoggedTestBase loggedTestBase) { - var classType = loggedTestClass.GetType(); - var logLevelAttribute = TestMethod.GetCustomAttribute() as LogLevelAttribute; - var testName = TestMethodArguments.Aggregate(TestMethod.Name, (a, b) => $"{a}-{(b ?? "null")}"); + // Used for testing + loggedTestBase.RetryContext = _retryContext; - // Try resolving ITestOutputHelper from constructor arguments - loggedTestClass.TestOutputHelper = ConstructorArguments?.SingleOrDefault(a => typeof(ITestOutputHelper).IsAssignableFrom(a.GetType())) as ITestOutputHelper; - - var useShortClassName = TestMethod.DeclaringType.GetCustomAttribute() - ?? TestMethod.DeclaringType.Assembly.GetCustomAttribute(); - var resolvedClassName = useShortClassName == null ? classType.FullName : classType.Name; - // None resolved so create a new one and retain a reference to it for initialization/uninitialization - if (loggedTestClass.TestOutputHelper == null) + if (_retryContext != null) { - loggedTestClass.TestOutputHelper = _output = new TestOutputHelper(); + // Log retry attempt as warning + if (_retryContext.CurrentIteration > 0) + { + loggedTestBase.Logger.LogWarning($"{TestMethod.Name} failed and retry conditions are met, re-executing. The reason for failure is {_retryContext.Reason}."); + } + + // Save the test class instance for non-static predicates + _retryContext.TestClassInstance = testClass; } - - AssemblyTestLog - .ForAssembly(classType.GetTypeInfo().Assembly) - .StartTestLog( - loggedTestClass.TestOutputHelper, - resolvedClassName, - out var loggerFactory, - logLevelAttribute?.LogLevel ?? LogLevel.Trace, - out var resolvedTestName, - testName); - - // internal for testing - loggedTestClass.ResolvedTestMethodName = resolvedTestName; - loggedTestClass.ResolvedTestClassName = resolvedClassName; - - loggedTestClass.LoggerFactory = loggerFactory; - loggedTestClass.Logger = loggerFactory.CreateLogger(classType); - loggedTestClass.TestSink = new TestSink(); - loggerFactory.AddProvider(new TestLoggerProvider(loggedTestClass.TestSink)); - - loggedTestClass.AdditionalSetup(); } return testClass; diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs index 07ad0978d2..909ea10a6b 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs @@ -3,9 +3,13 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; +using Microsoft.Extensions.Logging.Testing; using Xunit.Abstractions; using Xunit.Sdk; @@ -27,7 +31,100 @@ namespace Microsoft.Extensions.Logging.Testing { } + protected async override Task> InvokeTestAsync(ExceptionAggregator aggregator) + { + var testOutputHelper = ConstructorArguments.SingleOrDefault(a => typeof(TestOutputHelper).IsAssignableFrom(a.GetType())) as TestOutputHelper + ?? new TestOutputHelper(); + testOutputHelper.Initialize(MessageBus, Test); + + var executionTime = await InvokeTestMethodAsync(aggregator, testOutputHelper); + + var output = testOutputHelper.Output; + testOutputHelper.Uninitialize(); + + return Tuple.Create(executionTime, output); + } + protected override Task InvokeTestMethodAsync(ExceptionAggregator aggregator) - => new LoggedTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, aggregator, CancellationTokenSource).RunAsync(); + => InvokeTestMethodAsync(aggregator, null); + + private async Task InvokeTestMethodAsync(ExceptionAggregator aggregator, ITestOutputHelper output) + { + var retryAttribute = GetRetryAttribute(TestMethod); + if (!typeof(LoggedTestBase).IsAssignableFrom(TestClass) || retryAttribute == null) + { + return await new LoggedTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, aggregator, CancellationTokenSource, output, null).RunAsync(); + } + + var retryPredicateMethodName = retryAttribute.RetryPredicateName; + var retryPredicateMethod = TestClass.GetMethod(retryPredicateMethodName, + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static, + null, + new Type[] { typeof(Exception) }, + null) + ?? throw new InvalidOperationException($"No valid static retry predicate method {retryPredicateMethodName} was found on the type {TestClass.FullName}."); + + if (retryPredicateMethod.ReturnType != typeof(bool)) + { + throw new InvalidOperationException($"Retry predicate method {retryPredicateMethodName} on {TestClass.FullName} does not return bool."); + } + + var retryContext = new RetryContext() + { + Limit = retryAttribute.RetryLimit, + Reason = retryAttribute.RetryReason, + }; + + var retryAggregator = new ExceptionAggregator(); + var loggedTestInvoker = new LoggedTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, retryAggregator, CancellationTokenSource, output, retryContext); + var totalTime = 0.0M; + + do + { + retryAggregator.Clear(); + totalTime += await loggedTestInvoker.RunAsync(); + retryContext.CurrentIteration++; + } + while (retryAggregator.HasExceptions + && retryContext.CurrentIteration < retryContext.Limit + && (retryPredicateMethod.IsStatic + ? (bool)retryPredicateMethod.Invoke(null, new object[] { retryAggregator.ToException() }) + : (bool)retryPredicateMethod.Invoke(retryContext.TestClassInstance, new object[] { retryAggregator.ToException() })) + ); + + aggregator.Aggregate(retryAggregator); + return totalTime; + } + + + private RetryTestAttribute GetRetryAttribute(MethodInfo methodInfo) + { + var os = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? OperatingSystems.MacOSX + : RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? OperatingSystems.Windows + : OperatingSystems.Linux; + + var attributeCandidate = methodInfo.GetCustomAttribute(); + + if (attributeCandidate != null && (attributeCandidate.OperatingSystems & os) != 0) + { + return attributeCandidate; + } + + attributeCandidate = methodInfo.DeclaringType.GetCustomAttribute(); + + if (attributeCandidate != null && (attributeCandidate.OperatingSystems & os) != 0) + { + return attributeCandidate; + } + + attributeCandidate = methodInfo.DeclaringType.Assembly.GetCustomAttribute(); + + if (attributeCandidate != null && (attributeCandidate.OperatingSystems & os) != 0) + { + return attributeCandidate; + } + + return null; + } } } diff --git a/src/Logging/Logging.Testing/src/Xunit/RetryTestAttribute.cs b/src/Logging/Logging.Testing/src/Xunit/RetryTestAttribute.cs new file mode 100644 index 0000000000..e85f2c517e --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/RetryTestAttribute.cs @@ -0,0 +1,68 @@ +// 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; +using System.ComponentModel; +using Microsoft.AspNetCore.Testing.xunit; + +namespace Microsoft.Extensions.Logging.Testing +{ + /// + /// WARNING: This attribute should only be used on well understood flaky test failures caused by external issues and should be removed once the underlying issues have been resolved. + /// This is not intended to be a long term solution to ensure passing of flaky tests but instead a method to improve test reliability without reducing coverage. + /// Issues should be filed to remove these attributes from affected tests as soon as the underlying issue is fixed. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)] + public class RetryTestAttribute : Attribute + { + /// + /// WARNING: This attribute should only be used on well understood flaky test failures caused by external issues and should be removed once the underlying issues have been resolved. + /// This is not intended to be a long term solution to ensure passing of flaky tests but instead a method to improve test reliability without reducing coverage. + /// Issues should be filed to remove these attributes from affected tests as soon as the underlying issue is fixed. + /// + /// The predicate of the format Func<Exception,bool> that is used to determine if the test should be retried + /// The reason for retrying the test + /// The number of retries to attempt before failing the test, for most purposes this this should be kept at 2 to avoid excessive retries. + public RetryTestAttribute(string retryPredicateName, string retryReason, int retryLimit = 2) + : this(retryPredicateName, retryReason, OperatingSystems.Linux | OperatingSystems.MacOSX | OperatingSystems.Windows, retryLimit) { } + + /// + /// WARNING: This attribute should only be used on well understood flaky test failures caused by external issuesand should be removed once the underlying issues have been resolved. + /// This is not intended to be a long term solution to ensure passing of flaky tests but instead a method to improve test reliability without reducing coverage. + /// Issues should be filed to remove these attributes from affected tests as soon as the underlying issue is fixed. + /// + /// The os(es) this retry should be attempted on. + /// The predicate of the format Func<Exception,bool> that is used to determine if the test should be retried + /// The reason for retrying the test + /// The number of retries to attempt before failing the test, for most purposes this this should be kept at 2 to avoid excessive retries. + public RetryTestAttribute(string retryPredicateName, string retryReason, OperatingSystems operatingSystems, int retryLimit = 2) + { + if (string.IsNullOrEmpty(retryPredicateName)) + { + throw new ArgumentNullException(nameof(RetryPredicateName), "A valid non-empty predicate method name must be provided."); + } + if (string.IsNullOrEmpty(retryReason)) + { + throw new ArgumentNullException(nameof(retryReason), "A valid non-empty reason for retrying the test must be provided."); + } + if (retryLimit < 1) + { + throw new ArgumentOutOfRangeException(nameof(retryLimit), retryLimit, "Retry count must be positive."); + } + + OperatingSystems = operatingSystems; + RetryPredicateName = retryPredicateName; + RetryReason = retryReason; + RetryLimit = retryLimit; + } + + public string RetryPredicateName { get; } + + public string RetryReason { get; } + + public int RetryLimit { get; } + + public OperatingSystems OperatingSystems { get; } + } +} diff --git a/src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs b/src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs index 498ef39c35..f646a68e58 100644 --- a/src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs +++ b/src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs @@ -22,6 +22,12 @@ namespace Microsoft.Extensions.Logging return builder; } + public static ILoggingBuilder AddXunit(this ILoggingBuilder builder, ITestOutputHelper output, LogLevel minLevel, DateTimeOffset? logStart) + { + builder.Services.AddSingleton(new XunitLoggerProvider(output, minLevel, logStart)); + return builder; + } + public static ILoggerFactory AddXunit(this ILoggerFactory loggerFactory, ITestOutputHelper output) { loggerFactory.AddProvider(new XunitLoggerProvider(output)); @@ -33,5 +39,11 @@ namespace Microsoft.Extensions.Logging loggerFactory.AddProvider(new XunitLoggerProvider(output, minLevel)); return loggerFactory; } + + public static ILoggerFactory AddXunit(this ILoggerFactory loggerFactory, ITestOutputHelper output, LogLevel minLevel, DateTimeOffset? logStart) + { + loggerFactory.AddProvider(new XunitLoggerProvider(output, minLevel, logStart)); + return loggerFactory; + } } } diff --git a/src/Logging/Logging.Testing/src/XunitLoggerProvider.cs b/src/Logging/Logging.Testing/src/XunitLoggerProvider.cs index 60ca147a30..8e28d6a19f 100644 --- a/src/Logging/Logging.Testing/src/XunitLoggerProvider.cs +++ b/src/Logging/Logging.Testing/src/XunitLoggerProvider.cs @@ -12,6 +12,7 @@ namespace Microsoft.Extensions.Logging.Testing { private readonly ITestOutputHelper _output; private readonly LogLevel _minLevel; + private readonly DateTimeOffset? _logStart; public XunitLoggerProvider(ITestOutputHelper output) : this(output, LogLevel.Trace) @@ -19,14 +20,20 @@ namespace Microsoft.Extensions.Logging.Testing } public XunitLoggerProvider(ITestOutputHelper output, LogLevel minLevel) + : this(output, minLevel, null) + { + } + + public XunitLoggerProvider(ITestOutputHelper output, LogLevel minLevel, DateTimeOffset? logStart) { _output = output; _minLevel = minLevel; + _logStart = logStart; } public ILogger CreateLogger(string categoryName) { - return new XunitLogger(_output, categoryName, _minLevel); + return new XunitLogger(_output, categoryName, _minLevel, _logStart); } public void Dispose() @@ -40,12 +47,14 @@ namespace Microsoft.Extensions.Logging.Testing private readonly string _category; private readonly LogLevel _minLogLevel; private readonly ITestOutputHelper _output; + private DateTimeOffset? _logStart; - public XunitLogger(ITestOutputHelper output, string category, LogLevel minLogLevel) + public XunitLogger(ITestOutputHelper output, string category, LogLevel minLogLevel, DateTimeOffset? logStart) { _minLogLevel = minLogLevel; _category = category; _output = output; + _logStart = logStart; } public void Log( @@ -59,7 +68,8 @@ namespace Microsoft.Extensions.Logging.Testing // Buffer the message into a single string in order to avoid shearing the message when running across multiple threads. var messageBuilder = new StringBuilder(); - var timestamp = DateTime.Now.ToString("s"); + var timestamp = _logStart.HasValue ? $"{(DateTimeOffset.UtcNow - _logStart.Value).TotalSeconds.ToString("N3")}s" : DateTimeOffset.UtcNow.ToString("s"); + var firstLinePrefix = $"| [{timestamp}] {_category} {logLevel}: "; var lines = formatter(state, exception).Split(NewLineChars, StringSplitOptions.RemoveEmptyEntries); messageBuilder.AppendLine(firstLinePrefix + lines.FirstOrDefault() ?? string.Empty); diff --git a/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props b/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props index f98e3e13b5..0d2585146c 100644 --- a/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props +++ b/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props @@ -1,8 +1,23 @@  - - - <_Parameter1>Microsoft.Extensions.Logging.Testing.LoggedTestFramework - <_Parameter2>Microsoft.Extensions.Logging.Testing - - + + + $(ASPNETCORE_TEST_LOG_DIR) + $(RepositoryRoot)artifacts\logs\ + + + + + + <_Parameter1>Microsoft.Extensions.Logging.Testing.LoggedTestFramework + <_Parameter2>Microsoft.Extensions.Logging.Testing + + + + <_Parameter1>$(TargetFramework) + <_Parameter2 Condition="'$(LoggingTestingDisableFileLogging)' != 'true'">$(LoggingTestingFileLoggingDirectory) + + + \ No newline at end of file diff --git a/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs b/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs index 0efadb4367..20f597defc 100644 --- a/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs +++ b/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs @@ -6,7 +6,6 @@ using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Threading.Tasks; using Xunit; @@ -15,7 +14,9 @@ namespace Microsoft.Extensions.Logging.Testing.Tests { public class AssemblyTestLogTests : LoggedTest { - private static readonly Assembly ThisAssembly = typeof(AssemblyTestLog).GetTypeInfo().Assembly; + private static readonly Assembly ThisAssembly = typeof(AssemblyTestLogTests).GetTypeInfo().Assembly; + private static readonly string ThisAssemblyName = ThisAssembly.GetName().Name; + private static readonly string TFM = new DirectoryInfo(AppContext.BaseDirectory).Name; [Fact] public void FullClassNameUsedWhenShortClassNameAttributeNotSpecified() @@ -35,7 +36,7 @@ namespace Microsoft.Extensions.Logging.Testing.Tests public void TestLogWritesToITestOutputHelper() { var output = new TestTestOutputHelper(); - var assemblyLog = AssemblyTestLog.Create("NonExistant.Test.Assembly", baseDirectory: null); + var assemblyLog = AssemblyTestLog.Create(ThisAssemblyName, baseDirectory: null); using (assemblyLog.StartTestLog(output, "NonExistant.Test.Class", out var loggerFactory)) { @@ -46,20 +47,23 @@ namespace Microsoft.Extensions.Logging.Testing.Tests logger.LogTrace("Trace!"); } - Assert.Equal(@"[TIMESTAMP] TestLifetime Information: Starting test TestLogWritesToITestOutputHelper -[TIMESTAMP] TestLogger Information: Information! -[TIMESTAMP] TestLifetime Information: Finished test TestLogWritesToITestOutputHelper in DURATION -", MakeConsistent(output.Output), ignoreLineEndingDifferences: true); + var testLogContent = MakeConsistent(output.Output); + + Assert.Equal( +@"[OFFSET] TestLifetime Information: Starting test TestLogWritesToITestOutputHelper at TIMESTAMP +[OFFSET] TestLogger Information: Information! +[OFFSET] TestLifetime Information: Finished test TestLogWritesToITestOutputHelper in DURATION +", testLogContent, ignoreLineEndingDifferences: true); } [Fact] private Task TestLogEscapesIllegalFileNames() => RunTestLogFunctionalTest((tempDir) => { - var illegalTestName = "Testing-https://localhost:5000"; - var escapedTestName = "Testing-https_localhost_5000"; - using (var testAssemblyLog = AssemblyTestLog.Create("FakeTestAssembly", baseDirectory: tempDir)) - using (testAssemblyLog.StartTestLog(output: null, className: "FakeTestAssembly.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, resolvedTestName: out var resolvedTestname, testName: illegalTestName)) + var illegalTestName = "T:e/s//t"; + var escapedTestName = "T_e_s_t"; + using (var testAssemblyLog = AssemblyTestLog.Create(ThisAssemblyName, baseDirectory: tempDir)) + using (testAssemblyLog.StartTestLog(output: null, className: "FakeTestAssembly.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, resolvedTestName: out var resolvedTestname, out var _, testName: illegalTestName)) { Assert.Equal(escapedTestName, resolvedTestname); } @@ -73,11 +77,11 @@ namespace Microsoft.Extensions.Logging.Testing.Tests // but it's also testing the test logging facility. So this is pretty meta ;) var logger = LoggerFactory.CreateLogger("Test"); - using (var testAssemblyLog = AssemblyTestLog.Create("FakeTestAssembly", tempDir)) + using (var testAssemblyLog = AssemblyTestLog.Create(ThisAssemblyName, tempDir)) { logger.LogInformation("Created test log in {baseDirectory}", tempDir); - using (testAssemblyLog.StartTestLog(output: null, className: "FakeTestAssembly.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, testName: "FakeTestName")) + using (testAssemblyLog.StartTestLog(output: null, className: $"{ThisAssemblyName}.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, testName: "FakeTestName")) { var testLogger = testLoggerFactory.CreateLogger("TestLogger"); testLogger.LogInformation("Information!"); @@ -87,8 +91,8 @@ namespace Microsoft.Extensions.Logging.Testing.Tests logger.LogInformation("Finished test log in {baseDirectory}", tempDir); - var globalLogPath = Path.Combine(tempDir, "FakeTestAssembly", RuntimeInformation.FrameworkDescription.TrimStart('.'), "global.log"); - var testLog = Path.Combine(tempDir, "FakeTestAssembly", RuntimeInformation.FrameworkDescription.TrimStart('.'), "FakeTestClass", $"FakeTestName.log"); + var globalLogPath = Path.Combine(tempDir, ThisAssemblyName, TFM, "global.log"); + var testLog = Path.Combine(tempDir, ThisAssemblyName, TFM, "FakeTestClass", "FakeTestName.log"); Assert.True(File.Exists(globalLogPath), $"Expected global log file {globalLogPath} to exist"); Assert.True(File.Exists(testLog), $"Expected test log file {testLog} to exist"); @@ -96,14 +100,16 @@ namespace Microsoft.Extensions.Logging.Testing.Tests var globalLogContent = MakeConsistent(File.ReadAllText(globalLogPath)); var testLogContent = MakeConsistent(File.ReadAllText(testLog)); - Assert.Equal(@"[GlobalTestLog] [Information] Global Test Logging initialized. Set the 'ASPNETCORE_TEST_LOG_DIR' Environment Variable in order to create log files on disk. -[GlobalTestLog] [Information] Starting test ""FakeTestName"" -[GlobalTestLog] [Information] Finished test ""FakeTestName"" in DURATION + Assert.Equal( +@"[OFFSET] [GlobalTestLog] [Information] Global Test Logging initialized at TIMESTAMP. Configure the output directory via 'LoggingTestingFileLoggingDirectory' MSBuild property or set 'LoggingTestingDisableFileLogging' to 'true' to disable file logging. +[OFFSET] [GlobalTestLog] [Information] Starting test FakeTestName +[OFFSET] [GlobalTestLog] [Information] Finished test FakeTestName in DURATION ", globalLogContent, ignoreLineEndingDifferences: true); - Assert.Equal(@"[TestLifetime] [Information] Starting test ""FakeTestName"" -[TestLogger] [Information] Information! -[TestLogger] [Verbose] Trace! -[TestLifetime] [Information] Finished test ""FakeTestName"" in DURATION + Assert.Equal( +@"[OFFSET] [TestLifetime] [Information] Starting test FakeTestName at TIMESTAMP +[OFFSET] [TestLogger] [Information] Information! +[OFFSET] [TestLogger] [Verbose] Trace! +[OFFSET] [TestLifetime] [Information] Finished test FakeTestName in DURATION ", testLogContent, ignoreLineEndingDifferences: true); }); @@ -113,18 +119,18 @@ namespace Microsoft.Extensions.Logging.Testing.Tests { var longTestName = new string('0', 50) + new string('1', 50) + new string('2', 50) + new string('3', 50) + new string('4', 50); var logger = LoggerFactory.CreateLogger("Test"); - using (var testAssemblyLog = AssemblyTestLog.Create("FakeTestAssembly", tempDir)) + using (var testAssemblyLog = AssemblyTestLog.Create(ThisAssemblyName, tempDir)) { logger.LogInformation("Created test log in {baseDirectory}", tempDir); - using (testAssemblyLog.StartTestLog(output: null, className: "FakeTestAssembly.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, testName: longTestName)) + using (testAssemblyLog.StartTestLog(output: null, className: $"{ThisAssemblyName}.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, testName: longTestName)) { testLoggerFactory.CreateLogger("TestLogger").LogInformation("Information!"); } } logger.LogInformation("Finished test log in {baseDirectory}", tempDir); - var testLogFiles = new DirectoryInfo(Path.Combine(tempDir, "FakeTestAssembly", RuntimeInformation.FrameworkDescription.TrimStart('.'), "FakeTestClass")).EnumerateFiles(); + var testLogFiles = new DirectoryInfo(Path.Combine(tempDir, ThisAssemblyName, TFM, "FakeTestClass")).EnumerateFiles(); var testLog = Assert.Single(testLogFiles); var testFileName = Path.GetFileNameWithoutExtension(testLog.Name); @@ -139,13 +145,13 @@ namespace Microsoft.Extensions.Logging.Testing.Tests RunTestLogFunctionalTest((tempDir) => { var logger = LoggerFactory.CreateLogger("Test"); - using (var testAssemblyLog = AssemblyTestLog.Create("FakeTestAssembly", tempDir)) + using (var testAssemblyLog = AssemblyTestLog.Create(ThisAssemblyName, tempDir)) { logger.LogInformation("Created test log in {baseDirectory}", tempDir); for (var i = 0; i < 10; i++) { - using (testAssemblyLog.StartTestLog(output: null, className: "FakeTestAssembly.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, testName: "FakeTestName")) + using (testAssemblyLog.StartTestLog(output: null, className: $"{ThisAssemblyName}.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, testName: "FakeTestName")) { testLoggerFactory.CreateLogger("TestLogger").LogInformation("Information!"); } @@ -154,16 +160,17 @@ namespace Microsoft.Extensions.Logging.Testing.Tests logger.LogInformation("Finished test log in {baseDirectory}", tempDir); // The first log file exists - Assert.True(File.Exists(Path.Combine(tempDir, "FakeTestAssembly", RuntimeInformation.FrameworkDescription.TrimStart('.'), "FakeTestClass", $"FakeTestName.log"))); + Assert.True(File.Exists(Path.Combine(tempDir, ThisAssemblyName, TFM, "FakeTestClass", "FakeTestName.log"))); // Subsequent files exist for (var i = 0; i < 9; i++) { - Assert.True(File.Exists(Path.Combine(tempDir, "FakeTestAssembly", RuntimeInformation.FrameworkDescription.TrimStart('.'), "FakeTestClass", $"FakeTestName.{i}.log"))); + Assert.True(File.Exists(Path.Combine(tempDir, ThisAssemblyName, TFM, "FakeTestClass", $"FakeTestName.{i}.log"))); } }); private static readonly Regex TimestampRegex = new Regex(@"\d+-\d+-\d+T\d+:\d+:\d+"); + private static readonly Regex TimestampOffsetRegex = new Regex(@"\d+\.\d+s"); private static readonly Regex DurationRegex = new Regex(@"[^ ]+s$"); private async Task RunTestLogFunctionalTest(Action action, [CallerMemberName] string testName = null) @@ -197,10 +204,10 @@ namespace Microsoft.Extensions.Logging.Testing.Tests { var strippedPrefix = line.IndexOf("[") >= 0 ? line.Substring(line.IndexOf("[")) : line; - var strippedDuration = - DurationRegex.Replace(strippedPrefix, "DURATION"); + var strippedDuration = DurationRegex.Replace(strippedPrefix, "DURATION"); var strippedTimestamp = TimestampRegex.Replace(strippedDuration, "TIMESTAMP"); - return strippedTimestamp; + var strippedTimestampOffset = TimestampOffsetRegex.Replace(strippedTimestamp, "OFFSET"); + return strippedTimestampOffset; })); } } diff --git a/src/Logging/Logging.Testing/test/LoggedTestXunitRetryTests.cs b/src/Logging/Logging.Testing/test/LoggedTestXunitRetryTests.cs new file mode 100644 index 0000000000..1e49f45046 --- /dev/null +++ b/src/Logging/Logging.Testing/test/LoggedTestXunitRetryTests.cs @@ -0,0 +1,101 @@ +// 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; +using System.Linq; +using Microsoft.AspNetCore.Testing.xunit; +using Xunit; + +namespace Microsoft.Extensions.Logging.Testing.Tests +{ + [RetryTest(nameof(RetryAllPredicate), "sample reason")] + public class LoggedTestXunitRetryTests : LoggedTest + { + [Fact] + public void CompletesWithoutRetryOnSuccess() + { + Assert.Equal(2, RetryContext.Limit); + + // This assert would fail on the second run + Assert.Equal(0, RetryContext.CurrentIteration); + } + + [Fact] + public void RetriesUntilSuccess() + { + // This assert will fail the first time but pass on the second + Assert.Equal(1, RetryContext.CurrentIteration); + + // This assert will ensure a message is logged for retried tests. + Assert.Equal(1, TestSink.Writes.Count); + var loggedMessage = TestSink.Writes.ToArray()[0]; + Assert.Equal(LogLevel.Warning, loggedMessage.LogLevel); + Assert.Equal($"{nameof(RetriesUntilSuccess)} failed and retry conditions are met, re-executing. The reason for failure is sample reason.", loggedMessage.Message); + } + + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Windows)] + [RetryTest(nameof(RetryAllPredicate), "sample reason", OperatingSystems.Windows, 3)] + public void RetryCountNotOverridenWhenOSDoesNotMatch() + { + Assert.Equal(2, RetryContext.Limit); + } + + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [RetryTest(nameof(RetryAllPredicate), "sample reason", OperatingSystems.Windows, 3)] + public void RetryCountOverridenWhenOSMatches() + { + Assert.Equal(3, RetryContext.Limit); + } + + [Fact] + [RetryTest(nameof(RetryInvalidOperationExceptionPredicate), "sample reason")] + public void RetryIfPredicateIsTrue() + { + if (RetryContext.CurrentIteration == 0) + { + Logger.LogWarning("Throw on first iteration"); + throw new Exception(); + } + + // This assert will ensure a message is logged for retried tests. + Assert.Equal(1, TestSink.Writes.Count); + var loggedMessage = TestSink.Writes.ToArray()[0]; + Assert.Equal(LogLevel.Warning, loggedMessage.LogLevel); + Assert.Equal($"{nameof(RetryIfPredicateIsTrue)} failed and retry conditions are met, re-executing. The reason for failure is sample reason.", loggedMessage.Message); + } + + // Static predicates are valid + private static bool RetryAllPredicate(Exception e) + => true; + + // Instance predicates are valid + private bool RetryInvalidOperationExceptionPredicate(Exception e) + => TestSink.Writes.Any(m => m.Message.Contains("Throw on first iteration")); + } + + [RetryTest(nameof(RetryAllPredicate), "sample reason")] + public class LoggedTestXunitRetryConstructorTest : LoggedTest + { + private static int _constructorInvocationCount; + + public LoggedTestXunitRetryConstructorTest() + { + _constructorInvocationCount++; + } + + [Fact] + public void RetriesUntilSuccess() + { + // The constructor is invoked before the test method but the current iteration is updated after + Assert.Equal(_constructorInvocationCount, RetryContext.CurrentIteration + 1); + + // This assert will fail the first time but pass on the second + Assert.Equal(1, RetryContext.CurrentIteration); + } + + private static bool RetryAllPredicate(Exception e) + => true; + } +} diff --git a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs index 31fd6d631f..d1d8581193 100644 --- a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs +++ b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs @@ -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.Reflection; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -130,12 +131,29 @@ namespace Microsoft.Extensions.Logging.Testing.Tests } } + public class LoggedTestXunitInitializationTests : TestLoggedTest + { + [Fact] + public void ITestOutputHelperInitializedByDefault() + { + Assert.True(ITestOutputHelperIsInitialized); + } + } + public class TestLoggedTest : LoggedTest { public bool SetupInvoked { get; private set; } = false; + public bool ITestOutputHelperIsInitialized { get; private set; } = false; - public override void AdditionalSetup() + public override void Initialize(MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) { + base.Initialize(methodInfo, testMethodArguments, testOutputHelper); + + try + { + TestOutputHelper.WriteLine("Test"); + ITestOutputHelperIsInitialized = true; + } catch { } SetupInvoked = true; } } From fc4e64de38452ccab7442f0b42a540649fe15ec9 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 6 Nov 2018 16:58:30 -0800 Subject: [PATCH 03/44] Reorganize source code in preparation to move into aspnet/Extensions Prior to reorganization, this source code was found in https://github.com/aspnet/Logging/tree/f7d8e4e0537eaab54dcf28c2b148b82688a3d62d --- ...AzureAppServicesLoggerFactoryExtensions.cs | 3 ++ .../src/AzureFileLoggerOptions.cs | 7 +-- .../src/Internal/BatchingLogger.cs | 17 ++++++- .../src/Internal/BatchingLoggerOptions.cs | 6 +++ .../src/Internal/BatchingLoggerProvider.cs | 14 +++++- .../test/BatchingLoggerProviderTests.cs | 38 +++++++++++++-- src/Logging/Logging.Testing/src/ITestSink.cs | 4 ++ .../src/LoggedTest/LoggedTestBase.cs | 4 +- src/Logging/Logging.Testing/src/TestSink.cs | 6 +++ .../src/Xunit/LogLevelAttribute.cs | 2 +- .../test/LoggedTestXunitTests.cs | 46 ++++++++++++++++++- .../test/Properties/AssemlyInfo.cs | 4 ++ 12 files changed, 139 insertions(+), 12 deletions(-) create mode 100644 src/Logging/Logging.Testing/test/Properties/AssemlyInfo.cs diff --git a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs index a0e73027fb..ea558a0974 100644 --- a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs +++ b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs @@ -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>(new FileLoggerConfigureOptions(config, context)); services.AddSingleton>( new ConfigurationChangeTokenSource(config)); + LoggerProviderOptions.RegisterProviderOptions(builder.Services); } if (addedBlobLogger) @@ -63,6 +65,7 @@ namespace Microsoft.Extensions.Logging services.AddSingleton>(new BlobLoggerConfigureOptions(config, context)); services.AddSingleton>( new ConfigurationChangeTokenSource(config)); + LoggerProviderOptions.RegisterProviderOptions(builder.Services); } return builder; diff --git a/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs index 47795d9954..d9b8e89198 100644 --- a/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs @@ -51,8 +51,9 @@ namespace Microsoft.Extensions.Logging.AzureAppServices } /// - /// Gets or sets a strictly positive value representing the maximum retained file count or null for no limit. - /// Defaults to 2. + /// 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 diagnostics-. /// public string FileName { @@ -69,4 +70,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices internal string LogDirectory { get; set; } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLogger.cs b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLogger.cs index 2cfb26582f..e207fbf2a2 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLogger.cs +++ b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLogger.cs @@ -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) diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs index fbbb5cfd08..89a8f2a1e7 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs @@ -66,5 +66,11 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal /// Gets or sets value indicating if logger accepts and queues writes. /// public bool IsEnabled { get; set; } + + /// + /// Gets or sets a value indicating whether scopes should be included in the message. + /// Defaults to false. + /// + public bool IncludeScopes { get; set; } = false; } } \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs index 79720c5531..c507b6e671 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs @@ -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 _currentBatch = new List(); 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 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; + } } } \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs b/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs index 42cefe99df..0d4e1b85e0 100644 --- a/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs @@ -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 Batches { get; } = new List(); 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(new BatchingLoggerOptions { FlushPeriod = interval ?? TimeSpan.FromSeconds(1), BatchSize = maxBatchSize, BackgroundQueueSize = maxQueueSize, - IsEnabled = true + IsEnabled = true, + IncludeScopes = includeScopes })) { } diff --git a/src/Logging/Logging.Testing/src/ITestSink.cs b/src/Logging/Logging.Testing/src/ITestSink.cs index bd2d1955ae..8b0bef5033 100644 --- a/src/Logging/Logging.Testing/src/ITestSink.cs +++ b/src/Logging/Logging.Testing/src/ITestSink.cs @@ -5,6 +5,10 @@ namespace Microsoft.Extensions.Logging.Testing { public interface ITestSink { + event Action MessageLogged; + + event Action ScopeStarted; + Func WriteEnabled { get; set; } Func BeginEnabled { get; set; } diff --git a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs index f714a632a4..c3a4e78931 100644 --- a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs +++ b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs @@ -51,7 +51,9 @@ namespace Microsoft.Extensions.Logging.Testing TestOutputHelper = testOutputHelper; var classType = GetType(); - var logLevelAttribute = methodInfo.GetCustomAttribute(); + var logLevelAttribute = methodInfo.GetCustomAttribute() + ?? methodInfo.DeclaringType.GetCustomAttribute() + ?? methodInfo.DeclaringType.Assembly.GetCustomAttribute(); var testName = testMethodArguments.Aggregate(methodInfo.Name, (a, b) => $"{a}-{(b ?? "null")}"); var useShortClassName = methodInfo.DeclaringType.GetCustomAttribute() diff --git a/src/Logging/Logging.Testing/src/TestSink.cs b/src/Logging/Logging.Testing/src/TestSink.cs index f67cab5648..cc9c1ce7bc 100644 --- a/src/Logging/Logging.Testing/src/TestSink.cs +++ b/src/Logging/Logging.Testing/src/TestSink.cs @@ -30,12 +30,17 @@ namespace Microsoft.Extensions.Logging.Testing public IProducerConsumerCollection Writes { get => _writes; set => _writes = new ConcurrentQueue(value); } + public event Action MessageLogged; + + public event Action 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(WriteContext context) diff --git a/src/Logging/Logging.Testing/src/Xunit/LogLevelAttribute.cs b/src/Logging/Logging.Testing/src/Xunit/LogLevelAttribute.cs index 9f6f621374..5de51cfe91 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LogLevelAttribute.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LogLevelAttribute.cs @@ -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) diff --git a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs index d1d8581193..507453a242 100644 --- a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs +++ b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs @@ -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 diff --git a/src/Logging/Logging.Testing/test/Properties/AssemlyInfo.cs b/src/Logging/Logging.Testing/test/Properties/AssemlyInfo.cs new file mode 100644 index 0000000000..63c2b71d23 --- /dev/null +++ b/src/Logging/Logging.Testing/test/Properties/AssemlyInfo.cs @@ -0,0 +1,4 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; + +[assembly: LogLevel(LogLevel.Trace)] From ef4b2141254930e963f3502695a4d193459d4c8f Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 14 Nov 2018 09:59:30 -0800 Subject: [PATCH 04/44] Drop messages in azure loggers if queue is full (#494) --- .../src/Internal/BatchingLoggerProvider.cs | 25 ++++++++++++++++--- .../test/BatchingLoggerProviderTests.cs | 19 ++++++-------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs index c507b6e671..626412e504 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs @@ -18,6 +18,8 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal private readonly int? _batchSize; private readonly IDisposable _optionsChangeToken; + private int _messagesDropped; + private BlockingCollection _messageQueue; private Task _outputTask; private CancellationTokenSource _cancellationTokenSource; @@ -85,6 +87,16 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal limit--; } + var messagesDropped = Interlocked.Exchange(ref _messagesDropped, 0); + if (messagesDropped != 0) + { + _currentBatch.Add(new LogMessage() + { + Message = $"{messagesDropped} message(s) dropped because of queue size limit. Increase the queue size or decrease logging verbosity to avoid this.{Environment.NewLine}", + Timestamp = DateTimeOffset.Now + }); + } + if (_currentBatch.Count > 0) { try @@ -98,8 +110,10 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal _currentBatch.Clear(); } - - await IntervalAsync(_interval, _cancellationTokenSource.Token); + else + { + await IntervalAsync(_interval, _cancellationTokenSource.Token); + } } } @@ -114,7 +128,10 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal { try { - _messageQueue.Add(new LogMessage { Message = message, Timestamp = timestamp }, _cancellationTokenSource.Token); + if (!_messageQueue.TryAdd(new LogMessage { Message = message, Timestamp = timestamp }, millisecondsTimeout: 0, cancellationToken: _cancellationTokenSource.Token)) + { + Interlocked.Increment(ref _messagesDropped); + } } catch { @@ -172,4 +189,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal _scopeProvider = scopeProvider; } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs b/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs index 0d4e1b85e0..9c9a42b966 100644 --- a/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -77,21 +77,16 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test provider.IntervalControl.Resume(); await provider.IntervalControl.Pause; - Assert.Single(provider.Batches); + Assert.Equal(2, provider.Batches.Count); Assert.Single(provider.Batches[0]); Assert.Equal("2016-05-04 03:02:01.000 +00:00 [Information] Cat: Info message" + _nl, provider.Batches[0][0].Message); - provider.IntervalControl.Resume(); - await provider.IntervalControl.Pause; - - Assert.Equal(2, provider.Batches.Count); Assert.Single(provider.Batches[1]); - Assert.Equal("2016-05-04 04:02:01.000 +00:00 [Error] Cat: Error message" + _nl, provider.Batches[1][0].Message); } [Fact] - public async Task BlocksWhenReachingMaxQueue() + public async Task DropsMessagesWhenReachingMaxQueue() { var provider = new TestBatchingLoggingProvider(maxQueueSize: 1); var logger = (BatchingLogger)provider.CreateLogger("Cat"); @@ -99,14 +94,14 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test await provider.IntervalControl.Pause; logger.Log(_timestampOne, LogLevel.Information, 0, "Info message", null, (state, ex) => state); - var task = Task.Run(() => logger.Log(_timestampOne.AddHours(1), LogLevel.Error, 0, "Error message", null, (state, ex) => state)); - - Assert.False(task.Wait(1000)); + logger.Log(_timestampOne.AddHours(1), LogLevel.Error, 0, "Error message", null, (state, ex) => state); provider.IntervalControl.Resume(); await provider.IntervalControl.Pause; - Assert.True(task.Wait(1000)); + Assert.Equal(2, provider.Batches[0].Length); + Assert.Equal("2016-05-04 03:02:01.000 +00:00 [Information] Cat: Info message" + _nl, provider.Batches[0][0].Message); + Assert.Equal("1 message(s) dropped because of queue size limit. Increase the queue size or decrease logging verbosity to avoid this." + _nl, provider.Batches[0][1].Message); } private class TestBatchingLoggingProvider: BatchingLoggerProvider From 8a586ceb577b49c2528641135a624530233ade37 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 14 Nov 2018 12:46:22 -0800 Subject: [PATCH 05/44] Remove obsolete types from Azure logging (#498) --- .../AzureAppServicesDiagnosticsSettings.cs | 162 ------------------ ...AzureAppServicesLoggerFactoryExtensions.cs | 101 +---------- .../src/AzureBlobLoggerOptions.cs | 5 +- .../src/AzureFileLoggerOptions.cs | 3 +- .../BatchLoggerConfigureOptions.cs | 6 +- .../src/{Internal => }/BatchingLogger.cs | 6 +- .../{Internal => }/BatchingLoggerOptions.cs | 6 +- .../{Internal => }/BatchingLoggerProvider.cs | 14 +- .../BlobAppendReferenceWrapper.cs | 8 +- .../BlobLoggerConfigureOptions.cs | 8 +- .../src/{Internal => }/BlobLoggerProvider.cs | 12 +- .../ConfigurationBasedLevelSwitcher.cs | 8 +- .../FileLoggerConfigureOptions.cs | 8 +- .../src/{Internal => }/FileLoggerProvider.cs | 12 +- .../src/{Internal => }/ICloudAppendBlob.cs | 8 +- .../src/{Internal => }/IWebAppContext.cs | 6 +- .../src/Internal/ForwardingLoggerProvider.cs | 25 --- .../src/Internal/LogMessage.cs | 13 -- .../src/LogMessage.cs | 19 ++ .../src/Properties/AssemblyInfo.cs | 1 + .../SiteConfigurationProvider.cs | 8 +- .../src/{Internal => }/WebAppContext.cs | 6 +- .../src/breakingchanges.netcore.json | 24 +++ .../test/AzureAppendBlobTests.cs | 3 +- .../test/AzureBlobSinkTests.cs | 3 +- ...reDiagnosticsConfigurationProviderTests.cs | 5 +- .../test/BatchingLoggerProviderTests.cs | 3 +- .../test/ConfigureOptionsTests.cs | 3 +- .../test/FileLoggerTests.cs | 3 +- .../test/LoggerBuilderExtensionsTests.cs | 5 +- .../test/TestBlobSink.cs | 4 +- .../test/TestFileLoggerProvider.cs | 3 +- .../test/WebConfigurationLevelSwitchTests.cs | 3 +- 33 files changed, 116 insertions(+), 388 deletions(-) delete mode 100644 src/Logging/Logging.AzureAppServices/src/AzureAppServicesDiagnosticsSettings.cs rename src/Logging/Logging.AzureAppServices/src/{Internal => }/BatchLoggerConfigureOptions.cs (86%) rename src/Logging/Logging.AzureAppServices/src/{Internal => }/BatchingLogger.cs (92%) rename src/Logging/Logging.AzureAppServices/src/{Internal => }/BatchingLoggerOptions.cs (95%) rename src/Logging/Logging.AzureAppServices/src/{Internal => }/BatchingLoggerProvider.cs (87%) rename src/Logging/Logging.AzureAppServices/src/{Internal => }/BlobAppendReferenceWrapper.cs (94%) rename src/Logging/Logging.AzureAppServices/src/{Internal => }/BlobLoggerConfigureOptions.cs (79%) rename src/Logging/Logging.AzureAppServices/src/{Internal => }/BlobLoggerProvider.cs (89%) rename src/Logging/Logging.AzureAppServices/src/{Internal => }/ConfigurationBasedLevelSwitcher.cs (87%) rename src/Logging/Logging.AzureAppServices/src/{Internal => }/FileLoggerConfigureOptions.cs (74%) rename src/Logging/Logging.AzureAppServices/src/{Internal => }/FileLoggerProvider.cs (85%) rename src/Logging/Logging.AzureAppServices/src/{Internal => }/ICloudAppendBlob.cs (82%) rename src/Logging/Logging.AzureAppServices/src/{Internal => }/IWebAppContext.cs (83%) delete mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/ForwardingLoggerProvider.cs delete mode 100644 src/Logging/Logging.AzureAppServices/src/Internal/LogMessage.cs create mode 100644 src/Logging/Logging.AzureAppServices/src/LogMessage.cs rename src/Logging/Logging.AzureAppServices/src/{Internal => }/SiteConfigurationProvider.cs (79%) rename src/Logging/Logging.AzureAppServices/src/{Internal => }/WebAppContext.cs (85%) create mode 100644 src/Logging/Logging.AzureAppServices/src/breakingchanges.netcore.json diff --git a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesDiagnosticsSettings.cs b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesDiagnosticsSettings.cs deleted file mode 100644 index f93538218f..0000000000 --- a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesDiagnosticsSettings.cs +++ /dev/null @@ -1,162 +0,0 @@ -// 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; - -namespace Microsoft.Extensions.Logging.AzureAppServices -{ - /// - /// Settings for Azure diagnostics logging. - /// - [Obsolete("This type is obsolete and will be removed in a future version. The recommended alternative is AzureBlobLoggerOptions.")] - public class AzureAppServicesDiagnosticsSettings - { - private TimeSpan _blobCommitPeriod = TimeSpan.FromSeconds(5); - private int _blobBatchSize = 32; - private string _outputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"; - private int _retainedFileCountLimit = 2; - private int _fileSizeLimit = 10 * 1024 * 1024; - private string _blobName = "applicationLog.txt"; - private TimeSpan? _fileFlushPeriod = TimeSpan.FromSeconds(1); - private int _backgroundQueueSize; - - /// - /// Gets or sets a strictly positive value representing the maximum log size in bytes. - /// Once the log is full, no more messages will be appended. - /// Defaults to 10MB. - /// - public int FileSizeLimit - { - get { return _fileSizeLimit; } - set - { - if (value <= 0) - { - throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(FileSizeLimit)} must be positive."); - } - _fileSizeLimit = value; - } - } - - /// - /// Gets or sets a strictly positive value representing the maximum retained file count. - /// Defaults to 2. - /// - public int RetainedFileCountLimit - { - get { return _retainedFileCountLimit; } - set - { - if (value <= 0) - { - throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(RetainedFileCountLimit)} must be positive."); - } - _retainedFileCountLimit = value; - } - } - - /// - /// Gets or sets a message template describing the output messages. - /// Defaults to "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}". - /// - public string OutputTemplate - { - get { return _outputTemplate; } - set - { - if (string.IsNullOrEmpty(value)) - { - throw new ArgumentException(nameof(value), $"{nameof(OutputTemplate)} must be non-empty string."); - } - _outputTemplate = value; - } - } - - /// - /// Gets or sets a maximum number of events to include in a single blob append batch. - /// Defaults to 32. - /// - public int BlobBatchSize - { - get { return _blobBatchSize; } - set - { - if (value <= 0) - { - throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(BlobBatchSize)} must be positive."); - } - _blobBatchSize = value; - } - } - - /// - /// Gets or sets a time to wait between checking for blob log batches. - /// Defaults to 5 seconds. - /// - public TimeSpan BlobCommitPeriod - { - get { return _blobCommitPeriod; } - set - { - if (value < TimeSpan.Zero) - { - throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(BlobCommitPeriod)} must be positive."); - } - _blobCommitPeriod = value; - } - } - - /// - /// Gets or sets the last section of log blob name. - /// Defaults to "applicationLog.txt". - /// - public string BlobName - { - get { return _blobName; } - set - { - if (string.IsNullOrEmpty(value)) - { - throw new ArgumentException(nameof(value), $"{nameof(BlobName)} must be non-empty string."); - } - _blobName = value; - } - } - - /// - /// Gets or sets the maximum size of the background log message queue or 0 for no limit. - /// After maximum queue size is reached log event sink would start blocking. - /// Defaults to 0. - /// - public int BackgroundQueueSize - { - get { return _backgroundQueueSize; } - set - { - if (value < 0) - { - throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(BackgroundQueueSize)} must be non-negative."); - } - _backgroundQueueSize = value; - } - } - - /// - /// Gets or sets the period after which logs will be flushed to disk or - /// null if auto flushing is not required. - /// Defaults to 1 second. - /// - public TimeSpan? FileFlushPeriod - { - get { return _fileFlushPeriod; } - set - { - if (value < TimeSpan.Zero) - { - throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(FileFlushPeriod)} must be positive."); - } - _fileFlushPeriod = value; - } - } - } -} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs index ea558a0974..cbf9ec7d35 100644 --- a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs +++ b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -6,7 +6,6 @@ using Microsoft.Extensions.Configuration; 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; @@ -93,103 +92,5 @@ namespace Microsoft.Extensions.Logging provider: typeof(FileLoggerProvider), levelKey: "AzureDriveTraceLevel"); } - - /// - /// Adds an Azure Web Apps diagnostics logger. - /// - /// The extension method argument - [Obsolete("This method is obsolete and will be removed in a future version. The recommended alternative is AddAzureWebAppDiagnostics(this ILoggingBuilder builder).")] - public static ILoggerFactory AddAzureWebAppDiagnostics(this ILoggerFactory factory) - { - return AddAzureWebAppDiagnostics(factory, new AzureAppServicesDiagnosticsSettings()); - } - - /// - /// Adds an Azure Web Apps diagnostics logger. - /// - /// The extension method argument - /// The setting object to configure loggers. - [Obsolete("This method is obsolete and will be removed in a future version. The recommended alternative is AddAzureWebAppDiagnostics(this ILoggingBuilder builder).")] - public static ILoggerFactory AddAzureWebAppDiagnostics(this ILoggerFactory factory, AzureAppServicesDiagnosticsSettings settings) - { - var context = WebAppContext.Default; - if (!context.IsRunningInAzureWebApp) - { - return factory; - } - - var config = SiteConfigurationProvider.GetAzureLoggingConfiguration(context); - - // Only add the provider if we're in Azure WebApp. That cannot change once the apps started - var fileOptions = new OptionsMonitor( - new OptionsFactory( - new IConfigureOptions[] - { - new FileLoggerConfigureOptions(config, context), - new ConfigureOptions(options => - { - options.FileSizeLimit = settings.FileSizeLimit; - options.RetainedFileCountLimit = settings.RetainedFileCountLimit; - options.BackgroundQueueSize = settings.BackgroundQueueSize == 0 ? (int?) null : settings.BackgroundQueueSize; - - if (settings.FileFlushPeriod != null) - { - options.FlushPeriod = settings.FileFlushPeriod.Value; - } - }) - }, - new IPostConfigureOptions[0] - ), - new[] - { - new ConfigurationChangeTokenSource(config) - }, - new OptionsCache() - ); - - var blobOptions = new OptionsMonitor( - new OptionsFactory( - new IConfigureOptions[] { - new BlobLoggerConfigureOptions(config, context), - new ConfigureOptions(options => - { - options.BlobName = settings.BlobName; - options.FlushPeriod = settings.BlobCommitPeriod; - options.BatchSize = settings.BlobBatchSize; - options.BackgroundQueueSize = settings.BackgroundQueueSize == 0 ? (int?) null : settings.BackgroundQueueSize; - }) - }, - new IPostConfigureOptions[0] - ), - new[] - { - new ConfigurationChangeTokenSource(config) - }, - new OptionsCache() - ); - - var filterOptions = new OptionsMonitor( - new OptionsFactory( - new[] - { - CreateFileFilterConfigureOptions(config), - CreateBlobFilterConfigureOptions(config) - }, - new IPostConfigureOptions[0]), - new [] { new ConfigurationChangeTokenSource(config) }, - new OptionsCache()); - - factory.AddProvider(new ForwardingLoggerProvider( - new LoggerFactory( - new ILoggerProvider[] - { - new FileLoggerProvider(fileOptions), - new BlobLoggerProvider(blobOptions) - }, - filterOptions - ) - )); - return factory; - } } } diff --git a/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs index 2f1285f8ac..6af815457c 100644 --- a/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs @@ -1,8 +1,7 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; -using Microsoft.Extensions.Logging.AzureAppServices.Internal; namespace Microsoft.Extensions.Logging.AzureAppServices { @@ -36,4 +35,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices internal string ApplicationInstanceId { get; set; } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs index d9b8e89198..30694e5fc7 100644 --- a/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs @@ -1,8 +1,7 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; -using Microsoft.Extensions.Logging.AzureAppServices.Internal; namespace Microsoft.Extensions.Logging.AzureAppServices { diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchLoggerConfigureOptions.cs b/src/Logging/Logging.AzureAppServices/src/BatchLoggerConfigureOptions.cs similarity index 86% rename from src/Logging/Logging.AzureAppServices/src/Internal/BatchLoggerConfigureOptions.cs rename to src/Logging/Logging.AzureAppServices/src/BatchLoggerConfigureOptions.cs index 3982193dd8..a50bd65b32 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/BatchLoggerConfigureOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/BatchLoggerConfigureOptions.cs @@ -4,9 +4,9 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { - public class BatchLoggerConfigureOptions : IConfigureOptions + internal class BatchLoggerConfigureOptions : IConfigureOptions { private readonly IConfiguration _configuration; private readonly string _isEnabledKey; @@ -33,4 +33,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal return result; } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLogger.cs b/src/Logging/Logging.AzureAppServices/src/BatchingLogger.cs similarity index 92% rename from src/Logging/Logging.AzureAppServices/src/Internal/BatchingLogger.cs rename to src/Logging/Logging.AzureAppServices/src/BatchingLogger.cs index e207fbf2a2..b2960802d4 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLogger.cs +++ b/src/Logging/Logging.AzureAppServices/src/BatchingLogger.cs @@ -1,12 +1,12 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; using System.Text; -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { - public class BatchingLogger : ILogger + internal class BatchingLogger : ILogger { private readonly BatchingLoggerProvider _provider; private readonly string _category; diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerOptions.cs similarity index 95% rename from src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs rename to src/Logging/Logging.AzureAppServices/src/BatchingLoggerOptions.cs index 89a8f2a1e7..23998fb5d1 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerOptions.cs @@ -1,9 +1,9 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { public class BatchingLoggerOptions { @@ -73,4 +73,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal /// public bool IncludeScopes { get; set; } = false; } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs similarity index 87% rename from src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs rename to src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs index 626412e504..5b375a2b5a 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs @@ -8,7 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Options; -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { public abstract class BatchingLoggerProvider: ILoggerProvider, ISupportExternalScope { @@ -29,7 +29,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal internal IExternalScopeProvider ScopeProvider => _includeScopes ? _scopeProvider : null; - protected BatchingLoggerProvider(IOptionsMonitor options) + internal BatchingLoggerProvider(IOptionsMonitor options) { // NOTE: Only IsEnabled is monitored @@ -73,7 +73,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal } - protected abstract Task WriteMessagesAsync(IEnumerable messages, CancellationToken token); + internal abstract Task WriteMessagesAsync(IEnumerable messages, CancellationToken token); private async Task ProcessLogQueue(object state) { @@ -90,11 +90,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal var messagesDropped = Interlocked.Exchange(ref _messagesDropped, 0); if (messagesDropped != 0) { - _currentBatch.Add(new LogMessage() - { - Message = $"{messagesDropped} message(s) dropped because of queue size limit. Increase the queue size or decrease logging verbosity to avoid this.{Environment.NewLine}", - Timestamp = DateTimeOffset.Now - }); + _currentBatch.Add(new LogMessage(DateTimeOffset.Now, $"{messagesDropped} message(s) dropped because of queue size limit. Increase the queue size or decrease logging verbosity to avoid this.{Environment.NewLine}")); } if (_currentBatch.Count > 0) @@ -128,7 +124,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal { try { - if (!_messageQueue.TryAdd(new LogMessage { Message = message, Timestamp = timestamp }, millisecondsTimeout: 0, cancellationToken: _cancellationTokenSource.Token)) + if (!_messageQueue.TryAdd(new LogMessage(timestamp, message), millisecondsTimeout: 0, cancellationToken: _cancellationTokenSource.Token)) { Interlocked.Increment(ref _messagesDropped); } diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BlobAppendReferenceWrapper.cs b/src/Logging/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs similarity index 94% rename from src/Logging/Logging.AzureAppServices/src/Internal/BlobAppendReferenceWrapper.cs rename to src/Logging/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs index e0702275cb..bf6656f9f3 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/BlobAppendReferenceWrapper.cs +++ b/src/Logging/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -7,10 +7,10 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { /// - public class BlobAppendReferenceWrapper : ICloudAppendBlob + internal class BlobAppendReferenceWrapper : ICloudAppendBlob { private readonly Uri _fullUri; private readonly HttpClient _client; @@ -93,4 +93,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal uriBuilder.Query = queryToAppend; } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerConfigureOptions.cs b/src/Logging/Logging.AzureAppServices/src/BlobLoggerConfigureOptions.cs similarity index 79% rename from src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerConfigureOptions.cs rename to src/Logging/Logging.AzureAppServices/src/BlobLoggerConfigureOptions.cs index 25ea1b6af6..d07f76795d 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerConfigureOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/BlobLoggerConfigureOptions.cs @@ -1,12 +1,12 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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 Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { - public class BlobLoggerConfigureOptions : BatchLoggerConfigureOptions, IConfigureOptions + internal class BlobLoggerConfigureOptions : BatchLoggerConfigureOptions, IConfigureOptions { private readonly IConfiguration _configuration; private readonly IWebAppContext _context; @@ -26,4 +26,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal options.ApplicationInstanceId = _context.SiteInstanceId; } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs similarity index 89% rename from src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerProvider.cs rename to src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs index 96c98fa455..abcba026fb 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/BlobLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -11,7 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Options; -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { /// /// The implementation that stores messages by appending them to Azure Blob in batches. @@ -28,7 +28,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal /// Creates a new instance of /// /// - public BlobLoggerProvider(IOptionsMonitor options) + internal BlobLoggerProvider(IOptionsMonitor options) : this(options, null) { _blobReferenceFactory = name => new BlobAppendReferenceWrapper( @@ -42,7 +42,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal /// /// The container to store logs to. /// - public BlobLoggerProvider( + internal BlobLoggerProvider( IOptionsMonitor options, Func blobReferenceFactory) : base(options) @@ -54,7 +54,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal _httpClient = new HttpClient(); } - protected override async Task WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) + internal override async Task WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { var eventGroups = messages.GroupBy(GetBlobKey); foreach (var eventGroup in eventGroups) @@ -88,4 +88,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal e.Timestamp.Hour); } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/ConfigurationBasedLevelSwitcher.cs b/src/Logging/Logging.AzureAppServices/src/ConfigurationBasedLevelSwitcher.cs similarity index 87% rename from src/Logging/Logging.AzureAppServices/src/Internal/ConfigurationBasedLevelSwitcher.cs rename to src/Logging/Logging.AzureAppServices/src/ConfigurationBasedLevelSwitcher.cs index 388a4ed54e..77e5a399d0 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/ConfigurationBasedLevelSwitcher.cs +++ b/src/Logging/Logging.AzureAppServices/src/ConfigurationBasedLevelSwitcher.cs @@ -1,13 +1,13 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { - public class ConfigurationBasedLevelSwitcher: IConfigureOptions + internal class ConfigurationBasedLevelSwitcher: IConfigureOptions { private readonly IConfiguration _configuration; private readonly Type _provider; @@ -47,4 +47,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal } } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerConfigureOptions.cs b/src/Logging/Logging.AzureAppServices/src/FileLoggerConfigureOptions.cs similarity index 74% rename from src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerConfigureOptions.cs rename to src/Logging/Logging.AzureAppServices/src/FileLoggerConfigureOptions.cs index 00037bca87..e7d8a84492 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerConfigureOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/FileLoggerConfigureOptions.cs @@ -1,13 +1,13 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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.IO; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { - public class FileLoggerConfigureOptions : BatchLoggerConfigureOptions, IConfigureOptions + internal class FileLoggerConfigureOptions : BatchLoggerConfigureOptions, IConfigureOptions { private readonly IWebAppContext _context; @@ -23,4 +23,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal options.LogDirectory = Path.Combine(_context.HomeFolder, "LogFiles", "Application"); } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs similarity index 85% rename from src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerProvider.cs rename to src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs index 154f609225..9da2dcbe5a 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/FileLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs @@ -8,7 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Options; -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { [ProviderAlias("AzureAppServicesFile")] public class FileLoggerProvider : BatchingLoggerProvider @@ -18,7 +18,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal private readonly int? _maxFileSize; private readonly int? _maxRetainedFiles; - public FileLoggerProvider(IOptionsMonitor options) : base(options) + internal FileLoggerProvider(IOptionsMonitor options) : base(options) { var loggerOptions = options.CurrentValue; _path = loggerOptions.LogDirectory; @@ -27,7 +27,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal _maxRetainedFiles = loggerOptions.RetainedFileCountLimit; } - protected override async Task WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) + internal override async Task WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { Directory.CreateDirectory(_path); @@ -57,12 +57,12 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal return Path.Combine(_path, $"{_fileName}{group.Year:0000}{group.Month:00}{group.Day:00}.txt"); } - public (int Year, int Month, int Day) GetGrouping(LogMessage message) + private (int Year, int Month, int Day) GetGrouping(LogMessage message) { return (message.Timestamp.Year, message.Timestamp.Month, message.Timestamp.Day); } - protected void RollFiles() + private void RollFiles() { if (_maxRetainedFiles > 0) { @@ -78,4 +78,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal } } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/ICloudAppendBlob.cs b/src/Logging/Logging.AzureAppServices/src/ICloudAppendBlob.cs similarity index 82% rename from src/Logging/Logging.AzureAppServices/src/Internal/ICloudAppendBlob.cs rename to src/Logging/Logging.AzureAppServices/src/ICloudAppendBlob.cs index ccca525090..98f3b34d28 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/ICloudAppendBlob.cs +++ b/src/Logging/Logging.AzureAppServices/src/ICloudAppendBlob.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -6,12 +6,12 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { /// /// Represents an append blob, a type of blob where blocks of data are always committed to the end of the blob. /// - public interface ICloudAppendBlob + internal interface ICloudAppendBlob { /// /// Initiates an asynchronous operation to open a stream for writing to the blob. @@ -19,4 +19,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal /// A object of type that represents the asynchronous operation. Task AppendAsync(ArraySegment data, CancellationToken cancellationToken); } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/IWebAppContext.cs b/src/Logging/Logging.AzureAppServices/src/IWebAppContext.cs similarity index 83% rename from src/Logging/Logging.AzureAppServices/src/Internal/IWebAppContext.cs rename to src/Logging/Logging.AzureAppServices/src/IWebAppContext.cs index 21e2982192..a888de16af 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/IWebAppContext.cs +++ b/src/Logging/Logging.AzureAppServices/src/IWebAppContext.cs @@ -1,12 +1,12 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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. -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { /// /// Represents an Azure WebApp context /// - public interface IWebAppContext + internal interface IWebAppContext { /// /// Gets the path to the home folder if running in Azure WebApp diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/ForwardingLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/Internal/ForwardingLoggerProvider.cs deleted file mode 100644 index 0474f0ba9e..0000000000 --- a/src/Logging/Logging.AzureAppServices/src/Internal/ForwardingLoggerProvider.cs +++ /dev/null @@ -1,25 +0,0 @@ -// 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. - -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal -{ - internal class ForwardingLoggerProvider : ILoggerProvider - { - private readonly ILoggerFactory _loggerFactory; - - public ForwardingLoggerProvider(ILoggerFactory loggerFactory) - { - _loggerFactory = loggerFactory; - } - - public void Dispose() - { - _loggerFactory.Dispose(); - } - - public ILogger CreateLogger(string categoryName) - { - return _loggerFactory.CreateLogger(categoryName); - } - } -} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/LogMessage.cs b/src/Logging/Logging.AzureAppServices/src/Internal/LogMessage.cs deleted file mode 100644 index b330f4dda7..0000000000 --- a/src/Logging/Logging.AzureAppServices/src/Internal/LogMessage.cs +++ /dev/null @@ -1,13 +0,0 @@ -// 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; - -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal -{ - public struct LogMessage - { - public DateTimeOffset Timestamp { get; set; } - public string Message { get; set; } - } -} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/LogMessage.cs b/src/Logging/Logging.AzureAppServices/src/LogMessage.cs new file mode 100644 index 0000000000..460ebd8c0f --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/LogMessage.cs @@ -0,0 +1,19 @@ +// 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; + +namespace Microsoft.Extensions.Logging.AzureAppServices +{ + internal readonly struct LogMessage + { + public LogMessage(DateTimeOffset timestamp, string message) + { + Timestamp = timestamp; + Message = message; + } + + public DateTimeOffset Timestamp { get; } + public string Message { get; } + } +} diff --git a/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs b/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs index 85c4d7c575..83f3ffe055 100644 --- a/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs +++ b/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs @@ -5,3 +5,4 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft.Extensions.Logging.AzureAppServices.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/SiteConfigurationProvider.cs b/src/Logging/Logging.AzureAppServices/src/SiteConfigurationProvider.cs similarity index 79% rename from src/Logging/Logging.AzureAppServices/src/Internal/SiteConfigurationProvider.cs rename to src/Logging/Logging.AzureAppServices/src/SiteConfigurationProvider.cs index b7aa39de2c..e685db2ebc 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/SiteConfigurationProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/SiteConfigurationProvider.cs @@ -1,12 +1,12 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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.IO; using Microsoft.Extensions.Configuration; -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { - public class SiteConfigurationProvider + internal class SiteConfigurationProvider { public static IConfiguration GetAzureLoggingConfiguration(IWebAppContext context) { @@ -19,4 +19,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal .Build(); } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/WebAppContext.cs b/src/Logging/Logging.AzureAppServices/src/WebAppContext.cs similarity index 85% rename from src/Logging/Logging.AzureAppServices/src/Internal/WebAppContext.cs rename to src/Logging/Logging.AzureAppServices/src/WebAppContext.cs index 774020afdb..149766f25c 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/WebAppContext.cs +++ b/src/Logging/Logging.AzureAppServices/src/WebAppContext.cs @@ -1,14 +1,14 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; -namespace Microsoft.Extensions.Logging.AzureAppServices.Internal +namespace Microsoft.Extensions.Logging.AzureAppServices { /// /// Represents the default implementation of . /// - public class WebAppContext : IWebAppContext + internal class WebAppContext : IWebAppContext { /// /// Gets the default instance of the WebApp context. diff --git a/src/Logging/Logging.AzureAppServices/src/breakingchanges.netcore.json b/src/Logging/Logging.AzureAppServices/src/breakingchanges.netcore.json new file mode 100644 index 0000000000..7b778dd14a --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/src/breakingchanges.netcore.json @@ -0,0 +1,24 @@ +[ + { + "TypeId": "public class Microsoft.Extensions.Logging.AzureAppServices.AzureAppServicesDiagnosticsSettings", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.Extensions.Logging.AzureAppServices.AzureBlobLoggerOptions : Microsoft.Extensions.Logging.AzureAppServices.Internal.BatchingLoggerOptions", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.Extensions.Logging.AzureAppServices.AzureFileLoggerOptions : Microsoft.Extensions.Logging.AzureAppServices.Internal.BatchingLoggerOptions", + "Kind": "Removal" + }, + { + "TypeId": "public static class Microsoft.Extensions.Logging.AzureAppServicesLoggerFactoryExtensions", + "MemberId": "public static Microsoft.Extensions.Logging.ILoggerFactory AddAzureWebAppDiagnostics(this Microsoft.Extensions.Logging.ILoggerFactory factory)", + "Kind": "Removal" + }, + { + "TypeId": "public static class Microsoft.Extensions.Logging.AzureAppServicesLoggerFactoryExtensions", + "MemberId": "public static Microsoft.Extensions.Logging.ILoggerFactory AddAzureWebAppDiagnostics(this Microsoft.Extensions.Logging.ILoggerFactory factory, Microsoft.Extensions.Logging.AzureAppServices.AzureAppServicesDiagnosticsSettings settings)", + "Kind": "Removal" + } +] diff --git a/src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs b/src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs index e9fe0b65b1..d9badcde31 100644 --- a/src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -6,7 +6,6 @@ using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Logging.AzureAppServices.Internal; using Xunit; namespace Microsoft.Extensions.Logging.AzureAppServices.Test diff --git a/src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs b/src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs index a1ee0e97d3..d8642aeae7 100644 --- a/src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -9,7 +9,6 @@ using System.Threading; using System.Threading.Tasks; using Moq; using Xunit; -using Microsoft.Extensions.Logging.AzureAppServices.Internal; namespace Microsoft.Extensions.Logging.AzureAppServices.Test { diff --git a/src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs b/src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs index 51ba07f12b..c2bfa516d2 100644 --- a/src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs @@ -1,9 +1,8 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; using System.IO; -using Microsoft.Extensions.Logging.AzureAppServices.Internal; using Moq; using Xunit; @@ -67,4 +66,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test } } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs b/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs index 9c9a42b966..a8fe9d596c 100644 --- a/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Logging.AzureAppServices.Internal; using Xunit; namespace Microsoft.Extensions.Logging.AzureAppServices.Test @@ -121,7 +120,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test { } - protected override Task WriteMessagesAsync(IEnumerable messages, CancellationToken token) + internal override Task WriteMessagesAsync(IEnumerable messages, CancellationToken token) { Batches.Add(messages.ToArray()); return Task.CompletedTask; diff --git a/src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs b/src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs index 077ebd726a..9d46aeb832 100644 --- a/src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs @@ -1,11 +1,10 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; using System.Collections.Generic; using System.IO; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging.AzureAppServices.Internal; using Moq; using Xunit; diff --git a/src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs b/src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs index ea838b93cf..430f8852d8 100644 --- a/src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs @@ -5,7 +5,6 @@ using System; using System.IO; using System.Linq; using System.Threading.Tasks; -using Microsoft.Extensions.Logging.AzureAppServices.Internal; using Xunit; namespace Microsoft.Extensions.Logging.AzureAppServices.Test @@ -119,4 +118,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test }, actualFiles); } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs b/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs index ddf38d0137..de148f2c3a 100644 --- a/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs @@ -1,10 +1,9 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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 Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.AzureAppServices.Internal; using Microsoft.Extensions.Options; using Moq; using Xunit; @@ -66,4 +65,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test Assert.Equal(4, serviceCollection.Count(d => d.ServiceType == typeof(IConfigureOptions))); } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs b/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs index df9665e44e..23afaf1787 100644 --- a/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs +++ b/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs @@ -1,8 +1,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Logging.AzureAppServices.Internal; -using Microsoft.Extensions.Options; namespace Microsoft.Extensions.Logging.AzureAppServices.Test { @@ -27,4 +25,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test return IntervalControl.IntervalAsync(); } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs index 4b0b87c4e4..8350133d99 100644 --- a/src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs @@ -4,7 +4,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Logging.AzureAppServices.Internal; namespace Microsoft.Extensions.Logging.AzureAppServices.Test { @@ -33,4 +32,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test return IntervalControl.IntervalAsync(); } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs b/src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs index afb5dc037f..c4f92115e7 100644 --- a/src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs @@ -1,9 +1,8 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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.Collections.Generic; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging.AzureAppServices.Internal; using Xunit; namespace Microsoft.Extensions.Logging.AzureAppServices.Test From 7d2b7a5fb8aa71b81bb80c9c606d69e2c1b8bda7 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 16 Nov 2018 08:33:57 -0800 Subject: [PATCH 06/44] Remove internal types from Logging and Abstractions (#513) --- .../src/AzureAppServicesLoggerFactoryExtensions.cs | 1 - src/Logging/Logging.Testing/src/RetryContext.cs | 4 +--- src/Logging/Logging.Testing/src/TestLoggerFactory.cs | 4 +--- .../Logging.Testing/src/{TestLoggerOfT.cs => TestLoggerT.cs} | 0 src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs | 3 +-- src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs | 1 - 6 files changed, 3 insertions(+), 10 deletions(-) rename src/Logging/Logging.Testing/src/{TestLoggerOfT.cs => TestLoggerT.cs} (100%) diff --git a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs index cbf9ec7d35..79b486b585 100644 --- a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs +++ b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs @@ -1,7 +1,6 @@ // 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; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; diff --git a/src/Logging/Logging.Testing/src/RetryContext.cs b/src/Logging/Logging.Testing/src/RetryContext.cs index 2a774cfd3e..529de656b5 100644 --- a/src/Logging/Logging.Testing/src/RetryContext.cs +++ b/src/Logging/Logging.Testing/src/RetryContext.cs @@ -1,8 +1,6 @@ // 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; - namespace Microsoft.Extensions.Logging.Testing { public class RetryContext @@ -15,4 +13,4 @@ namespace Microsoft.Extensions.Logging.Testing internal int CurrentIteration { get; set; } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.Testing/src/TestLoggerFactory.cs b/src/Logging/Logging.Testing/src/TestLoggerFactory.cs index b0513fed66..7200e254b8 100644 --- a/src/Logging/Logging.Testing/src/TestLoggerFactory.cs +++ b/src/Logging/Logging.Testing/src/TestLoggerFactory.cs @@ -1,8 +1,6 @@ // 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; - namespace Microsoft.Extensions.Logging.Testing { public class TestLoggerFactory : ILoggerFactory @@ -29,4 +27,4 @@ namespace Microsoft.Extensions.Logging.Testing { } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.Testing/src/TestLoggerOfT.cs b/src/Logging/Logging.Testing/src/TestLoggerT.cs similarity index 100% rename from src/Logging/Logging.Testing/src/TestLoggerOfT.cs rename to src/Logging/Logging.Testing/src/TestLoggerT.cs diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs index 909ea10a6b..7dc847a113 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -9,7 +9,6 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; -using Microsoft.Extensions.Logging.Testing; using Xunit.Abstractions; using Xunit.Sdk; diff --git a/src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs b/src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs index 9720e15a09..c991073b4a 100644 --- a/src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs +++ b/src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs @@ -3,7 +3,6 @@ using System; using System.Text.RegularExpressions; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Test; using Xunit; From 22097c6c358f557d0daa8e9c7edc699038a19908 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 17 Dec 2018 09:18:26 -0800 Subject: [PATCH 07/44] Capture LoggedTest.Initialize exception and re-trow in Dispose (#770) --- .../src/LoggedTest/LoggedTestBase.cs | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs index c3a4e78931..72de6a87c3 100644 --- a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs +++ b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; using Microsoft.Extensions.DependencyInjection; using Xunit.Abstractions; @@ -12,6 +13,8 @@ namespace Microsoft.Extensions.Logging.Testing { public class LoggedTestBase : ILoggedTest { + private ExceptionDispatchInfo _initializationException; + private IDisposable _testLog; // Obsolete but keeping for back compat @@ -48,37 +51,48 @@ namespace Microsoft.Extensions.Logging.Testing public virtual void Initialize(MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) { - TestOutputHelper = testOutputHelper; + try + { + TestOutputHelper = testOutputHelper; - var classType = GetType(); - var logLevelAttribute = methodInfo.GetCustomAttribute() - ?? methodInfo.DeclaringType.GetCustomAttribute() - ?? methodInfo.DeclaringType.Assembly.GetCustomAttribute(); - var testName = testMethodArguments.Aggregate(methodInfo.Name, (a, b) => $"{a}-{(b ?? "null")}"); + var classType = GetType(); + var logLevelAttribute = methodInfo.GetCustomAttribute() + ?? methodInfo.DeclaringType.GetCustomAttribute() + ?? methodInfo.DeclaringType.Assembly.GetCustomAttribute(); + var testName = testMethodArguments.Aggregate(methodInfo.Name, (a, b) => $"{a}-{(b ?? "null")}"); - var useShortClassName = methodInfo.DeclaringType.GetCustomAttribute() - ?? methodInfo.DeclaringType.Assembly.GetCustomAttribute(); - // internal for testing - ResolvedTestClassName = useShortClassName == null ? classType.FullName : classType.Name; + var useShortClassName = methodInfo.DeclaringType.GetCustomAttribute() + ?? methodInfo.DeclaringType.Assembly.GetCustomAttribute(); + // internal for testing + ResolvedTestClassName = useShortClassName == null ? classType.FullName : classType.Name; - _testLog = AssemblyTestLog - .ForAssembly(classType.GetTypeInfo().Assembly) - .StartTestLog( - TestOutputHelper, - ResolvedTestClassName, - out var loggerFactory, - logLevelAttribute?.LogLevel ?? LogLevel.Debug, - out var resolvedTestName, - out var logOutputDirectory, - testName); + _testLog = AssemblyTestLog + .ForAssembly(classType.GetTypeInfo().Assembly) + .StartTestLog( + TestOutputHelper, + ResolvedTestClassName, + out var loggerFactory, + logLevelAttribute?.LogLevel ?? LogLevel.Debug, + out var resolvedTestName, + out var logOutputDirectory, + testName); - ResolvedLogOutputDirectory = logOutputDirectory; - ResolvedTestMethodName = resolvedTestName; + ResolvedLogOutputDirectory = logOutputDirectory; + ResolvedTestMethodName = resolvedTestName; - LoggerFactory = loggerFactory; - Logger = loggerFactory.CreateLogger(classType); + LoggerFactory = loggerFactory; + Logger = loggerFactory.CreateLogger(classType); + } + catch (Exception e) + { + _initializationException = ExceptionDispatchInfo.Capture(e); + } } - public virtual void Dispose() => _testLog.Dispose(); + public virtual void Dispose() + { + _initializationException?.Throw(); + _testLog.Dispose(); + } } } From e21dc21b403fdc7d4d8b5ba96cbe3fa41b9548db Mon Sep 17 00:00:00 2001 From: Andrew Lock Date: Wed, 2 Jan 2019 17:12:26 +0000 Subject: [PATCH 08/44] Use Task.Run instead of Task.Factory.StartNew (#611) Addresses #571 Using `TaskCreationOptions.LongRunning` creates a dedicated thread, but it's released on the first await. Using Task.Run uses the thread pool instead --- .../Logging.AzureAppServices/src/BatchingLoggerProvider.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs index 5b375a2b5a..7d0bd3ae40 100644 --- a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs @@ -75,7 +75,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices internal abstract Task WriteMessagesAsync(IEnumerable messages, CancellationToken token); - private async Task ProcessLogQueue(object state) + private async Task ProcessLogQueue() { while (!_cancellationTokenSource.IsCancellationRequested) { @@ -143,10 +143,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices new BlockingCollection(new ConcurrentQueue(), _queueSize.Value); _cancellationTokenSource = new CancellationTokenSource(); - _outputTask = Task.Factory.StartNew( - ProcessLogQueue, - null, - TaskCreationOptions.LongRunning); + _outputTask = Task.Run(ProcessLogQueue); } private void Stop() From 2283bd63f5d71782e852aa2b1d2917aea51e87e2 Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 7 Jan 2019 13:42:22 -0500 Subject: [PATCH 09/44] Add attribute to allow LoggedTest to collect dump on failure (#905) * Add attribute for collecting dumps for failed LoggedTest --- .../src/CollectDumpAttribute.cs | 18 +++++ .../DumpCollector/DumpCollector.Windows.cs | 76 +++++++++++++++++++ .../src/DumpCollector/DumpCollector.cs | 20 +++++ .../src/Xunit/LoggedTestInvoker.cs | 29 ++++++- .../src/Xunit/LoggedTestRunner.cs | 7 +- 5 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 src/Logging/Logging.Testing/src/CollectDumpAttribute.cs create mode 100644 src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.Windows.cs create mode 100644 src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.cs diff --git a/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs b/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs new file mode 100644 index 0000000000..8a6aa84bac --- /dev/null +++ b/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs @@ -0,0 +1,18 @@ +// 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; + +namespace Microsoft.Extensions.Logging.Testing +{ + /// + /// Capture the memory dump upon test failure. + /// + /// + /// This currently only works in Windows environments + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class CollectDumpAttribute : Attribute + { + } +} diff --git a/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.Windows.cs b/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.Windows.cs new file mode 100644 index 0000000000..8d4168c20c --- /dev/null +++ b/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.Windows.cs @@ -0,0 +1,76 @@ +// 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; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.Extensions.Logging.Testing +{ + public static partial class DumpCollector + { + private static class Windows + { + internal static void Collect(Process process, string outputFile) + { + // Open the file for writing + using (var stream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) + { + // Dump the process! + var exceptionInfo = new NativeMethods.MINIDUMP_EXCEPTION_INFORMATION(); + if (!NativeMethods.MiniDumpWriteDump(process.Handle, (uint)process.Id, stream.SafeFileHandle, NativeMethods.MINIDUMP_TYPE.MiniDumpWithFullMemory, ref exceptionInfo, IntPtr.Zero, IntPtr.Zero)) + { + var err = Marshal.GetHRForLastWin32Error(); + Marshal.ThrowExceptionForHR(err); + } + } + } + + private static class NativeMethods + { + [DllImport("Dbghelp.dll")] + public static extern bool MiniDumpWriteDump(IntPtr hProcess, uint ProcessId, SafeFileHandle hFile, MINIDUMP_TYPE DumpType, ref MINIDUMP_EXCEPTION_INFORMATION ExceptionParam, IntPtr UserStreamParam, IntPtr CallbackParam); + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct MINIDUMP_EXCEPTION_INFORMATION + { + public uint ThreadId; + public IntPtr ExceptionPointers; + public int ClientPointers; + } + + [Flags] + public enum MINIDUMP_TYPE : uint + { + MiniDumpNormal = 0, + MiniDumpWithDataSegs = 1 << 0, + MiniDumpWithFullMemory = 1 << 1, + MiniDumpWithHandleData = 1 << 2, + MiniDumpFilterMemory = 1 << 3, + MiniDumpScanMemory = 1 << 4, + MiniDumpWithUnloadedModules = 1 << 5, + MiniDumpWithIndirectlyReferencedMemory = 1 << 6, + MiniDumpFilterModulePaths = 1 << 7, + MiniDumpWithProcessThreadData = 1 << 8, + MiniDumpWithPrivateReadWriteMemory = 1 << 9, + MiniDumpWithoutOptionalData = 1 << 10, + MiniDumpWithFullMemoryInfo = 1 << 11, + MiniDumpWithThreadInfo = 1 << 12, + MiniDumpWithCodeSegs = 1 << 13, + MiniDumpWithoutAuxiliaryState = 1 << 14, + MiniDumpWithFullAuxiliaryState = 1 << 15, + MiniDumpWithPrivateWriteCopyMemory = 1 << 16, + MiniDumpIgnoreInaccessibleMemory = 1 << 17, + MiniDumpWithTokenInformation = 1 << 18, + MiniDumpWithModuleHeaders = 1 << 19, + MiniDumpFilterTriage = 1 << 20, + MiniDumpWithAvxXStateContext = 1 << 21, + MiniDumpWithIptTrace = 1 << 22, + MiniDumpValidTypeFlags = (-1) ^ ((~1) << 22) + } + } + } + } +} diff --git a/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.cs b/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.cs new file mode 100644 index 0000000000..67043ed827 --- /dev/null +++ b/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.cs @@ -0,0 +1,20 @@ +// 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.Diagnostics; +using System.Runtime.InteropServices; + +namespace Microsoft.Extensions.Logging.Testing +{ + public static partial class DumpCollector + { + public static void Collect(Process process, string fileName) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Windows.Collect(process, fileName); + } + // No implementations yet for macOS and Linux + } + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs index 708db37105..788c38b306 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs @@ -1,8 +1,10 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; using System.Collections.Generic; +using System.Diagnostics; +using System.IO; using System.Linq; using System.Reflection; using System.Threading; @@ -15,6 +17,7 @@ namespace Microsoft.Extensions.Logging.Testing { private readonly ITestOutputHelper _output; private readonly RetryContext _retryContext; + private readonly bool _collectDumpOnFailure; public LoggedTestInvoker( ITest test, @@ -27,11 +30,13 @@ namespace Microsoft.Extensions.Logging.Testing ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, ITestOutputHelper output, - RetryContext retryContext) + RetryContext retryContext, + bool collectDumpOnFailure) : base(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, beforeAfterAttributes, aggregator, cancellationTokenSource) { _output = output; _retryContext = retryContext; + _collectDumpOnFailure = collectDumpOnFailure; } protected override object CreateTestClass() @@ -63,5 +68,25 @@ namespace Microsoft.Extensions.Logging.Testing return testClass; } + + protected override object CallTestMethod(object testClassInstance) + { + try + { + return base.CallTestMethod(testClassInstance); + } + catch + { + if (_collectDumpOnFailure && testClassInstance is LoggedTestBase loggedTestBase) + { + var path = Path.Combine(loggedTestBase.ResolvedLogOutputDirectory, loggedTestBase.ResolvedTestMethodName + ".dmp"); + var process = Process.GetCurrentProcess(); + + DumpCollector.Collect(process, path); + } + + throw; + } + } } } diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs index 7dc847a113..11537eb679 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs @@ -50,9 +50,11 @@ namespace Microsoft.Extensions.Logging.Testing private async Task InvokeTestMethodAsync(ExceptionAggregator aggregator, ITestOutputHelper output) { var retryAttribute = GetRetryAttribute(TestMethod); + var collectDump = TestMethod.GetCustomAttribute() != null; + if (!typeof(LoggedTestBase).IsAssignableFrom(TestClass) || retryAttribute == null) { - return await new LoggedTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, aggregator, CancellationTokenSource, output, null).RunAsync(); + return await new LoggedTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, aggregator, CancellationTokenSource, output, null, collectDump).RunAsync(); } var retryPredicateMethodName = retryAttribute.RetryPredicateName; @@ -75,7 +77,7 @@ namespace Microsoft.Extensions.Logging.Testing }; var retryAggregator = new ExceptionAggregator(); - var loggedTestInvoker = new LoggedTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, retryAggregator, CancellationTokenSource, output, retryContext); + var loggedTestInvoker = new LoggedTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, retryAggregator, CancellationTokenSource, output, retryContext, collectDump); var totalTime = 0.0M; do @@ -95,7 +97,6 @@ namespace Microsoft.Extensions.Logging.Testing return totalTime; } - private RetryTestAttribute GetRetryAttribute(MethodInfo methodInfo) { var os = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? OperatingSystems.MacOSX From 88865365b3206097e50be768e5efc0bbbd6ffa53 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 7 Jan 2019 15:52:44 -0800 Subject: [PATCH 10/44] Remove netcoreapp2.0 test TFMs (#907) .NET Core 2.0 reached EOL last year. This removes multi-targeting our test projects and test assets to only use .NET Core 2.1 and .NET Framework 4.6.1. --- .../Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj | 2 +- .../test/Microsoft.Extensions.Logging.Testing.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj b/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj index e89ce311d8..5464e6a928 100644 --- a/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj +++ b/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj @@ -1,7 +1,7 @@  - $(StandardTestTfms) + netcoreapp2.1;net461 diff --git a/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj b/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj index 7d2170b241..a3ed4260cc 100644 --- a/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj +++ b/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj @@ -2,7 +2,7 @@ - $(StandardTestTfms) + netcoreapp2.1;net461 From 7940062040d4e8f8c3016c7b8300dfed31c8b9ce Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Tue, 15 Jan 2019 09:04:57 -0800 Subject: [PATCH 11/44] [2.2.x] Port Drop messages in azure loggers if queue is full (#592) --- .../src/Internal/BatchingLoggerProvider.cs | 20 ++++++++++++++++--- .../test/BatchingLoggerProviderTests.cs | 13 ++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs index 79720c5531..34250addd8 100644 --- a/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/Internal/BatchingLoggerProvider.cs @@ -18,6 +18,8 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal private readonly int? _batchSize; private readonly IDisposable _optionsChangeToken; + private int _messagesDropped; + private BlockingCollection _messageQueue; private Task _outputTask; private CancellationTokenSource _cancellationTokenSource; @@ -78,6 +80,16 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal limit--; } + var messagesDropped = Interlocked.Exchange(ref _messagesDropped, 0); + if (messagesDropped != 0) + { + _currentBatch.Add(new LogMessage() + { + Message = $"{messagesDropped} message(s) dropped because of queue size limit. Increase the queue size or decrease logging verbosity to avoid this.{Environment.NewLine}", + Timestamp = DateTimeOffset.Now + }); + } + if (_currentBatch.Count > 0) { try @@ -91,7 +103,6 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal _currentBatch.Clear(); } - await IntervalAsync(_interval, _cancellationTokenSource.Token); } } @@ -107,7 +118,10 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal { try { - _messageQueue.Add(new LogMessage { Message = message, Timestamp = timestamp }, _cancellationTokenSource.Token); + if (!_messageQueue.TryAdd(new LogMessage { Message = message, Timestamp = timestamp }, millisecondsTimeout: 0, cancellationToken: _cancellationTokenSource.Token)) + { + Interlocked.Increment(ref _messagesDropped); + } } catch { @@ -160,4 +174,4 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Internal return new BatchingLogger(this, categoryName); } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs b/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs index 42cefe99df..9d25b5a547 100644 --- a/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -51,7 +51,6 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test Assert.Single(provider.Batches); Assert.Single(provider.Batches[0]); Assert.Equal("2016-05-04 03:02:01.000 +00:00 [Information] Cat: Info message" + _nl, provider.Batches[0][0].Message); - provider.IntervalControl.Resume(); await provider.IntervalControl.Pause; @@ -62,7 +61,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test } [Fact] - public async Task BlocksWhenReachingMaxQueue() + public async Task DropsMessagesWhenReachingMaxQueue() { var provider = new TestBatchingLoggingProvider(maxQueueSize: 1); var logger = (BatchingLogger)provider.CreateLogger("Cat"); @@ -70,14 +69,14 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test await provider.IntervalControl.Pause; logger.Log(_timestampOne, LogLevel.Information, 0, "Info message", null, (state, ex) => state); - var task = Task.Run(() => logger.Log(_timestampOne.AddHours(1), LogLevel.Error, 0, "Error message", null, (state, ex) => state)); - - Assert.False(task.Wait(1000)); + logger.Log(_timestampOne.AddHours(1), LogLevel.Error, 0, "Error message", null, (state, ex) => state); provider.IntervalControl.Resume(); await provider.IntervalControl.Pause; - Assert.True(task.Wait(1000)); + Assert.Equal(2, provider.Batches[0].Length); + Assert.Equal("2016-05-04 03:02:01.000 +00:00 [Information] Cat: Info message" + _nl, provider.Batches[0][0].Message); + Assert.Equal("1 message(s) dropped because of queue size limit. Increase the queue size or decrease logging verbosity to avoid this." + _nl, provider.Batches[0][1].Message); } private class TestBatchingLoggingProvider: BatchingLoggerProvider From c4c2df54eb47ceb70f63469c83716eff21df511e Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Tue, 29 Jan 2019 13:26:53 -0800 Subject: [PATCH 12/44] Use Arcade (#586) Use arcade --- .../Microsoft.Extensions.Logging.AzureAppServices.csproj | 5 +++++ .../Logging.AzureAppServices/src/Properties/AssemblyInfo.cs | 2 -- .../src/Microsoft.Extensions.Logging.Testing.csproj | 5 +++++ src/Logging/Logging.Testing/src/Properties/AssemblyInfo.cs | 6 ------ .../src/Xunit/LoggedConditionalFactDiscoverer.cs | 4 ++-- .../src/Xunit/LoggedConditionalTheoryDiscoverer.cs | 4 ++-- .../Logging.Testing/src/Xunit/LoggedFactDiscoverer.cs | 4 ++-- src/Logging/Logging.Testing/src/Xunit/LoggedTestCase.cs | 5 +++-- .../src/Xunit/LoggedTestFrameworkDiscoverer.cs | 6 +++--- .../Logging.Testing/src/Xunit/LoggedTheoryDiscoverer.cs | 6 +++--- .../Logging.Testing/src/Xunit/LoggedTheoryTestCase.cs | 5 +++-- .../test/Properties/{AssemlyInfo.cs => AssemblyInfo.cs} | 2 +- 12 files changed, 29 insertions(+), 25 deletions(-) delete mode 100644 src/Logging/Logging.Testing/src/Properties/AssemblyInfo.cs rename src/Logging/Logging.Testing/test/Properties/{AssemlyInfo.cs => AssemblyInfo.cs} (67%) diff --git a/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj b/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj index d6eb186122..4eace047d4 100644 --- a/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj +++ b/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj @@ -4,8 +4,13 @@ Logger implementation to support Azure App Services 'Diagnostics logs' and 'Log stream' features. netstandard2.0 $(NoWarn);CS1591 + true + + + + diff --git a/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs b/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs index 83f3ffe055..d77af5dc95 100644 --- a/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs +++ b/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs @@ -1,8 +1,6 @@ // 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.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("Microsoft.Extensions.Logging.AzureAppServices.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] diff --git a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj index 22a1db0243..84fbab2966 100644 --- a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj +++ b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj @@ -6,8 +6,13 @@ $(NoWarn);CS1591 $(PackageTags);testing false + true + + + + diff --git a/src/Logging/Logging.Testing/src/Properties/AssemblyInfo.cs b/src/Logging/Logging.Testing/src/Properties/AssemblyInfo.cs deleted file mode 100644 index a5cc6c1da7..0000000000 --- a/src/Logging/Logging.Testing/src/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// 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.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("Microsoft.Extensions.Logging.Testing.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs index ebb9ecf92e..4ac4c6fe9c 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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 Microsoft.AspNetCore.Testing.xunit; @@ -20,7 +20,7 @@ namespace Microsoft.Extensions.Logging.Testing { var skipReason = testMethod.EvaluateSkipConditions(); return skipReason != null - ? new SkippedTestCase(skipReason, _diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod) + ? new SkippedTestCase(skipReason, _diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod) : base.CreateTestCase(discoveryOptions, testMethod, factAttribute); } diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs index d239b1147c..773ef71541 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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.Collections.Generic; @@ -22,7 +22,7 @@ namespace Microsoft.Extensions.Logging.Testing { var skipReason = testMethod.EvaluateSkipConditions(); return skipReason != null - ? new[] { new SkippedTestCase(skipReason, DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod) } + ? new[] { new SkippedTestCase(skipReason, DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod) } : base.CreateTestCasesForTheory(discoveryOptions, testMethod, theoryAttribute); } diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedFactDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedFactDiscoverer.cs index c52d99c822..e2268d96cb 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedFactDiscoverer.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedFactDiscoverer.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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 Xunit.Abstractions; @@ -13,6 +13,6 @@ namespace Microsoft.Extensions.Logging.Testing } protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) - => new LoggedTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod); + => new LoggedTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod); } } diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestCase.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestCase.cs index b8d3684c18..c43180df89 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestCase.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestCase.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -19,9 +19,10 @@ namespace Microsoft.Extensions.Logging.Testing public LoggedTestCase( IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, + TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, object[] testMethodArguments = null) - : base(diagnosticMessageSink, defaultMethodDisplay, testMethod, testMethodArguments) + : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) { } diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs index 4b1668ce95..9905404ed9 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -43,7 +43,7 @@ namespace Microsoft.Extensions.Logging.Testing if (factAttributes.Count() > 1) { var message = $"Test method '{testMethod.TestClass.Class.Name}.{testMethod.Method.Name}' has multiple [Fact]-derived attributes"; - var testCase = new ExecutionErrorTestCase(DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod, testMethod, message); + var testCase = new ExecutionErrorTestCase(DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod, TestMethodDisplayOptions.None, testMethod, message); return ReportDiscoveredTestCase(testCase, includeSourceInformation, messageBus); } @@ -77,4 +77,4 @@ namespace Microsoft.Extensions.Logging.Testing } } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryDiscoverer.cs index 535099c690..9d5402a09b 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryDiscoverer.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryDiscoverer.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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.Collections.Generic; @@ -18,12 +18,12 @@ namespace Microsoft.Extensions.Logging.Testing ITestMethod testMethod, IAttributeInfo theoryAttribute, object[] dataRow) - => new[] { new LoggedTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod, dataRow) }; + => new[] { new LoggedTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod, dataRow) }; protected override IEnumerable CreateTestCasesForTheory( ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute) - => new[] { new LoggedTheoryTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod) }; + => new[] { new LoggedTheoryTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod) }; } } diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCase.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCase.cs index db78f093c2..fa3e3a050d 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCase.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCase.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -19,8 +19,9 @@ namespace Microsoft.Extensions.Logging.Testing public LoggedTheoryTestCase( IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, + TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod) - : base(diagnosticMessageSink, defaultMethodDisplay, testMethod) + : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod) { } diff --git a/src/Logging/Logging.Testing/test/Properties/AssemlyInfo.cs b/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs similarity index 67% rename from src/Logging/Logging.Testing/test/Properties/AssemlyInfo.cs rename to src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs index 63c2b71d23..82616e2737 100644 --- a/src/Logging/Logging.Testing/test/Properties/AssemlyInfo.cs +++ b/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; [assembly: LogLevel(LogLevel.Trace)] From 6d452e9b05f1b1bfe7e346863b9e3675ecf86b18 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 29 Jan 2019 18:34:54 -0800 Subject: [PATCH 13/44] Cleanup conversion to Arcade (#1014) * Remove obsolete targets, properties, and scripts * Replace IsProductComponent with IsShipping * Undo bad merge to version.props * Update documentation, and put workarounds into a common file * Replace usages of RepositoryRoot with RepoRoot * Remove API baselines * Remove unnecessary restore feeds and split workarounds into two files * Enable PR checks on all branches, and disable autocancel --- .../Directory.Build.props | 7 - ...Extensions.Logging.AzureAppServices.csproj | 2 +- .../src/baseline.netcore.json | 368 ----- .../src/breakingchanges.netcore.json | 24 - ...icrosoft.Extensions.Logging.Testing.csproj | 3 +- .../Logging.Testing/src/baseline.netcore.json | 1321 ----------------- ...Microsoft.Extensions.Logging.Testing.props | 5 +- 7 files changed, 6 insertions(+), 1724 deletions(-) delete mode 100644 src/Logging/Logging.AzureAppServices/Directory.Build.props delete mode 100644 src/Logging/Logging.AzureAppServices/src/baseline.netcore.json delete mode 100644 src/Logging/Logging.AzureAppServices/src/breakingchanges.netcore.json delete mode 100644 src/Logging/Logging.Testing/src/baseline.netcore.json diff --git a/src/Logging/Logging.AzureAppServices/Directory.Build.props b/src/Logging/Logging.AzureAppServices/Directory.Build.props deleted file mode 100644 index f25c1d90ce..0000000000 --- a/src/Logging/Logging.AzureAppServices/Directory.Build.props +++ /dev/null @@ -1,7 +0,0 @@ - - - - - true - - diff --git a/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj b/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj index 4eace047d4..2a25b5b2c3 100644 --- a/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj +++ b/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj @@ -4,7 +4,7 @@ Logger implementation to support Azure App Services 'Diagnostics logs' and 'Log stream' features. netstandard2.0 $(NoWarn);CS1591 - true + true diff --git a/src/Logging/Logging.AzureAppServices/src/baseline.netcore.json b/src/Logging/Logging.AzureAppServices/src/baseline.netcore.json deleted file mode 100644 index f9b148ceae..0000000000 --- a/src/Logging/Logging.AzureAppServices/src/baseline.netcore.json +++ /dev/null @@ -1,368 +0,0 @@ -{ - "AssemblyIdentity": "Microsoft.Extensions.Logging.AzureAppServices, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", - "Types": [ - { - "Name": "Microsoft.Extensions.Logging.AzureAppServicesLoggerFactoryExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "AddAzureWebAppDiagnostics", - "Parameters": [ - { - "Name": "builder", - "Type": "Microsoft.Extensions.Logging.ILoggingBuilder" - } - ], - "ReturnType": "Microsoft.Extensions.Logging.ILoggingBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddAzureWebAppDiagnostics", - "Parameters": [ - { - "Name": "factory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - } - ], - "ReturnType": "Microsoft.Extensions.Logging.ILoggerFactory", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddAzureWebAppDiagnostics", - "Parameters": [ - { - "Name": "factory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "settings", - "Type": "Microsoft.Extensions.Logging.AzureAppServices.AzureAppServicesDiagnosticsSettings" - } - ], - "ReturnType": "Microsoft.Extensions.Logging.ILoggerFactory", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.AzureAppServices.AzureAppServicesDiagnosticsSettings", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_FileSizeLimit", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_FileSizeLimit", - "Parameters": [ - { - "Name": "value", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_RetainedFileCountLimit", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_RetainedFileCountLimit", - "Parameters": [ - { - "Name": "value", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OutputTemplate", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OutputTemplate", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_BlobBatchSize", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_BlobBatchSize", - "Parameters": [ - { - "Name": "value", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_BlobCommitPeriod", - "Parameters": [], - "ReturnType": "System.TimeSpan", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_BlobCommitPeriod", - "Parameters": [ - { - "Name": "value", - "Type": "System.TimeSpan" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_BlobName", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_BlobName", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_BackgroundQueueSize", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_BackgroundQueueSize", - "Parameters": [ - { - "Name": "value", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_FileFlushPeriod", - "Parameters": [], - "ReturnType": "System.Nullable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_FileFlushPeriod", - "Parameters": [ - { - "Name": "value", - "Type": "System.Nullable" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.AzureAppServices.AzureBlobLoggerOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.Extensions.Logging.AzureAppServices.Internal.BatchingLoggerOptions", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_BlobName", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_BlobName", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.AzureAppServices.AzureFileLoggerOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.Extensions.Logging.AzureAppServices.Internal.BatchingLoggerOptions", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_FileSizeLimit", - "Parameters": [], - "ReturnType": "System.Nullable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_FileSizeLimit", - "Parameters": [ - { - "Name": "value", - "Type": "System.Nullable" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_RetainedFileCountLimit", - "Parameters": [], - "ReturnType": "System.Nullable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_RetainedFileCountLimit", - "Parameters": [ - { - "Name": "value", - "Type": "System.Nullable" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_FileName", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_FileName", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - } - ] -} \ No newline at end of file diff --git a/src/Logging/Logging.AzureAppServices/src/breakingchanges.netcore.json b/src/Logging/Logging.AzureAppServices/src/breakingchanges.netcore.json deleted file mode 100644 index 7b778dd14a..0000000000 --- a/src/Logging/Logging.AzureAppServices/src/breakingchanges.netcore.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "TypeId": "public class Microsoft.Extensions.Logging.AzureAppServices.AzureAppServicesDiagnosticsSettings", - "Kind": "Removal" - }, - { - "TypeId": "public class Microsoft.Extensions.Logging.AzureAppServices.AzureBlobLoggerOptions : Microsoft.Extensions.Logging.AzureAppServices.Internal.BatchingLoggerOptions", - "Kind": "Removal" - }, - { - "TypeId": "public class Microsoft.Extensions.Logging.AzureAppServices.AzureFileLoggerOptions : Microsoft.Extensions.Logging.AzureAppServices.Internal.BatchingLoggerOptions", - "Kind": "Removal" - }, - { - "TypeId": "public static class Microsoft.Extensions.Logging.AzureAppServicesLoggerFactoryExtensions", - "MemberId": "public static Microsoft.Extensions.Logging.ILoggerFactory AddAzureWebAppDiagnostics(this Microsoft.Extensions.Logging.ILoggerFactory factory)", - "Kind": "Removal" - }, - { - "TypeId": "public static class Microsoft.Extensions.Logging.AzureAppServicesLoggerFactoryExtensions", - "MemberId": "public static Microsoft.Extensions.Logging.ILoggerFactory AddAzureWebAppDiagnostics(this Microsoft.Extensions.Logging.ILoggerFactory factory, Microsoft.Extensions.Logging.AzureAppServices.AzureAppServicesDiagnosticsSettings settings)", - "Kind": "Removal" - } -] diff --git a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj index 84fbab2966..8ab44e2067 100644 --- a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj +++ b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj @@ -5,8 +5,9 @@ netstandard2.0;net461 $(NoWarn);CS1591 $(PackageTags);testing - false + true + false diff --git a/src/Logging/Logging.Testing/src/baseline.netcore.json b/src/Logging/Logging.Testing/src/baseline.netcore.json deleted file mode 100644 index 95ba2ad582..0000000000 --- a/src/Logging/Logging.Testing/src/baseline.netcore.json +++ /dev/null @@ -1,1321 +0,0 @@ -{ - "AssemblyIdentity": "Microsoft.Extensions.Logging.Testing, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", - "Types": [ - { - "Name": "Microsoft.Extensions.Logging.XunitLoggerFactoryExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "AddXunit", - "Parameters": [ - { - "Name": "builder", - "Type": "Microsoft.Extensions.Logging.ILoggingBuilder" - }, - { - "Name": "output", - "Type": "Xunit.Abstractions.ITestOutputHelper" - } - ], - "ReturnType": "Microsoft.Extensions.Logging.ILoggingBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddXunit", - "Parameters": [ - { - "Name": "builder", - "Type": "Microsoft.Extensions.Logging.ILoggingBuilder" - }, - { - "Name": "output", - "Type": "Xunit.Abstractions.ITestOutputHelper" - }, - { - "Name": "minLevel", - "Type": "Microsoft.Extensions.Logging.LogLevel" - } - ], - "ReturnType": "Microsoft.Extensions.Logging.ILoggingBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddXunit", - "Parameters": [ - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "output", - "Type": "Xunit.Abstractions.ITestOutputHelper" - } - ], - "ReturnType": "Microsoft.Extensions.Logging.ILoggerFactory", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddXunit", - "Parameters": [ - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "output", - "Type": "Xunit.Abstractions.ITestOutputHelper" - }, - { - "Name": "minLevel", - "Type": "Microsoft.Extensions.Logging.LogLevel" - } - ], - "ReturnType": "Microsoft.Extensions.Logging.ILoggerFactory", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.Testing.AssemblyTestLog", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "System.IDisposable" - ], - "Members": [ - { - "Kind": "Method", - "Name": "StartTestLog", - "Parameters": [ - { - "Name": "output", - "Type": "Xunit.Abstractions.ITestOutputHelper" - }, - { - "Name": "className", - "Type": "System.String" - }, - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory", - "Direction": "Out" - }, - { - "Name": "testName", - "Type": "System.String", - "DefaultValue": "null" - } - ], - "ReturnType": "System.IDisposable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "CreateLoggerFactory", - "Parameters": [ - { - "Name": "output", - "Type": "Xunit.Abstractions.ITestOutputHelper" - }, - { - "Name": "className", - "Type": "System.String" - }, - { - "Name": "testName", - "Type": "System.String", - "DefaultValue": "null" - } - ], - "ReturnType": "Microsoft.Extensions.Logging.ILoggerFactory", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Create", - "Parameters": [ - { - "Name": "assemblyName", - "Type": "System.String" - }, - { - "Name": "baseDirectory", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.Extensions.Logging.Testing.AssemblyTestLog", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ForAssembly", - "Parameters": [ - { - "Name": "assembly", - "Type": "System.Reflection.Assembly" - } - ], - "ReturnType": "Microsoft.Extensions.Logging.Testing.AssemblyTestLog", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Dispose", - "Parameters": [], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "System.IDisposable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Field", - "Name": "OutputDirectoryEnvironmentVariableName", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "ReadOnly": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.Testing.BeginScopeContext", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Scope", - "Parameters": [], - "ReturnType": "System.Object", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Scope", - "Parameters": [ - { - "Name": "value", - "Type": "System.Object" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_LoggerName", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_LoggerName", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.Testing.ITestSink", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_WriteEnabled", - "Parameters": [], - "ReturnType": "System.Func", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_WriteEnabled", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_BeginEnabled", - "Parameters": [], - "ReturnType": "System.Func", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_BeginEnabled", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Scopes", - "Parameters": [], - "ReturnType": "System.Collections.Generic.List", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Scopes", - "Parameters": [ - { - "Name": "value", - "Type": "System.Collections.Generic.List" - } - ], - "ReturnType": "System.Void", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Writes", - "Parameters": [], - "ReturnType": "System.Collections.Generic.List", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Writes", - "Parameters": [ - { - "Name": "value", - "Type": "System.Collections.Generic.List" - } - ], - "ReturnType": "System.Void", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Write", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.Extensions.Logging.Testing.WriteContext" - } - ], - "ReturnType": "System.Void", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Begin", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.Extensions.Logging.Testing.BeginScopeContext" - } - ], - "ReturnType": "System.Void", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.Testing.LoggedTest", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "StartLog", - "Parameters": [ - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory", - "Direction": "Out" - }, - { - "Name": "testName", - "Type": "System.String", - "DefaultValue": "null" - } - ], - "ReturnType": "System.IDisposable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "output", - "Type": "Xunit.Abstractions.ITestOutputHelper" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.Testing.LogValuesAssert", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Contains", - "Parameters": [ - { - "Name": "key", - "Type": "System.String" - }, - { - "Name": "value", - "Type": "System.Object" - }, - { - "Name": "actualValues", - "Type": "System.Collections.Generic.IEnumerable>" - } - ], - "ReturnType": "System.Void", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Contains", - "Parameters": [ - { - "Name": "expectedValues", - "Type": "System.Collections.Generic.IEnumerable>" - }, - { - "Name": "actualValues", - "Type": "System.Collections.Generic.IEnumerable>" - } - ], - "ReturnType": "System.Void", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.Testing.TestLogger", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.Extensions.Logging.ILogger" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_Name", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Name", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "BeginScope", - "Parameters": [ - { - "Name": "state", - "Type": "T0" - } - ], - "ReturnType": "System.IDisposable", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", - "Visibility": "Public", - "GenericParameter": [ - { - "ParameterName": "TState", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Kind": "Method", - "Name": "Log", - "Parameters": [ - { - "Name": "logLevel", - "Type": "Microsoft.Extensions.Logging.LogLevel" - }, - { - "Name": "eventId", - "Type": "Microsoft.Extensions.Logging.EventId" - }, - { - "Name": "state", - "Type": "T0" - }, - { - "Name": "exception", - "Type": "System.Exception" - }, - { - "Name": "formatter", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", - "Visibility": "Public", - "GenericParameter": [ - { - "ParameterName": "TState", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Kind": "Method", - "Name": "IsEnabled", - "Parameters": [ - { - "Name": "logLevel", - "Type": "Microsoft.Extensions.Logging.LogLevel" - } - ], - "ReturnType": "System.Boolean", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "name", - "Type": "System.String" - }, - { - "Name": "sink", - "Type": "Microsoft.Extensions.Logging.Testing.ITestSink" - }, - { - "Name": "enabled", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "name", - "Type": "System.String" - }, - { - "Name": "sink", - "Type": "Microsoft.Extensions.Logging.Testing.ITestSink" - }, - { - "Name": "filter", - "Type": "System.Func" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.Testing.TestLoggerFactory", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.Extensions.Logging.ILoggerFactory" - ], - "Members": [ - { - "Kind": "Method", - "Name": "CreateLogger", - "Parameters": [ - { - "Name": "name", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.Extensions.Logging.ILogger", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.ILoggerFactory", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddProvider", - "Parameters": [ - { - "Name": "provider", - "Type": "Microsoft.Extensions.Logging.ILoggerProvider" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.ILoggerFactory", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "sink", - "Type": "Microsoft.Extensions.Logging.Testing.ITestSink" - }, - { - "Name": "enabled", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.Testing.TestLogger", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.Extensions.Logging.ILogger" - ], - "Members": [ - { - "Kind": "Method", - "Name": "BeginScope", - "Parameters": [ - { - "Name": "state", - "Type": "T0" - } - ], - "ReturnType": "System.IDisposable", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", - "Visibility": "Public", - "GenericParameter": [ - { - "ParameterName": "TState", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Kind": "Method", - "Name": "IsEnabled", - "Parameters": [ - { - "Name": "logLevel", - "Type": "Microsoft.Extensions.Logging.LogLevel" - } - ], - "ReturnType": "System.Boolean", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Log", - "Parameters": [ - { - "Name": "logLevel", - "Type": "Microsoft.Extensions.Logging.LogLevel" - }, - { - "Name": "eventId", - "Type": "Microsoft.Extensions.Logging.EventId" - }, - { - "Name": "state", - "Type": "T0" - }, - { - "Name": "exception", - "Type": "System.Exception" - }, - { - "Name": "formatter", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", - "Visibility": "Public", - "GenericParameter": [ - { - "ParameterName": "TState", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "factory", - "Type": "Microsoft.Extensions.Logging.Testing.TestLoggerFactory" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [ - { - "ParameterName": "T", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Name": "Microsoft.Extensions.Logging.Testing.TestSink", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.Extensions.Logging.Testing.ITestSink" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_WriteEnabled", - "Parameters": [], - "ReturnType": "System.Func", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_WriteEnabled", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_BeginEnabled", - "Parameters": [], - "ReturnType": "System.Func", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_BeginEnabled", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Scopes", - "Parameters": [], - "ReturnType": "System.Collections.Generic.List", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Scopes", - "Parameters": [ - { - "Name": "value", - "Type": "System.Collections.Generic.List" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Writes", - "Parameters": [], - "ReturnType": "System.Collections.Generic.List", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Writes", - "Parameters": [ - { - "Name": "value", - "Type": "System.Collections.Generic.List" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Write", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.Extensions.Logging.Testing.WriteContext" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Begin", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.Extensions.Logging.Testing.BeginScopeContext" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.Testing.ITestSink", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "EnableWithTypeName", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.Extensions.Logging.Testing.WriteContext" - } - ], - "ReturnType": "System.Boolean", - "Static": true, - "Visibility": "Public", - "GenericParameter": [ - { - "ParameterName": "T", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Kind": "Method", - "Name": "EnableWithTypeName", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.Extensions.Logging.Testing.BeginScopeContext" - } - ], - "ReturnType": "System.Boolean", - "Static": true, - "Visibility": "Public", - "GenericParameter": [ - { - "ParameterName": "T", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "writeEnabled", - "Type": "System.Func", - "DefaultValue": "null" - }, - { - "Name": "beginEnabled", - "Type": "System.Func", - "DefaultValue": "null" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.Testing.WriteContext", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_LogLevel", - "Parameters": [], - "ReturnType": "Microsoft.Extensions.Logging.LogLevel", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_LogLevel", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.Extensions.Logging.LogLevel" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_EventId", - "Parameters": [], - "ReturnType": "Microsoft.Extensions.Logging.EventId", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_EventId", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.Extensions.Logging.EventId" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_State", - "Parameters": [], - "ReturnType": "System.Object", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_State", - "Parameters": [ - { - "Name": "value", - "Type": "System.Object" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Exception", - "Parameters": [], - "ReturnType": "System.Exception", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Exception", - "Parameters": [ - { - "Name": "value", - "Type": "System.Exception" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Formatter", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Formatter", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Scope", - "Parameters": [], - "ReturnType": "System.Object", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Scope", - "Parameters": [ - { - "Name": "value", - "Type": "System.Object" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_LoggerName", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_LoggerName", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.Testing.XunitLoggerProvider", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.Extensions.Logging.ILoggerProvider" - ], - "Members": [ - { - "Kind": "Method", - "Name": "CreateLogger", - "Parameters": [ - { - "Name": "categoryName", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.Extensions.Logging.ILogger", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.ILoggerProvider", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "output", - "Type": "Xunit.Abstractions.ITestOutputHelper" - } - ], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "output", - "Type": "Xunit.Abstractions.ITestOutputHelper" - }, - { - "Name": "minLevel", - "Type": "Microsoft.Extensions.Logging.LogLevel" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.Logging.Testing.XunitLogger", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.Extensions.Logging.ILogger" - ], - "Members": [ - { - "Kind": "Method", - "Name": "Log", - "Parameters": [ - { - "Name": "logLevel", - "Type": "Microsoft.Extensions.Logging.LogLevel" - }, - { - "Name": "eventId", - "Type": "Microsoft.Extensions.Logging.EventId" - }, - { - "Name": "state", - "Type": "T0" - }, - { - "Name": "exception", - "Type": "System.Exception" - }, - { - "Name": "formatter", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", - "Visibility": "Public", - "GenericParameter": [ - { - "ParameterName": "TState", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Kind": "Method", - "Name": "IsEnabled", - "Parameters": [ - { - "Name": "logLevel", - "Type": "Microsoft.Extensions.Logging.LogLevel" - } - ], - "ReturnType": "System.Boolean", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "BeginScope", - "Parameters": [ - { - "Name": "state", - "Type": "T0" - } - ], - "ReturnType": "System.IDisposable", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.Extensions.Logging.ILogger", - "Visibility": "Public", - "GenericParameter": [ - { - "ParameterName": "TState", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "output", - "Type": "Xunit.Abstractions.ITestOutputHelper" - }, - { - "Name": "category", - "Type": "System.String" - }, - { - "Name": "minLogLevel", - "Type": "Microsoft.Extensions.Logging.LogLevel" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - } - ] -} \ No newline at end of file diff --git a/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props b/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props index 0d2585146c..c503c32d40 100644 --- a/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props +++ b/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props @@ -1,8 +1,9 @@  + $(RepositoryRoot) $(ASPNETCORE_TEST_LOG_DIR) - $(RepositoryRoot)artifacts\logs\ + $(RepoRoot)artifacts\log\ - \ No newline at end of file + From 478a18fb731cd19efaf6a9dc0591edf0373fc72d Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 31 Jan 2019 12:37:12 -0800 Subject: [PATCH 14/44] Make sure AzureAppServices logger is resolvable from DI contatiner (#1039) --- .../src/AzureAppServicesLoggerFactoryExtensions.cs | 2 ++ .../Logging.AzureAppServices/src/BlobLoggerProvider.cs | 2 +- .../Logging.AzureAppServices/src/FileLoggerProvider.cs | 2 +- .../test/LoggerBuilderExtensionsTests.cs | 10 ++++++++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs index 79b486b585..2b8398ef1c 100644 --- a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs +++ b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs @@ -35,6 +35,8 @@ namespace Microsoft.Extensions.Logging return builder; } + builder.AddConfiguration(); + var config = SiteConfigurationProvider.GetAzureLoggingConfiguration(context); var services = builder.Services; diff --git a/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs index abcba026fb..1a60bee215 100644 --- a/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs @@ -28,7 +28,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices /// Creates a new instance of /// /// - internal BlobLoggerProvider(IOptionsMonitor options) + public BlobLoggerProvider(IOptionsMonitor options) : this(options, null) { _blobReferenceFactory = name => new BlobAppendReferenceWrapper( diff --git a/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs index 9da2dcbe5a..b80322139a 100644 --- a/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs @@ -18,7 +18,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices private readonly int? _maxFileSize; private readonly int? _maxRetainedFiles; - internal FileLoggerProvider(IOptionsMonitor options) : base(options) + public FileLoggerProvider(IOptionsMonitor options) : base(options) { var loggerOptions = options.CurrentValue; _path = loggerOptions.LogDirectory; diff --git a/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs b/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs index de148f2c3a..468d52c7e4 100644 --- a/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs @@ -64,5 +64,15 @@ namespace Microsoft.Extensions.Logging.AzureAppServices.Test Assert.Equal(4, serviceCollection.Count(d => d.ServiceType == typeof(IConfigureOptions))); } + + [Fact] + public void LoggerProviderIsResolvable() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(builder => builder.AddAzureWebAppDiagnostics(_appContext)); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + var loggerFactory = serviceProvider.GetService(); + } } } From fca5c9cee82bd774df2379a63d0d769ac170de9a Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 31 Jan 2019 13:20:34 -0800 Subject: [PATCH 15/44] Remove implicit references for non-test projects (#1037) --- .../src/Microsoft.Extensions.Logging.Testing.csproj | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj index 8ab44e2067..4af8f8ac12 100644 --- a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj +++ b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj @@ -5,6 +5,8 @@ netstandard2.0;net461 $(NoWarn);CS1591 $(PackageTags);testing + + false true false @@ -21,6 +23,15 @@ + + From 8dc935ceee3dce6f69fe061bfa7b6fa357c8da05 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 11 Feb 2019 12:10:15 -0800 Subject: [PATCH 16/44] Add reference assembly generations support (#1093) --- ...Extensions.Logging.AzureAppServices.csproj | 16 ++++++ ...Logging.AzureAppServices.netstandard2.0.cs | 53 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.csproj create mode 100644 src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs diff --git a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.csproj b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.csproj new file mode 100644 index 0000000000..ff5ed03a15 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.csproj @@ -0,0 +1,16 @@ + + + + netstandard2.0 + false + + + + + + + + + + + diff --git a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs new file mode 100644 index 0000000000..e8392cdb51 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs @@ -0,0 +1,53 @@ +// 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. + +namespace Microsoft.Extensions.Logging +{ + public static partial class AzureAppServicesLoggerFactoryExtensions + { + public static Microsoft.Extensions.Logging.ILoggingBuilder AddAzureWebAppDiagnostics(this Microsoft.Extensions.Logging.ILoggingBuilder builder) { throw null; } + } +} +namespace Microsoft.Extensions.Logging.AzureAppServices +{ + public partial class AzureBlobLoggerOptions : Microsoft.Extensions.Logging.AzureAppServices.BatchingLoggerOptions + { + public AzureBlobLoggerOptions() { } + public string BlobName { get { throw null; } set { } } + } + public partial class AzureFileLoggerOptions : Microsoft.Extensions.Logging.AzureAppServices.BatchingLoggerOptions + { + public AzureFileLoggerOptions() { } + public string FileName { get { throw null; } set { } } + public System.Nullable FileSizeLimit { get { throw null; } set { } } + public System.Nullable RetainedFileCountLimit { get { throw null; } set { } } + } + public partial class BatchingLoggerOptions + { + public BatchingLoggerOptions() { } + public System.Nullable BackgroundQueueSize { get { throw null; } set { } } + public System.Nullable BatchSize { get { throw null; } set { } } + public System.TimeSpan FlushPeriod { get { throw null; } set { } } + public bool IncludeScopes { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } + public bool IsEnabled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } + } + public abstract partial class BatchingLoggerProvider : Microsoft.Extensions.Logging.ILoggerProvider, Microsoft.Extensions.Logging.ISupportExternalScope, System.IDisposable + { + internal BatchingLoggerProvider() { } + public bool IsEnabled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) { throw null; } + public void Dispose() { } + protected virtual System.Threading.Tasks.Task IntervalAsync(System.TimeSpan interval, System.Threading.CancellationToken cancellationToken) { throw null; } + void Microsoft.Extensions.Logging.ISupportExternalScope.SetScopeProvider(Microsoft.Extensions.Logging.IExternalScopeProvider scopeProvider) { } + } + [Microsoft.Extensions.Logging.ProviderAliasAttribute("AzureAppServicesBlob")] + public partial class BlobLoggerProvider : Microsoft.Extensions.Logging.AzureAppServices.BatchingLoggerProvider + { + public BlobLoggerProvider(Microsoft.Extensions.Options.IOptionsMonitor options) { } + } + [Microsoft.Extensions.Logging.ProviderAliasAttribute("AzureAppServicesFile")] + public partial class FileLoggerProvider : Microsoft.Extensions.Logging.AzureAppServices.BatchingLoggerProvider + { + public FileLoggerProvider(Microsoft.Extensions.Options.IOptionsMonitor options) { } + } +} From 75def8fa2b7936a3675d67f562cfd14dac6c8f96 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 15 Feb 2019 13:40:33 -0800 Subject: [PATCH 17/44] Deprecate and replace IHostingEnvronment & IApplicationLifetime (#1100) * Deprecate and replace IHostingEnvronment & IApplicationLifetime #966 * Fix startvs * Fix ref generation for obosolete --- .../ref/Microsoft.Extensions.Logging.AzureAppServices.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.csproj b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.csproj index ff5ed03a15..0132b21870 100644 --- a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.csproj +++ b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.csproj @@ -2,7 +2,6 @@ netstandard2.0 - false From 75672fe22e51e97a0e3ba83d52acffc2144b3021 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Tue, 19 Feb 2019 17:25:53 -0800 Subject: [PATCH 18/44] Manualy update tooling dependencies to normalize names (#1135) * Manualy update tooling dependencies to normalize names * Nullable --- ....Extensions.Logging.AzureAppServices.netstandard2.0.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs index e8392cdb51..6599438d40 100644 --- a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs +++ b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs @@ -19,14 +19,14 @@ namespace Microsoft.Extensions.Logging.AzureAppServices { public AzureFileLoggerOptions() { } public string FileName { get { throw null; } set { } } - public System.Nullable FileSizeLimit { get { throw null; } set { } } - public System.Nullable RetainedFileCountLimit { get { throw null; } set { } } + public int? FileSizeLimit { get { throw null; } set { } } + public int? RetainedFileCountLimit { get { throw null; } set { } } } public partial class BatchingLoggerOptions { public BatchingLoggerOptions() { } - public System.Nullable BackgroundQueueSize { get { throw null; } set { } } - public System.Nullable BatchSize { get { throw null; } set { } } + public int? BackgroundQueueSize { get { throw null; } set { } } + public int? BatchSize { get { throw null; } set { } } public System.TimeSpan FlushPeriod { get { throw null; } set { } } public bool IncludeScopes { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } public bool IsEnabled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } From e9fd9d7ab3d498e6ae18cca226bc9082b5eca08a Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 22 Feb 2019 12:35:31 -0800 Subject: [PATCH 19/44] Add xml docs to targeting pack (#1149) --- .../test/Microsoft.Extensions.Logging.Testing.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj b/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj index 95b5ae16c0..e240ba281c 100644 --- a/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj +++ b/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj @@ -8,6 +8,6 @@ - + From 52be71db2bbcc6248b8c0c2efa805574a5a3207e Mon Sep 17 00:00:00 2001 From: Andrew Stanton-Nurse Date: Wed, 6 Mar 2019 15:19:11 -0800 Subject: [PATCH 20/44] add FlakyAttribute to mark flaky tests (#1222) part of aspnet/AspNetCore#8237 --- .../Logging.Testing/src/LoggedTest/LoggedTestBase.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs index 72de6a87c3..492de61cb6 100644 --- a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs +++ b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs @@ -91,6 +91,14 @@ namespace Microsoft.Extensions.Logging.Testing public virtual void Dispose() { + if(_testLog == null) + { + // It seems like sometimes the MSBuild goop that adds the test framework can end up in a bad state and not actually add it + // Not sure yet why that happens but the exception isn't clear so I'm adding this error so we can detect it better. + // -anurse + throw new InvalidOperationException("LoggedTest base class was used but nothing initialized it! The test framework may not be enabled. Try cleaning your 'obj' directory."); + } + _initializationException?.Throw(); _testLog.Dispose(); } From 1bc41e09616585fb21ad5887586b1b00d6b834f7 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Tue, 9 Apr 2019 14:03:12 -0700 Subject: [PATCH 21/44] Add Repeat attribute (#1375) --- .../src/LoggedTest/LoggedTestBase.cs | 2 +- .../src/{RetryContext.cs => RepeatContext.cs} | 6 +- .../src/Xunit/LoggedTestInvoker.cs | 20 +--- .../src/Xunit/LoggedTestRunner.cs | 100 ++++++++--------- .../src/Xunit/RepeatAttribute.cs | 28 +++++ .../src/Xunit/RetryTestAttribute.cs | 68 ------------ .../test/LoggedTestXunitRepeatTests.cs | 43 ++++++++ .../test/LoggedTestXunitRetryTests.cs | 101 ------------------ .../test/LoggedTestXunitTests.cs | 2 +- .../test/Properties/AssemblyInfo.cs | 1 + 10 files changed, 121 insertions(+), 250 deletions(-) rename src/Logging/Logging.Testing/src/{RetryContext.cs => RepeatContext.cs} (70%) create mode 100644 src/Logging/Logging.Testing/src/Xunit/RepeatAttribute.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/RetryTestAttribute.cs create mode 100644 src/Logging/Logging.Testing/test/LoggedTestXunitRepeatTests.cs delete mode 100644 src/Logging/Logging.Testing/test/LoggedTestXunitRetryTests.cs diff --git a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs index 492de61cb6..94cdf82257 100644 --- a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs +++ b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs @@ -26,7 +26,7 @@ namespace Microsoft.Extensions.Logging.Testing // Internal for testing internal string ResolvedTestClassName { get; set; } - internal RetryContext RetryContext { get; set; } + internal RepeatContext RepeatContext { get; set; } public string ResolvedLogOutputDirectory { get; set; } diff --git a/src/Logging/Logging.Testing/src/RetryContext.cs b/src/Logging/Logging.Testing/src/RepeatContext.cs similarity index 70% rename from src/Logging/Logging.Testing/src/RetryContext.cs rename to src/Logging/Logging.Testing/src/RepeatContext.cs index 529de656b5..decc7a173c 100644 --- a/src/Logging/Logging.Testing/src/RetryContext.cs +++ b/src/Logging/Logging.Testing/src/RepeatContext.cs @@ -3,14 +3,10 @@ namespace Microsoft.Extensions.Logging.Testing { - public class RetryContext + public class RepeatContext { internal int Limit { get; set; } - internal object TestClassInstance { get; set; } - - internal string Reason { get; set; } - internal int CurrentIteration { get; set; } } } diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs index 788c38b306..0e6638cb57 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs @@ -16,7 +16,7 @@ namespace Microsoft.Extensions.Logging.Testing public class LoggedTestInvoker : XunitTestInvoker { private readonly ITestOutputHelper _output; - private readonly RetryContext _retryContext; + private readonly RepeatContext _repeatContext; private readonly bool _collectDumpOnFailure; public LoggedTestInvoker( @@ -30,12 +30,12 @@ namespace Microsoft.Extensions.Logging.Testing ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, ITestOutputHelper output, - RetryContext retryContext, + RepeatContext repeatContext, bool collectDumpOnFailure) : base(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, beforeAfterAttributes, aggregator, cancellationTokenSource) { _output = output; - _retryContext = retryContext; + _repeatContext = repeatContext; _collectDumpOnFailure = collectDumpOnFailure; } @@ -51,19 +51,7 @@ namespace Microsoft.Extensions.Logging.Testing if (testClass is LoggedTestBase loggedTestBase) { // Used for testing - loggedTestBase.RetryContext = _retryContext; - - if (_retryContext != null) - { - // Log retry attempt as warning - if (_retryContext.CurrentIteration > 0) - { - loggedTestBase.Logger.LogWarning($"{TestMethod.Name} failed and retry conditions are met, re-executing. The reason for failure is {_retryContext.Reason}."); - } - - // Save the test class instance for non-static predicates - _retryContext.TestClassInstance = testClass; - } + loggedTestBase.RepeatContext = _repeatContext; } return testClass; diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs index 11537eb679..8069801fbe 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs @@ -49,82 +49,66 @@ namespace Microsoft.Extensions.Logging.Testing private async Task InvokeTestMethodAsync(ExceptionAggregator aggregator, ITestOutputHelper output) { - var retryAttribute = GetRetryAttribute(TestMethod); var collectDump = TestMethod.GetCustomAttribute() != null; - - if (!typeof(LoggedTestBase).IsAssignableFrom(TestClass) || retryAttribute == null) + var repeatAttribute = GetRepeatAttribute(TestMethod); + + if (!typeof(LoggedTestBase).IsAssignableFrom(TestClass) || repeatAttribute == null) { return await new LoggedTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, aggregator, CancellationTokenSource, output, null, collectDump).RunAsync(); } - var retryPredicateMethodName = retryAttribute.RetryPredicateName; - var retryPredicateMethod = TestClass.GetMethod(retryPredicateMethodName, - BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static, - null, - new Type[] { typeof(Exception) }, - null) - ?? throw new InvalidOperationException($"No valid static retry predicate method {retryPredicateMethodName} was found on the type {TestClass.FullName}."); - - if (retryPredicateMethod.ReturnType != typeof(bool)) - { - throw new InvalidOperationException($"Retry predicate method {retryPredicateMethodName} on {TestClass.FullName} does not return bool."); - } - - var retryContext = new RetryContext() - { - Limit = retryAttribute.RetryLimit, - Reason = retryAttribute.RetryReason, - }; - - var retryAggregator = new ExceptionAggregator(); - var loggedTestInvoker = new LoggedTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, retryAggregator, CancellationTokenSource, output, retryContext, collectDump); - var totalTime = 0.0M; - - do - { - retryAggregator.Clear(); - totalTime += await loggedTestInvoker.RunAsync(); - retryContext.CurrentIteration++; - } - while (retryAggregator.HasExceptions - && retryContext.CurrentIteration < retryContext.Limit - && (retryPredicateMethod.IsStatic - ? (bool)retryPredicateMethod.Invoke(null, new object[] { retryAggregator.ToException() }) - : (bool)retryPredicateMethod.Invoke(retryContext.TestClassInstance, new object[] { retryAggregator.ToException() })) - ); - - aggregator.Aggregate(retryAggregator); - return totalTime; + return await RunRepeatTestInvoker(aggregator, output, collectDump, repeatAttribute); } - private RetryTestAttribute GetRetryAttribute(MethodInfo methodInfo) + private async Task RunRepeatTestInvoker(ExceptionAggregator aggregator, ITestOutputHelper output, bool collectDump, RepeatAttribute repeatAttribute) { - var os = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? OperatingSystems.MacOSX - : RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? OperatingSystems.Windows - : OperatingSystems.Linux; + var repeatContext = new RepeatContext + { + Limit = repeatAttribute.RunCount + }; - var attributeCandidate = methodInfo.GetCustomAttribute(); + var timeTaken = 0.0M; + var testLogger = new LoggedTestInvoker( + Test, + MessageBus, + TestClass, + ConstructorArguments, + TestMethod, + TestMethodArguments, + BeforeAfterAttributes, + aggregator, + CancellationTokenSource, + output, + repeatContext, + collectDump); - if (attributeCandidate != null && (attributeCandidate.OperatingSystems & os) != 0) + for (repeatContext.CurrentIteration = 0; repeatContext.CurrentIteration < repeatContext.Limit; repeatContext.CurrentIteration++) + { + timeTaken = await testLogger.RunAsync(); + if (aggregator.HasExceptions) + { + return timeTaken; + } + } + + return timeTaken; + } + + private RepeatAttribute GetRepeatAttribute(MethodInfo methodInfo) + { + var attributeCandidate = methodInfo.GetCustomAttribute(); + if (attributeCandidate != null) { return attributeCandidate; } - attributeCandidate = methodInfo.DeclaringType.GetCustomAttribute(); - - if (attributeCandidate != null && (attributeCandidate.OperatingSystems & os) != 0) + attributeCandidate = methodInfo.DeclaringType.GetCustomAttribute(); + if (attributeCandidate != null) { return attributeCandidate; } - attributeCandidate = methodInfo.DeclaringType.Assembly.GetCustomAttribute(); - - if (attributeCandidate != null && (attributeCandidate.OperatingSystems & os) != 0) - { - return attributeCandidate; - } - - return null; + return methodInfo.DeclaringType.Assembly.GetCustomAttribute(); } } } diff --git a/src/Logging/Logging.Testing/src/Xunit/RepeatAttribute.cs b/src/Logging/Logging.Testing/src/Xunit/RepeatAttribute.cs new file mode 100644 index 0000000000..ec86c0b601 --- /dev/null +++ b/src/Logging/Logging.Testing/src/Xunit/RepeatAttribute.cs @@ -0,0 +1,28 @@ +// 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; +using System.ComponentModel; + +namespace Microsoft.Extensions.Logging.Testing +{ + /// + /// Runs a test multiple times to stress flaky tests that are believed to be fixed. + /// This can be used on an assembly, class, or method name. + /// Requires using to run. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false)] + public class RepeatAttribute : Attribute + { + public RepeatAttribute(int runCount = 10) + { + RunCount = runCount; + } + + /// + /// The number of times to run a test. + /// + public int RunCount { get; } + } +} diff --git a/src/Logging/Logging.Testing/src/Xunit/RetryTestAttribute.cs b/src/Logging/Logging.Testing/src/Xunit/RetryTestAttribute.cs deleted file mode 100644 index e85f2c517e..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/RetryTestAttribute.cs +++ /dev/null @@ -1,68 +0,0 @@ -// 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; -using System.ComponentModel; -using Microsoft.AspNetCore.Testing.xunit; - -namespace Microsoft.Extensions.Logging.Testing -{ - /// - /// WARNING: This attribute should only be used on well understood flaky test failures caused by external issues and should be removed once the underlying issues have been resolved. - /// This is not intended to be a long term solution to ensure passing of flaky tests but instead a method to improve test reliability without reducing coverage. - /// Issues should be filed to remove these attributes from affected tests as soon as the underlying issue is fixed. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)] - public class RetryTestAttribute : Attribute - { - /// - /// WARNING: This attribute should only be used on well understood flaky test failures caused by external issues and should be removed once the underlying issues have been resolved. - /// This is not intended to be a long term solution to ensure passing of flaky tests but instead a method to improve test reliability without reducing coverage. - /// Issues should be filed to remove these attributes from affected tests as soon as the underlying issue is fixed. - /// - /// The predicate of the format Func<Exception,bool> that is used to determine if the test should be retried - /// The reason for retrying the test - /// The number of retries to attempt before failing the test, for most purposes this this should be kept at 2 to avoid excessive retries. - public RetryTestAttribute(string retryPredicateName, string retryReason, int retryLimit = 2) - : this(retryPredicateName, retryReason, OperatingSystems.Linux | OperatingSystems.MacOSX | OperatingSystems.Windows, retryLimit) { } - - /// - /// WARNING: This attribute should only be used on well understood flaky test failures caused by external issuesand should be removed once the underlying issues have been resolved. - /// This is not intended to be a long term solution to ensure passing of flaky tests but instead a method to improve test reliability without reducing coverage. - /// Issues should be filed to remove these attributes from affected tests as soon as the underlying issue is fixed. - /// - /// The os(es) this retry should be attempted on. - /// The predicate of the format Func<Exception,bool> that is used to determine if the test should be retried - /// The reason for retrying the test - /// The number of retries to attempt before failing the test, for most purposes this this should be kept at 2 to avoid excessive retries. - public RetryTestAttribute(string retryPredicateName, string retryReason, OperatingSystems operatingSystems, int retryLimit = 2) - { - if (string.IsNullOrEmpty(retryPredicateName)) - { - throw new ArgumentNullException(nameof(RetryPredicateName), "A valid non-empty predicate method name must be provided."); - } - if (string.IsNullOrEmpty(retryReason)) - { - throw new ArgumentNullException(nameof(retryReason), "A valid non-empty reason for retrying the test must be provided."); - } - if (retryLimit < 1) - { - throw new ArgumentOutOfRangeException(nameof(retryLimit), retryLimit, "Retry count must be positive."); - } - - OperatingSystems = operatingSystems; - RetryPredicateName = retryPredicateName; - RetryReason = retryReason; - RetryLimit = retryLimit; - } - - public string RetryPredicateName { get; } - - public string RetryReason { get; } - - public int RetryLimit { get; } - - public OperatingSystems OperatingSystems { get; } - } -} diff --git a/src/Logging/Logging.Testing/test/LoggedTestXunitRepeatTests.cs b/src/Logging/Logging.Testing/test/LoggedTestXunitRepeatTests.cs new file mode 100644 index 0000000000..dbd1d7260a --- /dev/null +++ b/src/Logging/Logging.Testing/test/LoggedTestXunitRepeatTests.cs @@ -0,0 +1,43 @@ +// 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 Xunit; + +namespace Microsoft.Extensions.Logging.Testing.Tests +{ + [Repeat] + public class LoggedTestXunitRepeatTests : LoggedTest + { + public static int _runCount = 0; + + [Fact] + [Repeat(5)] + public void RepeatLimitIsSetCorrectly() + { + Assert.Equal(5, RepeatContext.Limit); + } + + [Fact] + [Repeat(5)] + public void RepeatRunsTestSpecifiedNumberOfTimes() + { + Assert.Equal(RepeatContext.CurrentIteration, _runCount); + _runCount++; + } + + [Fact] + public void RepeatCanBeSetOnClass() + { + Assert.Equal(10, RepeatContext.Limit); + } + } + + public class LoggedTestXunitRepeatAssemblyTests : LoggedTest + { + [Fact] + public void RepeatCanBeSetOnAssembly() + { + Assert.Equal(1, RepeatContext.Limit); + } + } +} diff --git a/src/Logging/Logging.Testing/test/LoggedTestXunitRetryTests.cs b/src/Logging/Logging.Testing/test/LoggedTestXunitRetryTests.cs deleted file mode 100644 index 1e49f45046..0000000000 --- a/src/Logging/Logging.Testing/test/LoggedTestXunitRetryTests.cs +++ /dev/null @@ -1,101 +0,0 @@ -// 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; -using System.Linq; -using Microsoft.AspNetCore.Testing.xunit; -using Xunit; - -namespace Microsoft.Extensions.Logging.Testing.Tests -{ - [RetryTest(nameof(RetryAllPredicate), "sample reason")] - public class LoggedTestXunitRetryTests : LoggedTest - { - [Fact] - public void CompletesWithoutRetryOnSuccess() - { - Assert.Equal(2, RetryContext.Limit); - - // This assert would fail on the second run - Assert.Equal(0, RetryContext.CurrentIteration); - } - - [Fact] - public void RetriesUntilSuccess() - { - // This assert will fail the first time but pass on the second - Assert.Equal(1, RetryContext.CurrentIteration); - - // This assert will ensure a message is logged for retried tests. - Assert.Equal(1, TestSink.Writes.Count); - var loggedMessage = TestSink.Writes.ToArray()[0]; - Assert.Equal(LogLevel.Warning, loggedMessage.LogLevel); - Assert.Equal($"{nameof(RetriesUntilSuccess)} failed and retry conditions are met, re-executing. The reason for failure is sample reason.", loggedMessage.Message); - } - - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows)] - [RetryTest(nameof(RetryAllPredicate), "sample reason", OperatingSystems.Windows, 3)] - public void RetryCountNotOverridenWhenOSDoesNotMatch() - { - Assert.Equal(2, RetryContext.Limit); - } - - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] - [RetryTest(nameof(RetryAllPredicate), "sample reason", OperatingSystems.Windows, 3)] - public void RetryCountOverridenWhenOSMatches() - { - Assert.Equal(3, RetryContext.Limit); - } - - [Fact] - [RetryTest(nameof(RetryInvalidOperationExceptionPredicate), "sample reason")] - public void RetryIfPredicateIsTrue() - { - if (RetryContext.CurrentIteration == 0) - { - Logger.LogWarning("Throw on first iteration"); - throw new Exception(); - } - - // This assert will ensure a message is logged for retried tests. - Assert.Equal(1, TestSink.Writes.Count); - var loggedMessage = TestSink.Writes.ToArray()[0]; - Assert.Equal(LogLevel.Warning, loggedMessage.LogLevel); - Assert.Equal($"{nameof(RetryIfPredicateIsTrue)} failed and retry conditions are met, re-executing. The reason for failure is sample reason.", loggedMessage.Message); - } - - // Static predicates are valid - private static bool RetryAllPredicate(Exception e) - => true; - - // Instance predicates are valid - private bool RetryInvalidOperationExceptionPredicate(Exception e) - => TestSink.Writes.Any(m => m.Message.Contains("Throw on first iteration")); - } - - [RetryTest(nameof(RetryAllPredicate), "sample reason")] - public class LoggedTestXunitRetryConstructorTest : LoggedTest - { - private static int _constructorInvocationCount; - - public LoggedTestXunitRetryConstructorTest() - { - _constructorInvocationCount++; - } - - [Fact] - public void RetriesUntilSuccess() - { - // The constructor is invoked before the test method but the current iteration is updated after - Assert.Equal(_constructorInvocationCount, RetryContext.CurrentIteration + 1); - - // This assert will fail the first time but pass on the second - Assert.Equal(1, RetryContext.CurrentIteration); - } - - private static bool RetryAllPredicate(Exception e) - => true; - } -} diff --git a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs index 507453a242..520ffaaa9e 100644 --- a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs +++ b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; diff --git a/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs b/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs index 82616e2737..b104c11dfc 100644 --- a/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs +++ b/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs @@ -2,3 +2,4 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; [assembly: LogLevel(LogLevel.Trace)] +[assembly: Repeat(1)] From 56fe4e0f030973a058f541a593384566d3697e58 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 23 May 2019 16:33:55 -0700 Subject: [PATCH 22/44] Add support for source-build (#1740) --- .../Logging.AzureAppServices/Directory.Build.props | 8 ++++++++ .../src/Microsoft.Extensions.Logging.Testing.csproj | 1 + 2 files changed, 9 insertions(+) create mode 100644 src/Logging/Logging.AzureAppServices/Directory.Build.props diff --git a/src/Logging/Logging.AzureAppServices/Directory.Build.props b/src/Logging/Logging.AzureAppServices/Directory.Build.props new file mode 100644 index 0000000000..68f87d4f24 --- /dev/null +++ b/src/Logging/Logging.AzureAppServices/Directory.Build.props @@ -0,0 +1,8 @@ + + + + + + true + + diff --git a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj index 4af8f8ac12..0670cffcc9 100644 --- a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj +++ b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj @@ -10,6 +10,7 @@ true false + true From ab1dbe11051fe1740dac5c399f91028ac4efc5bc Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 12 Jun 2019 22:39:41 -0700 Subject: [PATCH 23/44] Use even more Arcade and other csproj cleanups (#1833) * Use Arcade's convention for setting IsPackable (must be explicitly set) * Use Arcade conventions for using DebugType and eng/Versions.props * Remove dead code * Update restore feeds in daily builds.md * Disable UsingToolNetFrameworkReferenceAssemblies in analyzer tests * Remove usage of TestGroupName (an obsolete KoreBuild setting) * Use IVT as a .csproj attribute --- .../src/Microsoft.Extensions.Logging.AzureAppServices.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj b/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj index 2a25b5b2c3..5bedde8c6d 100644 --- a/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj +++ b/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj @@ -4,6 +4,7 @@ Logger implementation to support Azure App Services 'Diagnostics logs' and 'Log stream' features. netstandard2.0 $(NoWarn);CS1591 + true true From 92ead8b7904187f7d8efa4dbdf1c200c0f395be5 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 13 Jun 2019 16:27:19 -0700 Subject: [PATCH 24/44] Disable transitive project references in test projects (#1834) --- ...rosoft.Extensions.Logging.AzureAppServices.Tests.csproj | 7 +++++++ .../test/Microsoft.Extensions.Logging.Testing.Tests.csproj | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj b/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj index f75f3429e2..54b36b5aab 100644 --- a/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj +++ b/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj @@ -5,8 +5,15 @@ + + + + + + + diff --git a/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj b/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj index e240ba281c..e4e19773e3 100644 --- a/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj +++ b/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj @@ -6,8 +6,12 @@ + + + + From 8bce347b3b486b4ec026390614478a3bad1272f0 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 27 Jun 2019 15:58:43 -0700 Subject: [PATCH 25/44] Add some missing doc comments --- .../src/BatchingLoggerOptions.cs | 3 +++ .../src/BatchingLoggerProvider.cs | 24 ++++++++++++++++++- .../src/BlobLoggerProvider.cs | 2 +- .../src/FileLoggerProvider.cs | 7 ++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerOptions.cs index 23998fb5d1..b474af5489 100644 --- a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerOptions.cs @@ -5,6 +5,9 @@ using System; namespace Microsoft.Extensions.Logging.AzureAppServices { + /// + /// Options for a logger which batches up log messages. + /// public class BatchingLoggerOptions { private int? _batchSize; diff --git a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs index 7d0bd3ae40..5cf8ccd27c 100644 --- a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs @@ -10,7 +10,10 @@ using Microsoft.Extensions.Options; namespace Microsoft.Extensions.Logging.AzureAppServices { - public abstract class BatchingLoggerProvider: ILoggerProvider, ISupportExternalScope + /// + /// A provider of 's. + /// + public abstract class BatchingLoggerProvider : ILoggerProvider, ISupportExternalScope { private readonly List _currentBatch = new List(); private readonly TimeSpan _interval; @@ -51,6 +54,9 @@ namespace Microsoft.Extensions.Logging.AzureAppServices UpdateOptions(options.CurrentValue); } + /// + /// Checks if the queue is enabled. + /// public bool IsEnabled { get; private set; } private void UpdateOptions(BatchingLoggerOptions options) @@ -113,6 +119,12 @@ namespace Microsoft.Extensions.Logging.AzureAppServices } } + /// + /// Wait for the given . + /// + /// The amount of time to wait. + /// A that can be used to cancel the delay. + /// A which completes when the has passed or the has been canceled. protected virtual Task IntervalAsync(TimeSpan interval, CancellationToken cancellationToken) { return Task.Delay(interval, cancellationToken); @@ -163,6 +175,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices } } + /// public void Dispose() { _optionsChangeToken?.Dispose(); @@ -172,11 +185,20 @@ namespace Microsoft.Extensions.Logging.AzureAppServices } } + /// + /// Creates a with the given . + /// + /// The name of the category to create this logger with. + /// The that was created. public ILogger CreateLogger(string categoryName) { return new BatchingLogger(this, categoryName); } + /// + /// Sets the scope on this provider. + /// + /// Provides the scope. void ISupportExternalScope.SetScopeProvider(IExternalScopeProvider scopeProvider) { _scopeProvider = scopeProvider; diff --git a/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs index 1a60bee215..77182ea933 100644 --- a/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs @@ -27,7 +27,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices /// /// Creates a new instance of /// - /// + /// The options to use when creating a provider. public BlobLoggerProvider(IOptionsMonitor options) : this(options, null) { diff --git a/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs index b80322139a..fb34d63d5b 100644 --- a/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs @@ -10,6 +10,9 @@ using Microsoft.Extensions.Options; namespace Microsoft.Extensions.Logging.AzureAppServices { + /// + /// A which writes out to a file. + /// [ProviderAlias("AzureAppServicesFile")] public class FileLoggerProvider : BatchingLoggerProvider { @@ -18,6 +21,10 @@ namespace Microsoft.Extensions.Logging.AzureAppServices private readonly int? _maxFileSize; private readonly int? _maxRetainedFiles; + /// + /// Creates a new instance of . + /// + /// The options to use when creating a provider. public FileLoggerProvider(IOptionsMonitor options) : base(options) { var loggerOptions = options.CurrentValue; From 0ef640d043fbf81fc07a9fd6c6e2a05708992a9a Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 27 Jun 2019 16:57:47 -0700 Subject: [PATCH 26/44] More doc comments --- src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs index 77182ea933..e906c2746f 100644 --- a/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs @@ -41,7 +41,7 @@ namespace Microsoft.Extensions.Logging.AzureAppServices /// Creates a new instance of /// /// The container to store logs to. - /// + /// Options to be used in creating a logger. internal BlobLoggerProvider( IOptionsMonitor options, Func blobReferenceFactory) : From 6ef6930b1babfb5ba99d429d6ff53ec877f5b918 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Tue, 2 Jul 2019 16:39:42 -0700 Subject: [PATCH 27/44] PR feedback --- .../Logging.AzureAppServices/src/BatchingLoggerProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs index 5cf8ccd27c..a78a7f7bc7 100644 --- a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs @@ -11,7 +11,7 @@ using Microsoft.Extensions.Options; namespace Microsoft.Extensions.Logging.AzureAppServices { /// - /// A provider of 's. + /// A provider of instances. /// public abstract class BatchingLoggerProvider : ILoggerProvider, ISupportExternalScope { From 9898a0eb719660b5add5717a4125974513aedb49 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Thu, 15 Aug 2019 09:12:53 -0700 Subject: [PATCH 28/44] Cleanup to skip/flaky attributes (#2186) --- .../src/Xunit/LoggedConditionalFactDiscoverer.cs | 2 +- .../src/Xunit/LoggedConditionalTheoryDiscoverer.cs | 2 +- .../Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs | 2 +- src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs | 2 +- src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs index 4ac4c6fe9c..4d61c9592d 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs @@ -1,7 +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 Microsoft.AspNetCore.Testing.xunit; +using Microsoft.AspNetCore.Testing; using Xunit.Abstractions; using Xunit.Sdk; diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs index 773ef71541..bce28051a6 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using Microsoft.AspNetCore.Testing.xunit; +using Microsoft.AspNetCore.Testing; using Xunit.Abstractions; using Xunit.Sdk; diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs index 9905404ed9..d7ff598f8e 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.AspNetCore.Testing.xunit; +using Microsoft.AspNetCore.Testing; using Xunit; using Xunit.Abstractions; using Xunit.Sdk; diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs index 8069801fbe..a630a4c50d 100644 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs +++ b/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs @@ -8,7 +8,7 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Testing.xunit; +using Microsoft.AspNetCore.Testing; using Xunit.Abstractions; using Xunit.Sdk; diff --git a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs index 520ffaaa9e..ab9ee746c3 100644 --- a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs +++ b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Reflection; -using Microsoft.AspNetCore.Testing.xunit; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; using Xunit; using Xunit.Abstractions; From 31b0a53a9f0f4244b169103bedb409b1d7c2c5af Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 12 Sep 2019 22:34:52 -0700 Subject: [PATCH 29/44] Support netcoreapp3.1 TFM (#2336) * Support netcoreapp3.1 TFM * Unpin SDK for source build * Update to preview1 branding --- .../Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj | 2 +- .../test/Microsoft.Extensions.Logging.Testing.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj b/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj index 54b36b5aab..b1a396085d 100644 --- a/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj +++ b/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 diff --git a/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj b/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj index e4e19773e3..7b478d5ce9 100644 --- a/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj +++ b/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj @@ -2,7 +2,7 @@ - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 From 0e7ff1e6ec19534df8d98710e1ab4228a3cb559a Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Mon, 16 Sep 2019 13:33:09 -0700 Subject: [PATCH 30/44] Refactor xUnit extensibility Adds our own hook for before/after logic that's more usable, called `ITestMethodLifecycle`. This provides access to a context object including the information about the test and the output helper. This can be implemented by attributes or by the class itself. The goal (and result) of this, is that we have a single *test executor* extensibility point that provides all of the features we need. We should use this everywhere we need features xUnit doesn't have. Adding a new extensibility point (`ITestMethodLifecycle`) allows us to do this without turning all of these features into a giant monolith. --- Also updated our existing extensibility to use this new hook. I did as much cleanup as a could to remove duplication from logging and keep it loosly coupled. I didn't want to tease this apart completely because the scope of this PR is already pretty large. --- .../Logging.Testing/src/AssemblyTestLog.cs | 55 ++------- .../src/CollectDumpAttribute.cs | 23 +++- .../src/{Xunit => }/LogLevelAttribute.cs | 0 .../src/LoggedTest/ILoggedTest.cs | 3 +- .../src/LoggedTest/LoggedTest.cs | 5 +- .../src/LoggedTest/LoggedTestBase.cs | 41 +++++-- .../Logging.Testing/src/RepeatContext.cs | 12 -- .../src/ShortClassNameAttribute.cs | 12 -- .../src/TestFrameworkFileLoggerAttribute.cs | 13 +- .../Xunit/LoggedConditionalFactDiscoverer.cs | 28 ----- .../LoggedConditionalTheoryDiscoverer.cs | 55 --------- .../src/Xunit/LoggedFactDiscoverer.cs | 18 --- .../src/Xunit/LoggedTestAssemblyRunner.cs | 31 ----- .../src/Xunit/LoggedTestCase.cs | 37 ------ .../src/Xunit/LoggedTestCaseRunner.cs | 42 ------- .../src/Xunit/LoggedTestClassRunner.cs | 36 ------ .../src/Xunit/LoggedTestCollectionRunner.cs | 33 ----- .../src/Xunit/LoggedTestFramework.cs | 26 ---- .../Xunit/LoggedTestFrameworkDiscoverer.cs | 80 ------------ .../src/Xunit/LoggedTestFrameworkExecutor.cs | 26 ---- .../src/Xunit/LoggedTestInvoker.cs | 80 ------------ .../src/Xunit/LoggedTestMethodRunner.cs | 36 ------ .../src/Xunit/LoggedTestRunner.cs | 114 ------------------ .../src/Xunit/LoggedTheoryDiscoverer.cs | 29 ----- .../src/Xunit/LoggedTheoryTestCase.cs | 36 ------ .../src/Xunit/LoggedTheoryTestCaseRunner.cs | 41 ------- .../src/Xunit/RepeatAttribute.cs | 28 ----- ...Microsoft.Extensions.Logging.Testing.props | 4 +- .../test/AssemblyTestLogTests.cs | 8 +- .../test/LoggedTestXunitRepeatTests.cs | 43 ------- .../test/LoggedTestXunitTests.cs | 16 +-- .../test/Properties/AssemblyInfo.cs | 1 - 32 files changed, 76 insertions(+), 936 deletions(-) rename src/Logging/Logging.Testing/src/{Xunit => }/LogLevelAttribute.cs (100%) delete mode 100644 src/Logging/Logging.Testing/src/RepeatContext.cs delete mode 100644 src/Logging/Logging.Testing/src/ShortClassNameAttribute.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedFactDiscoverer.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestAssemblyRunner.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestCase.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestCaseRunner.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestClassRunner.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestCollectionRunner.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestFramework.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkExecutor.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestMethodRunner.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTheoryDiscoverer.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCase.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCaseRunner.cs delete mode 100644 src/Logging/Logging.Testing/src/Xunit/RepeatAttribute.cs delete mode 100644 src/Logging/Logging.Testing/test/LoggedTestXunitRepeatTests.cs diff --git a/src/Logging/Logging.Testing/src/AssemblyTestLog.cs b/src/Logging/Logging.Testing/src/AssemblyTestLog.cs index e84df52554..3c598b67d5 100644 --- a/src/Logging/Logging.Testing/src/AssemblyTestLog.cs +++ b/src/Logging/Logging.Testing/src/AssemblyTestLog.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; using Serilog; using Serilog.Core; @@ -23,14 +24,6 @@ namespace Microsoft.Extensions.Logging.Testing private static readonly string MaxPathLengthEnvironmentVariableName = "ASPNETCORE_TEST_LOG_MAXPATH"; private static readonly string LogFileExtension = ".log"; private static readonly int MaxPathLength = GetMaxPathLength(); - private static char[] InvalidFileChars = new char[] - { - '\"', '<', '>', '|', '\0', - (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10, - (char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17, (char)18, (char)19, (char)20, - (char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30, - (char)31, ':', '*', '?', '\\', '/', ' ', (char)127 - }; private static readonly object _lock = new object(); private static readonly Dictionary _logs = new Dictionary(); @@ -113,8 +106,8 @@ namespace Microsoft.Extensions.Logging.Testing SerilogLoggerProvider serilogLoggerProvider = null; if (!string.IsNullOrEmpty(_baseDirectory)) { - logOutputDirectory = Path.Combine(GetAssemblyBaseDirectory(_baseDirectory, _assembly), className); - testName = RemoveIllegalFileChars(testName); + logOutputDirectory = Path.Combine(_baseDirectory, className); + testName = TestFileOutputContext.RemoveIllegalFileChars(testName); if (logOutputDirectory.Length + testName.Length + LogFileExtension.Length >= MaxPathLength) { @@ -184,10 +177,10 @@ namespace Microsoft.Extensions.Logging.Testing { var logStart = DateTimeOffset.UtcNow; SerilogLoggerProvider serilogLoggerProvider = null; - var globalLogDirectory = GetAssemblyBaseDirectory(baseDirectory, assembly); - if (!string.IsNullOrEmpty(globalLogDirectory)) + if (!string.IsNullOrEmpty(baseDirectory)) { - var globalLogFileName = Path.Combine(globalLogDirectory, "global.log"); + baseDirectory = TestFileOutputContext.GetAssemblyBaseDirectory(assembly, baseDirectory); + var globalLogFileName = Path.Combine(baseDirectory, "global.log"); serilogLoggerProvider = ConfigureFileLogging(globalLogFileName, logStart); } @@ -222,31 +215,26 @@ namespace Microsoft.Extensions.Logging.Testing { if (!_logs.TryGetValue(assembly, out var log)) { - var baseDirectory = GetFileLoggerAttribute(assembly).BaseDirectory; + var baseDirectory = TestFileOutputContext.GetOutputDirectory(assembly); log = Create(assembly, baseDirectory); _logs[assembly] = log; - // Try to clear previous logs - var assemblyBaseDirectory = GetAssemblyBaseDirectory(baseDirectory, assembly); - if (Directory.Exists(assemblyBaseDirectory)) + // Try to clear previous logs, continue if it fails. + var assemblyBaseDirectory = TestFileOutputContext.GetAssemblyBaseDirectory(assembly); + if (!string.IsNullOrEmpty(assemblyBaseDirectory)) { try { Directory.Delete(assemblyBaseDirectory, recursive: true); } - catch {} + catch { } } } return log; } } - private static string GetAssemblyBaseDirectory(string baseDirectory, Assembly assembly) - => string.IsNullOrEmpty(baseDirectory) - ? string.Empty - : Path.Combine(baseDirectory, assembly.GetName().Name, GetFileLoggerAttribute(assembly).TFM); - private static TestFrameworkFileLoggerAttribute GetFileLoggerAttribute(Assembly assembly) => assembly.GetCustomAttribute() ?? throw new InvalidOperationException($"No {nameof(TestFrameworkFileLoggerAttribute)} found on the assembly {assembly.GetName().Name}. " @@ -275,27 +263,6 @@ namespace Microsoft.Extensions.Logging.Testing return new SerilogLoggerProvider(serilogger, dispose: true); } - private static string RemoveIllegalFileChars(string s) - { - var sb = new StringBuilder(); - - foreach (var c in s) - { - if (InvalidFileChars.Contains(c)) - { - if (sb.Length > 0 && sb[sb.Length - 1] != '_') - { - sb.Append('_'); - } - } - else - { - sb.Append(c); - } - } - return sb.ToString(); - } - public void Dispose() { (_serviceProvider as IDisposable)?.Dispose(); diff --git a/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs b/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs index 8a6aa84bac..012a5c8fa1 100644 --- a/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs +++ b/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs @@ -2,6 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Diagnostics; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing; namespace Microsoft.Extensions.Logging.Testing { @@ -12,7 +17,23 @@ namespace Microsoft.Extensions.Logging.Testing /// This currently only works in Windows environments /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] - public class CollectDumpAttribute : Attribute + public class CollectDumpAttribute : Attribute, ITestMethodLifecycle { + public Task OnTestStartAsync(TestContext context, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + public Task OnTestEndAsync(TestContext context, Exception exception, CancellationToken cancellationToken) + { + if (exception != null) + { + var path = Path.Combine(context.FileOutput.TestClassOutputDirectory, context.FileOutput.GetUniqueFileName(context.FileOutput.TestName, ".dmp")); + var process = Process.GetCurrentProcess(); + DumpCollector.Collect(process, path); + } + + return Task.CompletedTask; + } } } diff --git a/src/Logging/Logging.Testing/src/Xunit/LogLevelAttribute.cs b/src/Logging/Logging.Testing/src/LogLevelAttribute.cs similarity index 100% rename from src/Logging/Logging.Testing/src/Xunit/LogLevelAttribute.cs rename to src/Logging/Logging.Testing/src/LogLevelAttribute.cs diff --git a/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs b/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs index a563cbdaf9..a906ae84a2 100644 --- a/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs +++ b/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs @@ -3,6 +3,7 @@ using System; using System.Reflection; +using Microsoft.AspNetCore.Testing; using Xunit.Abstractions; namespace Microsoft.Extensions.Logging.Testing @@ -18,6 +19,6 @@ namespace Microsoft.Extensions.Logging.Testing // For back compat IDisposable StartLog(out ILoggerFactory loggerFactory, LogLevel minLogLevel, string testName); - void Initialize(MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper); + void Initialize(TestContext context, MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper); } } diff --git a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs index 64a9adec06..d108ffb7e8 100644 --- a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs +++ b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Reflection; +using Microsoft.AspNetCore.Testing; using Xunit.Abstractions; namespace Microsoft.Extensions.Logging.Testing @@ -13,9 +14,9 @@ namespace Microsoft.Extensions.Logging.Testing public ITestSink TestSink { get; set; } - public override void Initialize(MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) + public override void Initialize(TestContext context, MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) { - base.Initialize(methodInfo, testMethodArguments, testOutputHelper); + base.Initialize(context, methodInfo, testMethodArguments, testOutputHelper); TestSink = new TestSink(); LoggerFactory.AddProvider(new TestLoggerProvider(TestSink)); diff --git a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs index 94cdf82257..324b855319 100644 --- a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs +++ b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs @@ -6,12 +6,16 @@ using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; +using Serilog; using Xunit.Abstractions; namespace Microsoft.Extensions.Logging.Testing { - public class LoggedTestBase : ILoggedTest + public class LoggedTestBase : ILoggedTest, ITestMethodLifecycle { private ExceptionDispatchInfo _initializationException; @@ -23,11 +27,11 @@ namespace Microsoft.Extensions.Logging.Testing TestOutputHelper = output; } + protected TestContext Context { get; private set; } + // Internal for testing internal string ResolvedTestClassName { get; set; } - internal RepeatContext RepeatContext { get; set; } - public string ResolvedLogOutputDirectory { get; set; } public string ResolvedTestMethodName { get; set; } @@ -49,7 +53,7 @@ namespace Microsoft.Extensions.Logging.Testing return AssemblyTestLog.ForAssembly(GetType().GetTypeInfo().Assembly).StartTestLog(TestOutputHelper, GetType().FullName, out loggerFactory, minLogLevel, testName); } - public virtual void Initialize(MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) + public virtual void Initialize(TestContext context, MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) { try { @@ -59,25 +63,22 @@ namespace Microsoft.Extensions.Logging.Testing var logLevelAttribute = methodInfo.GetCustomAttribute() ?? methodInfo.DeclaringType.GetCustomAttribute() ?? methodInfo.DeclaringType.Assembly.GetCustomAttribute(); - var testName = testMethodArguments.Aggregate(methodInfo.Name, (a, b) => $"{a}-{(b ?? "null")}"); - var useShortClassName = methodInfo.DeclaringType.GetCustomAttribute() - ?? methodInfo.DeclaringType.Assembly.GetCustomAttribute(); // internal for testing - ResolvedTestClassName = useShortClassName == null ? classType.FullName : classType.Name; + ResolvedTestClassName = context.FileOutput.TestClassName; _testLog = AssemblyTestLog .ForAssembly(classType.GetTypeInfo().Assembly) .StartTestLog( TestOutputHelper, - ResolvedTestClassName, + context.FileOutput.TestClassName, out var loggerFactory, logLevelAttribute?.LogLevel ?? LogLevel.Debug, out var resolvedTestName, - out var logOutputDirectory, - testName); + out var logDirectory, + context.FileOutput.TestName); - ResolvedLogOutputDirectory = logOutputDirectory; + ResolvedLogOutputDirectory = logDirectory; ResolvedTestMethodName = resolvedTestName; LoggerFactory = loggerFactory; @@ -91,7 +92,7 @@ namespace Microsoft.Extensions.Logging.Testing public virtual void Dispose() { - if(_testLog == null) + if (_testLog == null) { // It seems like sometimes the MSBuild goop that adds the test framework can end up in a bad state and not actually add it // Not sure yet why that happens but the exception isn't clear so I'm adding this error so we can detect it better. @@ -102,5 +103,19 @@ namespace Microsoft.Extensions.Logging.Testing _initializationException?.Throw(); _testLog.Dispose(); } + + Task ITestMethodLifecycle.OnTestStartAsync(TestContext context, CancellationToken cancellationToken) + { + + Context = context; + + Initialize(context, context.TestMethod, context.MethodArguments, context.Output); + return Task.CompletedTask; + } + + Task ITestMethodLifecycle.OnTestEndAsync(TestContext context, Exception exception, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } } } diff --git a/src/Logging/Logging.Testing/src/RepeatContext.cs b/src/Logging/Logging.Testing/src/RepeatContext.cs deleted file mode 100644 index decc7a173c..0000000000 --- a/src/Logging/Logging.Testing/src/RepeatContext.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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. - -namespace Microsoft.Extensions.Logging.Testing -{ - public class RepeatContext - { - internal int Limit { get; set; } - - internal int CurrentIteration { get; set; } - } -} diff --git a/src/Logging/Logging.Testing/src/ShortClassNameAttribute.cs b/src/Logging/Logging.Testing/src/ShortClassNameAttribute.cs deleted file mode 100644 index bd30718814..0000000000 --- a/src/Logging/Logging.Testing/src/ShortClassNameAttribute.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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; - -namespace Microsoft.Extensions.Logging.Testing -{ - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false)] - public class ShortClassNameAttribute : Attribute - { - } -} diff --git a/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs b/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs index 32d8f30584..025a5a9bd8 100644 --- a/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs +++ b/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs @@ -1,20 +1,17 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; +using Microsoft.AspNetCore.Testing; namespace Microsoft.Extensions.Logging.Testing { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] - public class TestFrameworkFileLoggerAttribute : Attribute + public class TestFrameworkFileLoggerAttribute : TestOutputDirectoryAttribute { public TestFrameworkFileLoggerAttribute(string tfm, string baseDirectory = null) + : base(tfm, baseDirectory) { - TFM = tfm; - BaseDirectory = baseDirectory; } - - public string TFM { get; } - public string BaseDirectory { get; } } -} \ No newline at end of file +} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs deleted file mode 100644 index 4d61c9592d..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalFactDiscoverer.cs +++ /dev/null @@ -1,28 +0,0 @@ -// 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 Microsoft.AspNetCore.Testing; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedConditionalFactDiscoverer : LoggedFactDiscoverer - { - private readonly IMessageSink _diagnosticMessageSink; - - public LoggedConditionalFactDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink) - { - _diagnosticMessageSink = diagnosticMessageSink; - } - - protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) - { - var skipReason = testMethod.EvaluateSkipConditions(); - return skipReason != null - ? new SkippedTestCase(skipReason, _diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod) - : base.CreateTestCase(discoveryOptions, testMethod, factAttribute); - } - - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs deleted file mode 100644 index bce28051a6..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedConditionalTheoryDiscoverer.cs +++ /dev/null @@ -1,55 +0,0 @@ -// 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.Collections.Generic; -using Microsoft.AspNetCore.Testing; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedConditionalTheoryDiscoverer : LoggedTheoryDiscoverer - { - public LoggedConditionalTheoryDiscoverer(IMessageSink diagnosticMessageSink) - : base(diagnosticMessageSink) - { - } - - protected override IEnumerable CreateTestCasesForTheory( - ITestFrameworkDiscoveryOptions discoveryOptions, - ITestMethod testMethod, - IAttributeInfo theoryAttribute) - { - var skipReason = testMethod.EvaluateSkipConditions(); - return skipReason != null - ? new[] { new SkippedTestCase(skipReason, DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod) } - : base.CreateTestCasesForTheory(discoveryOptions, testMethod, theoryAttribute); - } - - protected override IEnumerable CreateTestCasesForDataRow( - ITestFrameworkDiscoveryOptions discoveryOptions, - ITestMethod testMethod, IAttributeInfo theoryAttribute, - object[] dataRow) - { - var skipReason = testMethod.EvaluateSkipConditions(); - if (skipReason == null && dataRow?.Length > 0) - { - var obj = dataRow[0]; - if (obj != null) - { - var type = obj.GetType(); - var property = type.GetProperty("Skip"); - if (property != null && property.PropertyType.Equals(typeof(string))) - { - skipReason = property.GetValue(obj) as string; - } - } - } - - return skipReason != null - ? base.CreateTestCasesForSkippedDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow, skipReason) - : base.CreateTestCasesForDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow); - } - - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedFactDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedFactDiscoverer.cs deleted file mode 100644 index e2268d96cb..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedFactDiscoverer.cs +++ /dev/null @@ -1,18 +0,0 @@ -// 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 Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedFactDiscoverer : FactDiscoverer - { - public LoggedFactDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink) - { - } - - protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) - => new LoggedTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod); - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestAssemblyRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestAssemblyRunner.cs deleted file mode 100644 index 39dff8fce7..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestAssemblyRunner.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTestAssemblyRunner : XunitTestAssemblyRunner - { - public LoggedTestAssemblyRunner( - ITestAssembly testAssembly, - IEnumerable testCases, - IMessageSink diagnosticMessageSink, - IMessageSink executionMessageSink, - ITestFrameworkExecutionOptions executionOptions) - : base(testAssembly, testCases, diagnosticMessageSink, executionMessageSink, executionOptions) - { - } - - protected override Task RunTestCollectionAsync( - IMessageBus messageBus, - ITestCollection testCollection, - IEnumerable testCases, - CancellationTokenSource cancellationTokenSource) - => new LoggedTestCollectionRunner(testCollection, testCases, DiagnosticMessageSink, messageBus, TestCaseOrderer, new ExceptionAggregator(Aggregator), cancellationTokenSource).RunAsync(); - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestCase.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestCase.cs deleted file mode 100644 index c43180df89..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestCase.cs +++ /dev/null @@ -1,37 +0,0 @@ -// 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; -using System.Threading; -using System.Threading.Tasks; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTestCase : XunitTestCase - { - [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] - public LoggedTestCase() : base() - { - } - - public LoggedTestCase( - IMessageSink diagnosticMessageSink, - TestMethodDisplay defaultMethodDisplay, - TestMethodDisplayOptions defaultMethodDisplayOptions, - ITestMethod testMethod, - object[] testMethodArguments = null) - : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) - { - } - - public override Task RunAsync( - IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - object[] constructorArguments, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) - => new LoggedTestCaseRunner(this, DisplayName, SkipReason, constructorArguments, TestMethodArguments, messageBus, aggregator, cancellationTokenSource).RunAsync(); - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestCaseRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestCaseRunner.cs deleted file mode 100644 index 20cde6144e..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestCaseRunner.cs +++ /dev/null @@ -1,42 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Reflection; -using System.Threading; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTestCaseRunner : XunitTestCaseRunner - { - public LoggedTestCaseRunner( - IXunitTestCase testCase, - string displayName, - string skipReason, - object[] constructorArguments, - object[] testMethodArguments, - IMessageBus messageBus, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) - : base(testCase, displayName, skipReason, constructorArguments, testMethodArguments, messageBus, aggregator, cancellationTokenSource) - { - } - - protected override XunitTestRunner CreateTestRunner( - ITest test, - IMessageBus messageBus, - Type testClass, - object[] constructorArguments, - MethodInfo testMethod, - object[] testMethodArguments, - string skipReason, - IReadOnlyList beforeAfterAttributes, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) - => new LoggedTestRunner(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, - skipReason, beforeAfterAttributes, new ExceptionAggregator(aggregator), cancellationTokenSource); - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestClassRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestClassRunner.cs deleted file mode 100644 index e7c30264e6..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestClassRunner.cs +++ /dev/null @@ -1,36 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTestClassRunner : XunitTestClassRunner - { - public LoggedTestClassRunner( - ITestClass testClass, - IReflectionTypeInfo @class, - IEnumerable testCases, - IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - ITestCaseOrderer testCaseOrderer, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource, - IDictionary collectionFixtureMappings) - : base(testClass, @class, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource, collectionFixtureMappings) - { - } - - protected override Task RunTestMethodAsync( - ITestMethod testMethod, - IReflectionMethodInfo method, - IEnumerable testCases, - object[] constructorArguments) - => new LoggedTestMethodRunner(testMethod, Class, method, testCases, DiagnosticMessageSink, MessageBus, new ExceptionAggregator(Aggregator), CancellationTokenSource, constructorArguments).RunAsync(); - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestCollectionRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestCollectionRunner.cs deleted file mode 100644 index c3713d4245..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestCollectionRunner.cs +++ /dev/null @@ -1,33 +0,0 @@ -// 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.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTestCollectionRunner : XunitTestCollectionRunner - { - private readonly IMessageSink _diagnosticMessageSink; - - public LoggedTestCollectionRunner( - ITestCollection testCollection, - IEnumerable testCases, - IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - ITestCaseOrderer testCaseOrderer, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) - : base(testCollection, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource) - { - // Base class doesn't expose this, so capture it here. - _diagnosticMessageSink = diagnosticMessageSink; - } - - protected override Task RunTestClassAsync(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable testCases) - => new LoggedTestClassRunner(testClass, @class, testCases, _diagnosticMessageSink, MessageBus, TestCaseOrderer, new ExceptionAggregator(Aggregator), CancellationTokenSource, CollectionFixtureMappings).RunAsync(); - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFramework.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFramework.cs deleted file mode 100644 index dc5737d32b..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFramework.cs +++ /dev/null @@ -1,26 +0,0 @@ -// 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.Reflection; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTestFramework : XunitTestFramework - { - public LoggedTestFramework(IMessageSink messageSink) : base(messageSink) - { - } - - protected override ITestFrameworkDiscoverer CreateDiscoverer(IAssemblyInfo assemblyInfo) - { - return new LoggedTestFrameworkDiscoverer(assemblyInfo, SourceInformationProvider, DiagnosticMessageSink); - } - - protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName) - { - return new LoggedTestFrameworkExecutor(assemblyName, SourceInformationProvider, DiagnosticMessageSink); - } - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs deleted file mode 100644 index d7ff598f8e..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkDiscoverer.cs +++ /dev/null @@ -1,80 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Testing; -using Xunit; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTestFrameworkDiscoverer : XunitTestFrameworkDiscoverer - { - private IDictionary Discoverers { get; } - - public LoggedTestFrameworkDiscoverer( - IAssemblyInfo assemblyInfo, - ISourceInformationProvider sourceProvider, - IMessageSink diagnosticMessageSink, - IXunitTestCollectionFactory collectionFactory = null) - : base(assemblyInfo, sourceProvider, diagnosticMessageSink, collectionFactory) - { - Discoverers = new Dictionary() - { - { typeof(ConditionalTheoryAttribute), new LoggedConditionalTheoryDiscoverer(diagnosticMessageSink) }, - { typeof(ConditionalFactAttribute), new LoggedConditionalFactDiscoverer(diagnosticMessageSink) }, - { typeof(TheoryAttribute), new LoggedTheoryDiscoverer(diagnosticMessageSink) }, - { typeof(FactAttribute), new LoggedFactDiscoverer(diagnosticMessageSink) } - }; - } - - protected override bool FindTestsForMethod( - ITestMethod testMethod, - bool includeSourceInformation, - IMessageBus messageBus, - ITestFrameworkDiscoveryOptions discoveryOptions) - { - if (typeof(ILoggedTest).IsAssignableFrom(testMethod.TestClass.Class.ToRuntimeType())) - { - var factAttributes = testMethod.Method.GetCustomAttributes(typeof(FactAttribute)); - if (factAttributes.Count() > 1) - { - var message = $"Test method '{testMethod.TestClass.Class.Name}.{testMethod.Method.Name}' has multiple [Fact]-derived attributes"; - var testCase = new ExecutionErrorTestCase(DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod, TestMethodDisplayOptions.None, testMethod, message); - return ReportDiscoveredTestCase(testCase, includeSourceInformation, messageBus); - } - - var factAttribute = factAttributes.FirstOrDefault(); - if (factAttribute == null) - { - return true; - } - - var factAttributeType = (factAttribute as IReflectionAttributeInfo)?.Attribute.GetType(); - if (!Discoverers.TryGetValue(factAttributeType, out var discoverer)) - { - return base.FindTestsForMethod(testMethod, includeSourceInformation, messageBus, discoveryOptions); - } - else - { - foreach (var testCase in discoverer.Discover(discoveryOptions, testMethod, factAttribute)) - { - if (!ReportDiscoveredTestCase(testCase, includeSourceInformation, messageBus)) - { - return false; - } - } - - return true; - } - } - else - { - return base.FindTestsForMethod(testMethod, includeSourceInformation, messageBus, discoveryOptions); - } - } - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkExecutor.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkExecutor.cs deleted file mode 100644 index ece623fa7a..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestFrameworkExecutor.cs +++ /dev/null @@ -1,26 +0,0 @@ -// 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.Collections.Generic; -using System.Reflection; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTestFrameworkExecutor : XunitTestFrameworkExecutor - { - public LoggedTestFrameworkExecutor(AssemblyName assemblyName, ISourceInformationProvider sourceInformationProvider, IMessageSink diagnosticMessageSink) - : base(assemblyName, sourceInformationProvider, diagnosticMessageSink) - { - } - - protected override async void RunTestCases(IEnumerable testCases, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions) - { - using (var assemblyRunner = new LoggedTestAssemblyRunner(TestAssembly, testCases, DiagnosticMessageSink, executionMessageSink, executionOptions)) - { - await assemblyRunner.RunAsync(); - } - } - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs deleted file mode 100644 index 0e6638cb57..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestInvoker.cs +++ /dev/null @@ -1,80 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTestInvoker : XunitTestInvoker - { - private readonly ITestOutputHelper _output; - private readonly RepeatContext _repeatContext; - private readonly bool _collectDumpOnFailure; - - public LoggedTestInvoker( - ITest test, - IMessageBus messageBus, - Type testClass, - object[] constructorArguments, - MethodInfo testMethod, - object[] testMethodArguments, - IReadOnlyList beforeAfterAttributes, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource, - ITestOutputHelper output, - RepeatContext repeatContext, - bool collectDumpOnFailure) - : base(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, beforeAfterAttributes, aggregator, cancellationTokenSource) - { - _output = output; - _repeatContext = repeatContext; - _collectDumpOnFailure = collectDumpOnFailure; - } - - protected override object CreateTestClass() - { - var testClass = base.CreateTestClass(); - - (testClass as ILoggedTest).Initialize( - TestMethod, - TestMethodArguments, - _output ?? ConstructorArguments.SingleOrDefault(a => typeof(ITestOutputHelper).IsAssignableFrom(a.GetType())) as ITestOutputHelper); - - if (testClass is LoggedTestBase loggedTestBase) - { - // Used for testing - loggedTestBase.RepeatContext = _repeatContext; - } - - return testClass; - } - - protected override object CallTestMethod(object testClassInstance) - { - try - { - return base.CallTestMethod(testClassInstance); - } - catch - { - if (_collectDumpOnFailure && testClassInstance is LoggedTestBase loggedTestBase) - { - var path = Path.Combine(loggedTestBase.ResolvedLogOutputDirectory, loggedTestBase.ResolvedTestMethodName + ".dmp"); - var process = Process.GetCurrentProcess(); - - DumpCollector.Collect(process, path); - } - - throw; - } - } - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestMethodRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestMethodRunner.cs deleted file mode 100644 index 2ba2988257..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestMethodRunner.cs +++ /dev/null @@ -1,36 +0,0 @@ -// 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.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTestMethodRunner : XunitTestMethodRunner - { - private IMessageSink DiagnosticMessageSink { get; } - private object[] ConstructorArguments { get; } - - public LoggedTestMethodRunner( - ITestMethod testMethod, - IReflectionTypeInfo @class, - IReflectionMethodInfo method, - IEnumerable testCases, - IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource, - object[] constructorArguments) - : base(testMethod, @class, method, testCases, diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource, constructorArguments) - { - DiagnosticMessageSink = diagnosticMessageSink; - ConstructorArguments = constructorArguments; - } - - protected override Task RunTestCaseAsync(IXunitTestCase testCase) - => testCase.RunAsync(DiagnosticMessageSink, MessageBus, ConstructorArguments, new ExceptionAggregator(Aggregator), CancellationTokenSource); - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs deleted file mode 100644 index a630a4c50d..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTestRunner.cs +++ /dev/null @@ -1,114 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Testing; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTestRunner : XunitTestRunner - { - public LoggedTestRunner( - ITest test, - IMessageBus messageBus, - Type testClass, - object[] constructorArguments, - MethodInfo testMethod, object[] - testMethodArguments, string skipReason, - IReadOnlyList beforeAfterAttributes, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) - : base(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, skipReason, beforeAfterAttributes, aggregator, cancellationTokenSource) - { - } - - protected async override Task> InvokeTestAsync(ExceptionAggregator aggregator) - { - var testOutputHelper = ConstructorArguments.SingleOrDefault(a => typeof(TestOutputHelper).IsAssignableFrom(a.GetType())) as TestOutputHelper - ?? new TestOutputHelper(); - testOutputHelper.Initialize(MessageBus, Test); - - var executionTime = await InvokeTestMethodAsync(aggregator, testOutputHelper); - - var output = testOutputHelper.Output; - testOutputHelper.Uninitialize(); - - return Tuple.Create(executionTime, output); - } - - protected override Task InvokeTestMethodAsync(ExceptionAggregator aggregator) - => InvokeTestMethodAsync(aggregator, null); - - private async Task InvokeTestMethodAsync(ExceptionAggregator aggregator, ITestOutputHelper output) - { - var collectDump = TestMethod.GetCustomAttribute() != null; - var repeatAttribute = GetRepeatAttribute(TestMethod); - - if (!typeof(LoggedTestBase).IsAssignableFrom(TestClass) || repeatAttribute == null) - { - return await new LoggedTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, aggregator, CancellationTokenSource, output, null, collectDump).RunAsync(); - } - - return await RunRepeatTestInvoker(aggregator, output, collectDump, repeatAttribute); - } - - private async Task RunRepeatTestInvoker(ExceptionAggregator aggregator, ITestOutputHelper output, bool collectDump, RepeatAttribute repeatAttribute) - { - var repeatContext = new RepeatContext - { - Limit = repeatAttribute.RunCount - }; - - var timeTaken = 0.0M; - var testLogger = new LoggedTestInvoker( - Test, - MessageBus, - TestClass, - ConstructorArguments, - TestMethod, - TestMethodArguments, - BeforeAfterAttributes, - aggregator, - CancellationTokenSource, - output, - repeatContext, - collectDump); - - for (repeatContext.CurrentIteration = 0; repeatContext.CurrentIteration < repeatContext.Limit; repeatContext.CurrentIteration++) - { - timeTaken = await testLogger.RunAsync(); - if (aggregator.HasExceptions) - { - return timeTaken; - } - } - - return timeTaken; - } - - private RepeatAttribute GetRepeatAttribute(MethodInfo methodInfo) - { - var attributeCandidate = methodInfo.GetCustomAttribute(); - if (attributeCandidate != null) - { - return attributeCandidate; - } - - attributeCandidate = methodInfo.DeclaringType.GetCustomAttribute(); - if (attributeCandidate != null) - { - return attributeCandidate; - } - - return methodInfo.DeclaringType.Assembly.GetCustomAttribute(); - } - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryDiscoverer.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryDiscoverer.cs deleted file mode 100644 index 9d5402a09b..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryDiscoverer.cs +++ /dev/null @@ -1,29 +0,0 @@ -// 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.Collections.Generic; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTheoryDiscoverer : TheoryDiscoverer - { - public LoggedTheoryDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink) - { - } - - protected override IEnumerable CreateTestCasesForDataRow( - ITestFrameworkDiscoveryOptions discoveryOptions, - ITestMethod testMethod, - IAttributeInfo theoryAttribute, - object[] dataRow) - => new[] { new LoggedTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod, dataRow) }; - - protected override IEnumerable CreateTestCasesForTheory( - ITestFrameworkDiscoveryOptions discoveryOptions, - ITestMethod testMethod, - IAttributeInfo theoryAttribute) - => new[] { new LoggedTheoryTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod) }; - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCase.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCase.cs deleted file mode 100644 index fa3e3a050d..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCase.cs +++ /dev/null @@ -1,36 +0,0 @@ -// 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; -using System.Threading; -using System.Threading.Tasks; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTheoryTestCase : XunitTheoryTestCase - { - [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] - public LoggedTheoryTestCase() : base() - { - } - - public LoggedTheoryTestCase( - IMessageSink diagnosticMessageSink, - TestMethodDisplay defaultMethodDisplay, - TestMethodDisplayOptions defaultMethodDisplayOptions, - ITestMethod testMethod) - : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod) - { - } - - public override Task RunAsync( - IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - object[] constructorArguments, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) - => new LoggedTheoryTestCaseRunner(this, DisplayName, SkipReason, constructorArguments, diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource).RunAsync(); - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCaseRunner.cs b/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCaseRunner.cs deleted file mode 100644 index f1f92e1dcd..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/LoggedTheoryTestCaseRunner.cs +++ /dev/null @@ -1,41 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Reflection; -using System.Threading; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTheoryTestCaseRunner : XunitTheoryTestCaseRunner - { - public LoggedTheoryTestCaseRunner( - IXunitTestCase testCase, - string displayName, - string skipReason, - object[] constructorArguments, - IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) - : base(testCase, displayName, skipReason, constructorArguments, diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource) - { - } - - protected override XunitTestRunner CreateTestRunner( - ITest test, - IMessageBus messageBus, - Type testClass, - object[] constructorArguments, - MethodInfo testMethod, - object[] testMethodArguments, - string skipReason, - IReadOnlyList beforeAfterAttributes, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) - => new LoggedTestRunner(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, skipReason, beforeAfterAttributes, new ExceptionAggregator(aggregator), cancellationTokenSource); - } -} diff --git a/src/Logging/Logging.Testing/src/Xunit/RepeatAttribute.cs b/src/Logging/Logging.Testing/src/Xunit/RepeatAttribute.cs deleted file mode 100644 index ec86c0b601..0000000000 --- a/src/Logging/Logging.Testing/src/Xunit/RepeatAttribute.cs +++ /dev/null @@ -1,28 +0,0 @@ -// 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; -using System.ComponentModel; - -namespace Microsoft.Extensions.Logging.Testing -{ - /// - /// Runs a test multiple times to stress flaky tests that are believed to be fixed. - /// This can be used on an assembly, class, or method name. - /// Requires using to run. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false)] - public class RepeatAttribute : Attribute - { - public RepeatAttribute(int runCount = 10) - { - RunCount = runCount; - } - - /// - /// The number of times to run a test. - /// - public int RunCount { get; } - } -} diff --git a/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props b/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props index c503c32d40..3895cb5471 100644 --- a/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props +++ b/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props @@ -11,8 +11,8 @@ Condition="'$(GenerateLoggingTestingAssemblyAttributes)' != 'false'"> - <_Parameter1>Microsoft.Extensions.Logging.Testing.LoggedTestFramework - <_Parameter2>Microsoft.Extensions.Logging.Testing + <_Parameter1>Microsoft.AspNetCore.Testing.AspNetTestFramework + <_Parameter2>Microsoft.AspNetCore.Testing diff --git a/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs b/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs index 20f597defc..6d7ae5139a 100644 --- a/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs +++ b/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs @@ -18,12 +18,6 @@ namespace Microsoft.Extensions.Logging.Testing.Tests private static readonly string ThisAssemblyName = ThisAssembly.GetName().Name; private static readonly string TFM = new DirectoryInfo(AppContext.BaseDirectory).Name; - [Fact] - public void FullClassNameUsedWhenShortClassNameAttributeNotSpecified() - { - Assert.Equal(GetType().FullName, ResolvedTestClassName); - } - [Fact] public void ForAssembly_ReturnsSameInstanceForSameAssembly() { @@ -57,7 +51,7 @@ namespace Microsoft.Extensions.Logging.Testing.Tests } [Fact] - private Task TestLogEscapesIllegalFileNames() => + public Task TestLogEscapesIllegalFileNames() => RunTestLogFunctionalTest((tempDir) => { var illegalTestName = "T:e/s//t"; diff --git a/src/Logging/Logging.Testing/test/LoggedTestXunitRepeatTests.cs b/src/Logging/Logging.Testing/test/LoggedTestXunitRepeatTests.cs deleted file mode 100644 index dbd1d7260a..0000000000 --- a/src/Logging/Logging.Testing/test/LoggedTestXunitRepeatTests.cs +++ /dev/null @@ -1,43 +0,0 @@ -// 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 Xunit; - -namespace Microsoft.Extensions.Logging.Testing.Tests -{ - [Repeat] - public class LoggedTestXunitRepeatTests : LoggedTest - { - public static int _runCount = 0; - - [Fact] - [Repeat(5)] - public void RepeatLimitIsSetCorrectly() - { - Assert.Equal(5, RepeatContext.Limit); - } - - [Fact] - [Repeat(5)] - public void RepeatRunsTestSpecifiedNumberOfTimes() - { - Assert.Equal(RepeatContext.CurrentIteration, _runCount); - _runCount++; - } - - [Fact] - public void RepeatCanBeSetOnClass() - { - Assert.Equal(10, RepeatContext.Limit); - } - } - - public class LoggedTestXunitRepeatAssemblyTests : LoggedTest - { - [Fact] - public void RepeatCanBeSetOnAssembly() - { - Assert.Equal(1, RepeatContext.Limit); - } - } -} diff --git a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs index ab9ee746c3..d8454023a2 100644 --- a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs +++ b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs @@ -21,18 +21,6 @@ namespace Microsoft.Extensions.Logging.Testing.Tests _output = output; } - [Fact] - public void ShortClassNameUsedWhenShortClassNameAttributeSpecified() - { - Assert.Equal(GetType().Name, ResolvedTestClassName); - } - - [Fact] - public void LoggedTestTestOutputHelperSameInstanceAsInjectedConstructorArg() - { - Assert.Same(_output, TestOutputHelper); - } - [Fact] public void LoggedFactInitializesLoggedTestProperties() { @@ -189,9 +177,9 @@ namespace Microsoft.Extensions.Logging.Testing.Tests public bool SetupInvoked { get; private set; } = false; public bool ITestOutputHelperIsInitialized { get; private set; } = false; - public override void Initialize(MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) + public override void Initialize(TestContext context, MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) { - base.Initialize(methodInfo, testMethodArguments, testOutputHelper); + base.Initialize(context, methodInfo, testMethodArguments, testOutputHelper); try { diff --git a/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs b/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs index b104c11dfc..82616e2737 100644 --- a/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs +++ b/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs @@ -2,4 +2,3 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; [assembly: LogLevel(LogLevel.Trace)] -[assembly: Repeat(1)] From fd1f58c708c46da68153b40045802eb2451e9f64 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2019 22:47:08 +0000 Subject: [PATCH 31/44] [master] Update dependencies from dotnet/core-setup dotnet/arcade (#2559) * Update dependencies from https://github.com/dotnet/arcade build 20191023.3 - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19523.3 - Microsoft.DotNet.GenAPI - 5.0.0-beta.19523.3 - Microsoft.DotNet.Helix.Sdk - 5.0.0-beta.19523.3 * Updated ref asssemblies * Update dependencies from https://github.com/dotnet/core-setup build 20191024.4 - Microsoft.NETCore.App.Ref - 5.0.0-alpha1.19524.4 - NETStandard.Library.Ref - 2.1.0-alpha1.19524.4 - Microsoft.NETCore.App.Runtime.win-x64 - 5.0.0-alpha1.19524.4 Dependency coherency updates - Microsoft.Win32.Registry - 5.0.0-alpha.1.19524.14 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.ComponentModel.Annotations - 5.0.0-alpha.1.19524.14 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Diagnostics.DiagnosticSource - 5.0.0-alpha.1.19524.14 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Diagnostics.EventLog - 5.0.0-alpha.1.19524.14 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.IO.Pipelines - 5.0.0-alpha.1.19524.14 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Reflection.Metadata - 5.0.0-alpha.1.19524.14 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Runtime.CompilerServices.Unsafe - 5.0.0-alpha.1.19524.14 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Security.Cryptography.Cng - 5.0.0-alpha.1.19524.14 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Security.Cryptography.Xml - 5.0.0-alpha.1.19524.14 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.ServiceProcess.ServiceController - 5.0.0-alpha.1.19524.14 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Text.Encodings.Web - 5.0.0-alpha.1.19524.14 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Text.Json - 5.0.0-alpha.1.19524.14 (parent: Microsoft.NETCore.App.Runtime.win-x64) - Microsoft.NETCore.Platforms - 5.0.0-alpha.1.19524.14 (parent: Microsoft.NETCore.App.Runtime.win-x64) * Update dependencies from https://github.com/dotnet/core-setup build 20191025.8 - Microsoft.NETCore.App.Ref - 5.0.0-alpha1.19525.8 - NETStandard.Library.Ref - 2.1.0-alpha1.19525.8 - Microsoft.NETCore.App.Runtime.win-x64 - 5.0.0-alpha1.19525.8 Dependency coherency updates - Microsoft.Win32.Registry - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.ComponentModel.Annotations - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Diagnostics.DiagnosticSource - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Diagnostics.EventLog - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.IO.Pipelines - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Reflection.Metadata - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Runtime.CompilerServices.Unsafe - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Security.Cryptography.Cng - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Security.Cryptography.Xml - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.ServiceProcess.ServiceController - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Text.Encodings.Web - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Text.Json - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - Microsoft.NETCore.Platforms - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) * Update dependencies from https://github.com/dotnet/core-setup build 20191026.2 - Microsoft.NETCore.App.Ref - 5.0.0-alpha1.19526.2 - NETStandard.Library.Ref - 2.1.0-alpha1.19526.2 - Microsoft.NETCore.App.Runtime.win-x64 - 5.0.0-alpha1.19526.2 Dependency coherency updates - Microsoft.Win32.Registry - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.ComponentModel.Annotations - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Diagnostics.DiagnosticSource - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Diagnostics.EventLog - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.IO.Pipelines - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Reflection.Metadata - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Runtime.CompilerServices.Unsafe - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Security.Cryptography.Cng - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Security.Cryptography.Xml - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.ServiceProcess.ServiceController - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Text.Encodings.Web - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Text.Json - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - Microsoft.NETCore.Platforms - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) * Update dependencies from https://github.com/dotnet/arcade build 20191027.3 - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19527.3 - Microsoft.DotNet.GenAPI - 5.0.0-beta.19527.3 - Microsoft.DotNet.Helix.Sdk - 5.0.0-beta.19527.3 * Update dependencies from https://github.com/dotnet/core-setup build 20191027.2 - Microsoft.NETCore.App.Ref - 5.0.0-alpha1.19527.2 - NETStandard.Library.Ref - 2.1.0-alpha1.19527.2 - Microsoft.NETCore.App.Runtime.win-x64 - 5.0.0-alpha1.19527.2 Dependency coherency updates - Microsoft.Win32.Registry - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.ComponentModel.Annotations - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Diagnostics.DiagnosticSource - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Diagnostics.EventLog - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.IO.Pipelines - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Reflection.Metadata - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Runtime.CompilerServices.Unsafe - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Security.Cryptography.Cng - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Security.Cryptography.Xml - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.ServiceProcess.ServiceController - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Text.Encodings.Web - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Text.Json - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - Microsoft.NETCore.Platforms - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) * Update dependencies from https://github.com/dotnet/core-setup build 20191028.5 - Microsoft.NETCore.App.Ref - 5.0.0-alpha.1.19528.5 - NETStandard.Library.Ref - 2.1.0-alpha.1.19528.5 - Microsoft.NETCore.App.Runtime.win-x64 - 5.0.0-alpha.1.19528.5 Dependency coherency updates - Microsoft.Win32.Registry - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.ComponentModel.Annotations - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Diagnostics.DiagnosticSource - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Diagnostics.EventLog - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.IO.Pipelines - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Reflection.Metadata - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Runtime.CompilerServices.Unsafe - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Security.Cryptography.Cng - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Security.Cryptography.Xml - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.ServiceProcess.ServiceController - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Text.Encodings.Web - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Text.Json - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) - Microsoft.NETCore.Platforms - 5.0.0-alpha.1.19525.3 (parent: Microsoft.NETCore.App.Runtime.win-x64) * Update dependencies from https://github.com/dotnet/core-setup build 20191030.10 - Microsoft.NETCore.App.Ref - 5.0.0-alpha.1.19530.10 - NETStandard.Library.Ref - 2.1.0-alpha.1.19530.10 - Microsoft.NETCore.App.Runtime.win-x64 - 5.0.0-alpha.1.19530.10 Dependency coherency updates - Microsoft.Win32.Registry - 5.0.0-alpha.1.19530.13 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.ComponentModel.Annotations - 5.0.0-alpha.1.19530.13 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Diagnostics.DiagnosticSource - 5.0.0-alpha.1.19530.13 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Diagnostics.EventLog - 5.0.0-alpha.1.19530.13 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.IO.Pipelines - 5.0.0-alpha.1.19530.13 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Reflection.Metadata - 5.0.0-alpha.1.19530.13 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Runtime.CompilerServices.Unsafe - 5.0.0-alpha.1.19530.13 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Security.Cryptography.Cng - 5.0.0-alpha.1.19530.13 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Security.Cryptography.Xml - 5.0.0-alpha.1.19530.13 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.ServiceProcess.ServiceController - 5.0.0-alpha.1.19530.13 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Text.Encodings.Web - 5.0.0-alpha.1.19530.13 (parent: Microsoft.NETCore.App.Runtime.win-x64) - System.Text.Json - 5.0.0-alpha.1.19530.13 (parent: Microsoft.NETCore.App.Runtime.win-x64) - Microsoft.NETCore.Platforms - 5.0.0-alpha.1.19530.13 (parent: Microsoft.NETCore.App.Runtime.win-x64) * Update dependencies from https://github.com/dotnet/arcade build 20191031.8 - Microsoft.DotNet.Arcade.Sdk - 5.0.0-beta.19531.8 - Microsoft.DotNet.GenAPI - 5.0.0-beta.19531.8 - Microsoft.DotNet.Helix.Sdk - 5.0.0-beta.19531.8 --- ...ft.Extensions.Logging.AzureAppServices.netstandard2.0.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs index 6599438d40..9a80372198 100644 --- a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs +++ b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs @@ -28,13 +28,13 @@ namespace Microsoft.Extensions.Logging.AzureAppServices public int? BackgroundQueueSize { get { throw null; } set { } } public int? BatchSize { get { throw null; } set { } } public System.TimeSpan FlushPeriod { get { throw null; } set { } } - public bool IncludeScopes { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public bool IsEnabled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } + public bool IncludeScopes { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public bool IsEnabled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } } public abstract partial class BatchingLoggerProvider : Microsoft.Extensions.Logging.ILoggerProvider, Microsoft.Extensions.Logging.ISupportExternalScope, System.IDisposable { internal BatchingLoggerProvider() { } - public bool IsEnabled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + public bool IsEnabled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) { throw null; } public void Dispose() { } protected virtual System.Threading.Tasks.Task IntervalAsync(System.TimeSpan interval, System.Threading.CancellationToken cancellationToken) { throw null; } From e775cde6ddf0a6bab42835d037dcbd36c185ade4 Mon Sep 17 00:00:00 2001 From: dotnet-maestro-bot Date: Wed, 4 Dec 2019 17:07:43 -0800 Subject: [PATCH 32/44] [automated] Merge branch 'release/3.0' => 'release/3.1' (#2748) * [release/3.0] Update dependencies from dotnet/core-setup (#2719) * Update dependencies from https://github.com/dotnet/core-setup build 20191126.03 - Microsoft.NETCore.App.Runtime.win-x64 - 3.0.2-servicing-19576-03 * Update dependencies from https://github.com/dotnet/core-setup build 20191126.05 - Microsoft.NETCore.App.Runtime.win-x64 - 3.0.2-servicing-19576-05 * Update dependencies from https://github.com/dotnet/core-setup build 20191126.08 - Microsoft.NETCore.App.Runtime.win-x64 - 3.0.2-servicing-19576-08 Dependency coherency updates - Microsoft.NETCore.Platforms - 3.0.1-servicing.19576.7 (parent: Microsoft.NETCore.App.Runtime.win-x64) * Update dependencies from https://github.com/dotnet/arcade build 20191127.5 (#2729) - Microsoft.DotNet.Arcade.Sdk - 1.0.0-beta.19577.5 - Microsoft.DotNet.GenAPI - 1.0.0-beta.19577.5 - Microsoft.DotNet.Helix.Sdk - 2.0.0-beta.19577.5 * Build implementation projects against ref assemblies * Add explicit references in tests, where needed --- ...soft.Extensions.Logging.AzureAppServices.Tests.csproj | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj b/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj index b1a396085d..7365c79076 100644 --- a/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj +++ b/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj @@ -6,14 +6,23 @@ + + + + + + + + + From 6840731ab39827dfde10bd9835a3c09f3031dd74 Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 6 Jan 2020 11:40:44 -0800 Subject: [PATCH 33/44] Preserve functional test logs on CI (#2819) * Add option to preserve function test logs * Upload test logs as artifacts * Preserve binlogs * Add target to ensure all functional test logs preserved --- src/Logging/Logging.Testing/src/AssemblyTestLog.cs | 2 +- .../src/TestFrameworkFileLoggerAttribute.cs | 4 ++-- .../build/Microsoft.Extensions.Logging.Testing.props | 10 ++++++++-- .../Logging.Testing/test/AssemblyTestLogTests.cs | 12 ++++++++++++ 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/Logging/Logging.Testing/src/AssemblyTestLog.cs b/src/Logging/Logging.Testing/src/AssemblyTestLog.cs index 3c598b67d5..611b853fac 100644 --- a/src/Logging/Logging.Testing/src/AssemblyTestLog.cs +++ b/src/Logging/Logging.Testing/src/AssemblyTestLog.cs @@ -222,7 +222,7 @@ namespace Microsoft.Extensions.Logging.Testing // Try to clear previous logs, continue if it fails. var assemblyBaseDirectory = TestFileOutputContext.GetAssemblyBaseDirectory(assembly); - if (!string.IsNullOrEmpty(assemblyBaseDirectory)) + if (!string.IsNullOrEmpty(assemblyBaseDirectory) && !TestFileOutputContext.GetPreserveExistingLogsInOutput(assembly)) { try { diff --git a/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs b/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs index 025a5a9bd8..1059fa76f2 100644 --- a/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs +++ b/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs @@ -9,8 +9,8 @@ namespace Microsoft.Extensions.Logging.Testing [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] public class TestFrameworkFileLoggerAttribute : TestOutputDirectoryAttribute { - public TestFrameworkFileLoggerAttribute(string tfm, string baseDirectory = null) - : base(tfm, baseDirectory) + public TestFrameworkFileLoggerAttribute(string preserveExistingLogsInOutput, string tfm, string baseDirectory = null) + : base(preserveExistingLogsInOutput, tfm, baseDirectory) { } } diff --git a/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props b/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props index 3895cb5471..167efb3f82 100644 --- a/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props +++ b/src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props @@ -9,6 +9,11 @@ + + true + false + + <_Parameter1>Microsoft.AspNetCore.Testing.AspNetTestFramework @@ -16,8 +21,9 @@ - <_Parameter1>$(TargetFramework) - <_Parameter2 Condition="'$(LoggingTestingDisableFileLogging)' != 'true'">$(LoggingTestingFileLoggingDirectory) + <_Parameter1>$(PreserveExistingLogsInOutput) + <_Parameter2>$(TargetFramework) + <_Parameter3 Condition="'$(LoggingTestingDisableFileLogging)' != 'true'">$(LoggingTestingFileLoggingDirectory) diff --git a/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs b/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs index 6d7ae5139a..dbefa4ccd2 100644 --- a/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs +++ b/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs @@ -8,6 +8,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing; using Xunit; namespace Microsoft.Extensions.Logging.Testing.Tests @@ -18,6 +19,17 @@ namespace Microsoft.Extensions.Logging.Testing.Tests private static readonly string ThisAssemblyName = ThisAssembly.GetName().Name; private static readonly string TFM = new DirectoryInfo(AppContext.BaseDirectory).Name; + [Fact] + public void FunctionalLogs_LogsPreservedFromNonFlakyRun() + { + } + + [Fact] + [Flaky("http://example.com", FlakyOn.All)] + public void FunctionalLogs_LogsPreservedFromFlakyRun() + { + } + [Fact] public void ForAssembly_ReturnsSameInstanceForSameAssembly() { From e78f5966c79dc29d6616c2f7c58b0ab8f0bbad77 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 15 Jan 2020 16:36:56 -0800 Subject: [PATCH 34/44] Remove ref project from Microsoft.AspNetCore.Testing (#2817) --- .../src/Microsoft.Extensions.Logging.Testing.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj index 0670cffcc9..0c07c01c10 100644 --- a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj +++ b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj @@ -18,7 +18,7 @@ - + From 220bfec9d665d04ded0303b6fa90d6c6bb1e0a42 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Fri, 17 Jan 2020 19:24:54 -0800 Subject: [PATCH 35/44] Revert "Remove ref project from Microsoft.AspNetCore.Testing (#2817)" (#2882) This reverts commit b624d6ba91b9c292ff9a2aa786a575b0eaa31b4b. --- .../src/Microsoft.Extensions.Logging.Testing.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj index 0c07c01c10..0670cffcc9 100644 --- a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj +++ b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj @@ -18,7 +18,7 @@ - + From 609cdbe94e04bd5887a77b1dd309166715fb1b67 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 13 Feb 2020 15:49:45 -0800 Subject: [PATCH 36/44] Revert "Revert "Remove ref project from Microsoft.AspNetCore.Testing (#2817)" (#2882)" (#2936) This reverts commit 1286a6ff55e300352dabeb6d778c9fcdd258bd08. --- .../src/Microsoft.Extensions.Logging.Testing.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj index 0670cffcc9..0c07c01c10 100644 --- a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj +++ b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj @@ -18,7 +18,7 @@ - + From ea15690a471e13064b07e62f5ddc610e78225e9d Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Wed, 26 Feb 2020 10:27:22 -0800 Subject: [PATCH 37/44] Normalize all file headers to the expected Apache 2.0 license --- src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs | 3 +++ src/Logging/Logging.Testing/src/CollectDumpAttribute.cs | 2 +- src/Logging/Logging.Testing/src/ITestSink.cs | 5 ++++- src/Logging/Logging.Testing/src/LogValuesAssert.cs | 2 +- src/Logging/Logging.Testing/test/LogValuesAssertTest.cs | 2 +- src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs | 3 +++ 6 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs b/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs index 23afaf1787..c44a6d17e2 100644 --- a/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs +++ b/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs @@ -1,3 +1,6 @@ +// 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; using System.Threading; using System.Threading.Tasks; diff --git a/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs b/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs index 012a5c8fa1..c9e8ee3fa6 100644 --- a/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs +++ b/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs @@ -1,4 +1,4 @@ -// Copyright(c) .NET Foundation.All rights reserved. +// 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; diff --git a/src/Logging/Logging.Testing/src/ITestSink.cs b/src/Logging/Logging.Testing/src/ITestSink.cs index 8b0bef5033..ab468f420d 100644 --- a/src/Logging/Logging.Testing/src/ITestSink.cs +++ b/src/Logging/Logging.Testing/src/ITestSink.cs @@ -1,4 +1,7 @@ -using System; +// 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; using System.Collections.Concurrent; namespace Microsoft.Extensions.Logging.Testing diff --git a/src/Logging/Logging.Testing/src/LogValuesAssert.cs b/src/Logging/Logging.Testing/src/LogValuesAssert.cs index ea769e68e2..57b6e983a7 100644 --- a/src/Logging/Logging.Testing/src/LogValuesAssert.cs +++ b/src/Logging/Logging.Testing/src/LogValuesAssert.cs @@ -1,4 +1,4 @@ -// Copyright(c) .NET Foundation.All rights reserved. +// 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; diff --git a/src/Logging/Logging.Testing/test/LogValuesAssertTest.cs b/src/Logging/Logging.Testing/test/LogValuesAssertTest.cs index b5e1d98738..1d85ddec13 100644 --- a/src/Logging/Logging.Testing/test/LogValuesAssertTest.cs +++ b/src/Logging/Logging.Testing/test/LogValuesAssertTest.cs @@ -1,4 +1,4 @@ -// Copyright(c) .NET Foundation.All rights reserved. +// 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.Collections.Generic; diff --git a/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs b/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs index 82616e2737..8ae4233e71 100644 --- a/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs +++ b/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs @@ -1,3 +1,6 @@ +// 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 Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; From 567ebd4e4ebdade07d20f0c5b59d156f13634df3 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Wed, 26 Feb 2020 10:31:24 -0800 Subject: [PATCH 38/44] Switch file headers to the MIT license --- .../src/AzureAppServicesLoggerFactoryExtensions.cs | 5 +++-- .../Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs | 5 +++-- .../Logging.AzureAppServices/src/AzureFileLoggerOptions.cs | 5 +++-- .../src/BatchLoggerConfigureOptions.cs | 5 +++-- src/Logging/Logging.AzureAppServices/src/BatchingLogger.cs | 5 +++-- .../Logging.AzureAppServices/src/BatchingLoggerOptions.cs | 5 +++-- .../Logging.AzureAppServices/src/BatchingLoggerProvider.cs | 5 +++-- .../src/BlobAppendReferenceWrapper.cs | 5 +++-- .../src/BlobLoggerConfigureOptions.cs | 5 +++-- .../Logging.AzureAppServices/src/BlobLoggerProvider.cs | 5 +++-- .../src/ConfigurationBasedLevelSwitcher.cs | 5 +++-- .../src/FileLoggerConfigureOptions.cs | 5 +++-- .../Logging.AzureAppServices/src/FileLoggerProvider.cs | 5 +++-- .../Logging.AzureAppServices/src/ICloudAppendBlob.cs | 5 +++-- src/Logging/Logging.AzureAppServices/src/IWebAppContext.cs | 5 +++-- src/Logging/Logging.AzureAppServices/src/LogMessage.cs | 5 +++-- .../Logging.AzureAppServices/src/Properties/AssemblyInfo.cs | 6 ++++-- .../src/SiteConfigurationProvider.cs | 5 +++-- src/Logging/Logging.AzureAppServices/src/WebAppContext.cs | 5 +++-- .../Logging.AzureAppServices/test/AzureAppendBlobTests.cs | 5 +++-- .../Logging.AzureAppServices/test/AzureBlobSinkTests.cs | 5 +++-- .../test/AzureDiagnosticsConfigurationProviderTests.cs | 5 +++-- .../test/BatchingLoggerProviderTests.cs | 5 +++-- .../Logging.AzureAppServices/test/ConfigureOptionsTests.cs | 5 +++-- .../Logging.AzureAppServices/test/FileLoggerTests.cs | 5 +++-- .../test/LoggerBuilderExtensionsTests.cs | 5 +++-- .../Logging.AzureAppServices/test/ManualIntervalControl.cs | 5 +++-- .../Logging.AzureAppServices/test/OptionsWrapperMonitor.cs | 5 +++-- src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs | 5 +++-- .../Logging.AzureAppServices/test/TestFileLoggerProvider.cs | 5 +++-- .../test/WebConfigurationLevelSwitchTests.cs | 5 +++-- src/Logging/Logging.Testing/src/AssemblyTestLog.cs | 5 +++-- src/Logging/Logging.Testing/src/BeginScopeContext.cs | 5 +++-- src/Logging/Logging.Testing/src/CollectDumpAttribute.cs | 5 +++-- .../src/DumpCollector/DumpCollector.Windows.cs | 5 +++-- .../Logging.Testing/src/DumpCollector/DumpCollector.cs | 5 +++-- src/Logging/Logging.Testing/src/ITestSink.cs | 5 +++-- src/Logging/Logging.Testing/src/LogLevelAttribute.cs | 5 +++-- src/Logging/Logging.Testing/src/LogValuesAssert.cs | 5 +++-- src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs | 5 +++-- src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs | 5 +++-- .../Logging.Testing/src/LoggedTest/LoggedTestBase.cs | 5 +++-- .../Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs | 5 +++-- src/Logging/Logging.Testing/src/TestLogger.cs | 5 +++-- src/Logging/Logging.Testing/src/TestLoggerFactory.cs | 5 +++-- src/Logging/Logging.Testing/src/TestLoggerProvider.cs | 5 +++-- src/Logging/Logging.Testing/src/TestLoggerT.cs | 5 +++-- src/Logging/Logging.Testing/src/TestSink.cs | 5 +++-- src/Logging/Logging.Testing/src/WriteContext.cs | 5 +++-- .../Logging.Testing/src/XunitLoggerFactoryExtensions.cs | 5 +++-- src/Logging/Logging.Testing/src/XunitLoggerProvider.cs | 5 +++-- src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs | 5 +++-- src/Logging/Logging.Testing/test/LogValuesAssertTest.cs | 5 +++-- src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs | 5 +++-- src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs | 5 +++-- src/Logging/Logging.Testing/test/TestTestOutputHelper.cs | 5 +++-- src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs | 5 +++-- 57 files changed, 172 insertions(+), 114 deletions(-) diff --git a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs index 2b8398ef1c..9b680e9138 100644 --- a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs +++ b/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs index 6af815457c..1e1285b358 100644 --- a/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; diff --git a/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs index 30694e5fc7..af8b5a112e 100644 --- a/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; diff --git a/src/Logging/Logging.AzureAppServices/src/BatchLoggerConfigureOptions.cs b/src/Logging/Logging.AzureAppServices/src/BatchLoggerConfigureOptions.cs index a50bd65b32..8dc8727b3a 100644 --- a/src/Logging/Logging.AzureAppServices/src/BatchLoggerConfigureOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/BatchLoggerConfigureOptions.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; diff --git a/src/Logging/Logging.AzureAppServices/src/BatchingLogger.cs b/src/Logging/Logging.AzureAppServices/src/BatchingLogger.cs index b2960802d4..bd192169f3 100644 --- a/src/Logging/Logging.AzureAppServices/src/BatchingLogger.cs +++ b/src/Logging/Logging.AzureAppServices/src/BatchingLogger.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Text; diff --git a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerOptions.cs b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerOptions.cs index b474af5489..9fbd964800 100644 --- a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerOptions.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; diff --git a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs index a78a7f7bc7..227a616f3b 100644 --- a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Collections.Concurrent; diff --git a/src/Logging/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs b/src/Logging/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs index bf6656f9f3..e9805128b7 100644 --- a/src/Logging/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs +++ b/src/Logging/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Net; diff --git a/src/Logging/Logging.AzureAppServices/src/BlobLoggerConfigureOptions.cs b/src/Logging/Logging.AzureAppServices/src/BlobLoggerConfigureOptions.cs index d07f76795d..f9a186872b 100644 --- a/src/Logging/Logging.AzureAppServices/src/BlobLoggerConfigureOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/BlobLoggerConfigureOptions.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; diff --git a/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs index e906c2746f..3d62ea2ac6 100644 --- a/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; diff --git a/src/Logging/Logging.AzureAppServices/src/ConfigurationBasedLevelSwitcher.cs b/src/Logging/Logging.AzureAppServices/src/ConfigurationBasedLevelSwitcher.cs index 77e5a399d0..c62ccb2331 100644 --- a/src/Logging/Logging.AzureAppServices/src/ConfigurationBasedLevelSwitcher.cs +++ b/src/Logging/Logging.AzureAppServices/src/ConfigurationBasedLevelSwitcher.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using Microsoft.Extensions.Configuration; diff --git a/src/Logging/Logging.AzureAppServices/src/FileLoggerConfigureOptions.cs b/src/Logging/Logging.AzureAppServices/src/FileLoggerConfigureOptions.cs index e7d8a84492..8cd1f5eb91 100644 --- a/src/Logging/Logging.AzureAppServices/src/FileLoggerConfigureOptions.cs +++ b/src/Logging/Logging.AzureAppServices/src/FileLoggerConfigureOptions.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.IO; using Microsoft.Extensions.Configuration; diff --git a/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs index fb34d63d5b..1143d38c07 100644 --- a/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.IO; diff --git a/src/Logging/Logging.AzureAppServices/src/ICloudAppendBlob.cs b/src/Logging/Logging.AzureAppServices/src/ICloudAppendBlob.cs index 98f3b34d28..2f55bbb0d1 100644 --- a/src/Logging/Logging.AzureAppServices/src/ICloudAppendBlob.cs +++ b/src/Logging/Logging.AzureAppServices/src/ICloudAppendBlob.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.IO; diff --git a/src/Logging/Logging.AzureAppServices/src/IWebAppContext.cs b/src/Logging/Logging.AzureAppServices/src/IWebAppContext.cs index a888de16af..f8c826ceb8 100644 --- a/src/Logging/Logging.AzureAppServices/src/IWebAppContext.cs +++ b/src/Logging/Logging.AzureAppServices/src/IWebAppContext.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. namespace Microsoft.Extensions.Logging.AzureAppServices { diff --git a/src/Logging/Logging.AzureAppServices/src/LogMessage.cs b/src/Logging/Logging.AzureAppServices/src/LogMessage.cs index 460ebd8c0f..4a1179ceb3 100644 --- a/src/Logging/Logging.AzureAppServices/src/LogMessage.cs +++ b/src/Logging/Logging.AzureAppServices/src/LogMessage.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; diff --git a/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs b/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs index d77af5dc95..7c7d332545 100644 --- a/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs +++ b/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs @@ -1,5 +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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + using System.Runtime.CompilerServices; diff --git a/src/Logging/Logging.AzureAppServices/src/SiteConfigurationProvider.cs b/src/Logging/Logging.AzureAppServices/src/SiteConfigurationProvider.cs index e685db2ebc..452c936f93 100644 --- a/src/Logging/Logging.AzureAppServices/src/SiteConfigurationProvider.cs +++ b/src/Logging/Logging.AzureAppServices/src/SiteConfigurationProvider.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.IO; using Microsoft.Extensions.Configuration; diff --git a/src/Logging/Logging.AzureAppServices/src/WebAppContext.cs b/src/Logging/Logging.AzureAppServices/src/WebAppContext.cs index 149766f25c..8bdd3f1c76 100644 --- a/src/Logging/Logging.AzureAppServices/src/WebAppContext.cs +++ b/src/Logging/Logging.AzureAppServices/src/WebAppContext.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; diff --git a/src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs b/src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs index d9badcde31..2fd5955e86 100644 --- a/src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Net; diff --git a/src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs b/src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs index d8642aeae7..4d9125335a 100644 --- a/src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; diff --git a/src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs b/src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs index c2bfa516d2..00d7dcd58d 100644 --- a/src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.IO; diff --git a/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs b/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs index a8fe9d596c..9ab0c0cb45 100644 --- a/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; diff --git a/src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs b/src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs index 9d46aeb832..46b72c7a0d 100644 --- a/src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; diff --git a/src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs b/src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs index 430f8852d8..a3fcd2587d 100644 --- a/src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.IO; diff --git a/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs b/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs index 468d52c7e4..cf8bede1a5 100644 --- a/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.Linq; using Microsoft.Extensions.Configuration; diff --git a/src/Logging/Logging.AzureAppServices/test/ManualIntervalControl.cs b/src/Logging/Logging.AzureAppServices/test/ManualIntervalControl.cs index 0ce87f65dc..29cc883a28 100644 --- a/src/Logging/Logging.AzureAppServices/test/ManualIntervalControl.cs +++ b/src/Logging/Logging.AzureAppServices/test/ManualIntervalControl.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.Threading.Tasks; diff --git a/src/Logging/Logging.AzureAppServices/test/OptionsWrapperMonitor.cs b/src/Logging/Logging.AzureAppServices/test/OptionsWrapperMonitor.cs index 32da949cdb..fbc531c26d 100644 --- a/src/Logging/Logging.AzureAppServices/test/OptionsWrapperMonitor.cs +++ b/src/Logging/Logging.AzureAppServices/test/OptionsWrapperMonitor.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using Microsoft.Extensions.Options; diff --git a/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs b/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs index c44a6d17e2..4b9ec445be 100644 --- a/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs +++ b/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Threading; diff --git a/src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs b/src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs index 8350133d99..60fbb88bd8 100644 --- a/src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs +++ b/src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Threading; diff --git a/src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs b/src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs index c4f92115e7..f933b9f2fa 100644 --- a/src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs +++ b/src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.Collections.Generic; using Microsoft.Extensions.Configuration; diff --git a/src/Logging/Logging.Testing/src/AssemblyTestLog.cs b/src/Logging/Logging.Testing/src/AssemblyTestLog.cs index 611b853fac..bd69cd20a3 100644 --- a/src/Logging/Logging.Testing/src/AssemblyTestLog.cs +++ b/src/Logging/Logging.Testing/src/AssemblyTestLog.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; diff --git a/src/Logging/Logging.Testing/src/BeginScopeContext.cs b/src/Logging/Logging.Testing/src/BeginScopeContext.cs index b432f1ad7d..14ef991e0d 100644 --- a/src/Logging/Logging.Testing/src/BeginScopeContext.cs +++ b/src/Logging/Logging.Testing/src/BeginScopeContext.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. namespace Microsoft.Extensions.Logging.Testing { diff --git a/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs b/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs index c9e8ee3fa6..5f4a1eee59 100644 --- a/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs +++ b/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Diagnostics; diff --git a/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.Windows.cs b/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.Windows.cs index 8d4168c20c..20395208d7 100644 --- a/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.Windows.cs +++ b/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.Windows.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Diagnostics; diff --git a/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.cs b/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.cs index 67043ed827..d67e109b38 100644 --- a/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.cs +++ b/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.Diagnostics; using System.Runtime.InteropServices; diff --git a/src/Logging/Logging.Testing/src/ITestSink.cs b/src/Logging/Logging.Testing/src/ITestSink.cs index ab468f420d..b328e5c595 100644 --- a/src/Logging/Logging.Testing/src/ITestSink.cs +++ b/src/Logging/Logging.Testing/src/ITestSink.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Collections.Concurrent; diff --git a/src/Logging/Logging.Testing/src/LogLevelAttribute.cs b/src/Logging/Logging.Testing/src/LogLevelAttribute.cs index 5de51cfe91..74aa395d4b 100644 --- a/src/Logging/Logging.Testing/src/LogLevelAttribute.cs +++ b/src/Logging/Logging.Testing/src/LogLevelAttribute.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; diff --git a/src/Logging/Logging.Testing/src/LogValuesAssert.cs b/src/Logging/Logging.Testing/src/LogValuesAssert.cs index 57b6e983a7..ef2ff1f406 100644 --- a/src/Logging/Logging.Testing/src/LogValuesAssert.cs +++ b/src/Logging/Logging.Testing/src/LogValuesAssert.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; diff --git a/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs b/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs index a906ae84a2..750f45cd91 100644 --- a/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs +++ b/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Reflection; diff --git a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs index d108ffb7e8..169a94f59d 100644 --- a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs +++ b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.Reflection; using Microsoft.AspNetCore.Testing; diff --git a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs index 324b855319..16dde9676c 100644 --- a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs +++ b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Linq; diff --git a/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs b/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs index 1059fa76f2..61fa9993e8 100644 --- a/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs +++ b/src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using Microsoft.AspNetCore.Testing; diff --git a/src/Logging/Logging.Testing/src/TestLogger.cs b/src/Logging/Logging.Testing/src/TestLogger.cs index f7a73dfa6a..1f1b1d6aba 100644 --- a/src/Logging/Logging.Testing/src/TestLogger.cs +++ b/src/Logging/Logging.Testing/src/TestLogger.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; diff --git a/src/Logging/Logging.Testing/src/TestLoggerFactory.cs b/src/Logging/Logging.Testing/src/TestLoggerFactory.cs index 7200e254b8..a7f2f1398c 100644 --- a/src/Logging/Logging.Testing/src/TestLoggerFactory.cs +++ b/src/Logging/Logging.Testing/src/TestLoggerFactory.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. namespace Microsoft.Extensions.Logging.Testing { diff --git a/src/Logging/Logging.Testing/src/TestLoggerProvider.cs b/src/Logging/Logging.Testing/src/TestLoggerProvider.cs index 758ff32492..e604bda36e 100644 --- a/src/Logging/Logging.Testing/src/TestLoggerProvider.cs +++ b/src/Logging/Logging.Testing/src/TestLoggerProvider.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. namespace Microsoft.Extensions.Logging.Testing { diff --git a/src/Logging/Logging.Testing/src/TestLoggerT.cs b/src/Logging/Logging.Testing/src/TestLoggerT.cs index b54870eb87..096bb96535 100644 --- a/src/Logging/Logging.Testing/src/TestLoggerT.cs +++ b/src/Logging/Logging.Testing/src/TestLoggerT.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; diff --git a/src/Logging/Logging.Testing/src/TestSink.cs b/src/Logging/Logging.Testing/src/TestSink.cs index cc9c1ce7bc..5285b3068f 100644 --- a/src/Logging/Logging.Testing/src/TestSink.cs +++ b/src/Logging/Logging.Testing/src/TestSink.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Collections.Concurrent; diff --git a/src/Logging/Logging.Testing/src/WriteContext.cs b/src/Logging/Logging.Testing/src/WriteContext.cs index 661538e4c5..0ecfc8f1a9 100644 --- a/src/Logging/Logging.Testing/src/WriteContext.cs +++ b/src/Logging/Logging.Testing/src/WriteContext.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; diff --git a/src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs b/src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs index f646a68e58..7d053d45dd 100644 --- a/src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs +++ b/src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Logging/Logging.Testing/src/XunitLoggerProvider.cs b/src/Logging/Logging.Testing/src/XunitLoggerProvider.cs index 8e28d6a19f..3a1d751413 100644 --- a/src/Logging/Logging.Testing/src/XunitLoggerProvider.cs +++ b/src/Logging/Logging.Testing/src/XunitLoggerProvider.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Linq; diff --git a/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs b/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs index dbefa4ccd2..27a7cf83cf 100644 --- a/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs +++ b/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.IO; diff --git a/src/Logging/Logging.Testing/test/LogValuesAssertTest.cs b/src/Logging/Logging.Testing/test/LogValuesAssertTest.cs index 1d85ddec13..dc2db9d83d 100644 --- a/src/Logging/Logging.Testing/test/LogValuesAssertTest.cs +++ b/src/Logging/Logging.Testing/test/LogValuesAssertTest.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.Linq; diff --git a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs index d8454023a2..61d7802508 100644 --- a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs +++ b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.Linq; using System.Reflection; diff --git a/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs b/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs index 8ae4233e71..9ae4865e3a 100644 --- a/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs +++ b/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; diff --git a/src/Logging/Logging.Testing/test/TestTestOutputHelper.cs b/src/Logging/Logging.Testing/test/TestTestOutputHelper.cs index 7043fe4ed2..5a5f6aa85f 100644 --- a/src/Logging/Logging.Testing/test/TestTestOutputHelper.cs +++ b/src/Logging/Logging.Testing/test/TestTestOutputHelper.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Text; diff --git a/src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs b/src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs index c991073b4a..8a3fbbab25 100644 --- a/src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs +++ b/src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Text.RegularExpressions; From 8cd0f1d9408fe9e0e269901e4eda3eb8f43bbd73 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Wed, 26 Feb 2020 10:55:12 -0800 Subject: [PATCH 39/44] Update license in reference assemblies --- ...oft.Extensions.Logging.AzureAppServices.netstandard2.0.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs index 9a80372198..9b8f637cff 100644 --- a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs +++ b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. namespace Microsoft.Extensions.Logging { From 0d8bfb9676b86741258f06713dc76783d030ee00 Mon Sep 17 00:00:00 2001 From: John Luo Date: Fri, 6 Mar 2020 14:59:15 -0800 Subject: [PATCH 40/44] Remove Serilog dependency in extensions (#3040) * Remove Serilog dependency in extensions * Add xunit logging for shutdown tests * Need to remove dependency on AspNetCore.Testing and remove DumpCollector --- .../Logging.Testing/src/AssemblyTestLog.cs | 306 ------------------ .../src/CollectDumpAttribute.cs | 40 --- .../DumpCollector/DumpCollector.Windows.cs | 77 ----- .../src/DumpCollector/DumpCollector.cs | 21 -- .../src/LoggedTest/ILoggedTest.cs | 25 -- .../src/LoggedTest/LoggedTest.cs | 26 -- .../src/LoggedTest/LoggedTestBase.cs | 122 ------- ...icrosoft.Extensions.Logging.Testing.csproj | 6 - .../src/TestFrameworkFileLoggerAttribute.cs | 18 -- ...Microsoft.Extensions.Logging.Testing.props | 30 -- .../test/AssemblyTestLogTests.cs | 221 ------------- .../test/LoggedTestXunitTests.cs | 193 ----------- ...ft.Extensions.Logging.Testing.Tests.csproj | 2 - 13 files changed, 1087 deletions(-) delete mode 100644 src/Logging/Logging.Testing/src/AssemblyTestLog.cs delete mode 100644 src/Logging/Logging.Testing/src/CollectDumpAttribute.cs delete mode 100644 src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.Windows.cs delete mode 100644 src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.cs delete mode 100644 src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs delete mode 100644 src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs delete mode 100644 src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs delete mode 100644 src/Logging/Logging.Testing/src/TestFrameworkFileLoggerAttribute.cs delete mode 100644 src/Logging/Logging.Testing/src/build/Microsoft.Extensions.Logging.Testing.props delete mode 100644 src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs delete mode 100644 src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs diff --git a/src/Logging/Logging.Testing/src/AssemblyTestLog.cs b/src/Logging/Logging.Testing/src/AssemblyTestLog.cs deleted file mode 100644 index bd69cd20a3..0000000000 --- a/src/Logging/Logging.Testing/src/AssemblyTestLog.cs +++ /dev/null @@ -1,306 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Text; -using Microsoft.AspNetCore.Testing; -using Microsoft.Extensions.DependencyInjection; -using Serilog; -using Serilog.Core; -using Serilog.Events; -using Serilog.Extensions.Logging; -using Xunit.Abstractions; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class AssemblyTestLog : IDisposable - { - private static readonly string MaxPathLengthEnvironmentVariableName = "ASPNETCORE_TEST_LOG_MAXPATH"; - private static readonly string LogFileExtension = ".log"; - private static readonly int MaxPathLength = GetMaxPathLength(); - - private static readonly object _lock = new object(); - private static readonly Dictionary _logs = new Dictionary(); - - private readonly ILoggerFactory _globalLoggerFactory; - private readonly ILogger _globalLogger; - private readonly string _baseDirectory; - private readonly Assembly _assembly; - private readonly IServiceProvider _serviceProvider; - - private static int GetMaxPathLength() - { - var maxPathString = Environment.GetEnvironmentVariable(MaxPathLengthEnvironmentVariableName); - var defaultMaxPath = 245; - return string.IsNullOrEmpty(maxPathString) ? defaultMaxPath : int.Parse(maxPathString); - } - - private AssemblyTestLog(ILoggerFactory globalLoggerFactory, ILogger globalLogger, string baseDirectory, Assembly assembly, IServiceProvider serviceProvider) - { - _globalLoggerFactory = globalLoggerFactory; - _globalLogger = globalLogger; - _baseDirectory = baseDirectory; - _assembly = assembly; - _serviceProvider = serviceProvider; - } - - public IDisposable StartTestLog(ITestOutputHelper output, string className, out ILoggerFactory loggerFactory, [CallerMemberName] string testName = null) => - StartTestLog(output, className, out loggerFactory, LogLevel.Debug, testName); - - public IDisposable StartTestLog(ITestOutputHelper output, string className, out ILoggerFactory loggerFactory, LogLevel minLogLevel, [CallerMemberName] string testName = null) => - StartTestLog(output, className, out loggerFactory, minLogLevel, out var _, out var _, testName); - - internal IDisposable StartTestLog(ITestOutputHelper output, string className, out ILoggerFactory loggerFactory, LogLevel minLogLevel, out string resolvedTestName, out string logOutputDirectory, [CallerMemberName] string testName = null) - { - var logStart = DateTimeOffset.UtcNow; - var serviceProvider = CreateLoggerServices(output, className, minLogLevel, out resolvedTestName, out logOutputDirectory, testName, logStart); - var factory = serviceProvider.GetRequiredService(); - loggerFactory = factory; - var logger = loggerFactory.CreateLogger("TestLifetime"); - - var stopwatch = Stopwatch.StartNew(); - - var scope = logger.BeginScope("Test: {testName}", testName); - - _globalLogger.LogInformation("Starting test {testName}", testName); - logger.LogInformation("Starting test {testName} at {logStart}", testName, logStart.ToString("s")); - - return new Disposable(() => - { - stopwatch.Stop(); - _globalLogger.LogInformation("Finished test {testName} in {duration}s", testName, stopwatch.Elapsed.TotalSeconds); - logger.LogInformation("Finished test {testName} in {duration}s", testName, stopwatch.Elapsed.TotalSeconds); - scope.Dispose(); - factory.Dispose(); - (serviceProvider as IDisposable)?.Dispose(); - }); - } - - public ILoggerFactory CreateLoggerFactory(ITestOutputHelper output, string className, [CallerMemberName] string testName = null, DateTimeOffset? logStart = null) - => CreateLoggerFactory(output, className, LogLevel.Trace, testName, logStart); - - public ILoggerFactory CreateLoggerFactory(ITestOutputHelper output, string className, LogLevel minLogLevel, [CallerMemberName] string testName = null, DateTimeOffset? logStart = null) - => CreateLoggerServices(output, className, minLogLevel, out var _, out var _, testName, logStart).GetRequiredService(); - - public IServiceProvider CreateLoggerServices(ITestOutputHelper output, string className, LogLevel minLogLevel, out string normalizedTestName, [CallerMemberName] string testName = null, DateTimeOffset? logStart = null) - => CreateLoggerServices(output, className, minLogLevel, out normalizedTestName, out var _, testName, logStart); - - public IServiceProvider CreateLoggerServices(ITestOutputHelper output, string className, LogLevel minLogLevel, out string normalizedTestName, out string logOutputDirectory, [CallerMemberName] string testName = null, DateTimeOffset? logStart = null) - { - normalizedTestName = string.Empty; - logOutputDirectory = string.Empty; - var assemblyName = _assembly.GetName().Name; - - // Try to shorten the class name using the assembly name - if (className.StartsWith(assemblyName + ".")) - { - className = className.Substring(assemblyName.Length + 1); - } - - SerilogLoggerProvider serilogLoggerProvider = null; - if (!string.IsNullOrEmpty(_baseDirectory)) - { - logOutputDirectory = Path.Combine(_baseDirectory, className); - testName = TestFileOutputContext.RemoveIllegalFileChars(testName); - - if (logOutputDirectory.Length + testName.Length + LogFileExtension.Length >= MaxPathLength) - { - _globalLogger.LogWarning($"Test name {testName} is too long. Please shorten test name."); - - // Shorten the test name by removing the middle portion of the testname - var testNameLength = MaxPathLength - logOutputDirectory.Length - LogFileExtension.Length; - - if (testNameLength <= 0) - { - throw new InvalidOperationException("Output file path could not be constructed due to max path length restrictions. Please shorten test assembly, class or method names."); - } - - testName = testName.Substring(0, testNameLength / 2) + testName.Substring(testName.Length - testNameLength / 2, testNameLength / 2); - - _globalLogger.LogWarning($"To prevent long paths test name was shortened to {testName}."); - } - - var testOutputFile = Path.Combine(logOutputDirectory, $"{testName}{LogFileExtension}"); - - if (File.Exists(testOutputFile)) - { - _globalLogger.LogWarning($"Output log file {testOutputFile} already exists. Please try to keep log file names unique."); - - for (var i = 0; i < 1000; i++) - { - testOutputFile = Path.Combine(logOutputDirectory, $"{testName}.{i}{LogFileExtension}"); - - if (!File.Exists(testOutputFile)) - { - _globalLogger.LogWarning($"To resolve log file collision, the enumerated file {testOutputFile} will be used."); - testName = $"{testName}.{i}"; - break; - } - } - } - - normalizedTestName = testName; - serilogLoggerProvider = ConfigureFileLogging(testOutputFile, logStart); - } - - var serviceCollection = new ServiceCollection(); - serviceCollection.AddLogging(builder => - { - builder.SetMinimumLevel(minLogLevel); - - if (output != null) - { - builder.AddXunit(output, minLogLevel, logStart); - } - - if (serilogLoggerProvider != null) - { - // Use a factory so that the container will dispose it - builder.Services.AddSingleton(_ => serilogLoggerProvider); - } - }); - - return serviceCollection.BuildServiceProvider(); - } - - // For back compat - public static AssemblyTestLog Create(string assemblyName, string baseDirectory) - => Create(Assembly.Load(new AssemblyName(assemblyName)), baseDirectory); - - public static AssemblyTestLog Create(Assembly assembly, string baseDirectory) - { - var logStart = DateTimeOffset.UtcNow; - SerilogLoggerProvider serilogLoggerProvider = null; - if (!string.IsNullOrEmpty(baseDirectory)) - { - baseDirectory = TestFileOutputContext.GetAssemblyBaseDirectory(assembly, baseDirectory); - var globalLogFileName = Path.Combine(baseDirectory, "global.log"); - serilogLoggerProvider = ConfigureFileLogging(globalLogFileName, logStart); - } - - var serviceCollection = new ServiceCollection(); - - serviceCollection.AddLogging(builder => - { - // Global logging, when it's written, is expected to be outputted. So set the log level to minimum. - builder.SetMinimumLevel(LogLevel.Trace); - - if (serilogLoggerProvider != null) - { - // Use a factory so that the container will dispose it - builder.Services.AddSingleton(_ => serilogLoggerProvider); - } - }); - - var serviceProvider = serviceCollection.BuildServiceProvider(); - var loggerFactory = serviceProvider.GetRequiredService(); - - var logger = loggerFactory.CreateLogger("GlobalTestLog"); - logger.LogInformation("Global Test Logging initialized at {logStart}. " - + "Configure the output directory via 'LoggingTestingFileLoggingDirectory' MSBuild property " - + "or set 'LoggingTestingDisableFileLogging' to 'true' to disable file logging.", - logStart.ToString("s")); - return new AssemblyTestLog(loggerFactory, logger, baseDirectory, assembly, serviceProvider); - } - - public static AssemblyTestLog ForAssembly(Assembly assembly) - { - lock (_lock) - { - if (!_logs.TryGetValue(assembly, out var log)) - { - var baseDirectory = TestFileOutputContext.GetOutputDirectory(assembly); - - log = Create(assembly, baseDirectory); - _logs[assembly] = log; - - // Try to clear previous logs, continue if it fails. - var assemblyBaseDirectory = TestFileOutputContext.GetAssemblyBaseDirectory(assembly); - if (!string.IsNullOrEmpty(assemblyBaseDirectory) && !TestFileOutputContext.GetPreserveExistingLogsInOutput(assembly)) - { - try - { - Directory.Delete(assemblyBaseDirectory, recursive: true); - } - catch { } - } - } - return log; - } - } - - private static TestFrameworkFileLoggerAttribute GetFileLoggerAttribute(Assembly assembly) - => assembly.GetCustomAttribute() - ?? throw new InvalidOperationException($"No {nameof(TestFrameworkFileLoggerAttribute)} found on the assembly {assembly.GetName().Name}. " - + "The attribute is added via msbuild properties of the Microsoft.Extensions.Logging.Testing. " - + "Please ensure the msbuild property is imported or a direct reference to Microsoft.Extensions.Logging.Testing is added."); - - private static SerilogLoggerProvider ConfigureFileLogging(string fileName, DateTimeOffset? logStart) - { - var dir = Path.GetDirectoryName(fileName); - if (!Directory.Exists(dir)) - { - Directory.CreateDirectory(dir); - } - - if (File.Exists(fileName)) - { - File.Delete(fileName); - } - - var serilogger = new LoggerConfiguration() - .Enrich.FromLogContext() - .Enrich.With(new AssemblyLogTimestampOffsetEnricher(logStart)) - .MinimumLevel.Verbose() - .WriteTo.File(fileName, outputTemplate: "[{TimestampOffset}] [{SourceContext}] [{Level}] {Message:l}{NewLine}{Exception}", flushToDiskInterval: TimeSpan.FromSeconds(1), shared: true) - .CreateLogger(); - return new SerilogLoggerProvider(serilogger, dispose: true); - } - - public void Dispose() - { - (_serviceProvider as IDisposable)?.Dispose(); - _globalLoggerFactory.Dispose(); - } - - private class AssemblyLogTimestampOffsetEnricher : ILogEventEnricher - { - private DateTimeOffset? _logStart; - - public AssemblyLogTimestampOffsetEnricher(DateTimeOffset? logStart) - { - _logStart = logStart; - } - - public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) - => logEvent.AddPropertyIfAbsent( - propertyFactory.CreateProperty( - "TimestampOffset", - _logStart.HasValue - ? $"{(DateTimeOffset.UtcNow - _logStart.Value).TotalSeconds.ToString("N3")}s" - : DateTimeOffset.UtcNow.ToString("s"))); - } - - private class Disposable : IDisposable - { - private Action _action; - - public Disposable(Action action) - { - _action = action; - } - - public void Dispose() - { - _action(); - } - } - } -} diff --git a/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs b/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs deleted file mode 100644 index 5f4a1eee59..0000000000 --- a/src/Logging/Logging.Testing/src/CollectDumpAttribute.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Diagnostics; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Testing; - -namespace Microsoft.Extensions.Logging.Testing -{ - /// - /// Capture the memory dump upon test failure. - /// - /// - /// This currently only works in Windows environments - /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] - public class CollectDumpAttribute : Attribute, ITestMethodLifecycle - { - public Task OnTestStartAsync(TestContext context, CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - - public Task OnTestEndAsync(TestContext context, Exception exception, CancellationToken cancellationToken) - { - if (exception != null) - { - var path = Path.Combine(context.FileOutput.TestClassOutputDirectory, context.FileOutput.GetUniqueFileName(context.FileOutput.TestName, ".dmp")); - var process = Process.GetCurrentProcess(); - DumpCollector.Collect(process, path); - } - - return Task.CompletedTask; - } - } -} diff --git a/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.Windows.cs b/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.Windows.cs deleted file mode 100644 index 20395208d7..0000000000 --- a/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.Windows.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; -using Microsoft.Win32.SafeHandles; - -namespace Microsoft.Extensions.Logging.Testing -{ - public static partial class DumpCollector - { - private static class Windows - { - internal static void Collect(Process process, string outputFile) - { - // Open the file for writing - using (var stream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) - { - // Dump the process! - var exceptionInfo = new NativeMethods.MINIDUMP_EXCEPTION_INFORMATION(); - if (!NativeMethods.MiniDumpWriteDump(process.Handle, (uint)process.Id, stream.SafeFileHandle, NativeMethods.MINIDUMP_TYPE.MiniDumpWithFullMemory, ref exceptionInfo, IntPtr.Zero, IntPtr.Zero)) - { - var err = Marshal.GetHRForLastWin32Error(); - Marshal.ThrowExceptionForHR(err); - } - } - } - - private static class NativeMethods - { - [DllImport("Dbghelp.dll")] - public static extern bool MiniDumpWriteDump(IntPtr hProcess, uint ProcessId, SafeFileHandle hFile, MINIDUMP_TYPE DumpType, ref MINIDUMP_EXCEPTION_INFORMATION ExceptionParam, IntPtr UserStreamParam, IntPtr CallbackParam); - - [StructLayout(LayoutKind.Sequential, Pack = 4)] - public struct MINIDUMP_EXCEPTION_INFORMATION - { - public uint ThreadId; - public IntPtr ExceptionPointers; - public int ClientPointers; - } - - [Flags] - public enum MINIDUMP_TYPE : uint - { - MiniDumpNormal = 0, - MiniDumpWithDataSegs = 1 << 0, - MiniDumpWithFullMemory = 1 << 1, - MiniDumpWithHandleData = 1 << 2, - MiniDumpFilterMemory = 1 << 3, - MiniDumpScanMemory = 1 << 4, - MiniDumpWithUnloadedModules = 1 << 5, - MiniDumpWithIndirectlyReferencedMemory = 1 << 6, - MiniDumpFilterModulePaths = 1 << 7, - MiniDumpWithProcessThreadData = 1 << 8, - MiniDumpWithPrivateReadWriteMemory = 1 << 9, - MiniDumpWithoutOptionalData = 1 << 10, - MiniDumpWithFullMemoryInfo = 1 << 11, - MiniDumpWithThreadInfo = 1 << 12, - MiniDumpWithCodeSegs = 1 << 13, - MiniDumpWithoutAuxiliaryState = 1 << 14, - MiniDumpWithFullAuxiliaryState = 1 << 15, - MiniDumpWithPrivateWriteCopyMemory = 1 << 16, - MiniDumpIgnoreInaccessibleMemory = 1 << 17, - MiniDumpWithTokenInformation = 1 << 18, - MiniDumpWithModuleHeaders = 1 << 19, - MiniDumpFilterTriage = 1 << 20, - MiniDumpWithAvxXStateContext = 1 << 21, - MiniDumpWithIptTrace = 1 << 22, - MiniDumpValidTypeFlags = (-1) ^ ((~1) << 22) - } - } - } - } -} diff --git a/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.cs b/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.cs deleted file mode 100644 index d67e109b38..0000000000 --- a/src/Logging/Logging.Testing/src/DumpCollector/DumpCollector.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Microsoft.Extensions.Logging.Testing -{ - public static partial class DumpCollector - { - public static void Collect(Process process, string fileName) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - Windows.Collect(process, fileName); - } - // No implementations yet for macOS and Linux - } - } -} diff --git a/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs b/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs deleted file mode 100644 index 750f45cd91..0000000000 --- a/src/Logging/Logging.Testing/src/LoggedTest/ILoggedTest.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Reflection; -using Microsoft.AspNetCore.Testing; -using Xunit.Abstractions; - -namespace Microsoft.Extensions.Logging.Testing -{ - public interface ILoggedTest : IDisposable - { - ILogger Logger { get; } - - ILoggerFactory LoggerFactory { get; } - - ITestOutputHelper TestOutputHelper { get; } - - // For back compat - IDisposable StartLog(out ILoggerFactory loggerFactory, LogLevel minLogLevel, string testName); - - void Initialize(TestContext context, MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper); - } -} diff --git a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs deleted file mode 100644 index 169a94f59d..0000000000 --- a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTest.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Reflection; -using Microsoft.AspNetCore.Testing; -using Xunit.Abstractions; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTest : LoggedTestBase - { - // Obsolete but keeping for back compat - public LoggedTest(ITestOutputHelper output = null) : base (output) { } - - public ITestSink TestSink { get; set; } - - public override void Initialize(TestContext context, MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) - { - base.Initialize(context, methodInfo, testMethodArguments, testOutputHelper); - - TestSink = new TestSink(); - LoggerFactory.AddProvider(new TestLoggerProvider(TestSink)); - } - } -} diff --git a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs b/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs deleted file mode 100644 index 16dde9676c..0000000000 --- a/src/Logging/Logging.Testing/src/LoggedTest/LoggedTestBase.cs +++ /dev/null @@ -1,122 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.ExceptionServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Testing; -using Microsoft.Extensions.DependencyInjection; -using Serilog; -using Xunit.Abstractions; - -namespace Microsoft.Extensions.Logging.Testing -{ - public class LoggedTestBase : ILoggedTest, ITestMethodLifecycle - { - private ExceptionDispatchInfo _initializationException; - - private IDisposable _testLog; - - // Obsolete but keeping for back compat - public LoggedTestBase(ITestOutputHelper output = null) - { - TestOutputHelper = output; - } - - protected TestContext Context { get; private set; } - - // Internal for testing - internal string ResolvedTestClassName { get; set; } - - public string ResolvedLogOutputDirectory { get; set; } - - public string ResolvedTestMethodName { get; set; } - - public ILogger Logger { get; set; } - - public ILoggerFactory LoggerFactory { get; set; } - - public ITestOutputHelper TestOutputHelper { get; set; } - - public void AddTestLogging(IServiceCollection services) => services.AddSingleton(LoggerFactory); - - // For back compat - public IDisposable StartLog(out ILoggerFactory loggerFactory, [CallerMemberName] string testName = null) => StartLog(out loggerFactory, LogLevel.Debug, testName); - - // For back compat - public IDisposable StartLog(out ILoggerFactory loggerFactory, LogLevel minLogLevel, [CallerMemberName] string testName = null) - { - return AssemblyTestLog.ForAssembly(GetType().GetTypeInfo().Assembly).StartTestLog(TestOutputHelper, GetType().FullName, out loggerFactory, minLogLevel, testName); - } - - public virtual void Initialize(TestContext context, MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) - { - try - { - TestOutputHelper = testOutputHelper; - - var classType = GetType(); - var logLevelAttribute = methodInfo.GetCustomAttribute() - ?? methodInfo.DeclaringType.GetCustomAttribute() - ?? methodInfo.DeclaringType.Assembly.GetCustomAttribute(); - - // internal for testing - ResolvedTestClassName = context.FileOutput.TestClassName; - - _testLog = AssemblyTestLog - .ForAssembly(classType.GetTypeInfo().Assembly) - .StartTestLog( - TestOutputHelper, - context.FileOutput.TestClassName, - out var loggerFactory, - logLevelAttribute?.LogLevel ?? LogLevel.Debug, - out var resolvedTestName, - out var logDirectory, - context.FileOutput.TestName); - - ResolvedLogOutputDirectory = logDirectory; - ResolvedTestMethodName = resolvedTestName; - - LoggerFactory = loggerFactory; - Logger = loggerFactory.CreateLogger(classType); - } - catch (Exception e) - { - _initializationException = ExceptionDispatchInfo.Capture(e); - } - } - - public virtual void Dispose() - { - if (_testLog == null) - { - // It seems like sometimes the MSBuild goop that adds the test framework can end up in a bad state and not actually add it - // Not sure yet why that happens but the exception isn't clear so I'm adding this error so we can detect it better. - // -anurse - throw new InvalidOperationException("LoggedTest base class was used but nothing initialized it! The test framework may not be enabled. Try cleaning your 'obj' directory."); - } - - _initializationException?.Throw(); - _testLog.Dispose(); - } - - Task ITestMethodLifecycle.OnTestStartAsync(TestContext context, CancellationToken cancellationToken) - { - - Context = context; - - Initialize(context, context.TestMethod, context.MethodArguments, context.Output); - return Task.CompletedTask; - } - - Task ITestMethodLifecycle.OnTestEndAsync(TestContext context, Exception exception, CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - } -} diff --git a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj index 0c07c01c10..457843ba64 100644 --- a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj +++ b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj @@ -18,12 +18,9 @@ - - - - $(RepositoryRoot) - $(ASPNETCORE_TEST_LOG_DIR) - $(RepoRoot)artifacts\log\ - - - - - true - false - - - - - <_Parameter1>Microsoft.AspNetCore.Testing.AspNetTestFramework - <_Parameter2>Microsoft.AspNetCore.Testing - - - - <_Parameter1>$(PreserveExistingLogsInOutput) - <_Parameter2>$(TargetFramework) - <_Parameter3 Condition="'$(LoggingTestingDisableFileLogging)' != 'true'">$(LoggingTestingFileLoggingDirectory) - - - - diff --git a/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs b/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs deleted file mode 100644 index 27a7cf83cf..0000000000 --- a/src/Logging/Logging.Testing/test/AssemblyTestLogTests.cs +++ /dev/null @@ -1,221 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Testing; -using Xunit; - -namespace Microsoft.Extensions.Logging.Testing.Tests -{ - public class AssemblyTestLogTests : LoggedTest - { - private static readonly Assembly ThisAssembly = typeof(AssemblyTestLogTests).GetTypeInfo().Assembly; - private static readonly string ThisAssemblyName = ThisAssembly.GetName().Name; - private static readonly string TFM = new DirectoryInfo(AppContext.BaseDirectory).Name; - - [Fact] - public void FunctionalLogs_LogsPreservedFromNonFlakyRun() - { - } - - [Fact] - [Flaky("http://example.com", FlakyOn.All)] - public void FunctionalLogs_LogsPreservedFromFlakyRun() - { - } - - [Fact] - public void ForAssembly_ReturnsSameInstanceForSameAssembly() - { - Assert.Same( - AssemblyTestLog.ForAssembly(ThisAssembly), - AssemblyTestLog.ForAssembly(ThisAssembly)); - } - - [Fact] - public void TestLogWritesToITestOutputHelper() - { - var output = new TestTestOutputHelper(); - var assemblyLog = AssemblyTestLog.Create(ThisAssemblyName, baseDirectory: null); - - using (assemblyLog.StartTestLog(output, "NonExistant.Test.Class", out var loggerFactory)) - { - var logger = loggerFactory.CreateLogger("TestLogger"); - logger.LogInformation("Information!"); - - // Trace is disabled by default - logger.LogTrace("Trace!"); - } - - var testLogContent = MakeConsistent(output.Output); - - Assert.Equal( -@"[OFFSET] TestLifetime Information: Starting test TestLogWritesToITestOutputHelper at TIMESTAMP -[OFFSET] TestLogger Information: Information! -[OFFSET] TestLifetime Information: Finished test TestLogWritesToITestOutputHelper in DURATION -", testLogContent, ignoreLineEndingDifferences: true); - } - - [Fact] - public Task TestLogEscapesIllegalFileNames() => - RunTestLogFunctionalTest((tempDir) => - { - var illegalTestName = "T:e/s//t"; - var escapedTestName = "T_e_s_t"; - using (var testAssemblyLog = AssemblyTestLog.Create(ThisAssemblyName, baseDirectory: tempDir)) - using (testAssemblyLog.StartTestLog(output: null, className: "FakeTestAssembly.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, resolvedTestName: out var resolvedTestname, out var _, testName: illegalTestName)) - { - Assert.Equal(escapedTestName, resolvedTestname); - } - }); - - [Fact] - public Task TestLogWritesToGlobalLogFile() => - RunTestLogFunctionalTest((tempDir) => - { - // Because this test writes to a file, it is a functional test and should be logged - // but it's also testing the test logging facility. So this is pretty meta ;) - var logger = LoggerFactory.CreateLogger("Test"); - - using (var testAssemblyLog = AssemblyTestLog.Create(ThisAssemblyName, tempDir)) - { - logger.LogInformation("Created test log in {baseDirectory}", tempDir); - - using (testAssemblyLog.StartTestLog(output: null, className: $"{ThisAssemblyName}.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, testName: "FakeTestName")) - { - var testLogger = testLoggerFactory.CreateLogger("TestLogger"); - testLogger.LogInformation("Information!"); - testLogger.LogTrace("Trace!"); - } - } - - logger.LogInformation("Finished test log in {baseDirectory}", tempDir); - - var globalLogPath = Path.Combine(tempDir, ThisAssemblyName, TFM, "global.log"); - var testLog = Path.Combine(tempDir, ThisAssemblyName, TFM, "FakeTestClass", "FakeTestName.log"); - - Assert.True(File.Exists(globalLogPath), $"Expected global log file {globalLogPath} to exist"); - Assert.True(File.Exists(testLog), $"Expected test log file {testLog} to exist"); - - var globalLogContent = MakeConsistent(File.ReadAllText(globalLogPath)); - var testLogContent = MakeConsistent(File.ReadAllText(testLog)); - - Assert.Equal( -@"[OFFSET] [GlobalTestLog] [Information] Global Test Logging initialized at TIMESTAMP. Configure the output directory via 'LoggingTestingFileLoggingDirectory' MSBuild property or set 'LoggingTestingDisableFileLogging' to 'true' to disable file logging. -[OFFSET] [GlobalTestLog] [Information] Starting test FakeTestName -[OFFSET] [GlobalTestLog] [Information] Finished test FakeTestName in DURATION -", globalLogContent, ignoreLineEndingDifferences: true); - Assert.Equal( -@"[OFFSET] [TestLifetime] [Information] Starting test FakeTestName at TIMESTAMP -[OFFSET] [TestLogger] [Information] Information! -[OFFSET] [TestLogger] [Verbose] Trace! -[OFFSET] [TestLifetime] [Information] Finished test FakeTestName in DURATION -", testLogContent, ignoreLineEndingDifferences: true); - }); - - [Fact] - public Task TestLogTruncatesTestNameToAvoidLongPaths() => - RunTestLogFunctionalTest((tempDir) => - { - var longTestName = new string('0', 50) + new string('1', 50) + new string('2', 50) + new string('3', 50) + new string('4', 50); - var logger = LoggerFactory.CreateLogger("Test"); - using (var testAssemblyLog = AssemblyTestLog.Create(ThisAssemblyName, tempDir)) - { - logger.LogInformation("Created test log in {baseDirectory}", tempDir); - - using (testAssemblyLog.StartTestLog(output: null, className: $"{ThisAssemblyName}.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, testName: longTestName)) - { - testLoggerFactory.CreateLogger("TestLogger").LogInformation("Information!"); - } - } - logger.LogInformation("Finished test log in {baseDirectory}", tempDir); - - var testLogFiles = new DirectoryInfo(Path.Combine(tempDir, ThisAssemblyName, TFM, "FakeTestClass")).EnumerateFiles(); - var testLog = Assert.Single(testLogFiles); - var testFileName = Path.GetFileNameWithoutExtension(testLog.Name); - - // The first half of the file comes from the beginning of the test name passed to the logger - Assert.Equal(longTestName.Substring(0, testFileName.Length / 2), testFileName.Substring(0, testFileName.Length / 2)); - // The last half of the file comes from the ending of the test name passed to the logger - Assert.Equal(longTestName.Substring(longTestName.Length - testFileName.Length / 2, testFileName.Length / 2), testFileName.Substring(testFileName.Length - testFileName.Length / 2, testFileName.Length / 2)); - }); - - [Fact] - public Task TestLogEnumerateFilenamesToAvoidCollisions() => - RunTestLogFunctionalTest((tempDir) => - { - var logger = LoggerFactory.CreateLogger("Test"); - using (var testAssemblyLog = AssemblyTestLog.Create(ThisAssemblyName, tempDir)) - { - logger.LogInformation("Created test log in {baseDirectory}", tempDir); - - for (var i = 0; i < 10; i++) - { - using (testAssemblyLog.StartTestLog(output: null, className: $"{ThisAssemblyName}.FakeTestClass", loggerFactory: out var testLoggerFactory, minLogLevel: LogLevel.Trace, testName: "FakeTestName")) - { - testLoggerFactory.CreateLogger("TestLogger").LogInformation("Information!"); - } - } - } - logger.LogInformation("Finished test log in {baseDirectory}", tempDir); - - // The first log file exists - Assert.True(File.Exists(Path.Combine(tempDir, ThisAssemblyName, TFM, "FakeTestClass", "FakeTestName.log"))); - - // Subsequent files exist - for (var i = 0; i < 9; i++) - { - Assert.True(File.Exists(Path.Combine(tempDir, ThisAssemblyName, TFM, "FakeTestClass", $"FakeTestName.{i}.log"))); - } - }); - - private static readonly Regex TimestampRegex = new Regex(@"\d+-\d+-\d+T\d+:\d+:\d+"); - private static readonly Regex TimestampOffsetRegex = new Regex(@"\d+\.\d+s"); - private static readonly Regex DurationRegex = new Regex(@"[^ ]+s$"); - - private async Task RunTestLogFunctionalTest(Action action, [CallerMemberName] string testName = null) - { - var tempDir = Path.Combine(Path.GetTempPath(), $"TestLogging_{Guid.NewGuid().ToString("N")}"); - try - { - action(tempDir); - } - finally - { - if (Directory.Exists(tempDir)) - { - try - { - Directory.Delete(tempDir, recursive: true); - } - catch - { - await Task.Delay(100); - Directory.Delete(tempDir, recursive: true); - } - } - } - } - - private static string MakeConsistent(string input) - { - return string.Join(Environment.NewLine, input.Split(new[] { Environment.NewLine }, StringSplitOptions.None) - .Select(line => - { - var strippedPrefix = line.IndexOf("[") >= 0 ? line.Substring(line.IndexOf("[")) : line; - - var strippedDuration = DurationRegex.Replace(strippedPrefix, "DURATION"); - var strippedTimestamp = TimestampRegex.Replace(strippedDuration, "TIMESTAMP"); - var strippedTimestampOffset = TimestampOffsetRegex.Replace(strippedTimestamp, "OFFSET"); - return strippedTimestampOffset; - })); - } - } -} diff --git a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs b/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs deleted file mode 100644 index 61d7802508..0000000000 --- a/src/Logging/Logging.Testing/test/LoggedTestXunitTests.cs +++ /dev/null @@ -1,193 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Linq; -using System.Reflection; -using Microsoft.AspNetCore.Testing; -using Microsoft.Extensions.DependencyInjection; -using Xunit; -using Xunit.Abstractions; - -namespace Microsoft.Extensions.Logging.Testing.Tests -{ - [LogLevel(LogLevel.Debug)] - [ShortClassName] - public class LoggedTestXunitTests : TestLoggedTest - { - private readonly ITestOutputHelper _output; - - public LoggedTestXunitTests(ITestOutputHelper output) - { - _output = output; - } - - [Fact] - public void LoggedFactInitializesLoggedTestProperties() - { - Assert.NotNull(Logger); - Assert.NotNull(LoggerFactory); - Assert.NotNull(TestSink); - Assert.NotNull(TestOutputHelper); - } - - [Theory] - [InlineData("Hello world")] - public void LoggedTheoryInitializesLoggedTestProperties(string argument) - { - Assert.NotNull(Logger); - Assert.NotNull(LoggerFactory); - Assert.NotNull(TestSink); - Assert.NotNull(TestOutputHelper); - // Use the test argument - Assert.NotNull(argument); - } - - [ConditionalFact] - public void ConditionalLoggedFactGetsInitializedLoggerFactory() - { - Assert.NotNull(Logger); - Assert.NotNull(LoggerFactory); - Assert.NotNull(TestSink); - Assert.NotNull(TestOutputHelper); - } - - [ConditionalTheory] - [InlineData("Hello world")] - public void LoggedConditionalTheoryInitializesLoggedTestProperties(string argument) - { - Assert.NotNull(Logger); - Assert.NotNull(LoggerFactory); - Assert.NotNull(TestSink); - Assert.NotNull(TestOutputHelper); - // Use the test argument - Assert.NotNull(argument); - } - - [Fact] - [LogLevel(LogLevel.Information)] - public void LoggedFactFilteredByMethodLogLevel() - { - Logger.LogInformation("Information"); - Logger.LogDebug("Debug"); - - var message = Assert.Single(TestSink.Writes); - Assert.Equal(LogLevel.Information, message.LogLevel); - 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)] - public void LoggedTheoryFilteredByLogLevel(string argument) - { - Logger.LogInformation("Information"); - Logger.LogDebug("Debug"); - - var message = Assert.Single(TestSink.Writes); - Assert.Equal(LogLevel.Information, message.LogLevel); - Assert.Equal("Information", message.Formatter(message.State, null)); - - // Use the test argument - Assert.NotNull(argument); - } - - [Fact] - public void AddTestLoggingUpdatedWhenLoggerFactoryIsSet() - { - var loggerFactory = new LoggerFactory(); - var serviceCollection = new ServiceCollection(); - - LoggerFactory = loggerFactory; - AddTestLogging(serviceCollection); - - Assert.Same(loggerFactory, serviceCollection.BuildServiceProvider().GetRequiredService()); - } - - [ConditionalTheory] - [EnvironmentVariableSkipCondition("ASPNETCORE_TEST_LOG_DIR", "")] // The test name is only generated when logging is enabled via the environment variable - [InlineData(null)] - public void LoggedTheoryNullArgumentsAreEscaped(string argument) - { - Assert.NotNull(LoggerFactory); - Assert.Equal($"{nameof(LoggedTheoryNullArgumentsAreEscaped)}_null", ResolvedTestMethodName); - // Use the test argument - Assert.Null(argument); - } - - [Fact] - public void AdditionalSetupInvoked() - { - 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 - { - [Fact] - public void ITestOutputHelperInitializedByDefault() - { - Assert.True(ITestOutputHelperIsInitialized); - } - } - - public class TestLoggedTest : LoggedTest - { - public bool SetupInvoked { get; private set; } = false; - public bool ITestOutputHelperIsInitialized { get; private set; } = false; - - public override void Initialize(TestContext context, MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) - { - base.Initialize(context, methodInfo, testMethodArguments, testOutputHelper); - - try - { - TestOutputHelper.WriteLine("Test"); - ITestOutputHelperIsInitialized = true; - } catch { } - SetupInvoked = true; - } - } -} diff --git a/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj b/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj index 7b478d5ce9..4ec80710b7 100644 --- a/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj +++ b/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj @@ -1,6 +1,4 @@  - - $(DefaultNetCoreTargetFramework);net472 From 4294861945ca307a5ef622f279a01ffa5f7766ba Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 1 Apr 2020 12:02:53 -0700 Subject: [PATCH 41/44] Migration cleanup --- eng/Build.props | 1 + eng/Dependencies.props | 2 - eng/ProjectReferences.props | 2 + eng/Version.Details.xml | 8 --- eng/Versions.props | 2 - ...Extensions.Logging.AzureAppServices.csproj | 15 ------ ...Logging.AzureAppServices.netstandard2.0.cs | 54 ------------------- ...icrosoft.Extensions.Logging.Testing.csproj | 4 +- 8 files changed, 4 insertions(+), 84 deletions(-) delete mode 100644 src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.csproj delete mode 100644 src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs diff --git a/eng/Build.props b/eng/Build.props index 6f1b3f1908..8eb31fb823 100644 --- a/eng/Build.props +++ b/eng/Build.props @@ -191,6 +191,7 @@ $(RepoRoot)src\Security\**\src\*.csproj; $(RepoRoot)src\SiteExtensions\**\src\*.csproj; $(RepoRoot)src\Tools\**\src\*.csproj; + $(RepoRoot)src\Logging\**\src\*.csproj; $(RepoRoot)src\Middleware\**\src\*.csproj; $(RepoRoot)src\Razor\**\src\*.csproj; $(RepoRoot)src\Mvc\**\src\*.csproj; diff --git a/eng/Dependencies.props b/eng/Dependencies.props index d02e5158ae..6635f7f4e7 100644 --- a/eng/Dependencies.props +++ b/eng/Dependencies.props @@ -120,8 +120,6 @@ and are generated based on the last package release. - - diff --git a/eng/ProjectReferences.props b/eng/ProjectReferences.props index dda9b06ce8..3f63f1a68a 100644 --- a/eng/ProjectReferences.props +++ b/eng/ProjectReferences.props @@ -32,6 +32,8 @@ + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 54c6b6f9fb..85f8f0dab9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -161,10 +161,6 @@ https://github.com/dotnet/extensions 050d3aea0c8b18579c426d7ff2cb196953540327 - - https://github.com/dotnet/extensions - 050d3aea0c8b18579c426d7ff2cb196953540327 - https://github.com/dotnet/extensions 050d3aea0c8b18579c426d7ff2cb196953540327 @@ -189,10 +185,6 @@ https://github.com/dotnet/extensions 050d3aea0c8b18579c426d7ff2cb196953540327 - - https://github.com/dotnet/extensions - 050d3aea0c8b18579c426d7ff2cb196953540327 - https://github.com/dotnet/extensions 050d3aea0c8b18579c426d7ff2cb196953540327 diff --git a/eng/Versions.props b/eng/Versions.props index cb0ea3d54a..8236a7f114 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -123,14 +123,12 @@ 5.0.0-preview.4.20201.1 5.0.0-preview.4.20201.1 5.0.0-preview.4.20201.1 - 5.0.0-preview.4.20201.1 5.0.0-preview.4.20201.1 5.0.0-preview.4.20201.1 5.0.0-preview.4.20201.1 5.0.0-preview.4.20201.1 5.0.0-preview.4.20201.1 5.0.0-preview.4.20201.1 - 5.0.0-preview.4.20201.1 5.0.0-preview.4.20201.1 5.0.0-preview.4.20201.1 5.0.0-preview.4.20201.1 diff --git a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.csproj b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.csproj deleted file mode 100644 index 0132b21870..0000000000 --- a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netstandard2.0 - - - - - - - - - - - diff --git a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs b/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs deleted file mode 100644 index 9b8f637cff..0000000000 --- a/src/Logging/Logging.AzureAppServices/ref/Microsoft.Extensions.Logging.AzureAppServices.netstandard2.0.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Extensions.Logging -{ - public static partial class AzureAppServicesLoggerFactoryExtensions - { - public static Microsoft.Extensions.Logging.ILoggingBuilder AddAzureWebAppDiagnostics(this Microsoft.Extensions.Logging.ILoggingBuilder builder) { throw null; } - } -} -namespace Microsoft.Extensions.Logging.AzureAppServices -{ - public partial class AzureBlobLoggerOptions : Microsoft.Extensions.Logging.AzureAppServices.BatchingLoggerOptions - { - public AzureBlobLoggerOptions() { } - public string BlobName { get { throw null; } set { } } - } - public partial class AzureFileLoggerOptions : Microsoft.Extensions.Logging.AzureAppServices.BatchingLoggerOptions - { - public AzureFileLoggerOptions() { } - public string FileName { get { throw null; } set { } } - public int? FileSizeLimit { get { throw null; } set { } } - public int? RetainedFileCountLimit { get { throw null; } set { } } - } - public partial class BatchingLoggerOptions - { - public BatchingLoggerOptions() { } - public int? BackgroundQueueSize { get { throw null; } set { } } - public int? BatchSize { get { throw null; } set { } } - public System.TimeSpan FlushPeriod { get { throw null; } set { } } - public bool IncludeScopes { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public bool IsEnabled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - } - public abstract partial class BatchingLoggerProvider : Microsoft.Extensions.Logging.ILoggerProvider, Microsoft.Extensions.Logging.ISupportExternalScope, System.IDisposable - { - internal BatchingLoggerProvider() { } - public bool IsEnabled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) { throw null; } - public void Dispose() { } - protected virtual System.Threading.Tasks.Task IntervalAsync(System.TimeSpan interval, System.Threading.CancellationToken cancellationToken) { throw null; } - void Microsoft.Extensions.Logging.ISupportExternalScope.SetScopeProvider(Microsoft.Extensions.Logging.IExternalScopeProvider scopeProvider) { } - } - [Microsoft.Extensions.Logging.ProviderAliasAttribute("AzureAppServicesBlob")] - public partial class BlobLoggerProvider : Microsoft.Extensions.Logging.AzureAppServices.BatchingLoggerProvider - { - public BlobLoggerProvider(Microsoft.Extensions.Options.IOptionsMonitor options) { } - } - [Microsoft.Extensions.Logging.ProviderAliasAttribute("AzureAppServicesFile")] - public partial class FileLoggerProvider : Microsoft.Extensions.Logging.AzureAppServices.BatchingLoggerProvider - { - public FileLoggerProvider(Microsoft.Extensions.Options.IOptionsMonitor options) { } - } -} diff --git a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj index 457843ba64..eabb677844 100644 --- a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj +++ b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj @@ -2,13 +2,11 @@ Helpers for writing tests that use Microsoft.Extensions.Logging. Contains null implementations of the abstractions that do nothing, as well as test implementations that are observable. - netstandard2.0;net461 + netstandard2.0;net472 $(NoWarn);CS1591 $(PackageTags);testing false - - true false true From 36dcebbc234ed3a3e0d83ea599b313c5d591a1c9 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 1 Apr 2020 21:21:55 -0700 Subject: [PATCH 42/44] Update Build.props --- eng/Build.props | 1 + 1 file changed, 1 insertion(+) diff --git a/eng/Build.props b/eng/Build.props index 8eb31fb823..c28b3bc1e9 100644 --- a/eng/Build.props +++ b/eng/Build.props @@ -152,6 +152,7 @@ $(RepoRoot)src\SiteExtensions\LoggingAggregate\test\**\*.csproj; $(RepoRoot)src\Shared\**\*.*proj; $(RepoRoot)src\Tools\**\*.*proj; + $(RepoRoot)src\Logging\**\src\*.csproj; $(RepoRoot)src\Middleware\**\*.csproj; $(RepoRoot)src\Razor\**\*.*proj; $(RepoRoot)src\Mvc\**\*.*proj; From fcb23108b661aa95347047295563b3b80e2712eb Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 2 Apr 2020 00:15:24 -0700 Subject: [PATCH 43/44] Relocate Logging.Testing to AspNetCore.Testing --- eng/Build.props | 4 +- eng/ProjectReferences.props | 3 +- .../TestServer/Components.TestServer.csproj | 2 +- ...spNetCore.Server.IntegrationTesting.csproj | 1 - .../Directory.Build.props | 0 ...AzureAppServicesLoggerFactoryExtensions.cs | 0 .../src/AzureBlobLoggerOptions.cs | 0 .../src/AzureFileLoggerOptions.cs | 0 .../src/BatchLoggerConfigureOptions.cs | 0 .../src/BatchingLogger.cs | 0 .../src/BatchingLoggerOptions.cs | 0 .../src/BatchingLoggerProvider.cs | 0 .../src/BlobAppendReferenceWrapper.cs | 0 .../src/BlobLoggerConfigureOptions.cs | 0 .../src/BlobLoggerProvider.cs | 0 .../src/ConfigurationBasedLevelSwitcher.cs | 0 .../src/FileLoggerConfigureOptions.cs | 0 .../src/FileLoggerProvider.cs | 0 .../src/ICloudAppendBlob.cs | 0 .../src/IWebAppContext.cs | 0 .../src/LogMessage.cs | 0 ...Extensions.Logging.AzureAppServices.csproj | 0 .../src/Properties/AssemblyInfo.cs | 0 .../src/SiteConfigurationProvider.cs | 0 .../src/WebAppContext.cs | 0 .../test/AzureAppendBlobTests.cs | 0 .../test/AzureBlobSinkTests.cs | 0 ...reDiagnosticsConfigurationProviderTests.cs | 0 .../test/BatchingLoggerProviderTests.cs | 0 .../test/ConfigureOptionsTests.cs | 0 .../test/FileLoggerTests.cs | 0 .../test/LoggerBuilderExtensionsTests.cs | 0 .../test/ManualIntervalControl.cs | 0 ...ions.Logging.AzureAppServices.Tests.csproj | 0 .../test/OptionsWrapperMonitor.cs | 0 .../test/TestBlobSink.cs | 0 .../test/TestFileLoggerProvider.cs | 0 .../test/WebConfigurationLevelSwitchTests.cs | 0 ...icrosoft.Extensions.Logging.Testing.csproj | 36 ------------------ ...ft.Extensions.Logging.Testing.Tests.csproj | 15 -------- .../test/Properties/AssemblyInfo.cs | 8 ---- .../test/TestTestOutputHelper.cs | 37 ------------------- .../IIS.Common.TestLib.csproj | 2 +- src/Servers/Kestrel/Directory.Build.props | 2 - src/SignalR/Directory.Build.props | 1 - ...soft.AspNetCore.SignalR.Tests.Utils.csproj | 1 - .../src/Logging}/BeginScopeContext.cs | 0 .../src => Testing/src/Logging}/ITestSink.cs | 0 .../src/Logging}/LogLevelAttribute.cs | 0 .../src/Logging}/LogValuesAssert.cs | 0 .../src => Testing/src/Logging}/TestLogger.cs | 0 .../src/Logging}/TestLoggerFactory.cs | 0 .../src/Logging}/TestLoggerProvider.cs | 0 .../src/Logging}/TestLoggerT.cs | 0 .../src => Testing/src/Logging}/TestSink.cs | 0 .../src/Logging}/WriteContext.cs | 0 .../Logging}/XunitLoggerFactoryExtensions.cs | 0 .../src/Logging}/XunitLoggerProvider.cs | 0 .../src/Microsoft.AspNetCore.Testing.csproj | 4 +- .../test/LogValuesAssertTest.cs | 0 .../test/XunitLoggerProviderTest.cs | 18 ++++++--- 61 files changed, 21 insertions(+), 113 deletions(-) rename src/{Logging => }/Logging.AzureAppServices/Directory.Build.props (100%) rename src/{Logging => }/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/BatchLoggerConfigureOptions.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/BatchingLogger.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/BatchingLoggerOptions.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/BatchingLoggerProvider.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/BlobLoggerConfigureOptions.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/BlobLoggerProvider.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/ConfigurationBasedLevelSwitcher.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/FileLoggerConfigureOptions.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/FileLoggerProvider.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/ICloudAppendBlob.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/IWebAppContext.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/LogMessage.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj (100%) rename src/{Logging => }/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/SiteConfigurationProvider.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/src/WebAppContext.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/test/AzureAppendBlobTests.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/test/AzureBlobSinkTests.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/test/ConfigureOptionsTests.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/test/FileLoggerTests.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/test/ManualIntervalControl.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj (100%) rename src/{Logging => }/Logging.AzureAppServices/test/OptionsWrapperMonitor.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/test/TestBlobSink.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/test/TestFileLoggerProvider.cs (100%) rename src/{Logging => }/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs (100%) delete mode 100644 src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj delete mode 100644 src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj delete mode 100644 src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs delete mode 100644 src/Logging/Logging.Testing/test/TestTestOutputHelper.cs rename src/{Logging/Logging.Testing/src => Testing/src/Logging}/BeginScopeContext.cs (100%) rename src/{Logging/Logging.Testing/src => Testing/src/Logging}/ITestSink.cs (100%) rename src/{Logging/Logging.Testing/src => Testing/src/Logging}/LogLevelAttribute.cs (100%) rename src/{Logging/Logging.Testing/src => Testing/src/Logging}/LogValuesAssert.cs (100%) rename src/{Logging/Logging.Testing/src => Testing/src/Logging}/TestLogger.cs (100%) rename src/{Logging/Logging.Testing/src => Testing/src/Logging}/TestLoggerFactory.cs (100%) rename src/{Logging/Logging.Testing/src => Testing/src/Logging}/TestLoggerProvider.cs (100%) rename src/{Logging/Logging.Testing/src => Testing/src/Logging}/TestLoggerT.cs (100%) rename src/{Logging/Logging.Testing/src => Testing/src/Logging}/TestSink.cs (100%) rename src/{Logging/Logging.Testing/src => Testing/src/Logging}/WriteContext.cs (100%) rename src/{Logging/Logging.Testing/src => Testing/src/Logging}/XunitLoggerFactoryExtensions.cs (100%) rename src/{Logging/Logging.Testing/src => Testing/src/Logging}/XunitLoggerProvider.cs (100%) rename src/{Logging/Logging.Testing => Testing}/test/LogValuesAssertTest.cs (100%) rename src/{Logging/Logging.Testing => Testing}/test/XunitLoggerProviderTest.cs (85%) diff --git a/eng/Build.props b/eng/Build.props index c28b3bc1e9..ef89408b47 100644 --- a/eng/Build.props +++ b/eng/Build.props @@ -152,7 +152,7 @@ $(RepoRoot)src\SiteExtensions\LoggingAggregate\test\**\*.csproj; $(RepoRoot)src\Shared\**\*.*proj; $(RepoRoot)src\Tools\**\*.*proj; - $(RepoRoot)src\Logging\**\src\*.csproj; + $(RepoRoot)src\Logging.AzureAppServices\**\src\*.csproj; $(RepoRoot)src\Middleware\**\*.csproj; $(RepoRoot)src\Razor\**\*.*proj; $(RepoRoot)src\Mvc\**\*.*proj; @@ -192,7 +192,7 @@ $(RepoRoot)src\Security\**\src\*.csproj; $(RepoRoot)src\SiteExtensions\**\src\*.csproj; $(RepoRoot)src\Tools\**\src\*.csproj; - $(RepoRoot)src\Logging\**\src\*.csproj; + $(RepoRoot)src\Logging.AzureAppServices\**\src\*.csproj; $(RepoRoot)src\Middleware\**\src\*.csproj; $(RepoRoot)src\Razor\**\src\*.csproj; $(RepoRoot)src\Mvc\**\src\*.csproj; diff --git a/eng/ProjectReferences.props b/eng/ProjectReferences.props index 3f63f1a68a..a7d42c3782 100644 --- a/eng/ProjectReferences.props +++ b/eng/ProjectReferences.props @@ -32,8 +32,7 @@ - - + diff --git a/src/Components/test/testassets/TestServer/Components.TestServer.csproj b/src/Components/test/testassets/TestServer/Components.TestServer.csproj index 4eebc1f24b..d51a812210 100644 --- a/src/Components/test/testassets/TestServer/Components.TestServer.csproj +++ b/src/Components/test/testassets/TestServer/Components.TestServer.csproj @@ -14,8 +14,8 @@ + - diff --git a/src/Hosting/Server.IntegrationTesting/src/Microsoft.AspNetCore.Server.IntegrationTesting.csproj b/src/Hosting/Server.IntegrationTesting/src/Microsoft.AspNetCore.Server.IntegrationTesting.csproj index ba625f4332..939dfcf376 100644 --- a/src/Hosting/Server.IntegrationTesting/src/Microsoft.AspNetCore.Server.IntegrationTesting.csproj +++ b/src/Hosting/Server.IntegrationTesting/src/Microsoft.AspNetCore.Server.IntegrationTesting.csproj @@ -23,7 +23,6 @@ - diff --git a/src/Logging/Logging.AzureAppServices/Directory.Build.props b/src/Logging.AzureAppServices/Directory.Build.props similarity index 100% rename from src/Logging/Logging.AzureAppServices/Directory.Build.props rename to src/Logging.AzureAppServices/Directory.Build.props diff --git a/src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs b/src/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs rename to src/Logging.AzureAppServices/src/AzureAppServicesLoggerFactoryExtensions.cs diff --git a/src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs b/src/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs rename to src/Logging.AzureAppServices/src/AzureBlobLoggerOptions.cs diff --git a/src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs b/src/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs rename to src/Logging.AzureAppServices/src/AzureFileLoggerOptions.cs diff --git a/src/Logging/Logging.AzureAppServices/src/BatchLoggerConfigureOptions.cs b/src/Logging.AzureAppServices/src/BatchLoggerConfigureOptions.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/BatchLoggerConfigureOptions.cs rename to src/Logging.AzureAppServices/src/BatchLoggerConfigureOptions.cs diff --git a/src/Logging/Logging.AzureAppServices/src/BatchingLogger.cs b/src/Logging.AzureAppServices/src/BatchingLogger.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/BatchingLogger.cs rename to src/Logging.AzureAppServices/src/BatchingLogger.cs diff --git a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerOptions.cs b/src/Logging.AzureAppServices/src/BatchingLoggerOptions.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/BatchingLoggerOptions.cs rename to src/Logging.AzureAppServices/src/BatchingLoggerOptions.cs diff --git a/src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs b/src/Logging.AzureAppServices/src/BatchingLoggerProvider.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/BatchingLoggerProvider.cs rename to src/Logging.AzureAppServices/src/BatchingLoggerProvider.cs diff --git a/src/Logging/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs b/src/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs rename to src/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs diff --git a/src/Logging/Logging.AzureAppServices/src/BlobLoggerConfigureOptions.cs b/src/Logging.AzureAppServices/src/BlobLoggerConfigureOptions.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/BlobLoggerConfigureOptions.cs rename to src/Logging.AzureAppServices/src/BlobLoggerConfigureOptions.cs diff --git a/src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs b/src/Logging.AzureAppServices/src/BlobLoggerProvider.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/BlobLoggerProvider.cs rename to src/Logging.AzureAppServices/src/BlobLoggerProvider.cs diff --git a/src/Logging/Logging.AzureAppServices/src/ConfigurationBasedLevelSwitcher.cs b/src/Logging.AzureAppServices/src/ConfigurationBasedLevelSwitcher.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/ConfigurationBasedLevelSwitcher.cs rename to src/Logging.AzureAppServices/src/ConfigurationBasedLevelSwitcher.cs diff --git a/src/Logging/Logging.AzureAppServices/src/FileLoggerConfigureOptions.cs b/src/Logging.AzureAppServices/src/FileLoggerConfigureOptions.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/FileLoggerConfigureOptions.cs rename to src/Logging.AzureAppServices/src/FileLoggerConfigureOptions.cs diff --git a/src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs b/src/Logging.AzureAppServices/src/FileLoggerProvider.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/FileLoggerProvider.cs rename to src/Logging.AzureAppServices/src/FileLoggerProvider.cs diff --git a/src/Logging/Logging.AzureAppServices/src/ICloudAppendBlob.cs b/src/Logging.AzureAppServices/src/ICloudAppendBlob.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/ICloudAppendBlob.cs rename to src/Logging.AzureAppServices/src/ICloudAppendBlob.cs diff --git a/src/Logging/Logging.AzureAppServices/src/IWebAppContext.cs b/src/Logging.AzureAppServices/src/IWebAppContext.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/IWebAppContext.cs rename to src/Logging.AzureAppServices/src/IWebAppContext.cs diff --git a/src/Logging/Logging.AzureAppServices/src/LogMessage.cs b/src/Logging.AzureAppServices/src/LogMessage.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/LogMessage.cs rename to src/Logging.AzureAppServices/src/LogMessage.cs diff --git a/src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj b/src/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj rename to src/Logging.AzureAppServices/src/Microsoft.Extensions.Logging.AzureAppServices.csproj diff --git a/src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs b/src/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs rename to src/Logging.AzureAppServices/src/Properties/AssemblyInfo.cs diff --git a/src/Logging/Logging.AzureAppServices/src/SiteConfigurationProvider.cs b/src/Logging.AzureAppServices/src/SiteConfigurationProvider.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/SiteConfigurationProvider.cs rename to src/Logging.AzureAppServices/src/SiteConfigurationProvider.cs diff --git a/src/Logging/Logging.AzureAppServices/src/WebAppContext.cs b/src/Logging.AzureAppServices/src/WebAppContext.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/src/WebAppContext.cs rename to src/Logging.AzureAppServices/src/WebAppContext.cs diff --git a/src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs b/src/Logging.AzureAppServices/test/AzureAppendBlobTests.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/test/AzureAppendBlobTests.cs rename to src/Logging.AzureAppServices/test/AzureAppendBlobTests.cs diff --git a/src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs b/src/Logging.AzureAppServices/test/AzureBlobSinkTests.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/test/AzureBlobSinkTests.cs rename to src/Logging.AzureAppServices/test/AzureBlobSinkTests.cs diff --git a/src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs b/src/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs rename to src/Logging.AzureAppServices/test/AzureDiagnosticsConfigurationProviderTests.cs diff --git a/src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs b/src/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs rename to src/Logging.AzureAppServices/test/BatchingLoggerProviderTests.cs diff --git a/src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs b/src/Logging.AzureAppServices/test/ConfigureOptionsTests.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/test/ConfigureOptionsTests.cs rename to src/Logging.AzureAppServices/test/ConfigureOptionsTests.cs diff --git a/src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs b/src/Logging.AzureAppServices/test/FileLoggerTests.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/test/FileLoggerTests.cs rename to src/Logging.AzureAppServices/test/FileLoggerTests.cs diff --git a/src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs b/src/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs rename to src/Logging.AzureAppServices/test/LoggerBuilderExtensionsTests.cs diff --git a/src/Logging/Logging.AzureAppServices/test/ManualIntervalControl.cs b/src/Logging.AzureAppServices/test/ManualIntervalControl.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/test/ManualIntervalControl.cs rename to src/Logging.AzureAppServices/test/ManualIntervalControl.cs diff --git a/src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj b/src/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj similarity index 100% rename from src/Logging/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj rename to src/Logging.AzureAppServices/test/Microsoft.Extensions.Logging.AzureAppServices.Tests.csproj diff --git a/src/Logging/Logging.AzureAppServices/test/OptionsWrapperMonitor.cs b/src/Logging.AzureAppServices/test/OptionsWrapperMonitor.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/test/OptionsWrapperMonitor.cs rename to src/Logging.AzureAppServices/test/OptionsWrapperMonitor.cs diff --git a/src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs b/src/Logging.AzureAppServices/test/TestBlobSink.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/test/TestBlobSink.cs rename to src/Logging.AzureAppServices/test/TestBlobSink.cs diff --git a/src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs b/src/Logging.AzureAppServices/test/TestFileLoggerProvider.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/test/TestFileLoggerProvider.cs rename to src/Logging.AzureAppServices/test/TestFileLoggerProvider.cs diff --git a/src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs b/src/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs similarity index 100% rename from src/Logging/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs rename to src/Logging.AzureAppServices/test/WebConfigurationLevelSwitchTests.cs diff --git a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj b/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj deleted file mode 100644 index eabb677844..0000000000 --- a/src/Logging/Logging.Testing/src/Microsoft.Extensions.Logging.Testing.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - - Helpers for writing tests that use Microsoft.Extensions.Logging. Contains null implementations of the abstractions that do nothing, as well as test implementations that are observable. - netstandard2.0;net472 - $(NoWarn);CS1591 - $(PackageTags);testing - - false - false - true - - - - - - - - - - - - - - - - - - diff --git a/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj b/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj deleted file mode 100644 index 4ec80710b7..0000000000 --- a/src/Logging/Logging.Testing/test/Microsoft.Extensions.Logging.Testing.Tests.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - $(DefaultNetCoreTargetFramework);net472 - - - - - - - - - - - - diff --git a/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs b/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs deleted file mode 100644 index 9ae4865e3a..0000000000 --- a/src/Logging/Logging.Testing/test/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Testing; - -[assembly: LogLevel(LogLevel.Trace)] diff --git a/src/Logging/Logging.Testing/test/TestTestOutputHelper.cs b/src/Logging/Logging.Testing/test/TestTestOutputHelper.cs deleted file mode 100644 index 5a5f6aa85f..0000000000 --- a/src/Logging/Logging.Testing/test/TestTestOutputHelper.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Text; -using Xunit.Abstractions; - -namespace Microsoft.Extensions.Logging.Testing.Tests -{ - public class TestTestOutputHelper : ITestOutputHelper - { - private StringBuilder _output = new StringBuilder(); - - public bool Throw { get; set; } - - public string Output => _output.ToString(); - - public void WriteLine(string message) - { - if (Throw) - { - throw new Exception("Boom!"); - } - _output.AppendLine(message); - } - - public void WriteLine(string format, params object[] args) - { - if (Throw) - { - throw new Exception("Boom!"); - } - _output.AppendLine(string.Format(format, args)); - } - } -} diff --git a/src/Servers/IIS/IIS/test/testassets/IIS.Common.TestLib/IIS.Common.TestLib.csproj b/src/Servers/IIS/IIS/test/testassets/IIS.Common.TestLib/IIS.Common.TestLib.csproj index ced51607d8..e4ff5df0cc 100644 --- a/src/Servers/IIS/IIS/test/testassets/IIS.Common.TestLib/IIS.Common.TestLib.csproj +++ b/src/Servers/IIS/IIS/test/testassets/IIS.Common.TestLib/IIS.Common.TestLib.csproj @@ -7,8 +7,8 @@ + - diff --git a/src/Servers/Kestrel/Directory.Build.props b/src/Servers/Kestrel/Directory.Build.props index 05b71894da..1b0e999039 100644 --- a/src/Servers/Kestrel/Directory.Build.props +++ b/src/Servers/Kestrel/Directory.Build.props @@ -20,7 +20,5 @@ - - diff --git a/src/SignalR/Directory.Build.props b/src/SignalR/Directory.Build.props index 27a3751cd8..74b4c7adee 100644 --- a/src/SignalR/Directory.Build.props +++ b/src/SignalR/Directory.Build.props @@ -21,7 +21,6 @@ PreserveNewest - diff --git a/src/SignalR/common/testassets/Tests.Utils/Microsoft.AspNetCore.SignalR.Tests.Utils.csproj b/src/SignalR/common/testassets/Tests.Utils/Microsoft.AspNetCore.SignalR.Tests.Utils.csproj index 9e69675720..782c8410b8 100644 --- a/src/SignalR/common/testassets/Tests.Utils/Microsoft.AspNetCore.SignalR.Tests.Utils.csproj +++ b/src/SignalR/common/testassets/Tests.Utils/Microsoft.AspNetCore.SignalR.Tests.Utils.csproj @@ -21,7 +21,6 @@ - diff --git a/src/Logging/Logging.Testing/src/BeginScopeContext.cs b/src/Testing/src/Logging/BeginScopeContext.cs similarity index 100% rename from src/Logging/Logging.Testing/src/BeginScopeContext.cs rename to src/Testing/src/Logging/BeginScopeContext.cs diff --git a/src/Logging/Logging.Testing/src/ITestSink.cs b/src/Testing/src/Logging/ITestSink.cs similarity index 100% rename from src/Logging/Logging.Testing/src/ITestSink.cs rename to src/Testing/src/Logging/ITestSink.cs diff --git a/src/Logging/Logging.Testing/src/LogLevelAttribute.cs b/src/Testing/src/Logging/LogLevelAttribute.cs similarity index 100% rename from src/Logging/Logging.Testing/src/LogLevelAttribute.cs rename to src/Testing/src/Logging/LogLevelAttribute.cs diff --git a/src/Logging/Logging.Testing/src/LogValuesAssert.cs b/src/Testing/src/Logging/LogValuesAssert.cs similarity index 100% rename from src/Logging/Logging.Testing/src/LogValuesAssert.cs rename to src/Testing/src/Logging/LogValuesAssert.cs diff --git a/src/Logging/Logging.Testing/src/TestLogger.cs b/src/Testing/src/Logging/TestLogger.cs similarity index 100% rename from src/Logging/Logging.Testing/src/TestLogger.cs rename to src/Testing/src/Logging/TestLogger.cs diff --git a/src/Logging/Logging.Testing/src/TestLoggerFactory.cs b/src/Testing/src/Logging/TestLoggerFactory.cs similarity index 100% rename from src/Logging/Logging.Testing/src/TestLoggerFactory.cs rename to src/Testing/src/Logging/TestLoggerFactory.cs diff --git a/src/Logging/Logging.Testing/src/TestLoggerProvider.cs b/src/Testing/src/Logging/TestLoggerProvider.cs similarity index 100% rename from src/Logging/Logging.Testing/src/TestLoggerProvider.cs rename to src/Testing/src/Logging/TestLoggerProvider.cs diff --git a/src/Logging/Logging.Testing/src/TestLoggerT.cs b/src/Testing/src/Logging/TestLoggerT.cs similarity index 100% rename from src/Logging/Logging.Testing/src/TestLoggerT.cs rename to src/Testing/src/Logging/TestLoggerT.cs diff --git a/src/Logging/Logging.Testing/src/TestSink.cs b/src/Testing/src/Logging/TestSink.cs similarity index 100% rename from src/Logging/Logging.Testing/src/TestSink.cs rename to src/Testing/src/Logging/TestSink.cs diff --git a/src/Logging/Logging.Testing/src/WriteContext.cs b/src/Testing/src/Logging/WriteContext.cs similarity index 100% rename from src/Logging/Logging.Testing/src/WriteContext.cs rename to src/Testing/src/Logging/WriteContext.cs diff --git a/src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs b/src/Testing/src/Logging/XunitLoggerFactoryExtensions.cs similarity index 100% rename from src/Logging/Logging.Testing/src/XunitLoggerFactoryExtensions.cs rename to src/Testing/src/Logging/XunitLoggerFactoryExtensions.cs diff --git a/src/Logging/Logging.Testing/src/XunitLoggerProvider.cs b/src/Testing/src/Logging/XunitLoggerProvider.cs similarity index 100% rename from src/Logging/Logging.Testing/src/XunitLoggerProvider.cs rename to src/Testing/src/Logging/XunitLoggerProvider.cs diff --git a/src/Testing/src/Microsoft.AspNetCore.Testing.csproj b/src/Testing/src/Microsoft.AspNetCore.Testing.csproj index 5ddad7b645..7d95e026a7 100644 --- a/src/Testing/src/Microsoft.AspNetCore.Testing.csproj +++ b/src/Testing/src/Microsoft.AspNetCore.Testing.csproj @@ -19,7 +19,9 @@ - + + + diff --git a/src/Logging/Logging.Testing/test/LogValuesAssertTest.cs b/src/Testing/test/LogValuesAssertTest.cs similarity index 100% rename from src/Logging/Logging.Testing/test/LogValuesAssertTest.cs rename to src/Testing/test/LogValuesAssertTest.cs diff --git a/src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs b/src/Testing/test/XunitLoggerProviderTest.cs similarity index 85% rename from src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs rename to src/Testing/test/XunitLoggerProviderTest.cs index 8a3fbbab25..e43447c465 100644 --- a/src/Logging/Logging.Testing/test/XunitLoggerProviderTest.cs +++ b/src/Testing/test/XunitLoggerProviderTest.cs @@ -4,7 +4,7 @@ using System; using System.Text.RegularExpressions; -using Microsoft.Extensions.Logging.Test; +using Microsoft.Extensions.DependencyInjection; using Xunit; namespace Microsoft.Extensions.Logging.Testing.Tests @@ -16,7 +16,7 @@ namespace Microsoft.Extensions.Logging.Testing.Tests { var testTestOutputHelper = new TestTestOutputHelper(); - var loggerFactory = TestLoggerBuilder.Create(builder => builder + var loggerFactory = CreateTestLogger(builder => builder .SetMinimumLevel(LogLevel.Trace) .AddXunit(testTestOutputHelper)); @@ -35,7 +35,7 @@ namespace Microsoft.Extensions.Logging.Testing.Tests public void LoggerProviderDoesNotWriteLogMessagesBelowMinimumLevel() { var testTestOutputHelper = new TestTestOutputHelper(); - var loggerFactory = TestLoggerBuilder.Create(builder => builder + var loggerFactory = CreateTestLogger(builder => builder .AddXunit(testTestOutputHelper, LogLevel.Warning)); var logger = loggerFactory.CreateLogger("TestCategory"); @@ -49,7 +49,7 @@ namespace Microsoft.Extensions.Logging.Testing.Tests public void LoggerProviderPrependsPrefixToEachLine() { var testTestOutputHelper = new TestTestOutputHelper(); - var loggerFactory = TestLoggerBuilder.Create(builder => builder + var loggerFactory = CreateTestLogger(builder => builder .AddXunit(testTestOutputHelper)); var logger = loggerFactory.CreateLogger("TestCategory"); @@ -68,7 +68,7 @@ namespace Microsoft.Extensions.Logging.Testing.Tests public void LoggerProviderDoesNotThrowIfOutputHelperThrows() { var testTestOutputHelper = new TestTestOutputHelper(); - var loggerFactory = TestLoggerBuilder.Create(builder => builder + var loggerFactory = CreateTestLogger(builder => builder .AddXunit(testTestOutputHelper)); @@ -83,5 +83,13 @@ namespace Microsoft.Extensions.Logging.Testing.Tests private static readonly Regex TimestampRegex = new Regex(@"\d+-\d+-\d+T\d+:\d+:\d+"); private string MakeConsistent(string input) => TimestampRegex.Replace(input, "TIMESTAMP"); + + private static ILoggerFactory CreateTestLogger(Action configure) + { + return new ServiceCollection() + .AddLogging(configure) + .BuildServiceProvider() + .GetRequiredService(); + } } } From f4a43462980fec1ebce6a68cdecf52204523670d Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 2 Apr 2020 11:58:09 -0700 Subject: [PATCH 44/44] Because jkotalik told me to --- .../IIS/test/Common.FunctionalTests/ClientCertificateTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/ClientCertificateTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/ClientCertificateTests.cs index b0847f84a1..5503c2b4fa 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/ClientCertificateTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/ClientCertificateTests.cs @@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests } catch (Exception ex) { - Logger.LogError($"Certificate is invalid. Issuer name: {cert.Issuer}"); + Logger.LogError($"Certificate is invalid. Issuer name: {cert?.Issuer}"); using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine)) { Logger.LogError($"List of current certificates in root store:");