Browse Source

Refactor logging mechanism and enhance orphan module warning tests

pull/25223/head
maliming 2 weeks ago
parent
commit
36691ec106
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 15
      framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacRegistration.cs
  2. 11
      framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs
  3. 2
      framework/src/Volo.Abp.Core/Volo/Abp/Logging/AbpInitLogEntry.cs
  4. 1
      framework/src/Volo.Abp.Core/Volo/Abp/Logging/DefaultInitLogger.cs
  5. 22
      framework/src/Volo.Abp.Core/Volo/Abp/Logging/DefaultInitLoggerFactory.cs
  6. 8
      framework/src/Volo.Abp.Core/Volo/Abp/Logging/IInitLoggerFactory.cs
  7. 24
      framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/WarnForOrphanedAbpModules_Tests.cs

15
framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacRegistration.cs

@ -396,21 +396,30 @@ public static class AutofacRegistration
return;
}
var logger = services.GetInitLogger<AbpAutofacServiceProviderFactory>();
var logger = services.GetInitLogger<AbpAutofacModule>();
var loadedModuleTypes = new HashSet<Type>(
moduleContainer.Modules.Select(m => m.Type));
// Only assemblies that directly reference Volo.Abp.Core can contain AbpModule subclasses.
// This skips framework/third-party assemblies (Microsoft.Extensions.*, etc.) cheaply.
var abpCoreAssemblyName = typeof(AbpModule).Assembly.GetName().Name;
foreach (var assembly in nonModuleAssemblies)
{
if (!assembly.GetReferencedAssemblies().Any(r => r.Name == abpCoreAssemblyName))
{
continue;
}
Type[] types;
try
{
types = assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
catch (Exception)
{
types = ex.Types.Where(t => t != null).ToArray()!;
continue;
}
foreach (var type in types)

11
framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs

@ -128,20 +128,21 @@ public abstract class AbpApplicationBase : IAbpApplication
protected virtual void WriteInitLogs(IServiceProvider serviceProvider)
{
var logger = serviceProvider.GetService<ILogger<AbpApplicationBase>>();
if (logger == null)
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
if (loggerFactory == null)
{
return;
}
var initLogger = serviceProvider.GetRequiredService<IInitLoggerFactory>().Create<AbpApplicationBase>();
var initLoggerFactory = serviceProvider.GetRequiredService<IInitLoggerFactory>();
foreach (var entry in initLogger.Entries)
foreach (var entry in initLoggerFactory.GetAllEntries())
{
var logger = loggerFactory.CreateLogger(entry.CategoryName);
logger.Log(entry.LogLevel, entry.EventId, entry.State, entry.Exception, entry.Formatter);
}
initLogger.Entries.Clear();
initLoggerFactory.ClearAllEntries();
}
protected virtual IReadOnlyList<IAbpModuleDescriptor> LoadModules(IServiceCollection services, AbpApplicationCreationOptions options)

2
framework/src/Volo.Abp.Core/Volo/Abp/Logging/AbpInitLogEntry.cs

@ -5,6 +5,8 @@ namespace Volo.Abp.Logging;
public class AbpInitLogEntry
{
public string CategoryName { get; set; } = default!;
public LogLevel LogLevel { get; set; }
public EventId EventId { get; set; }

1
framework/src/Volo.Abp.Core/Volo/Abp/Logging/DefaultInitLogger.cs

@ -17,6 +17,7 @@ public class DefaultInitLogger<T> : IInitLogger<T>
{
Entries.Add(new AbpInitLogEntry
{
CategoryName = typeof(T).FullName!,
LogLevel = logLevel,
EventId = eventId,
State = state!,

22
framework/src/Volo.Abp.Core/Volo/Abp/Logging/DefaultInitLoggerFactory.cs

@ -1,14 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Volo.Abp.Logging;
public class DefaultInitLoggerFactory : IInitLoggerFactory
{
private readonly Dictionary<Type, object> _cache = [];
private readonly List<List<AbpInitLogEntry>> _entryLists = [];
public virtual IInitLogger<T> Create<T>()
{
return (IInitLogger<T>)_cache.GetOrAdd(typeof(T), () => new DefaultInitLogger<T>());
return (IInitLogger<T>)_cache.GetOrAdd(typeof(T), () =>
{
var logger = new DefaultInitLogger<T>();
_entryLists.Add(logger.Entries);
return logger;
});
}
public virtual List<AbpInitLogEntry> GetAllEntries()
{
return _entryLists.SelectMany(l => l).ToList();
}
public virtual void ClearAllEntries()
{
foreach (var list in _entryLists)
{
list.Clear();
}
}
}

8
framework/src/Volo.Abp.Core/Volo/Abp/Logging/IInitLoggerFactory.cs

@ -1,6 +1,12 @@
namespace Volo.Abp.Logging;
using System.Collections.Generic;
namespace Volo.Abp.Logging;
public interface IInitLoggerFactory
{
IInitLogger<T> Create<T>();
List<AbpInitLogEntry> GetAllEntries();
void ClearAllEntries();
}

24
framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/WarnForOrphanedAbpModules_Tests.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@ -13,19 +14,27 @@ namespace Volo.Abp.Autofac;
public class WarnForOrphanedAbpModules_Tests : AbpIntegratedTest<WarnForOrphanedAbpModules_Tests.TestModule>
{
private static readonly Type OrphanModuleType = typeof(AbpTestModule);
private List<AbpInitLogEntry> _initLogEntries = [];
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
protected override IServiceProvider CreateServiceProvider(IServiceCollection services)
{
var serviceProvider = base.CreateServiceProvider(services);
// Capture init log entries after Autofac Populate/Register but before WriteInitLogs clears them.
_initLogEntries = serviceProvider.GetRequiredService<IInitLoggerFactory>().GetAllEntries();
return serviceProvider;
}
[Fact]
public void Should_Warn_For_Orphaned_Abp_Modules()
{
var initLoggerFactory = GetRequiredService<IInitLoggerFactory>();
var logger = initLoggerFactory.Create<AbpAutofacServiceProviderFactory>();
logger.Entries
_initLogEntries
.Where(e => e.LogLevel == LogLevel.Warning)
.ShouldContain(e => e.Message.Contains(OrphanModuleType.FullName!),
$"Expected a warning for orphaned module '{OrphanModuleType.FullName}'.");
@ -34,11 +43,7 @@ public class WarnForOrphanedAbpModules_Tests : AbpIntegratedTest<WarnForOrphaned
[Fact]
public void Should_Not_Warn_For_Loaded_Modules()
{
var initLoggerFactory = GetRequiredService<IInitLoggerFactory>();
var logger = initLoggerFactory.Create<AbpAutofacServiceProviderFactory>();
// AbpAutofacModule IS in the DependsOn chain, so it should NOT trigger a warning.
logger.Entries
_initLogEntries
.Where(e => e.LogLevel == LogLevel.Warning)
.ShouldNotContain(e => e.Message.Contains(typeof(AbpAutofacModule).FullName!),
"Modules in the [DependsOn] chain should not be reported as orphaned.");
@ -51,7 +56,6 @@ public class WarnForOrphanedAbpModules_Tests : AbpIntegratedTest<WarnForOrphaned
{
// Simulate ASP.NET Core's AddControllersAsServices() registering a type
// from an assembly whose ABP module is NOT in the [DependsOn] chain.
// AbpTestModule lives in the Volo.Abp.Core.Tests assembly which is not depended on.
context.Services.AddTransient<AbpTestModule>();
}
}

Loading…
Cancel
Save