Files
HellionChat/HellionChat/Infrastructure/Logging/DalamudLogger.cs
T
JonKazama-Hellion f6d3794d87 feat(di): scaffold Microsoft.Extensions.Hosting container (DI-1 + DI-1b)
Lays down the DI foundation that v1.5.x will run on top of, without
flipping the switch on Plugin.cs yet (that move follows in C3). The new
files compile alongside the existing bootstrap but no caller resolves
the host, so the live behaviour is byte-identical to v1.4.10.

What's new:

- PluginHostFactory.cs: HostBuilder.Build(plugin, dependencies)
  registers ~46 services across Block A (21 Dalamud singletons), Block
  B (14 HellionChat services plus FileDialogManager), Block C (8
  windows), plus Plugin and PluginLifecycle. Service-class bodies are
  untouched - Plugin-backref ctors go through factory lambdas.
- PluginLifecycle.cs: thin IAsyncDisposable wrapping the host's
  StartAsync/StopAsync, with idempotent dispose and framework-thread
  Host.Dispose. The Host is assigned via a property setter from
  Plugin.ctor; HellionChat deviates from Lightless' Func-delegate
  pattern because the schema gate must run before Build.
- Infrastructure/Logging/{DalamudLogger, DalamudLoggingProvider,
  DalamudLoggingProviderExtensions}.cs: ILogger<T> -> IPluginLog
  bridge, ported from Lightless without the mod-sync hasModifiedGameFiles
  flag and without the LightlessConfigService log-level coupling.
- Infrastructure/Hosting/InitHostedServices.cs: seven IHostedService
  adapters around the existing init methods (FontManager.BuildFonts,
  ThemeRegistry warmup+switch, IpcManager/TypingIpc/ExtraChat eager
  resolve, MessageManager.FilterAllTabsAsync, AutoTellTabsService
  .Initialize). Adapter style rather than inlining ": IHostedService"
  on the service classes per the DI-2a "service bodies untouched"
  constraint.

Plan drift noted for cycle closure: MessageStore stays inside
MessageManager.ctor (not a standalone container singleton) because
MessageManager.ctor allocates it directly today; promoting it would
double-construct the SQLite handle. AutoTellTabsService reads it via
MessageManager.Store inside its factory lambda.
2026-05-17 02:44:54 +02:00

63 lines
1.8 KiB
C#

using System.Text;
using Dalamud.Plugin.Services;
using Microsoft.Extensions.Logging;
namespace HellionChat.Infrastructure.Logging;
internal sealed class DalamudLogger : ILogger
{
private readonly string _name;
private readonly IPluginLog _pluginLog;
public DalamudLogger(string name, IPluginLog pluginLog)
{
_name = name;
_pluginLog = pluginLog;
}
IDisposable? ILogger.BeginScope<TState>(TState state) => default!;
// Filtering happens in Dalamud's /xllog. Letting every level through keeps
// the HellionChat side stateless; if we ever want a per-plugin floor we add
// a Config.LogLevel and tighten this method.
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception? exception,
Func<TState, Exception?, string> formatter
)
{
if (!IsEnabled(logLevel))
return;
if ((int)logLevel <= (int)LogLevel.Information)
{
_pluginLog.Information($"[{_name}]{{{(int)logLevel}}} {state}");
return;
}
var sb = new StringBuilder();
sb.Append($"[{_name}]{{{(int)logLevel}}} {state} {exception?.Message}");
if (!string.IsNullOrWhiteSpace(exception?.StackTrace))
sb.AppendLine(exception.StackTrace);
var inner = exception?.InnerException;
while (inner != null)
{
sb.AppendLine($"InnerException {inner}: {inner.Message}");
sb.AppendLine(inner.StackTrace);
inner = inner.InnerException;
}
if (logLevel == LogLevel.Warning)
_pluginLog.Warning(sb.ToString());
else if (logLevel == LogLevel.Error)
_pluginLog.Error(sb.ToString());
else
_pluginLog.Fatal(sb.ToString());
}
}