Skip to content

Latest commit

 

History

History
74 lines (57 loc) · 3.1 KB

File metadata and controls

74 lines (57 loc) · 3.1 KB

Plugin Logging Fix Summary

Problem

Plugin logging was not working because the plugin loader was unable to inject ILogger dependencies into plugin constructors, causing all plugins to fall back to parameterless constructors where _logger remained null.

Root Cause Analysis

  1. Constructor Mismatch: Plugin constructors expected ILogger<T> (generic typed logger) but the plugin loader was trying to create ILogger (non-generic)
  2. Failed Reflection Call: The reflection code typeof(ILoggerFactory).GetMethod("CreateLogger", new Type[0]) was looking for a parameterless method but the generic CreateLogger<T>() method has different metadata
  3. Type Incompatibility: Even when logger creation worked, ILoggerFactory.CreateLogger(string) returns ILogger but plugins expected ILogger<PluginType>

Solution Implemented

1. Updated Plugin Constructors

Added support for both generic and non-generic ILogger constructors:

public PinValidationPlugin(ILogger<PinValidationPlugin> logger) : this()
{
    _logger = logger;
}

// Constructor for non-generic ILogger (used by plugin loader)
public PinValidationPlugin(ILogger logger) : this()
{
    _logger = logger;
}

2. Updated Logger Field Type

Changed from strongly-typed to generic interface:

// Before
private readonly ILogger<PinValidationPlugin>? _logger;

// After  
private readonly ILogger? _logger;

3. Enhanced Plugin Loader Logic

Updated CachedPluginLoader.CreatePluginInstance() to:

// Look for constructors that take ILogger<T> or ILogger
var genericLoggerType = typeof(ILogger<>).MakeGenericType(pluginType);
var nonGenericLoggerType = typeof(ILogger);

var constructorWithLogger = pluginType.GetConstructor(new[] { genericLoggerType }) 
                           ?? pluginType.GetConstructor(new[] { nonGenericLoggerType });

// Create logger using string-based method
var stringLogger = _loggerFactory.CreateLogger(pluginType.FullName ?? pluginType.Name);
var plugin = (IApBoxPlugin?)Activator.CreateInstance(pluginType, stringLogger);

Files Modified

  • src/ApBox.Plugins/CachedPluginLoader.cs - Enhanced plugin instantiation logic
  • src/ApBox.Plugins/PluginLoader.cs - Same fix for base plugin loader
  • src/ApBox.SamplePlugins/PinValidationPlugin.cs - Added non-generic logger constructor
  • src/ApBox.Web/Services/ServiceCollectionExtensions.cs - Added ILoggerFactory injection

Result

  • ✅ Plugins now receive proper logger injection
  • ✅ All plugin logging works correctly
  • ✅ Backward compatible with existing plugin constructors
  • ✅ Two-factor authentication demo shows detailed logging flow

Recommended Resolution for Main Branch

  1. Apply the plugin loader changes to support both ILogger<T> and ILogger constructors
  2. Update all sample plugins to include non-generic ILogger constructor overloads
  3. Consider making this the standard pattern for new plugins to ensure consistent logging
  4. Add unit tests to verify logger injection works for both constructor types

This fix enables proper debugging and monitoring of plugin behavior in production environments.