Browse Source

Guard ILogger calls that do work at call site (#47837)

* Guard ILogger calls that do work at call site

* Apply suggestions from code review

Co-authored-by: David Fowler <[email protected]>

* Apply suggestions from code review

---------

Co-authored-by: David Fowler <[email protected]>
Stephen Toub 2 years ago
parent
commit
103560b3d4
29 changed files with 255 additions and 94 deletions
  1. 6 3
      src/DataProtection/DataProtection/src/TypeForwardingActivator.cs
  2. 6 3
      src/Hosting/Hosting/src/Internal/HostingLoggerExtensions.cs
  3. 1 1
      src/Hosting/Hosting/src/WebHostBuilder.cs
  4. 8 2
      src/Identity/ApiAuthorization.IdentityServer/src/Configuration/ConfigureApiResources.cs
  5. 34 16
      src/Identity/ApiAuthorization.IdentityServer/src/Configuration/ConfigureClientScopes.cs
  6. 4 1
      src/Identity/ApiAuthorization.IdentityServer/src/Configuration/ConfigureClients.cs
  7. 12 3
      src/Identity/ApiAuthorization.IdentityServer/src/Configuration/ConfigureSigningCredentials.cs
  8. 17 5
      src/Identity/Extensions.Core/src/UserManager.cs
  9. 8 2
      src/Identity/UI/src/Areas/Identity/Pages/V4/Account/ExternalLogin.cshtml.cs
  10. 8 2
      src/Identity/UI/src/Areas/Identity/Pages/V5/Account/ExternalLogin.cshtml.cs
  11. 8 2
      src/Middleware/HttpOverrides/src/ForwardedHeadersMiddleware.cs
  12. 23 8
      src/Middleware/Spa/SpaProxy/src/SpaProxyLaunchManager.cs
  13. 4 1
      src/Middleware/Spa/SpaProxy/src/SpaProxyMiddleware.cs
  14. 4 1
      src/Middleware/Spa/SpaServices.Extensions/src/AngularCli/AngularCliMiddleware.cs
  15. 1 1
      src/Middleware/Spa/SpaServices.Extensions/src/Npm/NodeScriptRunner.cs
  16. 4 1
      src/Middleware/Spa/SpaServices.Extensions/src/ReactDevelopmentServer/ReactDevelopmentServerMiddleware.cs
  17. 4 1
      src/Middleware/WebSockets/src/WebSocketMiddleware.cs
  18. 21 12
      src/Mvc/Mvc.Core/src/Infrastructure/ConfigureCompatibilityOptions.cs
  19. 8 2
      src/ProjectTemplates/Shared/AspNetProcess.cs
  20. 4 1
      src/ProjectTemplates/Shared/TestOutputLogger.cs
  21. 4 1
      src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Worker.cs
  22. 3 3
      src/Security/Authentication/Negotiate/src/Internal/LdapAdapter.cs
  23. 9 6
      src/Security/Authentication/OpenIdConnect/src/OpenIdConnectHandler.cs
  24. 2 2
      src/Security/Authorization/Policy/src/AuthorizationMiddleware.cs
  25. 8 2
      src/Servers/Kestrel/Core/src/AnyIPListenOptions.cs
  26. 12 4
      src/Servers/Kestrel/Core/src/Internal/AddressBinder.cs
  27. 12 3
      src/Servers/Kestrel/Core/src/Internal/KestrelServerImpl.cs
  28. 8 2
      src/Servers/Kestrel/Core/src/LocalhostListenOptions.cs
  29. 12 3
      src/Shared/Http2cat/Http2CatHostedService.cs

+ 6 - 3
src/DataProtection/DataProtection/src/TypeForwardingActivator.cs

@@ -39,9 +39,12 @@ internal class TypeForwardingActivator : SimpleActivator
             var type = Type.GetType(forwardedTypeName, false);
             if (type != null)
             {
-                _logger.LogDebug("Forwarded activator type request from {FromType} to {ToType}",
-                    originalTypeName,
-                    forwardedTypeName);
+                if (_logger.IsEnabled(LogLevel.Debug))
+                {
+                    _logger.LogDebug("Forwarded activator type request from {FromType} to {ToType}",
+                        originalTypeName,
+                        forwardedTypeName);
+                }
                 forwarded = true;
                 return base.CreateInstance(expectedBaseType, forwardedTypeName);
             }

+ 6 - 3
src/Hosting/Hosting/src/Internal/HostingLoggerExtensions.cs

@@ -45,9 +45,12 @@ internal static class HostingLoggerExtensions
 
     public static void PortsOverridenByUrls(this ILogger logger, string httpPorts, string httpsPorts, string urls)
     {
-        logger.LogWarning(eventId: LoggerEventIds.PortsOverridenByUrls,
-            message: "Overriding HTTP_PORTS '{http}' and HTTPS_PORTS '{https}'. Binding to values defined by URLS instead '{urls}'.",
-            httpPorts, httpsPorts, urls);
+        if (logger.IsEnabled(LogLevel.Warning))
+        {
+            logger.LogWarning(eventId: LoggerEventIds.PortsOverridenByUrls,
+                message: "Overriding HTTP_PORTS '{http}' and HTTPS_PORTS '{https}'. Binding to values defined by URLS instead '{urls}'.",
+                httpPorts, httpsPorts, urls);
+        }
     }
 }
 

+ 1 - 1
src/Hosting/Hosting/src/WebHostBuilder.cs

