diff --git a/Dalamud.CorePlugin/PluginImpl.cs b/Dalamud.CorePlugin/PluginImpl.cs
index b858e9a0c..2f76a1087 100644
--- a/Dalamud.CorePlugin/PluginImpl.cs
+++ b/Dalamud.CorePlugin/PluginImpl.cs
@@ -6,6 +6,7 @@ using Dalamud.Game.Command;
using Dalamud.Interface.Windowing;
using Dalamud.Logging;
using Dalamud.Plugin;
+using Dalamud.Plugin.Services;
using Dalamud.Utility;
using Serilog;
@@ -56,7 +57,7 @@ namespace Dalamud.CorePlugin
///
/// Dalamud plugin interface.
/// Logging service.
- public PluginImpl(DalamudPluginInterface pluginInterface, PluginLog log)
+ public PluginImpl(DalamudPluginInterface pluginInterface, IPluginLog log)
{
try
{
diff --git a/Dalamud/Logging/PluginLog.cs b/Dalamud/Logging/PluginLog.cs
index acbd663e7..b2f2a5065 100644
--- a/Dalamud/Logging/PluginLog.cs
+++ b/Dalamud/Logging/PluginLog.cs
@@ -1,9 +1,6 @@
using System;
using System.Reflection;
-using Dalamud.IoC;
-using Dalamud.IoC.Internal;
-using Dalamud.Plugin.Internal.Types;
using Serilog;
using Serilog.Events;
@@ -12,29 +9,9 @@ namespace Dalamud.Logging;
///
/// Class offering various static methods to allow for logging in plugins.
///
-[PluginInterface]
-[InterfaceVersion("1.0")]
-[ServiceManager.ScopedService]
-public class PluginLog : IServiceType, IDisposable
+public static class PluginLog
{
- private readonly LocalPlugin plugin;
-
- ///
- /// Initializes a new instance of the class.
- /// Do not use this ctor, inject PluginLog instead.
- ///
- /// The plugin this service is scoped for.
- internal PluginLog(LocalPlugin plugin)
- {
- this.plugin = plugin;
- }
-
- ///
- /// Gets or sets a prefix appended to log messages.
- ///
- public string? LogPrefix { get; set; } = null;
-
- #region Legacy static "Log" prefixed Serilog style methods
+ #region "Log" prefixed Serilog style methods
///
/// Log a templated message to the in-game debug log.
@@ -157,7 +134,7 @@ public class PluginLog : IServiceType, IDisposable
#endregion
- #region Legacy static Serilog style methods
+ #region Serilog style methods
///
/// Log a templated verbose message to the in-game debug log.
@@ -277,25 +254,6 @@ public class PluginLog : IServiceType, IDisposable
public static void LogRaw(LogEventLevel level, Exception? exception, string messageTemplate, params object[] values)
=> WriteLog(Assembly.GetCallingAssembly().GetName().Name, level, messageTemplate, exception, values);
- ///
- void IDisposable.Dispose()
- {
- // ignored
- }
-
- #region New instanced methods
-
- ///
- /// Log some information.
- ///
- /// The message.
- internal void Information(string message)
- {
- Serilog.Log.Information($"[{this.plugin.InternalName}] {this.LogPrefix} {message}");
- }
-
- #endregion
-
private static ILogger GetPluginLogger(string? pluginName)
{
return Serilog.Log.ForContext("SourceContext", pluginName ?? string.Empty);
@@ -314,24 +272,3 @@ public class PluginLog : IServiceType, IDisposable
values);
}
}
-
-///
-/// Class offering logging services, for a specific type.
-///
-/// The type to log for.
-[PluginInterface]
-[InterfaceVersion("1.0")]
-[ServiceManager.ScopedService]
-public class PluginLog : PluginLog
-{
- ///
- /// Initializes a new instance of the class.
- /// Do not use this ctor, inject PluginLog instead.
- ///
- /// The plugin this service is scoped for.
- internal PluginLog(LocalPlugin plugin)
- : base(plugin)
- {
- this.LogPrefix = typeof(T).Name;
- }
-}
diff --git a/Dalamud/Logging/ScopedPluginLogService.cs b/Dalamud/Logging/ScopedPluginLogService.cs
new file mode 100644
index 000000000..8c502fcf0
--- /dev/null
+++ b/Dalamud/Logging/ScopedPluginLogService.cs
@@ -0,0 +1,130 @@
+using System;
+
+using Dalamud.IoC;
+using Dalamud.IoC.Internal;
+using Dalamud.Plugin.Internal.Types;
+using Dalamud.Plugin.Services;
+using Serilog;
+using Serilog.Core;
+using Serilog.Events;
+
+namespace Dalamud.Logging;
+
+///
+/// Implementation of .
+///
+[PluginInterface]
+[InterfaceVersion("1.0")]
+[ServiceManager.ScopedService]
+#pragma warning disable SA1015
+[ResolveVia]
+#pragma warning restore SA1015
+public class ScopedPluginLogService : IServiceType, IPluginLog, IDisposable
+{
+ private readonly LocalPlugin localPlugin;
+
+ private readonly LoggingLevelSwitch levelSwitch;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The plugin that owns this service.
+ internal ScopedPluginLogService(LocalPlugin localPlugin)
+ {
+ this.localPlugin = localPlugin;
+
+ this.levelSwitch = new LoggingLevelSwitch(this.GetDefaultLevel());
+
+ var loggerConfiguration = new LoggerConfiguration()
+ .Enrich.WithProperty("Dalamud.PluginName", localPlugin.InternalName)
+ .MinimumLevel.ControlledBy(this.levelSwitch)
+ .WriteTo.Logger(Log.Logger);
+
+ this.Logger = loggerConfiguration.CreateLogger();
+ }
+
+ ///
+ public LogEventLevel MinimumLogLevel
+ {
+ get => this.levelSwitch.MinimumLevel;
+ set => this.levelSwitch.MinimumLevel = value;
+ }
+
+ ///
+ public ILogger Logger { get; }
+
+ ///
+ public void Dispose()
+ {
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ public void Fatal(string messageTemplate, params object[] values) =>
+ this.Write(LogEventLevel.Fatal, null, messageTemplate, values);
+
+ ///
+ public void Fatal(Exception? exception, string messageTemplate, params object[] values) =>
+ this.Write(LogEventLevel.Fatal, exception, messageTemplate, values);
+
+ ///
+ public void Error(string messageTemplate, params object[] values) =>
+ this.Write(LogEventLevel.Error, null, messageTemplate, values);
+
+ ///
+ public void Error(Exception? exception, string messageTemplate, params object[] values) =>
+ this.Write(LogEventLevel.Error, exception, messageTemplate, values);
+
+ ///
+ public void Warning(string messageTemplate, params object[] values) =>
+ this.Write(LogEventLevel.Warning, null, messageTemplate, values);
+
+ ///
+ public void Warning(Exception? exception, string messageTemplate, params object[] values) =>
+ this.Write(LogEventLevel.Warning, exception, messageTemplate, values);
+
+ ///
+ public void Information(string messageTemplate, params object[] values) =>
+ this.Write(LogEventLevel.Information, null, messageTemplate, values);
+
+ ///
+ public void Information(Exception? exception, string messageTemplate, params object[] values) =>
+ this.Write(LogEventLevel.Information, exception, messageTemplate, values);
+
+ ///
+ public void Debug(string messageTemplate, params object[] values) =>
+ this.Write(LogEventLevel.Debug, null, messageTemplate, values);
+
+ ///
+ public void Debug(Exception? exception, string messageTemplate, params object[] values) =>
+ this.Write(LogEventLevel.Debug, exception, messageTemplate, values);
+
+ ///
+ public void Verbose(string messageTemplate, params object[] values) =>
+ this.Write(LogEventLevel.Verbose, null, messageTemplate, values);
+
+ ///
+ public void Verbose(Exception? exception, string messageTemplate, params object[] values) =>
+ this.Write(LogEventLevel.Verbose, exception, messageTemplate, values);
+
+ ///
+ public void Write(LogEventLevel level, Exception? exception, string messageTemplate, params object[] values)
+ {
+ this.Logger.Write(
+ level,
+ exception: exception,
+ messageTemplate: $"[{this.localPlugin.InternalName}] {messageTemplate}",
+ values);
+ }
+
+ ///
+ /// Gets the default log level for this plugin.
+ ///
+ /// A log level.
+ private LogEventLevel GetDefaultLevel()
+ {
+ // TODO: Add some way to save log levels to a config. Or let plugins handle it?
+
+ return this.localPlugin.IsDev ? LogEventLevel.Verbose : LogEventLevel.Debug;
+ }
+}
diff --git a/Dalamud/Plugin/Services/IPluginLog.cs b/Dalamud/Plugin/Services/IPluginLog.cs
new file mode 100644
index 000000000..87876f36f
--- /dev/null
+++ b/Dalamud/Plugin/Services/IPluginLog.cs
@@ -0,0 +1,128 @@
+using System;
+
+using Serilog;
+using Serilog.Events;
+
+namespace Dalamud.Plugin.Services;
+
+///
+/// An opinionated service to handle logging for plugins.
+///
+public interface IPluginLog
+{
+ ///
+ /// Gets or sets the minimum log level that will be recorded from this plugin to Dalamud's logs. This may be set
+ /// by either the plugin or by Dalamud itself.
+ ///
+ ///
+ /// Defaults to for downloaded plugins, and
+ /// for dev plugins.
+ ///
+ LogEventLevel MinimumLogLevel { get; set; }
+
+ ///
+ /// Gets an instance of the Serilog for advanced use cases. The provided logger will handle
+ /// tagging all log messages with the appropriate context variables and properties.
+ ///
+ ///
+ /// Not currently part of public API - will be added after some formatter work has been completed.
+ ///
+ internal ILogger Logger { get; }
+
+ ///
+ /// Log a message to the Dalamud log for this plugin. This log level should be
+ /// used primarily for unrecoverable errors or critical faults in a plugin.
+ ///
+ /// Message template describing the event.
+ /// Objects positionally formatted into the message template.
+ void Fatal(string messageTemplate, params object[] values);
+
+ ///
+ /// An (optional) exception that should be recorded alongside this event.
+ void Fatal(Exception? exception, string messageTemplate, params object[] values);
+
+ ///
+ /// Log a message to the Dalamud log for this plugin. This log level should be
+ /// used for recoverable errors or faults that impact plugin functionality.
+ ///
+ /// Message template describing the event.
+ /// Objects positionally formatted into the message template.
+ void Error(string messageTemplate, params object[] values);
+
+ ///
+ /// An (optional) exception that should be recorded alongside this event.
+ void Error(Exception? exception, string messageTemplate, params object[] values);
+
+ ///
+ /// Log a message to the Dalamud log for this plugin. This log level should be
+ /// used for user error, potential problems, or high-importance messages that should be logged.
+ ///
+ /// Message template describing the event.
+ /// Objects positionally formatted into the message template.
+ void Warning(string messageTemplate, params object[] values);
+
+ ///
+ /// An (optional) exception that should be recorded alongside this event.
+ void Warning(Exception? exception, string messageTemplate, params object[] values);
+
+ ///
+ /// Log an message to the Dalamud log for this plugin. This log level
+ /// should be used for general plugin operations and other relevant information to track a plugin's behavior.
+ ///
+ /// Message template describing the event.
+ /// Objects positionally formatted into the message template.
+ void Information(string messageTemplate, params object[] values);
+
+ ///
+ /// An (optional) exception that should be recorded alongside this event.
+ void Information(Exception? exception, string messageTemplate, params object[] values);
+
+ ///
+ /// Log a message to the Dalamud log for this plugin. This log level should be
+ /// used for messages or information that aid with debugging or tracing a plugin's operations, but should not be
+ /// recorded unless requested.
+ ///
+ ///
+ /// By default, this log level is below the default log level of Dalamud. Messages logged at this level will not be
+ /// recorded unless the global log level is specifically set to Debug or lower. If information should be generally
+ /// or easily accessible for support purposes without the user taking additional action, consider using the
+ /// Information level instead. Developers should not use this log level where it can be triggered on a
+ /// per-frame basis.
+ ///
+ /// Message template describing the event.
+ /// Objects positionally formatted into the message template.
+ void Debug(string messageTemplate, params object[] values);
+
+ ///
+ /// An (optional) exception that should be recorded alongside this event.
+ void Debug(Exception? exception, string messageTemplate, params object[] values);
+
+ ///
+ /// Log a message to the Dalamud log for this plugin. This log level is
+ /// intended almost primarily for development purposes and detailed tracing of a plugin's operations. Verbose logs
+ /// should not be used to expose information useful for support purposes.
+ ///
+ ///
+ /// By default, this log level is below the default log level of Dalamud. Messages logged at this level will not be
+ /// recorded unless the global log level is specifically set to Verbose. Release plugins must also set the
+ /// to to use this level, and should only do so
+ /// upon specific user request (e.g. a "Enable Troubleshooting Logs" button).
+ ///
+ /// Message template describing the event.
+ /// Objects positionally formatted into the message template.
+ void Verbose(string messageTemplate, params object[] values);
+
+ ///
+ /// An (optional) exception that should be recorded alongside this event.
+ void Verbose(Exception? exception, string messageTemplate, params object[] values);
+
+ ///
+ /// Write a raw log event to the plugin's log. Used for interoperability with other log systems, as well as
+ /// advanced use cases.
+ ///
+ /// The log level for this event.
+ /// An (optional) exception that should be recorded alongside this event.
+ /// Message template describing the event.
+ /// Objects positionally formatted into the message template.
+ void Write(LogEventLevel level, Exception? exception, string messageTemplate, params object[] values);
+}