소스 검색

Expand Blazor logging (#11919)

Steve Sanderson 6 년 전
부모
커밋
6534bcff32
29개의 변경된 파일322개의 추가작업 그리고 53개의 파일을 삭제
  1. 1 1
      src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.netstandard2.0.cs
  2. 4 1
      src/Components/Blazor/Blazor/src/Hosting/WebAssemblyBlazorApplicationBuilder.cs
  3. 4 2
      src/Components/Blazor/Blazor/src/Rendering/WebAssemblyRenderer.cs
  4. 2 1
      src/Components/Blazor/Build/test/RazorIntegrationTestBase.cs
  5. 2 1
      src/Components/Components/perf/RenderTreeDiffBuilderBenchmark.cs
  6. 3 3
      src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs
  7. 5 3
      src/Components/Components/src/Rendering/HtmlRenderer.cs
  8. 65 0
      src/Components/Components/src/Rendering/Renderer.Log.cs
  9. 31 7
      src/Components/Components/src/Rendering/Renderer.cs
  10. 38 1
      src/Components/Components/src/Routing/Router.cs
  11. 2 1
      src/Components/Components/test/RenderTreeBuilderTest.cs
  12. 2 1
      src/Components/Components/test/RenderTreeDiffBuilderTest.cs
  13. 2 1
      src/Components/Components/test/RendererTest.cs
  14. 2 1
      src/Components/Components/test/Rendering/HtmlRendererTests.cs
  15. 1 1
      src/Components/Server/src/Circuits/CircuitHost.cs
  16. 1 1
      src/Components/Server/src/Circuits/CircuitRegistry.cs
  17. 25 0
      src/Components/Server/src/Circuits/DefaultCircuitFactory.cs
  18. 50 11
      src/Components/Server/src/Circuits/RemoteRenderer.cs
  19. 22 5
      src/Components/Server/src/Circuits/RemoteUriHelper.cs
  20. 41 4
      src/Components/Server/src/ComponentHub.cs
  21. 1 1
      src/Components/Server/test/Circuits/CircuitHostTest.cs
  22. 1 0
      src/Components/Server/test/Circuits/RemoteRendererTest.cs
  23. 2 1
      src/Components/Server/test/Circuits/RenderBatchWriterTest.cs
  24. 1 0
      src/Components/Server/test/Circuits/TestCircuitHost.cs
  25. 3 2
      src/Components/Shared/test/TestRenderer.cs
  26. 3 1
      src/Components/test/Ignitor.Test/RenderBatchReaderTest.cs
  27. 2 1
      src/Components/test/testassets/Ignitor/RenderBatchReader.cs
  28. 3 1
      src/Mvc/Mvc.ViewFeatures/src/RazorComponents/StaticComponentRenderer.cs
  29. 3 0
      src/Mvc/Mvc.ViewFeatures/test/HtmlHelperComponentExtensionsTests.cs

+ 1 - 1
src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.netstandard2.0.cs

@@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
 {
     public partial class WebAssemblyRenderer : Microsoft.AspNetCore.Components.Rendering.Renderer
     {
-        public WebAssemblyRenderer(System.IServiceProvider serviceProvider) : base (default(System.IServiceProvider)) { }
+        public WebAssemblyRenderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) : base (default(System.IServiceProvider), default(Microsoft.Extensions.Logging.ILoggerFactory)) { }
         public System.Threading.Tasks.Task AddComponentAsync(System.Type componentType, string domElementSelector) { throw null; }
         public System.Threading.Tasks.Task AddComponentAsync<TComponent>(string domElementSelector) where TComponent : Microsoft.AspNetCore.Components.IComponent { throw null; }
         public override System.Threading.Tasks.Task DispatchEventAsync(int eventHandlerId, Microsoft.AspNetCore.Components.Rendering.EventFieldInfo eventFieldInfo, Microsoft.AspNetCore.Components.UIEventArgs eventArgs) { throw null; }

+ 4 - 1
src/Components/Blazor/Blazor/src/Hosting/WebAssemblyBlazorApplicationBuilder.cs

@@ -6,6 +6,8 @@ using System.Collections.Generic;
 using System.Threading.Tasks;
 using Microsoft.AspNetCore.Blazor.Rendering;
 using Microsoft.AspNetCore.Components.Builder;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
 
 namespace Microsoft.AspNetCore.Blazor.Hosting
 {
@@ -38,7 +40,8 @@ namespace Microsoft.AspNetCore.Blazor.Hosting
 
         public async Task<WebAssemblyRenderer> CreateRendererAsync()
         {
-            var renderer = new WebAssemblyRenderer(Services);
+            var loggerFactory = (ILoggerFactory)Services.GetService(typeof(ILoggerFactory));
+            var renderer = new WebAssemblyRenderer(Services, loggerFactory);
             for (var i = 0; i < Entries.Count; i++)
             {
                 var (componentType, domElementSelector) = Entries[i];

+ 4 - 2
src/Components/Blazor/Blazor/src/Rendering/WebAssemblyRenderer.cs

@@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Blazor.Services;
 using Microsoft.AspNetCore.Components;
 using Microsoft.AspNetCore.Components.Web;
 using Microsoft.AspNetCore.Components.Rendering;
+using Microsoft.Extensions.Logging;
 
 namespace Microsoft.AspNetCore.Blazor.Rendering
 {
@@ -26,8 +27,9 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
         /// Constructs an instance of <see cref="WebAssemblyRenderer"/>.
         /// </summary>
         /// <param name="serviceProvider">The <see cref="IServiceProvider"/> to use when initializing components.</param>
-        public WebAssemblyRenderer(IServiceProvider serviceProvider)
-            : base(serviceProvider)
+        /// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
+        public WebAssemblyRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory)
+            : base(serviceProvider, loggerFactory)
         {
             // The browser renderer registers and unregisters itself with the static
             // registry. This works well with the WebAssembly runtime, and is simple for the

+ 2 - 1
src/Components/Blazor/Build/test/RazorIntegrationTestBase.cs

@@ -20,6 +20,7 @@ using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
 using Microsoft.CodeAnalysis;
 using Microsoft.CodeAnalysis.CSharp;
 using Microsoft.CodeAnalysis.Razor;
+using Microsoft.Extensions.Logging.Abstractions;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Sdk;
@@ -441,7 +442,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
 
         protected class TestRenderer : Renderer
         {
-            public TestRenderer() : base(new TestServiceProvider(), CreateDefaultDispatcher())
+            public TestRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance, CreateDefaultDispatcher())
             {
             }
 

+ 2 - 1
src/Components/Components/perf/RenderTreeDiffBuilderBenchmark.cs

@@ -6,6 +6,7 @@ using System.Threading.Tasks;
 using BenchmarkDotNet.Attributes;
 using Microsoft.AspNetCore.Components.Rendering;
 using Microsoft.AspNetCore.Components.RenderTree;
+using Microsoft.Extensions.Logging.Abstractions;
 
 namespace Microsoft.AspNetCore.Components.Performance
 {
@@ -87,7 +88,7 @@ namespace Microsoft.AspNetCore.Components.Performance
         private class FakeRenderer : Renderer
         {
             public FakeRenderer()
-                : base(new TestServiceProvider(), new RendererSynchronizationContext())
+                : base(new TestServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
             {
             }
 

+ 3 - 3
src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs

@@ -674,7 +674,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
     }
     public partial class HtmlRenderer : Microsoft.AspNetCore.Components.Rendering.Renderer
     {
-        public HtmlRenderer(System.IServiceProvider serviceProvider, System.Func<string, string> htmlEncoder, Microsoft.AspNetCore.Components.IDispatcher dispatcher) : base (default(System.IServiceProvider)) { }
+        public HtmlRenderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.AspNetCore.Components.IDispatcher dispatcher, System.Func<string, string> htmlEncoder) : base (default(System.IServiceProvider), default(Microsoft.Extensions.Logging.ILoggerFactory)) { }
         protected override void HandleException(System.Exception exception) { }
         [System.Diagnostics.DebuggerStepThroughAttribute]
         public System.Threading.Tasks.Task<Microsoft.AspNetCore.Components.Rendering.ComponentRenderedText> RenderComponentAsync(System.Type componentType, Microsoft.AspNetCore.Components.ParameterCollection initialParameters) { throw null; }
@@ -692,8 +692,8 @@ namespace Microsoft.AspNetCore.Components.Rendering
     }
     public abstract partial class Renderer : System.IDisposable
     {
-        public Renderer(System.IServiceProvider serviceProvider) { }
-        public Renderer(System.IServiceProvider serviceProvider, Microsoft.AspNetCore.Components.IDispatcher dispatcher) { }
+        public Renderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
+        public Renderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.AspNetCore.Components.IDispatcher dispatcher) { }
         public event System.UnhandledExceptionEventHandler UnhandledSynchronizationException { add { } remove { } }
         protected internal virtual void AddToRenderQueue(int componentId, Microsoft.AspNetCore.Components.RenderFragment renderFragment) { }
         protected internal int AssignRootComponentId(Microsoft.AspNetCore.Components.IComponent component) { throw null; }

+ 5 - 3
src/Components/Components/src/Rendering/HtmlRenderer.cs

@@ -7,6 +7,7 @@ using System.Diagnostics;
 using System.Runtime.ExceptionServices;
 using System.Threading.Tasks;
 using Microsoft.AspNetCore.Components.RenderTree;
+using Microsoft.Extensions.Logging;
 
 namespace Microsoft.AspNetCore.Components.Rendering
 {
@@ -26,10 +27,11 @@ namespace Microsoft.AspNetCore.Components.Rendering
         /// Initializes a new instance of <see cref="HtmlRenderer"/>.
         /// </summary>
         /// <param name="serviceProvider">The <see cref="IServiceProvider"/> to use to instantiate components.</param>
+        /// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
+        /// <param name="dispatcher">The <see cref="IDispatcher"/> to be for invoking user actions into the <see cref="Renderer"/> context.</param>
         /// <param name="htmlEncoder">A <see cref="Func{T, TResult}"/> that will HTML encode the given string.</param>
-        /// <param name="dispatcher"></param>
-        public HtmlRenderer(IServiceProvider serviceProvider, Func<string, string> htmlEncoder, IDispatcher dispatcher)
-            : base(serviceProvider, dispatcher)
+        public HtmlRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory, IDispatcher dispatcher, Func<string, string> htmlEncoder)
+            : base(serviceProvider, loggerFactory, dispatcher)
         {
             _htmlEncoder = htmlEncoder;
         }

+ 65 - 0
src/Components/Components/src/Rendering/Renderer.Log.cs

@@ -0,0 +1,65 @@
+// 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;
+
+namespace Microsoft.AspNetCore.Components.Rendering
+{
+    public abstract partial class Renderer
+    {
+        internal static class Log
+        {
+            private static readonly Action<ILogger, int, Type, int, Type, Exception> _initializingChildComponent =
+                LoggerMessage.Define<int, Type, int, Type>(LogLevel.Debug, new EventId(1, "InitializingChildComponent"), "Initializing component {ComponentId} ({ComponentType}) as child of {ParentComponentId} ({ParentComponentId})");
+
+            private static readonly Action<ILogger, int, Type, Exception> _initializingRootComponent =
+                LoggerMessage.Define<int, Type>(LogLevel.Debug, new EventId(2, "InitializingRootComponent"), "Initializing root component {ComponentId} ({ComponentType})");
+
+            private static readonly Action<ILogger, int, Type, Exception> _renderingComponent =
+                LoggerMessage.Define<int, Type>(LogLevel.Debug, new EventId(3, "RenderingComponent"), "Rendering component {ComponentId} of type {ComponentType}");
+
+            private static readonly Action<ILogger, int, Type, Exception> _disposingComponent =
+                LoggerMessage.Define<int, Type>(LogLevel.Debug, new EventId(4, "DisposingComponent"), "Disposing component {ComponentId} of type {ComponentType}");
+
+            private static readonly Action<ILogger, int, string, Exception> _handlingEvent =
+                LoggerMessage.Define<int, string>(LogLevel.Debug, new EventId(5, "HandlingEvent"), "Handling event {EventId} of type '{EventType}'");
+
+            public static void InitializingComponent(ILogger logger, ComponentState componentState, ComponentState parentComponentState)
+            {
+                if (logger.IsEnabled(LogLevel.Debug)) // This is almost always false, so skip the evaluations
+                {
+                    if (parentComponentState == null)
+                    {
+                        _initializingRootComponent(logger, componentState.ComponentId, componentState.Component.GetType(), null);
+                    }
+                    else
+                    {
+                        _initializingChildComponent(logger, componentState.ComponentId, componentState.Component.GetType(), parentComponentState.ComponentId, parentComponentState.Component.GetType(), null);
+                    }
+                }
+            }
+
+            public static void RenderingComponent(ILogger logger, ComponentState componentState)
+            {
+                if (logger.IsEnabled(LogLevel.Debug)) // This is almost always false, so skip the evaluations
+                {
+                    _renderingComponent(logger, componentState.ComponentId, componentState.Component.GetType(), null);
+                }
+            }
+
+            internal static void DisposingComponent(ILogger<Renderer> logger, ComponentState componentState)
+            {
+                if (logger.IsEnabled(LogLevel.Debug)) // This is almost always false, so skip the evaluations
+                {
+                    _disposingComponent(logger, componentState.ComponentId, componentState.Component.GetType(), null);
+                }
+            }
+
+            internal static void HandlingEvent(ILogger<Renderer> logger, int eventHandlerId, UIEventArgs eventArgs)
+            {
+                _handlingEvent(logger, eventHandlerId, eventArgs?.Type ?? "null", null);
+            }
+        }
+    }
+}

+ 31 - 7
src/Components/Components/src/Rendering/Renderer.cs

@@ -7,6 +7,7 @@ using System.Diagnostics;
 using System.Threading;
 using System.Threading.Tasks;
 using Microsoft.AspNetCore.Components.RenderTree;
+using Microsoft.Extensions.Logging;
 
 namespace Microsoft.AspNetCore.Components.Rendering
 {
@@ -14,7 +15,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
     /// Provides mechanisms for rendering hierarchies of <see cref="IComponent"/> instances,
     /// dispatching events to them, and notifying when the user interface is being updated.
     /// </summary>
-    public abstract class Renderer : IDisposable
+    public abstract partial class Renderer : IDisposable
     {
         private readonly ComponentFactory _componentFactory;
         private readonly Dictionary<int, ComponentState> _componentStateById = new Dictionary<int, ComponentState>();
@@ -22,6 +23,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
         private readonly Dictionary<int, EventCallback> _eventBindings = new Dictionary<int, EventCallback>();
         private readonly Dictionary<int, int> _eventHandlerIdReplacements = new Dictionary<int, int>();
         private readonly IDispatcher _dispatcher;
+        private readonly ILogger<Renderer> _logger;
 
         private int _nextComponentId = 0; // TODO: change to 'long' when Mono .NET->JS interop supports it
         private bool _isBatchInProgress;
@@ -55,19 +57,33 @@ namespace Microsoft.AspNetCore.Components.Rendering
         /// Constructs an instance of <see cref="Renderer"/>.
         /// </summary>
         /// <param name="serviceProvider">The <see cref="IServiceProvider"/> to be used when initializing components.</param>
-        public Renderer(IServiceProvider serviceProvider)
+        /// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
+        public Renderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory)
         {
+            if (serviceProvider is null)
+            {
+                throw new ArgumentNullException(nameof(serviceProvider));
+            }
+
+            if (loggerFactory is null)
+            {
+                throw new ArgumentNullException(nameof(loggerFactory));
+            }
+
             _componentFactory = new ComponentFactory(serviceProvider);
+            _logger = loggerFactory.CreateLogger<Renderer>();
         }
 
         /// <summary>
         /// Constructs an instance of <see cref="Renderer"/>.
         /// </summary>
         /// <param name="serviceProvider">The <see cref="IServiceProvider"/> to be used when initializing components.</param>
+        /// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
         /// <param name="dispatcher">The <see cref="IDispatcher"/> to be for invoking user actions into the <see cref="Renderer"/> context.</param>
-        public Renderer(IServiceProvider serviceProvider, IDispatcher dispatcher) : this(serviceProvider)
+        public Renderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory, IDispatcher dispatcher)
+            : this(serviceProvider, loggerFactory)
         {
-            _dispatcher = dispatcher;
+            _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
         }
 
         /// <summary>
@@ -189,6 +205,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
             var componentId = _nextComponentId++;
             var parentComponentState = GetOptionalComponentState(parentComponentId);
             var componentState = new ComponentState(this, componentId, component, parentComponentState);
+            Log.InitializingComponent(_logger, componentState, parentComponentState);
             _componentStateById.Add(componentId, componentState);
             component.Configure(new RenderHandle(this, componentId));
             return componentState;
@@ -220,6 +237,8 @@ namespace Microsoft.AspNetCore.Components.Rendering
                 throw new ArgumentException($"There is no event handler with ID {eventHandlerId}");
             }
 
+            Log.HandlingEvent(_logger, eventHandlerId, eventArgs);
+
             if (fieldInfo != null)
             {
                 var latestEquivalentEventHandlerId = FindLatestEventHandlerIdInChain(eventHandlerId);
@@ -613,14 +632,17 @@ namespace Microsoft.AspNetCore.Components.Rendering
 
         private void RenderInExistingBatch(RenderQueueEntry renderQueueEntry)
         {
-            renderQueueEntry.ComponentState
-                .RenderIntoBatch(_batchBuilder, renderQueueEntry.RenderFragment);
+            var componentState = renderQueueEntry.ComponentState;
+            Log.RenderingComponent(_logger, componentState);
+            componentState.RenderIntoBatch(_batchBuilder, renderQueueEntry.RenderFragment);
 
             // Process disposal queue now in case it causes further component renders to be enqueued
             while (_batchBuilder.ComponentDisposalQueue.Count > 0)
             {
                 var disposeComponentId = _batchBuilder.ComponentDisposalQueue.Dequeue();
-                GetRequiredComponentState(disposeComponentId).DisposeInBatch(_batchBuilder);
+                var disposeComponentState = GetRequiredComponentState(disposeComponentId);
+                Log.DisposingComponent(_logger, disposeComponentState);
+                disposeComponentState.DisposeInBatch(_batchBuilder);
                 _componentStateById.Remove(disposeComponentId);
                 _batchBuilder.DisposedComponentIds.Append(disposeComponentId);
             }
@@ -710,6 +732,8 @@ namespace Microsoft.AspNetCore.Components.Rendering
         {
             foreach (var componentState in _componentStateById.Values)
             {
+                Log.DisposingComponent(_logger, componentState);
+
                 if (componentState.Component is IDisposable disposable)
                 {
                     try

+ 38 - 1
src/Components/Components/src/Routing/Router.cs

@@ -5,8 +5,9 @@ using System;
 using System.Collections.Generic;
 using System.Reflection;
 using System.Threading.Tasks;
-using Microsoft.AspNetCore.Components.Layouts;
 using Microsoft.AspNetCore.Components.RenderTree;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
 
 namespace Microsoft.AspNetCore.Components.Routing
 {
@@ -22,6 +23,7 @@ namespace Microsoft.AspNetCore.Components.Routing
         string _baseUri;
         string _locationAbsolute;
         bool _navigationInterceptionEnabled;
+        ILogger<Router> _logger;
 
         [Inject] private IUriHelper UriHelper { get; set; }
 
@@ -29,6 +31,8 @@ namespace Microsoft.AspNetCore.Components.Routing
 
         [Inject] private IComponentContext ComponentContext { get; set; }
 
+        [Inject] private ILoggerFactory LoggerFactory { get; set; }
+
         /// <summary>
         /// Gets or sets the assembly that should be searched, along with its referenced
         /// assemblies, for components matching the URI.
@@ -55,6 +59,7 @@ namespace Microsoft.AspNetCore.Components.Routing
         /// <inheritdoc />
         public void Configure(RenderHandle renderHandle)
         {
+            _logger = LoggerFactory.CreateLogger<Router>();
             _renderHandle = renderHandle;
             _baseUri = UriHelper.GetBaseUri();
             _locationAbsolute = UriHelper.GetAbsoluteUri();
@@ -111,12 +116,16 @@ namespace Microsoft.AspNetCore.Components.Routing
                         $"does not implement {typeof(IComponent).FullName}.");
                 }
 
+                Log.NavigatingToComponent(_logger, context.Handler, locationPath, _baseUri);
+
                 _renderHandle.Render(builder => Render(builder, context.Handler, context.Parameters));
             }
             else
             {
                 if (!isNavigationIntercepted && NotFoundContent != null)
                 {
+                    Log.DisplayingNotFoundContent(_logger, locationPath, _baseUri);
+
                     // We did not find a Component that matches the route.
                     // Only show the NotFoundContent if the application developer programatically got us here i.e we did not
                     // intercept the navigation. In all other cases, force a browser navigation since this could be non-Blazor content.
@@ -124,6 +133,7 @@ namespace Microsoft.AspNetCore.Components.Routing
                 }
                 else
                 {
+                    Log.NavigatingToExternalUri(_logger, _locationAbsolute, locationPath, _baseUri);
                     UriHelper.NavigateTo(_locationAbsolute, forceLoad: true);
                 }
             }
@@ -148,5 +158,32 @@ namespace Microsoft.AspNetCore.Components.Routing
 
             return Task.CompletedTask;
         }
+
+        private static class Log
+        {
+            private static readonly Action<ILogger, string, string, Exception> _displayingNotFoundContent =
+                LoggerMessage.Define<string, string>(LogLevel.Debug, new EventId(1, "DisplayingNotFoundContent"), $"Displaying {nameof(NotFoundContent)} because path '{{Path}}' with base URI '{{BaseUri}}' does not match any component route");
+
+            private static readonly Action<ILogger, Type, string, string, Exception> _navigatingToComponent =
+                LoggerMessage.Define<Type, string, string>(LogLevel.Debug, new EventId(2, "NavigatingToComponent"), "Navigating to component {ComponentType} in response to path '{Path}' with base URI '{BaseUri}'");
+
+            private static readonly Action<ILogger, string, string, string, Exception> _navigatingToExternalUri =
+                LoggerMessage.Define<string, string, string>(LogLevel.Debug, new EventId(3, "NavigatingToExternalUri"), "Navigating to non-component URI '{ExternalUri}' in response to path '{Path}' with base URI '{BaseUri}'");
+
+            internal static void DisplayingNotFoundContent(ILogger logger, string path, string baseUri)
+            {
+                _displayingNotFoundContent(logger, path, baseUri, null);
+            }
+
+            internal static void NavigatingToComponent(ILogger logger, Type componentType, string path, string baseUri)
+            {
+                _navigatingToComponent(logger, componentType, path, baseUri, null);
+            }
+
+            internal static void NavigatingToExternalUri(ILogger logger, string externalUri, string path, string baseUri)
+            {
+                _navigatingToExternalUri(logger, externalUri, path, baseUri, null);
+            }
+        }
     }
 }

+ 2 - 1
src/Components/Components/test/RenderTreeBuilderTest.cs

@@ -8,6 +8,7 @@ using System.Threading.Tasks;
 using Microsoft.AspNetCore.Components.Rendering;
 using Microsoft.AspNetCore.Components.RenderTree;
 using Microsoft.AspNetCore.Components.Test.Helpers;
+using Microsoft.Extensions.Logging.Abstractions;
 using Moq;
 using Xunit;
 
@@ -1794,7 +1795,7 @@ namespace Microsoft.AspNetCore.Components.Test
 
         private class TestRenderer : Renderer
         {
-            public TestRenderer() : base(new TestServiceProvider(), new RendererSynchronizationContext())
+            public TestRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
             {
             }
 

+ 2 - 1
src/Components/Components/test/RenderTreeDiffBuilderTest.cs

@@ -8,6 +8,7 @@ using System.Threading.Tasks;
 using Microsoft.AspNetCore.Components.Rendering;
 using Microsoft.AspNetCore.Components.RenderTree;
 using Microsoft.AspNetCore.Components.Test.Helpers;
+using Microsoft.Extensions.Logging.Abstractions;
 using Xunit;
 
 namespace Microsoft.AspNetCore.Components.Test
@@ -2207,7 +2208,7 @@ namespace Microsoft.AspNetCore.Components.Test
 
         private class FakeRenderer : Renderer
         {
-            public FakeRenderer() : base(new TestServiceProvider(), new RendererSynchronizationContext())
+            public FakeRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
             {
             }
 

+ 2 - 1
src/Components/Components/test/RendererTest.cs

@@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Components.RenderTree;
 using Microsoft.AspNetCore.Components.Test.Helpers;
 using Microsoft.AspNetCore.Testing;
 using Microsoft.AspNetCore.Testing.xunit;
+using Microsoft.Extensions.Logging.Abstractions;
 using Xunit;
 
 namespace Microsoft.AspNetCore.Components.Test
@@ -3372,7 +3373,7 @@ namespace Microsoft.AspNetCore.Components.Test
 
         private class NoOpRenderer : Renderer
         {
-            public NoOpRenderer() : base(new TestServiceProvider(), new RendererSynchronizationContext())
+            public NoOpRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
             {
             }
 

+ 2 - 1
src/Components/Components/test/Rendering/HtmlRendererTests.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;
+using Microsoft.Extensions.Logging.Abstractions;
 
 namespace Microsoft.AspNetCore.Components.Rendering
 {
@@ -9,7 +10,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
     {
         protected override HtmlRenderer GetHtmlRenderer(IServiceProvider serviceProvider)
         {
-            return new HtmlRenderer(serviceProvider, _encoder, Dispatcher);
+            return new HtmlRenderer(serviceProvider, NullLoggerFactory.Instance, Dispatcher, _encoder);
         }
     }
 }

+ 1 - 1
src/Components/Server/src/Circuits/CircuitHost.cs

@@ -351,7 +351,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
                     "Unhandled error invoking circuit handler type {handlerType}.{handlerMethod}: {Message}");
 
                 _disposingCircuit = LoggerMessage.Define<string>(
-                    LogLevel.Trace,
+                    LogLevel.Debug,
                     EventIds.DisposingCircuit,
                     "Disposing circuit with identifier {CircuitId}");
 

+ 1 - 1
src/Components/Server/src/Circuits/CircuitRegistry.cs

@@ -340,7 +340,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
                     "Unhandled exception disposing circuit host: {Message}");
 
                 _unhandledExceptionDisposingTokenSource = LoggerMessage.Define<string>(
-                    LogLevel.Trace,
+                    LogLevel.Debug,
                     EventIds.ExceptionDisposingTokenSource,
                     "Exception thrown when disposing token source: {Message}");
 

+ 25 - 0
src/Components/Server/src/Circuits/DefaultCircuitFactory.cs

@@ -21,6 +21,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
     {
         private readonly IServiceScopeFactory _scopeFactory;
         private readonly ILoggerFactory _loggerFactory;
+        private readonly ILogger _logger;
         private readonly CircuitIdFactory _circuitIdFactory;
 
         public DefaultCircuitFactory(
@@ -30,6 +31,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
         {
             _scopeFactory = scopeFactory ?? throw new ArgumentNullException(nameof(scopeFactory));
             _loggerFactory = loggerFactory;
+            _logger = _loggerFactory.CreateLogger<CircuitFactory>();
             _circuitIdFactory = circuitIdFactory ?? throw new ArgumentNullException(nameof(circuitIdFactory));
         }
 
@@ -72,6 +74,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
             var dispatcher = Renderer.CreateDefaultDispatcher();
             var renderer = new RemoteRenderer(
                 scope.ServiceProvider,
+                _loggerFactory,
                 rendererRegistry,
                 jsRuntime,
                 client,
@@ -94,6 +97,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
                 jsRuntime,
                 circuitHandlers,
                 _loggerFactory.CreateLogger<CircuitHost>());
+            Log.CreatedCircuit(_logger, circuitHost);
 
             // Initialize per - circuit data that services need
             (circuitHost.Services.GetRequiredService<ICircuitAccessor>() as DefaultCircuitAccessor).Circuit = circuitHost.Circuit;
@@ -124,5 +128,26 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
                 return componentsMetadata;
             }
         }
+
+        private static class Log
+        {
+            private static readonly Action<ILogger, string, string, Exception> _createdConnectedCircuit =
+                LoggerMessage.Define<string, string>(LogLevel.Debug, new EventId(1, "CreatedConnectedCircuit"), "Created circuit {CircuitId} for connection {ConnectionId}");
+
+            private static readonly Action<ILogger, string, Exception> _createdDisconnectedCircuit =
+                LoggerMessage.Define<string>(LogLevel.Debug, new EventId(2, "CreatedDisconnectedCircuit"), "Created circuit {CircuitId} for disconnected client");
+
+            internal static void CreatedCircuit(ILogger logger, CircuitHost circuitHost)
+            {
+                if (circuitHost.Client.Connected)
+                {
+                    _createdConnectedCircuit(logger, circuitHost.CircuitId, circuitHost.Client.ConnectionId, null);
+                }
+                else
+                {
+                    _createdDisconnectedCircuit(logger, circuitHost.CircuitId, null);
+                }
+            }
+        }
     }
 }

+ 50 - 11
src/Components/Server/src/Circuits/RemoteRenderer.cs

@@ -37,13 +37,14 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
         /// </summary>
         public RemoteRenderer(
             IServiceProvider serviceProvider,
+            ILoggerFactory loggerFactory,
             RendererRegistry rendererRegistry,
             IJSRuntime jsRuntime,
             CircuitClientProxy client,
             IDispatcher dispatcher,
             HtmlEncoder encoder,
             ILogger logger)
-            : base(serviceProvider, encoder.Encode, dispatcher)
+            : base(serviceProvider, loggerFactory, dispatcher, encoder.Encode)
         {
             _rendererRegistry = rendererRegistry;
             _jsRuntime = jsRuntime;
@@ -179,7 +180,7 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
                     return;
                 }
 
-                Log.BeginUpdateDisplayAsync(_logger, _client.ConnectionId);
+                Log.BeginUpdateDisplayAsync(_logger, _client.ConnectionId, pending.BatchId, pending.Data.Length);
                 await _client.SendAsync("JS.RenderBatch", Id, pending.BatchId, pending.Data);
             }
             catch (Exception e)
@@ -212,10 +213,15 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
             }
             else
             {
-                var message = $"Completing batch {entry.BatchId} " +
-                    (errorMessageOrNull == null ? "without error." : "with error.");
+                if (errorMessageOrNull == null)
+                {
+                    Log.CompletingBatchWithoutError(_logger, entry.BatchId);
+                }
+                else
+                {
+                    Log.CompletingBatchWithError(_logger, entry.BatchId, errorMessageOrNull);
+                }
 
-                _logger.LogDebug(message);
                 CompleteRender(entry.CompletionSource, errorMessageOrNull);
             }
         }
@@ -260,9 +266,11 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
         private static class Log
         {
             private static readonly Action<ILogger, string, Exception> _unhandledExceptionRenderingComponent;
-            private static readonly Action<ILogger, string, Exception> _beginUpdateDisplayAsync;
+            private static readonly Action<ILogger, long, int, string, Exception> _beginUpdateDisplayAsync;
             private static readonly Action<ILogger, string, Exception> _bufferingRenderDisconnectedClient;
             private static readonly Action<ILogger, string, Exception> _sendBatchDataFailed;
+            private static readonly Action<ILogger, long, string, Exception> _completingBatchWithError;
+            private static readonly Action<ILogger, long, Exception> _completingBatchWithoutError;
 
             private static class EventIds
             {
@@ -270,6 +278,8 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
                 public static readonly EventId BeginUpdateDisplayAsync = new EventId(101, "BeginUpdateDisplayAsync");
                 public static readonly EventId SkipUpdateDisplayAsync = new EventId(102, "SkipUpdateDisplayAsync");
                 public static readonly EventId SendBatchDataFailed = new EventId(103, "SendBatchDataFailed");
+                public static readonly EventId CompletingBatchWithError = new EventId(104, "CompletingBatchWithError");
+                public static readonly EventId CompletingBatchWithoutError = new EventId(105, "CompletingBatchWithoutError");
             }
 
             static Log()
@@ -279,13 +289,13 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
                     EventIds.UnhandledExceptionRenderingComponent,
                     "Unhandled exception rendering component: {Message}");
 
-                _beginUpdateDisplayAsync = LoggerMessage.Define<string>(
-                    LogLevel.Trace,
+                _beginUpdateDisplayAsync = LoggerMessage.Define<long, int, string>(
+                    LogLevel.Debug,
                     EventIds.BeginUpdateDisplayAsync,
-                    "Begin remote rendering of components on client {ConnectionId}.");
+                    "Sending render batch {BatchId} of size {DataLength} bytes to client {ConnectionId}.");
 
                 _bufferingRenderDisconnectedClient = LoggerMessage.Define<string>(
-                    LogLevel.Trace,
+                    LogLevel.Debug,
                     EventIds.SkipUpdateDisplayAsync,
                     "Buffering remote render because the client on connection {ConnectionId} is disconnected.");
 
@@ -293,6 +303,16 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
                     LogLevel.Information,
                     EventIds.SendBatchDataFailed,
                     "Sending data for batch failed: {Message}");
+
+                _completingBatchWithError = LoggerMessage.Define<long, string>(
+                    LogLevel.Debug,
+                    EventIds.CompletingBatchWithError,
+                    "Completing batch {BatchId} with error: {ErrorMessage}");
+
+                _completingBatchWithoutError = LoggerMessage.Define<long>(
+                    LogLevel.Debug,
+                    EventIds.CompletingBatchWithoutError,
+                    "Completing batch {BatchId} without error");
             }
 
             public static void SendBatchDataFailed(ILogger logger, Exception exception)
@@ -308,10 +328,12 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
                     exception);
             }
 