@@ -179,7 +179,7 @@ public class WebHostBuilder : IWebHostBuilder
             var assemblyNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
             foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies())
             {
-                if (!assemblyNames.Add(assemblyName))
+                if (!assemblyNames.Add(assemblyName) && logger.IsEnabled(LogLevel.Warning))
                 {
                     logger.LogWarning($"The assembly {assemblyName} was specified multiple times. Hosting startup assemblies should only be specified once.");
                 }

+ 8 - 2
src/Identity/ApiAuthorization.IdentityServer/src/Configuration/ConfigureApiResources.cs

@@ -46,7 +46,10 @@ internal sealed class ConfigureApiResources : IConfigureOptions<ApiAuthorization
         {
             foreach (var kvp in data)
             {
-                _logger.LogInformation(LoggerEventIds.ConfiguringAPIResource, "Configuring API resource '{ApiResourceName}'.", kvp.Key);
+                if (_logger.IsEnabled(LogLevel.Information))
+                {
+                    _logger.LogInformation(LoggerEventIds.ConfiguringAPIResource, "Configuring API resource '{ApiResourceName}'.", kvp.Key);
+                }
                 yield return GetResource(kvp.Key, kvp.Value);
             }
         }
@@ -56,7 +59,10 @@ internal sealed class ConfigureApiResources : IConfigureOptions<ApiAuthorization
         {
             foreach (var kvp in localResources)
             {
-                _logger.LogInformation(LoggerEventIds.ConfiguringLocalAPIResource, "Configuring local API resource '{ApiResourceName}'.", kvp.Key);
+                if (_logger.IsEnabled(LogLevel.Information))
+                {
+                    _logger.LogInformation(LoggerEventIds.ConfiguringLocalAPIResource, "Configuring local API resource '{ApiResourceName}'.", kvp.Key);
+                }
                 yield return GetResource(kvp.Key, kvp.Value);
             }
         }

+ 34 - 16
src/Identity/ApiAuthorization.IdentityServer/src/Configuration/ConfigureClientScopes.cs

@@ -30,24 +30,33 @@ internal sealed class ConfigureClientScopes : IPostConfigureOptions<ApiAuthoriza
         {
             if (!identityResource.Properties.TryGetValue(ApplicationProfilesPropertyNames.Clients, out var clientList))
             {
-                _logger.LogInformation(LoggerEventIds.AllowedApplicationNotDefienedForIdentityResource, "Identity resource '{IdentityResourceName}' doesn't define a list of allowed applications.", identityResource.Name);
+                if (_logger.IsEnabled(LogLevel.Information))
+                {
+                    _logger.LogInformation(LoggerEventIds.AllowedApplicationNotDefienedForIdentityResource, "Identity resource '{IdentityResourceName}' doesn't define a list of allowed applications.", identityResource.Name);
+                }
                 continue;
             }
 
             var resourceClients = clientList.Split(DefaultClientListSeparator, StringSplitOptions.RemoveEmptyEntries);
             if (resourceClients.Length == 0)
             {
-                _logger.LogInformation(LoggerEventIds.AllowedApplicationNotDefienedForIdentityResource, "Identity resource '{IdentityResourceName}' doesn't define a list of allowed applications.", identityResource.Name);
+                if (_logger.IsEnabled(LogLevel.Information))
+                {
+                    _logger.LogInformation(LoggerEventIds.AllowedApplicationNotDefienedForIdentityResource, "Identity resource '{IdentityResourceName}' doesn't define a list of allowed applications.", identityResource.Name);
+                }
                 continue;
             }
 
-            if (resourceClients.Length == 1 && resourceClients[0] == ApplicationProfilesPropertyValues.AllowAllApplications)
-            {
-                _logger.LogInformation(LoggerEventIds.AllApplicationsAllowedForIdentityResource, "Identity resource '{IdentityResourceName}' allows all applications.", identityResource.Name);
-            }
-            else
+            if (_logger.IsEnabled(LogLevel.Information))
             {
-                _logger.LogInformation(LoggerEventIds.ApplicationsAllowedForIdentityResource, "Identity resource '{IdentityResourceName}' allows applications '{ResourceClients}'.", identityResource.Name, string.Join(" ", resourceClients));
+                if (resourceClients.Length == 1 && resourceClients[0] == ApplicationProfilesPropertyValues.AllowAllApplications)
+                {
+                    _logger.LogInformation(LoggerEventIds.AllApplicationsAllowedForIdentityResource, "Identity resource '{IdentityResourceName}' allows all applications.", identityResource.Name);
+                }
+                else
+                {
+                    _logger.LogInformation(LoggerEventIds.ApplicationsAllowedForIdentityResource, "Identity resource '{IdentityResourceName}' allows applications '{ResourceClients}'.", identityResource.Name, string.Join(" ", resourceClients));
+                }
             }
 
             foreach (var client in options.Clients)
@@ -67,24 +76,33 @@ internal sealed class ConfigureClientScopes : IPostConfigureOptions<ApiAuthoriza
         {
             if (!resource.Properties.TryGetValue(ApplicationProfilesPropertyNames.Clients, out var clientList))
             {
-                _logger.LogInformation(LoggerEventIds.AllowedApplicationNotDefienedForApiResource, "Resource '{ApiResourceName}' doesn't define a list of allowed applications.", resource.Name);
+                if (_logger.IsEnabled(LogLevel.Information))
+                {
+                    _logger.LogInformation(LoggerEventIds.AllowedApplicationNotDefienedForApiResource, "Resource '{ApiResourceName}' doesn't define a list of allowed applications.", resource.Name);
+                }
                 continue;
             }
 
             var resourceClients = clientList.Split(DefaultClientListSeparator, StringSplitOptions.RemoveEmptyEntries);
             if (resourceClients.Length == 0)
             {
-                _logger.LogInformation(LoggerEventIds.AllowedApplicationNotDefienedForApiResource, "Resource '{ApiResourceName}' doesn't define a list of allowed applications.", resource.Name);
+                if (_logger.IsEnabled(LogLevel.Information))
+                {
+                    _logger.LogInformation(LoggerEventIds.AllowedApplicationNotDefienedForApiResource, "Resource '{ApiResourceName}' doesn't define a list of allowed applications.", resource.Name);
+                }
                 continue;
             }
 
-            if (resourceClients.Length == 1 && resourceClients[0] == ApplicationProfilesPropertyValues.AllowAllApplications)
-            {
-                _logger.LogInformation(LoggerEventIds.AllApplicationsAllowedForApiResource, "Resource '{ApiResourceName}' allows all applications.", resource.Name);
-            }
-            else
+            if (_logger.IsEnabled(LogLevel.Information))
             {
-                _logger.LogInformation(LoggerEventIds.ApplicationsAllowedForApiResource, "Resource '{ApiResourceName}' allows applications '{resourceClients}'.", resource.Name, string.Join(" ", resourceClients));
+                if (resourceClients.Length == 1 && resourceClients[0] == ApplicationProfilesPropertyValues.AllowAllApplications)
+                {
+                    _logger.LogInformation(LoggerEventIds.AllApplicationsAllowedForApiResource, "Resource '{ApiResourceName}' allows all applications.", resource.Name);
+                }
+                else
+                {
+                    _logger.LogInformation(LoggerEventIds.ApplicationsAllowedForApiResource, "Resource '{ApiResourceName}' allows applications '{resourceClients}'.", resource.Name, string.Join(" ", resourceClients));
+                }
             }
 
             foreach (var client in options.Clients)

+ 4 - 1
src/Identity/ApiAuthorization.IdentityServer/src/Configuration/ConfigureClients.cs

@@ -39,7 +39,10 @@ internal sealed class ConfigureClients : IConfigureOptions<ApiAuthorizationOptio
         {
             foreach (var kvp in data)
             {
-                _logger.LogInformation(LoggerEventIds.ConfiguringClient, "Configuring client '{ClientName}'.", kvp.Key);
+                if (_logger.IsEnabled(LogLevel.Information))
+                {
+                    _logger.LogInformation(LoggerEventIds.ConfiguringClient, "Configuring client '{ClientName}'.", kvp.Key);
+                }
                 var name = kvp.Key;
                 var definition = kvp.Value;
 

+ 12 - 3
src/Identity/ApiAuthorization.IdentityServer/src/Configuration/ConfigureSigningCredentials.cs

@@ -70,7 +70,10 @@ internal sealed class ConfigureSigningCredentials : IConfigureOptions<ApiAuthori
             case KeySources.Development:
                 var developmentKeyPath = Path.Combine(Directory.GetCurrentDirectory(), key.FilePath ?? DefaultTempKeyRelativePath);
                 var createIfMissing = key.Persisted ?? true;
-                _logger.LogInformation(LoggerEventIds.DevelopmentKeyLoaded, "Loading development key at '{developmentKeyPath}'.", developmentKeyPath);
+                if (_logger.IsEnabled(LogLevel.Information))
+                {
+                    _logger.LogInformation(LoggerEventIds.DevelopmentKeyLoaded, "Loading development key at '{developmentKeyPath}'.", developmentKeyPath);
+                }
                 var developmentKey = new RsaSecurityKey(SigningKeysLoader.LoadDevelopment(developmentKeyPath, createIfMissing))
                 {
                     KeyId = "Development"
@@ -79,14 +82,20 @@ internal sealed class ConfigureSigningCredentials : IConfigureOptions<ApiAuthori
             case KeySources.File:
                 var pfxPath = Path.Combine(Directory.GetCurrentDirectory(), key.FilePath);
                 var storageFlags = GetStorageFlags(key);
-                _logger.LogInformation(LoggerEventIds.CertificateLoadedFromFile, "Loading certificate file at '{CertificatePath}' with storage flags '{CertificateStorageFlags}'.", pfxPath, key.StorageFlags);
+                if (_logger.IsEnabled(LogLevel.Information))
+                {
+                    _logger.LogInformation(LoggerEventIds.CertificateLoadedFromFile, "Loading certificate file at '{CertificatePath}' with storage flags '{CertificateStorageFlags}'.", pfxPath, key.StorageFlags);
+                }
                 return new SigningCredentials(new X509SecurityKey(SigningKeysLoader.LoadFromFile(pfxPath, key.Password, storageFlags)), "RS256");
             case KeySources.Store:
                 if (!Enum.TryParse<StoreLocation>(key.StoreLocation, out var storeLocation))
                 {
                     throw new InvalidOperationException($"Invalid certificate store location '{key.StoreLocation}'.");
                 }
-                _logger.LogInformation(LoggerEventIds.CertificateLoadedFromStore, "Loading certificate with subject '{CertificateSubject}' in '{CertificateStoreLocation}\\{CertificateStoreName}'.", key.Name, key.StoreLocation, key.StoreName);
+                if (_logger.IsEnabled(LogLevel.Information))
+                {
+                    _logger.LogInformation(LoggerEventIds.CertificateLoadedFromStore, "Loading certificate with subject '{CertificateSubject}' in '{CertificateStoreLocation}\\{CertificateStoreName}'.", key.Name, key.StoreLocation, key.StoreName);
+                }
                 return new SigningCredentials(new X509SecurityKey(SigningKeysLoader.LoadFromStoreCert(key.Name, key.StoreName, storeLocation, GetCurrentTime())), "RS256");
             default:
                 throw new InvalidOperationException($"Invalid key type '{key.Type ?? "(null)"}'.");

+ 17 - 5
src/Identity/Extensions.Core/src/UserManager.cs

@@ -1162,13 +1162,19 @@ public class UserManager<TUser> : IDisposable where TUser : class
 
     private IdentityResult UserAlreadyInRoleError(string role)
     {
-        Logger.LogDebug(LoggerEventIds.UserAlreadyInRole, "User is already in role {role}.", role);
+        if (Logger.IsEnabled(LogLevel.Debug))
+        {
+            Logger.LogDebug(LoggerEventIds.UserAlreadyInRole, "User is already in role {role}.", role);
+        }
         return IdentityResult.Failed(ErrorDescriber.UserAlreadyInRole(role));
     }
 
     private IdentityResult UserNotInRoleError(string role)
     {
-        Logger.LogDebug(LoggerEventIds.UserNotInRole, "User is not in role {role}.", role);
+        if (Logger.IsEnabled(LogLevel.Debug))
+        {
+            Logger.LogDebug(LoggerEventIds.UserNotInRole, "User is not in role {role}.", role);
+        }
         return IdentityResult.Failed(ErrorDescriber.UserNotInRole(role));
     }
 
@@ -1549,7 +1555,7 @@ public class UserManager<TUser> : IDisposable where TUser : class
         // Make sure the token is valid
         var result = await _tokenProviders[tokenProvider].ValidateAsync(purpose, token, this, user).ConfigureAwait(false);
 
-        if (!result)
+        if (!result && Logger.IsEnabled(LogLevel.Debug))
         {
             Logger.LogDebug(LoggerEventIds.VerifyUserTokenFailed, "VerifyUserTokenAsync() failed with purpose: {purpose} for user.", purpose);
         }
@@ -2307,7 +2313,10 @@ public class UserManager<TUser> : IDisposable where TUser : class
         }
         if (errors?.Count > 0)
         {
-            Logger.LogDebug(LoggerEventIds.UserValidationFailed, "User validation failed: {errors}.", string.Join(";", errors.Select(e => e.Code)));
+            if (Logger.IsEnabled(LogLevel.Debug))
+            {
+                Logger.LogDebug(LoggerEventIds.UserValidationFailed, "User validation failed: {errors}.", string.Join(";", errors.Select(e => e.Code)));
+            }
             return IdentityResult.Failed(errors);
         }
         return IdentityResult.Success;
@@ -2340,7 +2349,10 @@ public class UserManager<TUser> : IDisposable where TUser : class
         }
         if (!isValid)
         {
-            Logger.LogDebug(LoggerEventIds.PasswordValidationFailed, "User password validation failed: {errors}.", string.Join(";", errors?.Select(e => e.Code) ?? Array.Empty<string>()));
+            if (Logger.IsEnabled(LogLevel.Debug))
+            {
+                Logger.LogDebug(LoggerEventIds.PasswordValidationFailed, "User password validation failed: {errors}.", string.Join(";", errors?.Select(e => e.Code) ?? Array.Empty<string>()));
+            }
             return IdentityResult.Failed(errors);
         }
         return IdentityResult.Success;

+ 8 - 2
src/Identity/UI/src/Areas/Identity/Pages/V4/Account/ExternalLogin.cshtml.cs

@@ -142,7 +142,10 @@ internal sealed class ExternalLoginModel<TUser> : ExternalLoginModel where TUser
         var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
         if (result.Succeeded)
         {
-            _logger.LogInformation(LoggerEventIds.UserLoggedInByExternalProvider, "User logged in with {LoginProvider} provider.", info.LoginProvider);
+            if (_logger.IsEnabled(LogLevel.Information))
+            {
+                _logger.LogInformation(LoggerEventIds.UserLoggedInByExternalProvider, "User logged in with {LoginProvider} provider.", info.LoginProvider);
+            }
             return LocalRedirect(returnUrl);
         }
         if (result.IsLockedOut)
@@ -189,7 +192,10 @@ internal sealed class ExternalLoginModel<TUser> : ExternalLoginModel where TUser
                 result = await _userManager.AddLoginAsync(user, info);
                 if (result.Succeeded)
                 {
-                    _logger.LogInformation(LoggerEventIds.UserCreatedByExternalProvider, "User created an account using {Name} provider.", info.LoginProvider);
+                    if (_logger.IsEnabled(LogLevel.Information))
+                    {
+                        _logger.LogInformation(LoggerEventIds.UserCreatedByExternalProvider, "User created an account using {Name} provider.", info.LoginProvider);
+                    }
 
                     var userId = await _userManager.GetUserIdAsync(user);
                     var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);

+ 8 - 2
src/Identity/UI/src/Areas/Identity/Pages/V5/Account/ExternalLogin.cshtml.cs

@@ -142,7 +142,10 @@ internal sealed class ExternalLoginModel<TUser> : ExternalLoginModel where TUser
         var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
         if (result.Succeeded)
         {
-            _logger.LogInformation(LoggerEventIds.UserLoggedInByExternalProvider, "User logged in with {LoginProvider} provider.", info.LoginProvider);
+            if (_logger.IsEnabled(LogLevel.Information))
+            {
+                _logger.LogInformation(LoggerEventIds.UserLoggedInByExternalProvider, "User logged in with {LoginProvider} provider.", info.LoginProvider);
+            }
             return LocalRedirect(returnUrl);
         }
         if (result.IsLockedOut)
@@ -189,7 +192,10 @@ internal sealed class ExternalLoginModel<TUser> : ExternalLoginModel where TUser
                 result = await _userManager.AddLoginAsync(user, info);
                 if (result.Succeeded)
                 {
-                    _logger.LogInformation(LoggerEventIds.UserCreatedByExternalProvider, "User created an account using {Name} provider.", info.LoginProvider);
+                    if (_logger.IsEnabled(LogLevel.Information))
+                    {
+                        _logger.LogInformation(LoggerEventIds.UserCreatedByExternalProvider, "User created an account using {Name} provider.", info.LoginProvider);
+                    }
 
                     var userId = await _userManager.GetUserIdAsync(user);
                     var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);

+ 8 - 2
src/Middleware/HttpOverrides/src/ForwardedHeadersMiddleware.cs

@@ -213,7 +213,10 @@ public class ForwardedHeadersMiddleware
                 if (currentValues.RemoteIpAndPort != null && checkKnownIps && !CheckKnownAddress(currentValues.RemoteIpAndPort.Address))
                 {
                     // Stop at the first unknown remote IP, but still apply changes processed so far.
-                    _logger.LogDebug(1, "Unknown proxy: {RemoteIpAndPort}", currentValues.RemoteIpAndPort);
+                    if (_logger.IsEnabled(LogLevel.Debug))
+                    {
+                        _logger.LogDebug(1, "Unknown proxy: {RemoteIpAndPort}", currentValues.RemoteIpAndPort);
+                    }
                     break;
                 }
 
@@ -227,7 +230,10 @@ public class ForwardedHeadersMiddleware
                 else if (!string.IsNullOrEmpty(set.IpAndPortText))
                 {
                     // Stop at the first unparsable IP, but still apply changes processed so far.
-                    _logger.LogDebug(1, "Unparsable IP: {IpAndPortText}", set.IpAndPortText);
+                    if (_logger.IsEnabled(LogLevel.Debug))
+                    {
+                        _logger.LogDebug(1, "Unparsable IP: {IpAndPortText}", set.IpAndPortText);
+                    }
                     break;
                 }
                 else if (_options.RequireHeaderSymmetry)

+ 23 - 8
src/Middleware/Spa/SpaProxy/src/SpaProxyLaunchManager.cs

@@ -42,7 +42,10 @@ internal sealed class SpaProxyLaunchManager : IDisposable
         {
             if (_launchTask == null)
             {
-                _logger.LogInformation($"No SPA development server running at {_options.ServerUrl} found.");
+                if (_logger.IsEnabled(LogLevel.Information))
+                {
+                    _logger.LogInformation($"No SPA development server running at {_options.ServerUrl} found.");
+                }
                 _launchTask = UpdateStatus(StartSpaProcessAndProbeForLiveness(cancellationToken));
             }
         }
@@ -145,13 +148,19 @@ internal sealed class SpaProxyLaunchManager : IDisposable
 
         if (_spaProcess == null || _spaProcess.HasExited)
         {
-            _logger.LogError($"Couldn't start the SPA development server with command '{_options.LaunchCommand}'.");
+            if (_logger.IsEnabled(LogLevel.Error))
+            {
+                _logger.LogError($"Couldn't start the SPA development server with command '{_options.LaunchCommand}'.");
+            }
         }
         else if (!livenessProbeSucceeded)
         {
-            _logger.LogError($"Unable to connect to the SPA development server at '{_options.ServerUrl}'.");
+            if (_logger.IsEnabled(LogLevel.Error))
+            {
+                _logger.LogError($"Unable to connect to the SPA development server at '{_options.ServerUrl}'.");
+            }
         }
-        else
+        else if (_logger.IsEnabled(LogLevel.Information))
         {
             _logger.LogInformation($"SPA development server running at '{_options.ServerUrl}'");
         }
@@ -237,13 +246,19 @@ catch
         var stopProcess = Process.Start(stopScriptInfo);
         if (stopProcess == null || stopProcess.HasExited)
         {
-            _logger.LogWarning($"The SPA process shutdown script '{stopProcess?.Id}' failed to start. The SPA proxy might" +
-                $" remain open if the dotnet process is terminated ungracefully. Use the operating system commands to kill" +
-                $" the process tree for {spaProcessId}");
+            if (_logger.IsEnabled(LogLevel.Warning))
+            {
+                _logger.LogWarning($"The SPA process shutdown script '{stopProcess?.Id}' failed to start. The SPA proxy might" +
+                    $" remain open if the dotnet process is terminated ungracefully. Use the operating system commands to kill" +
+                    $" the process tree for {spaProcessId}");
+            }
         }
         else
         {
-            _logger.LogDebug($"Watch process '{stopProcess}' started.");
+            if (_logger.IsEnabled(LogLevel.Debug))
+            {
+                _logger.LogDebug($"Watch process '{stopProcess}' started.");
+            }
         }
     }
 

+ 4 - 1
src/Middleware/Spa/SpaProxy/src/SpaProxyMiddleware.cs

@@ -64,7 +64,10 @@ internal sealed class SpaProxyMiddleware
         }
         else
         {
-            _logger.LogInformation($"SPA proxy is ready. Redirecting to {_options.Value.GetRedirectUrl()}.");
+            if (_logger.IsEnabled(LogLevel.Information))
+            {
+                _logger.LogInformation($"SPA proxy is ready. Redirecting to {_options.Value.GetRedirectUrl()}.");
+            }
             context.Response.Redirect(_options.Value.GetRedirectUrl());
         }
 

+ 4 - 1
src/Middleware/Spa/SpaServices.Extensions/src/AngularCli/AngularCliMiddleware.cs

@@ -63,7 +63,10 @@ internal static class AngularCliMiddleware
         {
             portNumber = TcpPortFinder.FindAvailablePort();
         }
-        logger.LogInformation($"Starting @angular/cli on port {portNumber}...");
+        if (logger.IsEnabled(LogLevel.Information))
+        {
+            logger.LogInformation($"Starting @angular/cli on port {portNumber}...");
+        }
 
         var scriptRunner = new NodeScriptRunner(
             sourcePath, scriptName, $"--port {portNumber}", null, pkgManagerCommand, diagnosticSource, applicationStoppingToken);

+ 1 - 1
src/Middleware/Spa/SpaServices.Extensions/src/Npm/NodeScriptRunner.cs

@@ -97,7 +97,7 @@ internal sealed class NodeScriptRunner : IDisposable
         // When the node task emits complete lines, pass them through to the real logger
         StdOut.OnReceivedLine += line =>
         {
-            if (!string.IsNullOrWhiteSpace(line))
+            if (!string.IsNullOrWhiteSpace(line) && logger.IsEnabled(LogLevel.Information))
             {
                 // Node tasks commonly emit ANSI colors, but it wouldn't make sense to forward
                 // those to loggers (because a logger isn't necessarily any kind of terminal)

+ 4 - 1
src/Middleware/Spa/SpaServices.Extensions/src/ReactDevelopmentServer/ReactDevelopmentServerMiddleware.cs

@@ -69,7 +69,10 @@ internal static class ReactDevelopmentServerMiddleware
         {
             portNumber = TcpPortFinder.FindAvailablePort();
         }
-        logger.LogInformation($"Starting create-react-app server on port {portNumber}...");
+        if (logger.IsEnabled(LogLevel.Information))
+        {
+            logger.LogInformation($"Starting create-react-app server on port {portNumber}...");
+        }
 
         var envVars = new Dictionary<string, string>
             {

+ 4 - 1
src/Middleware/WebSockets/src/WebSocketMiddleware.cs

@@ -72,7 +72,10 @@ public partial class WebSocketMiddleware
                     // Check allowed origins to see if request is allowed
                     if (!_allowedOrigins.Contains(originHeader.ToString(), StringComparer.Ordinal))
                     {
-                        _logger.LogDebug("Request origin {Origin} is not in the list of allowed origins.", originHeader.ToString());
+                        if (_logger.IsEnabled(LogLevel.Debug))
+                        {
+                            _logger.LogDebug("Request origin {Origin} is not in the list of allowed origins.", originHeader.ToString());
+                        }
                         context.Response.StatusCode = StatusCodes.Status403Forbidden;
                         return Task.CompletedTask;
                     }

+ 21 - 12
src/Mvc/Mvc.Core/src/Infrastructure/ConfigureCompatibilityOptions.cs

@@ -65,30 +65,39 @@ public abstract class ConfigureCompatibilityOptions<TOptions> : IPostConfigureOp
     {
         if (@switch.IsValueSet)
         {
-            _logger.LogDebug(
-                "Compatibility switch {SwitchName} in type {OptionsType} is using explicitly configured value {Value}",
-                @switch.Name,
-                typeof(TOptions).Name,
-                @switch.Value);
+            if (_logger.IsEnabled(LogLevel.Debug))
+            {
+                _logger.LogDebug(
+                    "Compatibility switch {SwitchName} in type {OptionsType} is using explicitly configured value {Value}",
+                    @switch.Name,
+                    typeof(TOptions).Name,
+                    @switch.Value);
+            }
             return;
         }
 
         if (!defaultValues.TryGetValue(@switch.Name, out var value))
         {
-            _logger.LogDebug(
+            if (_logger.IsEnabled(LogLevel.Debug))
+            {
+                _logger.LogDebug(
                 "Compatibility switch {SwitchName} in type {OptionsType} is using default value {Value}",
                 @switch.Name,
                 typeof(TOptions).Name,
                 @switch.Value);
+            }
             return;
         }
 
         @switch.Value = value;
-        _logger.LogDebug(
-            "Compatibility switch {SwitchName} in type {OptionsType} is using compatibility value {Value} for version {Version}",
-            @switch.Name,
-            typeof(TOptions).Name,
-            @switch.Value,
-            Version);
+        if (_logger.IsEnabled(LogLevel.Debug))
+        {
+            _logger.LogDebug(
+                "Compatibility switch {SwitchName} in type {OptionsType} is using compatibility value {Value} for version {Version}",
+                @switch.Name,
+                typeof(TOptions).Name,
+                @switch.Value,
+                Version);
+        }
     }
 }

+ 8 - 2
src/ProjectTemplates/Shared/AspNetProcess.cs

@@ -80,7 +80,10 @@ public class AspNetProcess : IDisposable
             arguments = $"run --no-build --urls \"{environmentVariables["ASPNETCORE_URLS"]}\"";
         }
 
-        logger?.LogInformation($"AspNetProcess - process: {process} arguments: {arguments}");
+        if (logger is not null && logger.IsEnabled(LogLevel.Information))
+        {
+            logger.LogInformation($"AspNetProcess - process: {process} arguments: {arguments}");
+        }
 
         var finalEnvironmentVariables = new Dictionary<string, string>(environmentVariables)
         {
@@ -96,7 +99,10 @@ public class AspNetProcess : IDisposable
         {
             logger?.LogInformation("AspNetProcess - Getting listening uri");
             ListeningUri = ResolveListeningUrl(output);
-            logger?.LogInformation($"AspNetProcess - Got {ListeningUri}");
+            if (logger is not null && logger.IsEnabled(LogLevel.Information))
+            {
+                logger?.LogInformation($"AspNetProcess - Got {ListeningUri}");
+            }
         }
     }
 

+ 4 - 1
src/ProjectTemplates/Shared/TestOutputLogger.cs

@@ -23,6 +23,9 @@ internal sealed class TestOutputLogger : ITestOutputHelper
 
     public void WriteLine(string format, params object[] args)
     {
-        _logger.LogInformation(string.Format(CultureInfo.InvariantCulture, format, args));
+        if (_logger.IsEnabled(LogLevel.Information))
+        {
+            _logger.LogInformation(string.Format(CultureInfo.InvariantCulture, format, args));
+        }
     }
 }

+ 4 - 1
src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Worker.cs

@@ -13,7 +13,10 @@ public class Worker : BackgroundService
     {
         while (!stoppingToken.IsCancellationRequested)
         {
-            _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
+            if (_logger.IsEnabled(LogLevel.Information))
+            {
+                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
+            }
             await Task.Delay(1000, stoppingToken);
         }
     }

+ 3 - 3
src/Security/Authentication/Negotiate/src/Internal/LdapAdapter.cs

@@ -54,7 +54,7 @@ internal static partial class LdapAdapter
 
         if (searchResponse.Entries.Count > 0)
         {
-            if (searchResponse.Entries.Count > 1)
+            if (searchResponse.Entries.Count > 1 && logger.IsEnabled(LogLevel.Warning))
             {
                 logger.LogWarning($"More than one response received for query: {filter} with distinguished name: {distinguishedName}");
             }
@@ -92,7 +92,7 @@ internal static partial class LdapAdapter
                     .SetSlidingExpiration(settings.ClaimsCacheSlidingExpiration)
                     .SetAbsoluteExpiration(settings.ClaimsCacheAbsoluteExpiration));
         }
-        else
+        else if (logger.IsEnabled(LogLevel.Warning))
         {
             logger.LogWarning($"No response received for query: {filter} with distinguished name: {distinguishedName}");
         }
@@ -108,7 +108,7 @@ internal static partial class LdapAdapter
 
         if (searchResponse.Entries.Count > 0)
         {
-            if (searchResponse.Entries.Count > 1)
+            if (searchResponse.Entries.Count > 1 && logger.IsEnabled(LogLevel.Warning))
             {
                 logger.LogWarning($"More than one response received for query: {filter} with distinguished name: {distinguishedName}");
             }

+ 9 - 6
src/Security/Authentication/OpenIdConnect/src/OpenIdConnectHandler.cs

@@ -855,13 +855,16 @@ public class OpenIdConnectHandler : RemoteAuthenticationHandler<OpenIdConnectOpt
         var responseMessage = await Backchannel.SendAsync(requestMessage, Context.RequestAborted);
 
         var contentMediaType = responseMessage.Content.Headers.ContentType?.MediaType;
-        if (string.IsNullOrEmpty(contentMediaType))
+        if (Logger.IsEnabled(LogLevel.Debug))
         {
-            Logger.LogDebug($"Unexpected token response format. Status Code: {(int)responseMessage.StatusCode}. Content-Type header is missing.");
-        }
-        else if (!string.Equals(contentMediaType, "application/json", StringComparison.OrdinalIgnoreCase))
-        {
-            Logger.LogDebug($"Unexpected token response format. Status Code: {(int)responseMessage.StatusCode}. Content-Type {responseMessage.Content.Headers.ContentType}.");
+            if (string.IsNullOrEmpty(contentMediaType))
+            {
+                Logger.LogDebug($"Unexpected token response format. Status Code: {(int)responseMessage.StatusCode}. Content-Type header is missing.");
+            }
+            else if (!string.Equals(contentMediaType, "application/json", StringComparison.OrdinalIgnoreCase))
+            {
+                Logger.LogDebug($"Unexpected token response format. Status Code: {(int)responseMessage.StatusCode}. Content-Type {responseMessage.Content.Headers.ContentType}.");
+            }
         }
 
         // Error handling:

+ 2 - 2
src/Security/Authorization/Policy/src/AuthorizationMiddleware.cs

@@ -164,9 +164,9 @@ public class AuthorizationMiddleware
             return;
         }
 
-        if (authenticateResult != null && !authenticateResult.Succeeded)
+        if (authenticateResult != null && !authenticateResult.Succeeded && _logger is ILogger log && log.IsEnabled(LogLevel.Debug))
         {
-            _logger?.LogDebug("Policy authentication schemes {policyName} did not succeed", String.Join(", ", policy.AuthenticationSchemes));
+            log.LogDebug("Policy authentication schemes {policyName} did not succeed", String.Join(", ", policy.AuthenticationSchemes));
         }
 
         object? resource;

+ 8 - 2
src/Servers/Kestrel/Core/src/AnyIPListenOptions.cs

@@ -28,8 +28,14 @@ internal sealed class AnyIPListenOptions : ListenOptions
             // HttpsConnectionMiddleware.CreateHttp3Options, Http3 doesn't support OnAuthenticate.
             && ex is not NotSupportedException)
         {
-            context.Logger.LogTrace(ex, CoreStrings.FailedToBindToIPv6Any, IPEndPoint.Port);
-            context.Logger.LogDebug(CoreStrings.FallbackToIPv4Any, IPEndPoint.Port, IPEndPoint.Port);
+            if (context.Logger.IsEnabled(LogLevel.Trace))
+            {
+                context.Logger.LogTrace(ex, CoreStrings.FailedToBindToIPv6Any, IPEndPoint.Port);
+            }
+            if (context.Logger.IsEnabled(LogLevel.Debug))
+            {
+                context.Logger.LogDebug(CoreStrings.FallbackToIPv4Any, IPEndPoint.Port, IPEndPoint.Port);
+            }
 
             // for machines that do not support IPv6
             EndPoint = new IPEndPoint(IPAddress.Any, IPEndPoint.Port);

+ 12 - 4
src/Servers/Kestrel/Core/src/Internal/AddressBinder.cs

@@ -156,7 +156,10 @@ internal sealed class AddressBinder
             context.ServerOptions.ApplyEndpointDefaults(httpDefault);
             await httpDefault.BindAsync(context, cancellationToken).ConfigureAwait(false);
 
-            context.Logger.LogDebug(CoreStrings.BindingToDefaultAddress, Constants.DefaultServerAddress);
+            if (context.Logger.IsEnabled(LogLevel.Debug))
+            {
+                context.Logger.LogDebug(CoreStrings.BindingToDefaultAddress, Constants.DefaultServerAddress);
+            }
         }
     }
 
