Dalamud/Dalamud/Logging/Internal/SerilogEventSink.cs
Kaz Wolfe abecf2ffe4
Add Per-Plugin Log Filtering Support
This commit adds first-pass support for more robust plugin log filtering. No changes were made that affect PluginLog's APIs nor log format. This change works by making use of Serilog's "SourceContext" property to attach plugin information to all log messages. The in-game log UI can then be used to filter based on this property.

Future expansions for this system include the ability to set different plugins to different log levels (something that already can technically be done, but requires those plugins be hard-coded through MinimumLevel.Override), creating new root loggers for each plugin (thereby giving plugin devs more control over their logging should they want to use it), plus other potential improvements in the way of adding context or rich information.

- Update PluginLog to attach a "SourceContext" property to all log messages.
- Tweak the SerilogEventSink to pass the original log event around.
- Suppress Info/Debug/Verbose exceptions from Troubleshooting reports.
- Fix the ConsoleWindow log filter to use _all_ filters, rather than just one.
- Add ConsoleWindow dropdown to select plugins to filter logs by
- Add support for multiple log levels to ConsoleWindow filtering
2022-08-23 21:36:55 -07:00

57 lines
1.7 KiB
C#

using System;
using Serilog.Core;
using Serilog.Events;
namespace Dalamud.Logging.Internal
{
/// <summary>
/// Serilog event sink.
/// </summary>
internal class SerilogEventSink : ILogEventSink
{
private static SerilogEventSink instance;
private readonly IFormatProvider formatProvider;
/// <summary>
/// Initializes a new instance of the <see cref="SerilogEventSink"/> class.
/// </summary>
/// <param name="formatProvider">Logging format provider.</param>
private SerilogEventSink(IFormatProvider formatProvider)
{
this.formatProvider = formatProvider;
}
/// <summary>
/// Event on a log line being emitted.
/// </summary>
public event EventHandler<(string Line, LogEvent LogEvent)>? LogLine;
/// <summary>
/// Gets the default instance.
/// </summary>
public static SerilogEventSink Instance => instance ??= new SerilogEventSink(null);
/// <summary>
/// Emit a log event.
/// </summary>
/// <param name="logEvent">Log event to be emitted.</param>
public void Emit(LogEvent logEvent)
{
var message = logEvent.RenderMessage(this.formatProvider);
if (logEvent.Properties.TryGetValue("SourceContext", out var sourceProp) &&
sourceProp is ScalarValue { Value: string source })
{
message = $"[{source}] {message}";
}
if (logEvent.Exception != null)
{
message += "\n" + logEvent.Exception;
}
this.LogLine?.Invoke(this, (message, logEvent));
}
}
}