-            public static void BeginUpdateDisplayAsync(ILogger logger, string connectionId)
+            public static void BeginUpdateDisplayAsync(ILogger logger, string connectionId, long batchId, int dataLength)
             {
                 _beginUpdateDisplayAsync(
                     logger,
+                    batchId,
+                    dataLength,
                     connectionId,
                     null);
             }
@@ -323,6 +345,23 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
                     connectionId,
                     null);
             }
+
+            public static void CompletingBatchWithError(ILogger logger, long batchId, string errorMessage)
+            {
+                _completingBatchWithError(
+                    logger,
+                    batchId,
+                    errorMessage,
+                    null);
+            }
+
+            public static void CompletingBatchWithoutError(ILogger logger, long batchId)
+            {
+                _completingBatchWithoutError(
+                    logger,
+                    batchId,
+                    null);
+            }
         }
     }
 }

+ 22 - 5
src/Components/Server/src/Circuits/RemoteUriHelper.cs

@@ -59,8 +59,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
                 Interop.ListenForNavigationEvents,
                 typeof(RemoteUriHelper).Assembly.GetName().Name,
                 nameof(NotifyLocationChanged));
-
-            _logger.LogDebug($"{nameof(RemoteUriHelper)} initialized.");
         }
 
         /// <summary>