@@ -170,7 +173,10 @@ internal sealed class AddressBinder
         public override Task BindAsync(AddressBindContext context, CancellationToken cancellationToken)
         {
             var joined = string.Join(", ", _addresses);
-            context.Logger.LogInformation(CoreStrings.OverridingWithPreferHostingUrls, nameof(IServerAddressesFeature.PreferHostingUrls), joined);
+            if (context.Logger.IsEnabled(LogLevel.Information))
+            {
+                context.Logger.LogInformation(CoreStrings.OverridingWithPreferHostingUrls, nameof(IServerAddressesFeature.PreferHostingUrls), joined);
+            }
 
             return base.BindAsync(context, cancellationToken);
         }
@@ -188,8 +194,10 @@ internal sealed class AddressBinder
 
         public override Task BindAsync(AddressBindContext context, CancellationToken cancellationToken)
         {
-            var joined = string.Join(", ", _originalAddresses);
-            context.Logger.LogWarning(CoreStrings.OverridingWithKestrelOptions, joined);
+            if (context.Logger.IsEnabled(LogLevel.Warning))
+            {
+                context.Logger.LogWarning(CoreStrings.OverridingWithKestrelOptions, string.Join(", ", _originalAddresses));
+            }
 
             return base.BindAsync(context, cancellationToken);
         }

