|
|
@@ -53,16 +53,16 @@ public static class Logger {
|
|
|
public static void Error(string message, LogBehavior behavior = LogBehavior.AlertThenFeedback, [CallerFilePath] string filePath = "")
|
|
|
=> Log(message, LogLevel.Error, behavior, filePath);
|
|
|
|
|
|
- public static void Log(Func<string> messageGetter, LogLevel level = LogLevel.Info, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "") {
|
|
|
- if (Instance.MinLevel <= level) Instance.Log(messageGetter(), level, behavior, filePath); }
|
|
|
- public static void Trace(Func<string> messageGetter, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "")
|
|
|
- => Log(messageGetter, LogLevel.Trace, behavior, filePath);
|
|
|
- public static void Info(Func<string> messageGetter, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "")
|
|
|
- => Log(messageGetter, LogLevel.Info, behavior, filePath);
|
|
|
- public static void Warn(Func<string> messageGetter, LogBehavior behavior = LogBehavior.ToastIfDebug, [CallerFilePath] string filePath = "")
|
|
|
- => Log(messageGetter, LogLevel.Warn, behavior, filePath);
|
|
|
- public static void Error(Func<string> messageGetter, LogBehavior behavior = LogBehavior.AlertThenFeedback, [CallerFilePath] string filePath = "")
|
|
|
- => Log(messageGetter, LogLevel.Error, behavior, filePath);
|
|
|
+ public static void Log(LogLevel level, [InterpolatedStringHandlerArgument("level")] ref LogInterpolatedStringHandler handler, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "") {
|
|
|
+ if (handler.IsEnabled) Instance.Log(handler.ToStringAndClear(), level, behavior, filePath); }
|
|
|
+ public static void Trace(ref TraceLogInterpolatedStringHandler handler, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "") {
|
|
|
+ if (handler.IsEnabled) Instance.Log(handler.ToStringAndClear(), LogLevel.Trace, behavior, filePath); }
|
|
|
+ public static void Info(ref InfoLogInterpolatedStringHandler handler, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "") {
|
|
|
+ if (handler.IsEnabled) Instance.Log(handler.ToStringAndClear(), LogLevel.Info, behavior, filePath); }
|
|
|
+ public static void Warn(ref WarnLogInterpolatedStringHandler handler, LogBehavior behavior = LogBehavior.ToastIfDebug, [CallerFilePath] string filePath = "") {
|
|
|
+ if (handler.IsEnabled) Instance.Log(handler.ToStringAndClear(), LogLevel.Warn, behavior, filePath); }
|
|
|
+ public static void Error(ref ErrorLogInterpolatedStringHandler handler, LogBehavior behavior = LogBehavior.AlertThenFeedback, [CallerFilePath] string filePath = "") {
|
|
|
+ if (handler.IsEnabled) Instance.Log(handler.ToStringAndClear(), LogLevel.Error, behavior, filePath); }
|
|
|
|
|
|
public static void Log(Exception ex, string? message = null, LogLevel level = LogLevel.Warn, LogBehavior behavior = LogBehavior.ToastIfDebug, [CallerFilePath] string filePath = "")
|
|
|
=> Instance.Log(ex, message, level, behavior, filePath);
|
|
|
@@ -156,6 +156,157 @@ public class BaseLogger {
|
|
|
|
|
|
}
|
|
|
|
|
|
+/// <summary>
|
|
|
+/// 用于 <see cref="Logger.Log(LogLevel, ref LogInterpolatedStringHandler, LogBehavior, string)"/> 的内插字符串处理器。
|
|
|
+/// 仅当日志等级满足要求时才格式化字符串,避免不必要的字符串拼接开销。
|
|
|
+/// </summary>
|
|
|
+[InterpolatedStringHandler]
|
|
|
+public ref struct LogInterpolatedStringHandler {
|
|
|
+ private StringBuilder? _sb;
|
|
|
+
|
|
|
+ /// <summary>当前日志等级是否满足输出要求。</summary>
|
|
|
+ public readonly bool IsEnabled;
|
|
|
+
|
|
|
+ public LogInterpolatedStringHandler(int literalLength, int formattedCount, LogLevel level, out bool isEnabled) {
|
|
|
+ IsEnabled = isEnabled = Logger.Instance.MinLevel <= level;
|
|
|
+ _sb = IsEnabled ? new StringBuilder(literalLength) : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>追加字面量字符串片段。</summary>
|
|
|
+ public void AppendLiteral(string value) => _sb?.Append(value);
|
|
|
+ /// <summary>追加格式化值。</summary>
|
|
|
+ public void AppendFormatted<T>(T value) => _sb?.Append(value?.ToString());
|
|
|
+ /// <summary>追加带格式字符串的格式化值。</summary>
|
|
|
+ public void AppendFormatted<T>(T value, string? format)
|
|
|
+ => _sb?.Append(value is IFormattable formattable ? formattable.ToString(format, null) : value?.ToString());
|
|
|
+ /// <summary>追加带对齐宽度的格式化值。</summary>
|
|
|
+ public void AppendFormatted<T>(T value, int alignment) {
|
|
|
+ if (_sb is null) return;
|
|
|
+ var s = value?.ToString() ?? string.Empty;
|
|
|
+ _sb.Append(alignment > 0 ? s.PadLeft(alignment) : alignment < 0 ? s.PadRight(-alignment) : s);
|
|
|
+ }
|
|
|
+ /// <summary>追加带对齐宽度和格式字符串的格式化值。</summary>
|
|
|
+ public void AppendFormatted<T>(T value, int alignment, string? format) {
|
|
|
+ if (_sb is null) return;
|
|
|
+ var s = value is IFormattable formattable ? formattable.ToString(format, null) : value?.ToString() ?? string.Empty;
|
|
|
+ _sb.Append(alignment > 0 ? s.PadLeft(alignment) : alignment < 0 ? s.PadRight(-alignment) : s);
|
|
|
+ }
|
|
|
+ /// <summary>追加字符串值。</summary>
|
|
|
+ public void AppendFormatted(string? value) => _sb?.Append(value);
|
|
|
+ /// <summary>追加带对齐宽度和格式字符串的对象值。</summary>
|
|
|
+ public void AppendFormatted(object? value, int alignment = 0, string? format = null) {
|
|
|
+ if (_sb is null) return;
|
|
|
+ var s = value is IFormattable formattable ? formattable.ToString(format, null) : value?.ToString() ?? string.Empty;
|
|
|
+ _sb.Append(alignment > 0 ? s.PadLeft(alignment) : alignment < 0 ? s.PadRight(-alignment) : s);
|
|
|
+ }
|
|
|
+
|
|
|
+ internal string ToStringAndClear() {
|
|
|
+ var result = _sb?.ToString() ?? string.Empty;
|
|
|
+ _sb = null;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>用于 <see cref="Logger.Trace(ref TraceLogInterpolatedStringHandler, LogBehavior, string)"/> 的内插字符串处理器。</summary>
|
|
|
+[InterpolatedStringHandler]
|
|
|
+public ref struct TraceLogInterpolatedStringHandler {
|
|
|
+ private LogInterpolatedStringHandler _inner;
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.IsEnabled"/>
|
|
|
+ public bool IsEnabled => _inner.IsEnabled;
|
|
|
+ public TraceLogInterpolatedStringHandler(int literalLength, int formattedCount, out bool isEnabled)
|
|
|
+ => _inner = new(literalLength, formattedCount, LogLevel.Trace, out isEnabled);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendLiteral"/>
|
|
|
+ public void AppendLiteral(string value) => _inner.AppendLiteral(value);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T)"/>
|
|
|
+ public void AppendFormatted<T>(T value) => _inner.AppendFormatted(value);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T, string?)"/>
|
|
|
+ public void AppendFormatted<T>(T value, string? format) => _inner.AppendFormatted(value, format);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T, int)"/>
|
|
|
+ public void AppendFormatted<T>(T value, int alignment) => _inner.AppendFormatted(value, alignment);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T, int, string?)"/>
|
|
|
+ public void AppendFormatted<T>(T value, int alignment, string? format) => _inner.AppendFormatted(value, alignment, format);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted(string?)"/>
|
|
|
+ public void AppendFormatted(string? value) => _inner.AppendFormatted(value);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted(object?, int, string?)"/>
|
|
|
+ public void AppendFormatted(object? value, int alignment = 0, string? format = null) => _inner.AppendFormatted(value, alignment, format);
|
|
|
+ internal string ToStringAndClear() => _inner.ToStringAndClear();
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>用于 <see cref="Logger.Info(ref InfoLogInterpolatedStringHandler, LogBehavior, string)"/> 的内插字符串处理器。</summary>
|
|
|
+[InterpolatedStringHandler]
|
|
|
+public ref struct InfoLogInterpolatedStringHandler {
|
|
|
+ private LogInterpolatedStringHandler _inner;
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.IsEnabled"/>
|
|
|
+ public bool IsEnabled => _inner.IsEnabled;
|
|
|
+ public InfoLogInterpolatedStringHandler(int literalLength, int formattedCount, out bool isEnabled)
|
|
|
+ => _inner = new(literalLength, formattedCount, LogLevel.Info, out isEnabled);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendLiteral"/>
|
|
|
+ public void AppendLiteral(string value) => _inner.AppendLiteral(value);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T)"/>
|
|
|
+ public void AppendFormatted<T>(T value) => _inner.AppendFormatted(value);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T, string?)"/>
|
|
|
+ public void AppendFormatted<T>(T value, string? format) => _inner.AppendFormatted(value, format);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T, int)"/>
|
|
|
+ public void AppendFormatted<T>(T value, int alignment) => _inner.AppendFormatted(value, alignment);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T, int, string?)"/>
|
|
|
+ public void AppendFormatted<T>(T value, int alignment, string? format) => _inner.AppendFormatted(value, alignment, format);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted(string?)"/>
|
|
|
+ public void AppendFormatted(string? value) => _inner.AppendFormatted(value);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted(object?, int, string?)"/>
|
|
|
+ public void AppendFormatted(object? value, int alignment = 0, string? format = null) => _inner.AppendFormatted(value, alignment, format);
|
|
|
+ internal string ToStringAndClear() => _inner.ToStringAndClear();
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>用于 <see cref="Logger.Warn(ref WarnLogInterpolatedStringHandler, LogBehavior, string)"/> 的内插字符串处理器。</summary>
|
|
|
+[InterpolatedStringHandler]
|
|
|
+public ref struct WarnLogInterpolatedStringHandler {
|
|
|
+ private LogInterpolatedStringHandler _inner;
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.IsEnabled"/>
|
|
|
+ public bool IsEnabled => _inner.IsEnabled;
|
|
|
+ public WarnLogInterpolatedStringHandler(int literalLength, int formattedCount, out bool isEnabled)
|
|
|
+ => _inner = new(literalLength, formattedCount, LogLevel.Warn, out isEnabled);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendLiteral"/>
|
|
|
+ public void AppendLiteral(string value) => _inner.AppendLiteral(value);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T)"/>
|
|
|
+ public void AppendFormatted<T>(T value) => _inner.AppendFormatted(value);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T, string?)"/>
|
|
|
+ public void AppendFormatted<T>(T value, string? format) => _inner.AppendFormatted(value, format);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T, int)"/>
|
|
|
+ public void AppendFormatted<T>(T value, int alignment) => _inner.AppendFormatted(value, alignment);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T, int, string?)"/>
|
|
|
+ public void AppendFormatted<T>(T value, int alignment, string? format) => _inner.AppendFormatted(value, alignment, format);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted(string?)"/>
|
|
|
+ public void AppendFormatted(string? value) => _inner.AppendFormatted(value);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted(object?, int, string?)"/>
|
|
|
+ public void AppendFormatted(object? value, int alignment = 0, string? format = null) => _inner.AppendFormatted(value, alignment, format);
|
|
|
+ internal string ToStringAndClear() => _inner.ToStringAndClear();
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>用于 <see cref="Logger.Error(ref ErrorLogInterpolatedStringHandler, LogBehavior, string)"/> 的内插字符串处理器。</summary>
|
|
|
+[InterpolatedStringHandler]
|
|
|
+public ref struct ErrorLogInterpolatedStringHandler {
|
|
|
+ private LogInterpolatedStringHandler _inner;
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.IsEnabled"/>
|
|
|
+ public bool IsEnabled => _inner.IsEnabled;
|
|
|
+ public ErrorLogInterpolatedStringHandler(int literalLength, int formattedCount, out bool isEnabled)
|
|
|
+ => _inner = new(literalLength, formattedCount, LogLevel.Error, out isEnabled);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendLiteral"/>
|
|
|
+ public void AppendLiteral(string value) => _inner.AppendLiteral(value);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T)"/>
|
|
|
+ public void AppendFormatted<T>(T value) => _inner.AppendFormatted(value);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T, string?)"/>
|
|
|
+ public void AppendFormatted<T>(T value, string? format) => _inner.AppendFormatted(value, format);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T, int)"/>
|
|
|
+ public void AppendFormatted<T>(T value, int alignment) => _inner.AppendFormatted(value, alignment);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted{T}(T, int, string?)"/>
|
|
|
+ public void AppendFormatted<T>(T value, int alignment, string? format) => _inner.AppendFormatted(value, alignment, format);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted(string?)"/>
|
|
|
+ public void AppendFormatted(string? value) => _inner.AppendFormatted(value);
|
|
|
+ /// <inheritdoc cref="LogInterpolatedStringHandler.AppendFormatted(object?, int, string?)"/>
|
|
|
+ public void AppendFormatted(object? value, int alignment = 0, string? format = null) => _inner.AppendFormatted(value, alignment, format);
|
|
|
+ internal string ToStringAndClear() => _inner.ToStringAndClear();
|
|
|
+}
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// 将日志输出到 <see cref="Debug"/> 并写入指定的文件夹,最多保留 5 个文件。
|
|
|
/// 不实现 <see cref="LogBehavior"/>。
|