From d784357fe55743cd205df05313ca09bc5098aaa9 Mon Sep 17 00:00:00 2001 From: limil Date: Sat, 1 Nov 2025 20:42:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=97=A5=E5=BF=97=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BangumiRenamer.csproj | 3 + Src/Log/Log.cs | 164 +++++++++++++++++++++++++++++ Src/Tools/EmbededResourceViewer.cs | 2 +- Src/Tools/FolderCloner.cs | 2 +- Src/Tools/ShowCompletionChecker.cs | 8 +- 5 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 Src/Log/Log.cs diff --git a/BangumiRenamer.csproj b/BangumiRenamer.csproj index eb83632..6c442a9 100644 --- a/BangumiRenamer.csproj +++ b/BangumiRenamer.csproj @@ -18,6 +18,9 @@ + + + diff --git a/Src/Log/Log.cs b/Src/Log/Log.cs new file mode 100644 index 0000000..d8e3583 --- /dev/null +++ b/Src/Log/Log.cs @@ -0,0 +1,164 @@ +using Serilog.Sinks.SystemConsole.Themes; + +namespace BangumiRenamer; + +using Serilog; +using Serilog.Core; +using Serilog.Events; + +public sealed class Log +{ + private static readonly Lazy _instance = new Lazy(() => new Log()); + private Logger _logger; + private bool _isInitialized = false; + private readonly object _lockObject = new object(); + + public static Log Instance => _instance.Value; + public static ILogger Logger => Instance._logger; + + private Log() { } + + /// + /// 初始化日志配置 + /// + public static void Initialize(Action configure = null) + { + Instance.InitializeInternal(configure); + } + + private void InitializeInternal(Action configure = null) + { + lock (_lockObject) + { + if (_isInitialized) + { + Warn("日志系统已经初始化过"); + return; + } + + var config = new LoggerConfiguration() + .MinimumLevel.Debug() + .WriteTo.Console( + outputTemplate: "[{Timestamp:HH:mm:ss}][{Level:u3}] {Message:lj}{NewLine}{Exception}", + theme: AnsiConsoleTheme.Sixteen + ) + .Enrich.FromLogContext() + .Enrich.WithProperty("Application", "MyApp") + .Enrich.WithThreadId(); + + configure?.Invoke(config); + + _logger = config.CreateLogger(); + _isInitialized = true; + + Info("日志系统初始化完成"); + } + } + + // 静态快捷方法 - 使用更简短的名称 + public static void Debug(string message, params object[] properties) + => Instance.EnsureAndLog(LogEventLevel.Debug, message, properties); + + public static void Info(string message, params object[] properties) + => Instance.EnsureAndLog(LogEventLevel.Information, message, properties); + + public static void Warn(string message, params object[] properties) + => Instance.EnsureAndLog(LogEventLevel.Warning, message, properties); + + public static void Error(string message, params object[] properties) + => Instance.EnsureAndLog(LogEventLevel.Error, message, properties); + + public static void Error(Exception ex, string message, params object[] properties) + => Instance.EnsureAndLog(ex, message, properties); + + public static void Fatal(string message, params object[] properties) + => Instance.EnsureAndLog(LogEventLevel.Fatal, message, properties); + + // 实例方法 + private void EnsureAndLog(LogEventLevel level, string message, object[] properties) + { + EnsureInitialized(); + _logger.Write(level, message, properties); + } + + private void EnsureAndLog(Exception ex, string message, object[] properties) + { + EnsureInitialized(); + _logger.Error(ex, message, properties); + } + + /// + /// 为特定类型创建Logger + /// + public static ILogger ForContext() + { + Instance.EnsureInitialized(); + return Instance._logger.ForContext(); + } + + /// + /// 为特定源创建Logger + /// + public static ILogger ForContext(string source) + { + Instance.EnsureInitialized(); + return Instance._logger.ForContext("SourceContext", source); + } + + /// + /// 开始一个带属性的日志上下文 + /// + public static IDisposable BeginScope(string propertyName, object value) + { + Instance.EnsureInitialized(); + return Serilog.Context.LogContext.PushProperty(propertyName, value); + } + + /// + /// 开始多个属性的日志上下文 + /// + public static IDisposable BeginScope(params (string Name, object Value)[] properties) + { + Instance.EnsureInitialized(); + var disposables = properties.Select(p => + Serilog.Context.LogContext.PushProperty(p.Name, p.Value)).ToArray(); + return new DisposableGroup(disposables); + } + + /// + /// 关闭并刷新日志 + /// + public static void Close() + { + Instance._logger?.Dispose(); + Serilog.Log.CloseAndFlush(); + Instance._isInitialized = false; + } + + private void EnsureInitialized() + { + if (!_isInitialized) + { + InitializeInternal(); + } + } + + // 辅助类:用于同时释放多个IDisposable + private class DisposableGroup : IDisposable + { + private readonly IDisposable[] _disposables; + + public DisposableGroup(IDisposable[] disposables) + { + _disposables = disposables; + } + + public void Dispose() + { + foreach (var disposable in _disposables) + { + disposable?.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Src/Tools/EmbededResourceViewer.cs b/Src/Tools/EmbededResourceViewer.cs index ad06fd3..3314497 100644 --- a/Src/Tools/EmbededResourceViewer.cs +++ b/Src/Tools/EmbededResourceViewer.cs @@ -9,7 +9,7 @@ public class EmbededResourceViewer var names = ResourceLoader.GetAllResNames(); foreach (var name in names) { - Console.WriteLine(name); + Log.Info(name); } } } \ No newline at end of file diff --git a/Src/Tools/FolderCloner.cs b/Src/Tools/FolderCloner.cs index 5860a49..a49acce 100644 --- a/Src/Tools/FolderCloner.cs +++ b/Src/Tools/FolderCloner.cs @@ -64,7 +64,7 @@ public static class FolderCloner } catch (Exception ex) { - Console.WriteLine($"Clone失败 {ex.Message}"); + Log.Error(ex, "Clone"); } } } diff --git a/Src/Tools/ShowCompletionChecker.cs b/Src/Tools/ShowCompletionChecker.cs index e42ab41..b48751a 100644 --- a/Src/Tools/ShowCompletionChecker.cs +++ b/Src/Tools/ShowCompletionChecker.cs @@ -53,7 +53,7 @@ public static class ShowCompletionChecker var checkPath = dir.Path; var shows = FindShows(checkPath); - Console.WriteLine($"Total Shows: {shows.Count}"); + Log.Info($"Total Shows: {shows.Count}"); var client = new TMDbClient( apiKey: Config.Default.Get().ApiKey , @@ -69,7 +69,7 @@ public static class ShowCompletionChecker var info = result.Results.FirstOrDefault(); if (info == null) { - Console.WriteLine($"找不到对应的TV:{t.title}"); + Log.Error($"找不到对应的TV:{t.title}"); continue; } foreach (var session in t.sessions) @@ -77,7 +77,7 @@ public static class ShowCompletionChecker var sessionInfo = client.GetTvSeasonAsync(info.Id, session.id).Result; if (sessionInfo == null) { - Console.WriteLine($"季度对不上,可能找错了:{t.title} -> {info.OriginalName}"); + Log.Error($"季度对不上,可能找错了:{t.title} -> {info.OriginalName}"); break; } foreach (var episode in sessionInfo.Episodes) @@ -90,6 +90,6 @@ public static class ShowCompletionChecker } } } - Console.Write(output); + Log.Info(output.ToString()); } } \ No newline at end of file