+ 12 - 3
src/Servers/Kestrel/Core/src/Internal/KestrelServerImpl.cs

@@ -348,7 +348,10 @@ internal sealed class KestrelServerImpl : IServer
             if (endpointsToStop.Count > 0)
             {
                 var urlsToStop = endpointsToStop.Select(lo => lo.EndpointConfig!.Url);
-                Trace.LogInformation("Config changed. Stopping the following endpoints: '{endpoints}'", string.Join("', '", urlsToStop));
+                if (Trace.IsEnabled(LogLevel.Information))
+                {
+                    Trace.LogInformation("Config changed. Stopping the following endpoints: '{endpoints}'", string.Join("', '", urlsToStop));
+                }
 
                 // 5 is the default value for WebHost's "shutdownTimeoutSeconds", so use that.
                 using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
@@ -373,7 +376,10 @@ internal sealed class KestrelServerImpl : IServer
             if (endpointsToStart.Count > 0)
             {
                 var urlsToStart = endpointsToStart.Select(lo => lo.EndpointConfig!.Url);
-                Trace.LogInformation("Config changed. Starting the following endpoints: '{endpoints}'", string.Join("', '", urlsToStart));
+                if (Trace.IsEnabled(LogLevel.Information))
+                {
+                    Trace.LogInformation("Config changed. Starting the following endpoints: '{endpoints}'", string.Join("', '", urlsToStart));
+                }
 
                 foreach (var listenOption in endpointsToStart)
                 {
@@ -383,7 +389,10 @@ internal sealed class KestrelServerImpl : IServer
                     }
                     catch (Exception ex)
                     {
-                        Trace.LogCritical(0, ex, "Unable to bind to '{url}' on config reload.", listenOption.EndpointConfig!.Url);
+                        if (Trace.IsEnabled(LogLevel.Critical))
+                        {
+                            Trace.LogCritical(0, ex, "Unable to bind to '{url}' on config reload.", listenOption.EndpointConfig!.Url);
+                        }
                     }
                 }
             }

