refactor(di): migrate services layer to ILogger<T> (DI-4 Slice A)

MessageStore, MessageEnumerator, MessageManager, AutoTellTabsService
move from Plugin.LogProxy / IPluginLogProxy onto
Microsoft.Extensions.Logging.ILogger<T> via constructor injection.

MessageStore additionally takes ILoggerFactory so it can build a
per-instance ILogger<MessageEnumerator> at each of the five reader-
spawning sites; the enumerator is not a container singleton.

PluginHostFactory's MessageManager and AutoTellTabsService factory
lambdas grow to resolve the new logger args; everything else stays in
place.

Site-level migration in the four files:
- MessageStore: 12 calls, _logger field IPluginLogProxy -> ILogger<MessageStore>
- MessageManager: 7 Plugin.LogProxy.* sites, new _logger field
- AutoTellTabsService: 9 Plugin.LogProxy.* sites, new _logger field

Plus a pre-existing template bug surfaced by CA2017: a LogDebug call
in AutoTellTabsService used "{tab.Name}" with no `$` prefix, which
landed in xllog as literal text under Plugin.LogProxy; ILogger now
reads that as a structured placeholder, so the call was promoted to
proper structured logging with tab.Name passed as a parameter.
This commit is contained in:
2026-05-17 09:09:55 +02:00
parent e0ead86616
commit d0be75e79d
4 changed files with 96 additions and 44 deletions
+18 -12
View File
@@ -9,6 +9,7 @@ using HellionChat.Code;
using HellionChat.GameFunctions.Types;
using HellionChat.Resources;
using HellionChat.Util;
using Microsoft.Extensions.Logging;
namespace HellionChat;
@@ -19,6 +20,7 @@ internal sealed class AutoTellTabsService : IDisposable
private readonly Plugin _plugin;
private readonly MessageManager _messageManager;
private readonly MessageStore _store;
private readonly ILogger<AutoTellTabsService> _logger;
private readonly object _tempTabsLock = new();
// Hard cap on pinned TempTabs so the sidebar doesn't inflate over years
@@ -29,11 +31,17 @@ internal sealed class AutoTellTabsService : IDisposable
private bool _initialized;
internal AutoTellTabsService(Plugin plugin, MessageManager messageManager, MessageStore store)
internal AutoTellTabsService(
Plugin plugin,
MessageManager messageManager,
MessageStore store,
ILogger<AutoTellTabsService> logger
)
{
_plugin = plugin;
_messageManager = messageManager;
_store = store;
_logger = logger;
}
// Derived from the tab list on read. Pin/Unpin/Promote/Logout simply
@@ -67,7 +75,7 @@ internal sealed class AutoTellTabsService : IDisposable
private void RehydratePinnedTabs()
{
var pinned = Plugin.Config.Tabs.Count(TabLifecycleHelpers.IsInPinnedPool);
Plugin.LogProxy.Debug($"[Pin] Rehydrate scan: {pinned} pinned tab(s) found");
_logger.LogDebug($"[Pin] Rehydrate scan: {pinned} pinned tab(s) found");
foreach (var tab in Plugin.Config.Tabs)
{
@@ -76,7 +84,7 @@ internal sealed class AutoTellTabsService : IDisposable
if (tab.TellTarget is null || !tab.TellTarget.IsSet())
{
Plugin.LogProxy.Warning(
_logger.LogWarning(
$"[Pin] Pinned tab '{tab.Name}' has no usable TellTarget "
+ $"(Name={tab.TellTarget?.Name ?? "<null>"} World={tab.TellTarget?.World ?? 0}). "
+ "Chat input on this tab will be empty until the partner sends a tell or you /tell manually."
@@ -93,7 +101,7 @@ internal sealed class AutoTellTabsService : IDisposable
// sees the recent conversation, not a blank tab.
PreloadHistory(tab, tab.TellTarget.Name, tab.TellTarget.World, Guid.Empty);
Plugin.LogProxy.Debug(
_logger.LogDebug(
$"[Pin] Rehydrated '{tab.Name}' -> Tell target {tab.TellTarget.Name}@{tab.TellTarget.World}"
);
}
@@ -130,7 +138,7 @@ internal sealed class AutoTellTabsService : IDisposable
if (partner == null)
{
// Diagnostics: helps detect regressions (FFXIV payload changes, new edge cases)
Plugin.LogProxy.Warning(
_logger.LogWarning(
$"[AutoTellTabs] Could not extract tell partner. type={message.Code.Type}, "
+ $"senderChunks={message.Sender.Count}, contentChunks={message.Content.Count}, "
+ $"senderSourcePayloads={message.SenderSource?.Payloads?.Count ?? 0}, "
@@ -361,7 +369,7 @@ internal sealed class AutoTellTabsService : IDisposable
catch (Exception ex)
{
// Non-fatal: tab still spawns with visible error notice instead of silent history loss
Plugin.LogProxy.Error(ex, "[AutoTellTabs] History preload failed");
_logger.LogError(ex, "[AutoTellTabs] History preload failed");
tab.Messages.AddPrune(
MakeSystemMarker(HellionStrings.AutoTellTabs_HistoryLoadError),
MessageManager.MessageDisplayLimit
@@ -456,7 +464,7 @@ internal sealed class AutoTellTabsService : IDisposable
{
if (!tab.IsTempTab || tab.IsPinned)
{
Plugin.LogProxy.Debug(
_logger.LogDebug(
$"[Pin] TryPin skipped: IsTempTab={tab.IsTempTab} IsPinned={tab.IsPinned}"
);
return false;
@@ -472,7 +480,7 @@ internal sealed class AutoTellTabsService : IDisposable
}
tab.IsPinned = true;
Plugin.LogProxy.Debug(
_logger.LogDebug(
$"[Pin] Pinned tab '{tab.Name}' target={tab.TellTarget?.Name}@{tab.TellTarget?.World}"
);
_plugin.SaveConfig();
@@ -495,7 +503,7 @@ internal sealed class AutoTellTabsService : IDisposable
}
tab.IsPinned = false;
Plugin.LogProxy.Debug("[Pin] Unpinned tab '{tab.Name}'");
_logger.LogDebug("[Pin] Unpinned tab '{TabName}'", tab.Name);
_plugin.SaveConfig();
}
@@ -509,9 +517,7 @@ internal sealed class AutoTellTabsService : IDisposable
tab.IsTempTab = false;
tab.IsPinned = false;
tab.TellTarget = TellTarget.Empty();
Plugin.LogProxy.Debug(
$"[Pin] Promoted tab '{tab.Name}' to permanent (tell-binding dropped)"
);
_logger.LogDebug($"[Pin] Promoted tab '{tab.Name}' to permanent (tell-binding dropped)");
_plugin.SaveConfig();
}
}