@@ -75,18 +73,18 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
                 var message = $"{nameof(NotifyLocationChanged)} called without a circuit.";
                 throw new InvalidOperationException(message);
             }
+
             var uriHelper = (RemoteUriHelper)circuit.Services.GetRequiredService<IUriHelper>();
+            Log.ReceivedLocationChangedNotification(uriHelper._logger, uriAbsolute, isInterceptedLink);
 
             uriHelper.SetAbsoluteUri(uriAbsolute);
-
-            uriHelper._logger.LogDebug($"Location changed to '{uriAbsolute}'.");
             uriHelper.TriggerOnLocationChanged(isInterceptedLink);
         }
 
         /// <inheritdoc />
         protected override void NavigateToCore(string uri, bool forceLoad)
         {
-            _logger.LogDebug($"{uri} force load {forceLoad}.");
+            Log.RequestingNavigation(_logger, uri, forceLoad);
 
             if (_jsRuntime == null)
             {
@@ -94,5 +92,24 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
             }
             _jsRuntime.InvokeAsync<object>(Interop.NavigateTo, uri, forceLoad);
         }
+
+        private static class Log
+        {
+            private static readonly Action<ILogger, string, bool, Exception> _requestingNavigation =
+                LoggerMessage.Define<string, bool>(LogLevel.Debug, new EventId(1, "RequestingNavigation"), "Requesting navigation to URI {Uri} with forceLoad={ForceLoad}");
+
+            private static readonly Action<ILogger, string, bool, Exception> _receivedLocationChangedNotification =
+                LoggerMessage.Define<string, bool>(LogLevel.Debug, new EventId(2, "ReceivedLocationChangedNotification"), "Received notification that the URI has changed to {Uri} with isIntercepted={IsIntercepted}");
+
+            public static void RequestingNavigation(ILogger logger, string uri, bool forceLoad)
+            {
+                _requestingNavigation(logger, uri, forceLoad, null);
+            }
+
+            public static void ReceivedLocationChangedNotification(ILogger logger, string uri, bool isIntercepted)
+            {
+                _receivedLocationChangedNotification(logger, uri, isIntercepted, null);
+            }
+        }
     }
 }

+ 41 - 4
src/Components/Server/src/ComponentHub.cs

@@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Components.Server
                 var endpointFeature = Context.GetHttpContext().Features.Get<IEndpointFeature>();
                 var endpoint = endpointFeature?.Endpoint;
 
-                _logger.LogDebug($"No components registered in the current endpoint '{endpoint.DisplayName}'.");
+                Log.NoComponentsRegisteredInEndpoint(_logger, endpoint.DisplayName);
 
                 // No components preregistered so return. This is totally normal if the components were prerendered.
                 return null;
@@ -131,16 +131,18 @@ namespace Microsoft.AspNetCore.Components.Server
         /// </summary>
         public void OnRenderCompleted(long renderId, string errorMessageOrNull)
         {
-            _logger.LogDebug($"Received confirmation for batch {renderId}.");
+            Log.ReceivedConfirmationForBatch(_logger, renderId);
             EnsureCircuitHost().Renderer.OnRenderCompleted(renderId, errorMessageOrNull);
         }
 
         private async void CircuitHost_UnhandledException(object sender, UnhandledExceptionEventArgs e)
         {
             var circuitHost = (CircuitHost)sender;
+            var circuitId = circuitHost?.CircuitId;
+
             try
             {
-                _logger.LogWarning((Exception)e.ExceptionObject, "Unhandled Server-Side exception");
+                Log.UnhandledExceptionInCircuit(_logger, circuitId, (Exception)e.ExceptionObject);
                 await circuitHost.Client.SendAsync("JS.Error", e.ExceptionObject);
 
                 // We generally can't abort the connection here since this is an async
@@ -149,7 +151,7 @@ namespace Microsoft.AspNetCore.Components.Server
             }
             catch (Exception ex)
             {
-                _logger.LogError(ex, "Failed to transmit exception to client");
+                Log.FailedToTransmitException(_logger, circuitId, ex);
             }
         }
 