+ 8 - 2
src/Servers/Kestrel/Core/src/LocalhostListenOptions.cs

@@ -37,7 +37,10 @@ internal sealed class LocalhostListenOptions : ListenOptions
         }
         catch (Exception ex) when (!(ex is IOException or OperationCanceledException))
         {
-            context.Logger.LogInformation(0, CoreStrings.NetworkInterfaceBindingFailed, GetDisplayName(), "IPv4 loopback", ex.Message);
+            if (context.Logger.IsEnabled(LogLevel.Information))
+            {
+                context.Logger.LogInformation(0, CoreStrings.NetworkInterfaceBindingFailed, GetDisplayName(), "IPv4 loopback", ex.Message);
+            }
             exceptions.Add(ex);
         }
 
@@ -48,7 +51,10 @@ internal sealed class LocalhostListenOptions : ListenOptions
         }
         catch (Exception ex) when (!(ex is IOException or OperationCanceledException))
         {
-            context.Logger.LogInformation(0, CoreStrings.NetworkInterfaceBindingFailed, GetDisplayName(), "IPv6 loopback", ex.Message);
+            if (context.Logger.IsEnabled(LogLevel.Information))
+            {
+                context.Logger.LogInformation(0, CoreStrings.NetworkInterfaceBindingFailed, GetDisplayName(), "IPv6 loopback", ex.Message);
+            }
             exceptions.Add(ex);
         }
 

