mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
Add Scoped Plugin Log Service (#1341)
Adds a new `IPluginLog` service to Dalamud, which provides scoped logging on a per-plugin basis. This improves log performance for plugins, and paves the way for per-plugin log levels.
* Plugins must opt in to enable verbose logging by setting `IPluginLog.MinimumLogLevel` to `LogEventLevel.Verbose`. This option is automatically enabled for dev plugins and is currently not persisted.
* All release plugins will default to `Debug` as their lowest allowed log level.
* This setting does not override the global log level set in Dalamud.
This commit is contained in:
parent
1dbf93e428
commit
8c51bbf0f8
4 changed files with 263 additions and 67 deletions
|
|
@ -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
|
|||
/// </summary>
|
||||
/// <param name="pluginInterface">Dalamud plugin interface.</param>
|
||||
/// <param name="log">Logging service.</param>
|
||||
public PluginImpl(DalamudPluginInterface pluginInterface, PluginLog log)
|
||||
public PluginImpl(DalamudPluginInterface pluginInterface, IPluginLog log)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
|||
/// <summary>
|
||||
/// Class offering various static methods to allow for logging in plugins.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
public class PluginLog : IServiceType, IDisposable
|
||||
public static class PluginLog
|
||||
{
|
||||
private readonly LocalPlugin plugin;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginLog"/> class.
|
||||
/// Do not use this ctor, inject PluginLog instead.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The plugin this service is scoped for.</param>
|
||||
internal PluginLog(LocalPlugin plugin)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a prefix appended to log messages.
|
||||
/// </summary>
|
||||
public string? LogPrefix { get; set; } = null;
|
||||
|
||||
#region Legacy static "Log" prefixed Serilog style methods
|
||||
#region "Log" prefixed Serilog style methods
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
|
||||
/// <summary>
|
||||
/// 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);
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
#region New instanced methods
|
||||
|
||||
/// <summary>
|
||||
/// Log some information.
|
||||
/// </summary>
|
||||
/// <param name="message">The message.</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class offering logging services, for a specific type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to log for.</typeparam>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
public class PluginLog<T> : PluginLog
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginLog{T}"/> class.
|
||||
/// Do not use this ctor, inject PluginLog instead.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The plugin this service is scoped for.</param>
|
||||
internal PluginLog(LocalPlugin plugin)
|
||||
: base(plugin)
|
||||
{
|
||||
this.LogPrefix = typeof(T).Name;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
130
Dalamud/Logging/ScopedPluginLogService.cs
Normal file
130
Dalamud/Logging/ScopedPluginLogService.cs
Normal file
|
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="IPluginLog"/>.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IPluginLog>]
|
||||
#pragma warning restore SA1015
|
||||
public class ScopedPluginLogService : IServiceType, IPluginLog, IDisposable
|
||||
{
|
||||
private readonly LocalPlugin localPlugin;
|
||||
|
||||
private readonly LoggingLevelSwitch levelSwitch;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScopedPluginLogService"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localPlugin">The plugin that owns this service.</param>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public LogEventLevel MinimumLogLevel
|
||||
{
|
||||
get => this.levelSwitch.MinimumLevel;
|
||||
set => this.levelSwitch.MinimumLevel = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ILogger Logger { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Fatal(string messageTemplate, params object[] values) =>
|
||||
this.Write(LogEventLevel.Fatal, null, messageTemplate, values);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Fatal(Exception? exception, string messageTemplate, params object[] values) =>
|
||||
this.Write(LogEventLevel.Fatal, exception, messageTemplate, values);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Error(string messageTemplate, params object[] values) =>
|
||||
this.Write(LogEventLevel.Error, null, messageTemplate, values);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Error(Exception? exception, string messageTemplate, params object[] values) =>
|
||||
this.Write(LogEventLevel.Error, exception, messageTemplate, values);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Warning(string messageTemplate, params object[] values) =>
|
||||
this.Write(LogEventLevel.Warning, null, messageTemplate, values);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Warning(Exception? exception, string messageTemplate, params object[] values) =>
|
||||
this.Write(LogEventLevel.Warning, exception, messageTemplate, values);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Information(string messageTemplate, params object[] values) =>
|
||||
this.Write(LogEventLevel.Information, null, messageTemplate, values);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Information(Exception? exception, string messageTemplate, params object[] values) =>
|
||||
this.Write(LogEventLevel.Information, exception, messageTemplate, values);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Debug(string messageTemplate, params object[] values) =>
|
||||
this.Write(LogEventLevel.Debug, null, messageTemplate, values);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Debug(Exception? exception, string messageTemplate, params object[] values) =>
|
||||
this.Write(LogEventLevel.Debug, exception, messageTemplate, values);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Verbose(string messageTemplate, params object[] values) =>
|
||||
this.Write(LogEventLevel.Verbose, null, messageTemplate, values);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Verbose(Exception? exception, string messageTemplate, params object[] values) =>
|
||||
this.Write(LogEventLevel.Verbose, exception, messageTemplate, values);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Write(LogEventLevel level, Exception? exception, string messageTemplate, params object[] values)
|
||||
{
|
||||
this.Logger.Write(
|
||||
level,
|
||||
exception: exception,
|
||||
messageTemplate: $"[{this.localPlugin.InternalName}] {messageTemplate}",
|
||||
values);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default log level for this plugin.
|
||||
/// </summary>
|
||||
/// <returns>A log level.</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
128
Dalamud/Plugin/Services/IPluginLog.cs
Normal file
128
Dalamud/Plugin/Services/IPluginLog.cs
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
using System;
|
||||
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace Dalamud.Plugin.Services;
|
||||
|
||||
/// <summary>
|
||||
/// An opinionated service to handle logging for plugins.
|
||||
/// </summary>
|
||||
public interface IPluginLog
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Defaults to <see cref="LogEventLevel.Debug"/> for downloaded plugins, and <see cref="LogEventLevel.Verbose"/>
|
||||
/// for dev plugins.
|
||||
/// </remarks>
|
||||
LogEventLevel MinimumLogLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets an instance of the Serilog <see cref="ILogger"/> for advanced use cases. The provided logger will handle
|
||||
/// tagging all log messages with the appropriate context variables and properties.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Not currently part of public API - will be added after some formatter work has been completed.
|
||||
/// </remarks>
|
||||
internal ILogger Logger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Log a <see cref="LogEventLevel.Fatal" /> message to the Dalamud log for this plugin. This log level should be
|
||||
/// used primarily for unrecoverable errors or critical faults in a plugin.
|
||||
/// </summary>
|
||||
/// <param name="messageTemplate">Message template describing the event.</param>
|
||||
/// <param name="values">Objects positionally formatted into the message template.</param>
|
||||
void Fatal(string messageTemplate, params object[] values);
|
||||
|
||||
/// <inheritdoc cref="Fatal(string,object[])"/>
|
||||
/// <param name="exception">An (optional) exception that should be recorded alongside this event.</param>
|
||||
void Fatal(Exception? exception, string messageTemplate, params object[] values);
|
||||
|
||||
/// <summary>
|
||||
/// Log a <see cref="LogEventLevel.Error" /> message to the Dalamud log for this plugin. This log level should be
|
||||
/// used for recoverable errors or faults that impact plugin functionality.
|
||||
/// </summary>
|
||||
/// <param name="messageTemplate">Message template describing the event.</param>
|
||||
/// <param name="values">Objects positionally formatted into the message template.</param>
|
||||
void Error(string messageTemplate, params object[] values);
|
||||
|
||||
/// <inheritdoc cref="Error(string,object[])"/>
|
||||
/// <param name="exception">An (optional) exception that should be recorded alongside this event.</param>
|
||||
void Error(Exception? exception, string messageTemplate, params object[] values);
|
||||
|
||||
/// <summary>
|
||||
/// Log a <see cref="LogEventLevel.Warning" /> 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.
|
||||
/// </summary>
|
||||
/// <param name="messageTemplate">Message template describing the event.</param>
|
||||
/// <param name="values">Objects positionally formatted into the message template.</param>
|
||||
void Warning(string messageTemplate, params object[] values);
|
||||
|
||||
/// <inheritdoc cref="Warning(string,object[])"/>
|
||||
/// <param name="exception">An (optional) exception that should be recorded alongside this event.</param>
|
||||
void Warning(Exception? exception, string messageTemplate, params object[] values);
|
||||
|
||||
/// <summary>
|
||||
/// Log an <see cref="LogEventLevel.Information" /> 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.
|
||||
/// </summary>
|
||||
/// <param name="messageTemplate">Message template describing the event.</param>
|
||||
/// <param name="values">Objects positionally formatted into the message template.</param>
|
||||
void Information(string messageTemplate, params object[] values);
|
||||
|
||||
/// <inheritdoc cref="Information(string,object[])"/>
|
||||
/// <param name="exception">An (optional) exception that should be recorded alongside this event.</param>
|
||||
void Information(Exception? exception, string messageTemplate, params object[] values);
|
||||
|
||||
/// <summary>
|
||||
/// Log a <see cref="LogEventLevel.Debug" /> 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.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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 <em>not</em> use this log level where it can be triggered on a
|
||||
/// per-frame basis.
|
||||
/// </remarks>
|
||||
/// <param name="messageTemplate">Message template describing the event.</param>
|
||||
/// <param name="values">Objects positionally formatted into the message template.</param>
|
||||
void Debug(string messageTemplate, params object[] values);
|
||||
|
||||
/// <inheritdoc cref="Debug(string,object[])"/>
|
||||
/// <param name="exception">An (optional) exception that should be recorded alongside this event.</param>
|
||||
void Debug(Exception? exception, string messageTemplate, params object[] values);
|
||||
|
||||
/// <summary>
|
||||
/// Log a <see cref="LogEventLevel.Verbose" /> 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.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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
|
||||
/// <see cref="MinimumLogLevel"/> to <see cref="LogEventLevel.Verbose"/> to use this level, and should only do so
|
||||
/// upon specific user request (e.g. a "Enable Troubleshooting Logs" button).
|
||||
/// </remarks>
|
||||
/// <param name="messageTemplate">Message template describing the event.</param>
|
||||
/// <param name="values">Objects positionally formatted into the message template.</param>
|
||||
void Verbose(string messageTemplate, params object[] values);
|
||||
|
||||
/// <inheritdoc cref="Verbose(string,object[])"/>
|
||||
/// <param name="exception">An (optional) exception that should be recorded alongside this event.</param>
|
||||
void Verbose(Exception? exception, string messageTemplate, params object[] values);
|
||||
|
||||
/// <summary>
|
||||
/// Write a raw log event to the plugin's log. Used for interoperability with other log systems, as well as
|
||||
/// advanced use cases.
|
||||
/// </summary>
|
||||
/// <param name="level">The log level for this event.</param>
|
||||
/// <param name="exception">An (optional) exception that should be recorded alongside this event.</param>
|
||||
/// <param name="messageTemplate">Message template describing the event.</param>
|
||||
/// <param name="values">Objects positionally formatted into the message template.</param>
|
||||
void Write(LogEventLevel level, Exception? exception, string messageTemplate, params object[] values);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue