|
|
@@ -91,6 +91,20 @@ public static class Logger {
|
|
|
=> Log(ex, message, LogLevel.Warning, behavior, filePath);
|
|
|
public static void Error(Exception ex, string? message = null, LogBehavior behavior = LogBehavior.AlertThenFeedback, [CallerFilePath] string filePath = "")
|
|
|
=> Log(ex, message, LogLevel.Error, behavior, filePath);
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 在不调用 Logger 的情况下,将信息直接发送到输出窗口。
|
|
|
+ /// </summary>
|
|
|
+ [Conditional("DEBUG")]
|
|
|
+ public static void SendToDebug(string message, LogLevel level = LogLevel.Error, [CallerFilePath] string filePath = "")
|
|
|
+ => Debug.WriteLine($"{BaseLogger.GetLogPrefix(level, filePath)}{message}");
|
|
|
+ /// <summary>
|
|
|
+ /// 在不调用 Logger 的情况下,将信息直接发送到输出窗口。
|
|
|
+ /// </summary>
|
|
|
+ [Conditional("DEBUG")]
|
|
|
+ public static void SendToDebug(Exception ex, string? message = null, LogLevel level = LogLevel.Error, [CallerFilePath] string filePath = "")
|
|
|
+ => Debug.WriteLine($"{BaseLogger.GetLogPrefix(level, filePath)}{(message is null ? "" : $"{message}:")}{ex.GetDisplay(true)}");
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -111,7 +125,9 @@ public class BaseLogger {
|
|
|
var formattedMessage = Format(message, level, filePath, null);
|
|
|
Output(formattedMessage, level);
|
|
|
HandleBehavior(message, formattedMessage, behavior, null);
|
|
|
- } catch {}
|
|
|
+ } catch (Exception logEx) {
|
|
|
+ Logger.SendToDebug(logEx, "打印日志失败");
|
|
|
+ }
|
|
|
}
|
|
|
public virtual void Log(Exception ex, string? message, LogLevel level, LogBehavior behavior, string filePath) {
|
|
|
if (MinLevel > level) return;
|
|
|
@@ -121,19 +137,23 @@ public class BaseLogger {
|
|
|
formattedMessage = Format(formattedMessage, level, filePath, ex);
|
|
|
Output(formattedMessage, level);
|
|
|
HandleBehavior(message, formattedMessage, behavior, ex);
|
|
|
- } catch { }
|
|
|
+ } catch (Exception logEx) {
|
|
|
+ Logger.SendToDebug(logEx, "打印日志失败");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 格式化日志文本。
|
|
|
/// </summary>
|
|
|
protected virtual string Format(string text, LogLevel level, string filePath, Exception? ex) {
|
|
|
- string prefix = $"{DateTime.Now:HH':'mm':'ss'.'fff} {level.ToString().First()} {(Thread.CurrentThread.Name is null ? "" : $"<{Thread.CurrentThread.Name}> ")}[{Path.GetFileName(filePath).BeforeFirst(".")}] ";
|
|
|
+ string prefix = GetLogPrefix(level, filePath);
|
|
|
return text
|
|
|
.ReplaceLineEndings("\n", mergeMultiple: true).Split(['\n'], StringSplitOptions.RemoveEmptyEntries)
|
|
|
.Select(t => prefix + t)
|
|
|
.Join("\r\n");
|
|
|
}
|
|
|
+ public static string GetLogPrefix(LogLevel level, string filePath)
|
|
|
+ => $"{DateTime.Now:HH':'mm':'ss'.'fff} {level.ToString().First()} {(Thread.CurrentThread.Name is null ? "" : $"<{Thread.CurrentThread.Name}> ")}[{Path.GetFileName(filePath).BeforeFirst(".")}] ";
|
|
|
|
|
|
/// <summary>
|
|
|
/// 输出格式化后的日志文本。
|
|
|
@@ -159,7 +179,7 @@ public class FileLogger : BaseLogger, IDisposable {
|
|
|
/// <inheritdoc/>
|
|
|
protected override void Output(string formattedText, LogLevel level) {
|
|
|
base.Output(formattedText, level);
|
|
|
- if (!writerAvaliable && queue.Count >= 100) return; // 在 writer 就绪前,最多缓存 100 条日志
|
|
|
+ if (!writerAvailable && queue.Count >= 100) return; // 在 writer 就绪前,最多缓存 100 条日志
|
|
|
queue.Enqueue(formattedText);
|
|
|
queuedEvent.Set();
|
|
|
}
|
|
|
@@ -167,7 +187,7 @@ public class FileLogger : BaseLogger, IDisposable {
|
|
|
private readonly ConcurrentQueue<string> queue = new();
|
|
|
private readonly AutoResetEvent queuedEvent = new(false);
|
|
|
private StreamWriter? writer;
|
|
|
- private volatile bool writerAvaliable = false;
|
|
|
+ private volatile bool writerAvailable = false;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 将日志立即写入文件。
|
|
|
@@ -175,10 +195,12 @@ public class FileLogger : BaseLogger, IDisposable {
|
|
|
/// </summary>
|
|
|
public void Flush() {
|
|
|
try {
|
|
|
- if (writer is null || !writerAvaliable) return;
|
|
|
- lock (flushLock)
|
|
|
+ if (writer is null || !writerAvailable) return;
|
|
|
+ lock (flushLock)
|
|
|
while (queue.TryDequeue(out string line)) writer.WriteLine(line); // writer 指定了 AutoFlush
|
|
|
- } catch { }
|
|
|
+ } catch (Exception logEx) {
|
|
|
+ Logger.SendToDebug(logEx, "写入日志失败");
|
|
|
+ }
|
|
|
}
|
|
|
private readonly object flushLock = new();
|
|
|
|
|
|
@@ -206,7 +228,7 @@ public class FileLogger : BaseLogger, IDisposable {
|
|
|
// 写入新日志文件
|
|
|
try {
|
|
|
writer = new StreamWriter(PathUtils.WithLongPath(Path.Combine(logFolder, $"{fileNamePrefix}1{fileNameSuffix}")), append: true) { AutoFlush = true };
|
|
|
- writerAvaliable = true;
|
|
|
+ writerAvailable = true;
|
|
|
Logger.Info("日志初始化成功");
|
|
|
while (true) {
|
|
|
queuedEvent.WaitOne();
|
|
|
@@ -214,14 +236,14 @@ public class FileLogger : BaseLogger, IDisposable {
|
|
|
}
|
|
|
} catch (Exception ex) {
|
|
|
Logger.Warning(ex, "写入日志文件失败", LogBehavior.Toast);
|
|
|
- writerAvaliable = false;
|
|
|
+ writerAvailable = false;
|
|
|
}
|
|
|
}) { Name = nameof(FileLogger), Priority = ThreadPriority.Lowest, IsBackground = true };
|
|
|
thread.Start();
|
|
|
}
|
|
|
|
|
|
public void Dispose() {
|
|
|
- writerAvaliable = false;
|
|
|
+ writerAvailable = false;
|
|
|
if (writer is not null) ((IDisposable) writer).Dispose();
|
|
|
queuedEvent.Dispose();
|
|
|
}
|