@@ -164,5 +166,40 @@ namespace Microsoft.AspNetCore.Components.Server
 
             return circuitHost;
         }
+
+        private static class Log
+        {
+            private static readonly Action<ILogger, string, Exception> _noComponentsRegisteredInEndpoint =
+                LoggerMessage.Define<string>(LogLevel.Debug, new EventId(1, "NoComponentsRegisteredInEndpoint"), "No components registered in the current endpoint '{Endpoint}'");
+
+            private static readonly Action<ILogger, long, Exception> _receivedConfirmationForBatch =
+                LoggerMessage.Define<long>(LogLevel.Debug, new EventId(2, "ReceivedConfirmationForBatch"), "Received confirmation for batch {BatchId}");
+
+            private static readonly Action<ILogger, string, Exception> _unhandledExceptionInCircuit =
+                LoggerMessage.Define<string>(LogLevel.Warning, new EventId(3, "UnhandledExceptionInCircuit"), "Unhandled exception in circuit {CircuitId}");
+
+            private static readonly Action<ILogger, string, Exception> _failedToTransmitException =
+                LoggerMessage.Define<string>(LogLevel.Debug, new EventId(4, "FailedToTransmitException"), "Failed to transmit exception to client in circuit {CircuitId}");
+
+            public static void NoComponentsRegisteredInEndpoint(ILogger logger, string endpointDisplayName)
+            {
+                _noComponentsRegisteredInEndpoint(logger, endpointDisplayName, null);
+            }
+
+            public static void ReceivedConfirmationForBatch(ILogger logger, long batchId)
+            {
+                _receivedConfirmationForBatch(logger, batchId, null);
+            }
+
+            public static void UnhandledExceptionInCircuit(ILogger logger, string circuitId, Exception exception)
+            {
+                _unhandledExceptionInCircuit(logger, circuitId, exception);
+            }
+
+            public static void FailedToTransmitException(ILogger logger, string circuitId, Exception transmissionException)
+            {
+                _failedToTransmitException(logger, circuitId, transmissionException);
+            }
+        }
     }
 }

