11// Licensed to the .NET Foundation under one or more agreements.
22// The .NET Foundation licenses this file to you under the MIT license.
33
4- using System . IO ;
5- using System . Threading . Tasks ;
64using Microsoft . AspNetCore . Builder ;
75using Microsoft . AspNetCore . Testing ;
86using Microsoft . Extensions . Logging ;
9- using Xunit ;
7+ using Microsoft . Extensions . Logging . EventLog ;
108
119namespace Microsoft . AspNetCore . Tests
1210{
@@ -15,9 +13,12 @@ public class WebApplicationFunctionalTests : LoggedTest
1513 [ Fact ]
1614 public async Task LoggingConfigurationSectionPassedToLoggerByDefault ( )
1715 {
16+ var contentRootPath = Path . Combine ( Path . GetTempPath ( ) , Path . GetRandomFileName ( ) ) ;
17+ Directory . CreateDirectory ( contentRootPath ) ;
18+
1819 try
1920 {
20- await File . WriteAllTextAsync ( "appsettings.json" , @"
21+ await File . WriteAllTextAsync ( Path . Combine ( contentRootPath , "appsettings.json" ) , @"
2122{
2223 ""Logging"": {
2324 ""LogLevel"": {
@@ -26,7 +27,7 @@ await File.WriteAllTextAsync("appsettings.json", @"
2627 }
2728}" ) ;
2829
29- await using var app = WebApplication . Create ( ) ;
30+ await using var app = WebApplication . Create ( new [ ] { "--contentRoot" , contentRootPath } ) ;
3031
3132 var factory = ( ILoggerFactory ) app . Services . GetService ( typeof ( ILoggerFactory ) ) ;
3233 var logger = factory . CreateLogger ( "Test" ) ;
@@ -48,16 +49,19 @@ await File.WriteAllTextAsync("appsettings.json", @"
4849 }
4950 finally
5051 {
51- File . Delete ( "appsettings.json" ) ;
52+ Directory . Delete ( contentRootPath , recursive : true ) ;
5253 }
5354 }
5455
5556 [ Fact ]
5657 public async Task EnvironmentSpecificLoggingConfigurationSectionPassedToLoggerByDefault ( )
5758 {
59+ var contentRootPath = Path . Combine ( Path . GetTempPath ( ) , Path . GetRandomFileName ( ) ) ;
60+ Directory . CreateDirectory ( contentRootPath ) ;
61+
5862 try
5963 {
60- await File . WriteAllTextAsync ( "appsettings.Development.json" , @"
64+ await File . WriteAllTextAsync ( Path . Combine ( contentRootPath , "appsettings.Development.json" ) , @"
6165{
6266 ""Logging"": {
6367 ""LogLevel"": {
@@ -66,13 +70,7 @@ await File.WriteAllTextAsync("appsettings.Development.json", @"
6670 }
6771}" ) ;
6872
69- var app = WebApplication . Create ( new [ ] { "--environment" , "Development" } ) ;
70-
71- // TODO: Make this work! I think it should be possible if we register our Configuration
72- // as a ChainedConfigurationSource instead of copying over the bootstrapped IConfigurationSources.
73- //var builder = WebApplication.CreateBuilder();
74- //builder.Environment.EnvironmentName = "Development";
75- //await using var app = builder.Build();
73+ var app = WebApplication . Create ( new [ ] { "--environment" , "Development" , "--contentRoot" , contentRootPath } ) ;
7674
7775 var factory = ( ILoggerFactory ) app . Services . GetService ( typeof ( ILoggerFactory ) ) ;
7876 var logger = factory . CreateLogger ( "Test" ) ;
@@ -94,9 +92,86 @@ await File.WriteAllTextAsync("appsettings.Development.json", @"
9492 }
9593 finally
9694 {
97- File . Delete ( "appsettings.json" ) ;
95+ Directory . Delete ( contentRootPath , recursive : true ) ;
9896 }
9997 }
10098
99+ [ Fact ]
100+ public async Task LoggingConfigurationReactsToRuntimeChanges ( )
101+ {
102+ var contentRootPath = Path . Combine ( Path . GetTempPath ( ) , Path . GetRandomFileName ( ) ) ;
103+ Directory . CreateDirectory ( contentRootPath ) ;
104+
105+ try
106+ {
107+ await File . WriteAllTextAsync ( Path . Combine ( contentRootPath , "appsettings.json" ) , @"
108+ {
109+ ""Logging"": {
110+ ""LogLevel"": {
111+ ""Default"": ""Error""
112+ }
113+ }
114+ }" ) ;
115+
116+ var builder = WebApplication . CreateBuilder ( new WebApplicationOptions
117+ {
118+ ContentRootPath = contentRootPath ,
119+ } ) ;
120+
121+ // Disable the EventLogLoggerProvider because HostBuilder.ConfigureDefaults() configures it to log everything warning and higher which overrides non-provider-specific config.
122+ // https://github.com/dotnet/runtime/blob/8048fe613933a1cd91e3fad6d571c74f726143ef/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs#L238
123+ builder . Logging . AddFilter < EventLogLoggerProvider > ( _ => false ) ;
124+
125+ await using var app = builder . Build ( ) ;
126+
127+ var factory = ( ILoggerFactory ) app . Services . GetService ( typeof ( ILoggerFactory ) ) ;
128+ var logger = factory . CreateLogger ( "Test" ) ;
129+
130+ Assert . False ( logger . IsEnabled ( LogLevel . Warning ) ) ;
131+
132+ logger . Log ( LogLevel . Warning , 0 , "Message" , null , ( s , e ) =>
133+ {
134+ Assert . True ( false ) ;
135+ return string . Empty ;
136+ } ) ;
137+
138+ // Lower log level from Error to Warning and wait for logging to react to the config changes.
139+ var configChangedTcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
140+ using var registration = app . Configuration . GetReloadToken ( ) . RegisterChangeCallback (
141+ tcs => ( ( TaskCompletionSource ) tcs ) . SetResult ( ) , configChangedTcs ) ;
142+
143+ await File . WriteAllTextAsync ( Path . Combine ( contentRootPath , "appsettings.json" ) , @"
144+ {
145+ ""Logging"": {
146+ ""LogLevel"": {
147+ ""Default"": ""Warning""
148+ }
149+ }
150+ }" ) ;
151+
152+ // Wait for a config change notification because logging will not react until this is fired. Even then, it won't react immediately
153+ // so we loop until success or a timeout.
154+ await configChangedTcs . Task . DefaultTimeout ( ) ;
155+
156+ var timeoutTicks = Environment . TickCount64 + Testing . TaskExtensions . DefaultTimeoutDuration ;
157+ var logWritten = false ;
158+
159+ while ( ! logWritten && Environment . TickCount < timeoutTicks )
160+ {
161+ logger . Log ( LogLevel . Warning , 0 , "Message" , null , ( s , e ) =>
162+ {
163+ logWritten = true ;
164+ return string . Empty ;
165+ } ) ;
166+ }
167+
168+ Assert . True ( logWritten ) ;
169+ Assert . True ( logger . IsEnabled ( LogLevel . Warning ) ) ;
170+ }
171+ finally
172+ {
173+ Directory . Delete ( contentRootPath , recursive : true ) ;
174+ }
175+ }
101176 }
102177}
0 commit comments