+ 12 - 3
src/Shared/Http2cat/Http2CatHostedService.cs

@@ -65,11 +65,17 @@ internal sealed class Http2CatHostedService : IHostedService
 
             var endpoint = new IPEndPoint(ip, address.Port);
 
-            _logger.LogInformation($"Connecting to '{endpoint}'.");
+            if (_logger.IsEnabled(LogLevel.Information))
+            {
+                _logger.LogInformation($"Connecting to '{endpoint}'.");
+            }
 
             await using var context = await _connectionFactory.ConnectAsync(endpoint);
 
-            _logger.LogInformation($"Connected to '{endpoint}'.");
+            if (_logger.IsEnabled(LogLevel.Information))
+            {
+                _logger.LogInformation($"Connected to '{endpoint}'.");
+            }
 
             var originalTransport = context.Transport;
             IAsyncDisposable sslState = null;
@@ -95,7 +101,10 @@ internal sealed class Http2CatHostedService : IHostedService
                     EnabledSslProtocols = SslProtocols.Tls12,
                 }, CancellationToken.None);
 
-                _logger.LogInformation($"TLS handshake completed successfully.");
+                if (_logger.IsEnabled(LogLevel.Information))
+                {
+                    _logger.LogInformation($"TLS handshake completed successfully.");
+                }
             }
 
             var http2Utilities = new Http2Utilities(context, _logger, _stopTokenSource.Token);