+ 1 - 1
src/Components/Server/test/Circuits/CircuitHostTest.cs

@@ -242,7 +242,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
         private class TestRemoteRenderer : RemoteRenderer
         {
             public TestRemoteRenderer(IServiceProvider serviceProvider, RendererRegistry rendererRegistry, IDispatcher dispatcher, IJSRuntime jsRuntime, IClientProxy client)
-                : base(serviceProvider, rendererRegistry, jsRuntime, new CircuitClientProxy(client, "connection"), dispatcher, HtmlEncoder.Default, NullLogger.Instance)
+                : base(serviceProvider, NullLoggerFactory.Instance, rendererRegistry, jsRuntime, new CircuitClientProxy(client, "connection"), dispatcher, HtmlEncoder.Default, NullLogger.Instance)
             {
             }
 

+ 1 - 0
src/Components/Server/test/Circuits/RemoteRendererTest.cs

@@ -264,6 +264,7 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
 
             return new RemoteRenderer(
                 serviceProvider,
+                NullLoggerFactory.Instance,
                 new RendererRegistry(),
                 jsRuntime.Object,
                 circuitClientProxy,

+ 2 - 1
src/Components/Server/test/Circuits/RenderBatchWriterTest.cs

@@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Components.Rendering;
 using Microsoft.AspNetCore.Components.RenderTree;
 using Microsoft.AspNetCore.Components.Server.Circuits;
 using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging.Abstractions;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -375,7 +376,7 @@ namespace Microsoft.AspNetCore.Components.Server
         class FakeRenderer : Renderer
         {
             public FakeRenderer()
-                : base(new ServiceCollection().BuildServiceProvider(), new RendererSynchronizationContext())
+                : base(new ServiceCollection().BuildServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
             {
             }
 

+ 1 - 0
src/Components/Server/test/Circuits/TestCircuitHost.cs

@@ -46,6 +46,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
             {
                 remoteRenderer = new RemoteRenderer(
                     serviceScope.ServiceProvider ?? Mock.Of<IServiceProvider>(),
+                    NullLoggerFactory.Instance,
                     new RendererRegistry(),
                     jsRuntime,
                     clientProxy,

+ 3 - 2
src/Components/Shared/test/TestRenderer.cs

@@ -7,6 +7,7 @@ using System.Linq;
 using System.Runtime.ExceptionServices;
 using System.Threading.Tasks;
 using Microsoft.AspNetCore.Components.Rendering;
+using Microsoft.Extensions.Logging.Abstractions;
 using Xunit;
 
 namespace Microsoft.AspNetCore.Components.Test.Helpers
@@ -17,11 +18,11 @@ namespace Microsoft.AspNetCore.Components.Test.Helpers
         {
         }
 
-        public TestRenderer(IDispatcher dispatcher) : base(new TestServiceProvider(), dispatcher)
+        public TestRenderer(IDispatcher dispatcher) : base(new TestServiceProvider(), NullLoggerFactory.Instance, dispatcher)
         {
         }
 
-        public TestRenderer(IServiceProvider serviceProvider) : base(serviceProvider, new RendererSynchronizationContext())
+        public TestRenderer(IServiceProvider serviceProvider) : base(serviceProvider, NullLoggerFactory.Instance, new RendererSynchronizationContext())
         {
         }
 

+ 3 - 1
src/Components/test/Ignitor.Test/RenderBatchReaderTest.cs

@@ -6,11 +6,13 @@ using System.Collections.Generic;
 using System.IO;
 using System.Text;
 using System.Threading.Tasks;
+using Castle.Core.Logging;
 using Microsoft.AspNetCore.Components;
 using Microsoft.AspNetCore.Components.Rendering;
 using Microsoft.AspNetCore.Components.RenderTree;
 using Microsoft.AspNetCore.Components.Server.Circuits;
 using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging.Abstractions;
 using Xunit;
 
 namespace Ignitor
@@ -333,7 +335,7 @@ namespace Ignitor
         class FakeRenderer : Renderer
         {
             public FakeRenderer()
-                : base(new ServiceCollection().BuildServiceProvider(), new RendererSynchronizationContext())
+                : base(new ServiceCollection().BuildServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
             {
             }
 

+ 2 - 1
src/Components/test/testassets/Ignitor/RenderBatchReader.cs

@@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Components;
 using Microsoft.AspNetCore.Components.Rendering;
 using Microsoft.AspNetCore.Components.RenderTree;
 using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging.Abstractions;
 
 namespace Ignitor
 {
@@ -288,7 +289,7 @@ namespace Ignitor
         public class FakeRenderer : Renderer
         {
             public FakeRenderer()
-                : base(new ServiceCollection().BuildServiceProvider(), new RendererSynchronizationContext())
+                : base(new ServiceCollection().BuildServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
             {
             }
 

+ 3 - 1
src/Mvc/Mvc.ViewFeatures/src/RazorComponents/StaticComponentRenderer.cs

@@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http.Extensions;
 using Microsoft.AspNetCore.Http.Features;
 using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
 
 namespace Microsoft.AspNetCore.Mvc.ViewFeatures.RazorComponents
 {
@@ -32,7 +33,8 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.RazorComponents
             var dispatcher = Renderer.CreateDefaultDispatcher();
 
             InitializeUriHelper(httpContext);
-            using (var htmlRenderer = new HtmlRenderer(httpContext.RequestServices, _encoder.Encode, dispatcher))
+            var loggerFactory = (ILoggerFactory)httpContext.RequestServices.GetService(typeof (ILoggerFactory));
+            using (var htmlRenderer = new HtmlRenderer(httpContext.RequestServices, loggerFactory, dispatcher, _encoder.Encode))
             {
                 ComponentRenderedText result = default;
                 try

+ 3 - 0
src/Mvc/Mvc.ViewFeatures/test/HtmlHelperComponentExtensionsTests.cs

@@ -13,6 +13,8 @@ using Microsoft.AspNetCore.Http.Features;
 using Microsoft.AspNetCore.Mvc.Rendering;
 using Microsoft.AspNetCore.Mvc.ViewFeatures.RazorComponents;
 using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
 using Microsoft.JSInterop;
 using Microsoft.Net.Http.Headers;
 using Moq;
@@ -224,6 +226,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Test
             services.AddSingleton<IJSRuntime,UnsupportedJavaScriptRuntime>();
             services.AddSingleton<IUriHelper,HttpUriHelper>();
             services.AddSingleton<StaticComponentRenderer>();
+            services.AddSingleton<ILoggerFactory, NullLoggerFactory>();
 
             configureServices?.Invoke(services);