.NET控制台应用如何添加文件日志并捕获日志用于程序结束后发邮件
实现方案
依赖安装
选用Serilog实现文件日志,先安装对应NuGet包:
- Serilog.AspNetCore
- Serilog.Sinks.File
核心实现步骤
步骤1:定义内存日志存储服务
用于存储所有运行时生成的日志条目,供后续发邮件使用:
// 日志条目实体 public class LogEntry { public DateTimeOffset Timestamp { get; set; } public LogLevel Level { get; set; } public string Message { get; set; } public Exception? Exception { get; set; } } // 日志存储接口 public interface IInMemoryLogStore { void Add(LogEntry entry); IReadOnlyList<LogEntry> GetAll(); } // 日志存储实现 public class InMemoryLogStore : IInMemoryLogStore { private readonly List<LogEntry> _logs = new(); public void Add(LogEntry entry) => _logs.Add(entry); public IReadOnlyList<LogEntry> GetAll() => _logs.AsReadOnly(); }
步骤2:自定义日志Provider实现内存日志收集
public class InMemoryLoggerProvider : ILoggerProvider { private readonly IInMemoryLogStore _logStore; public InMemoryLoggerProvider(IInMemoryLogStore logStore) => _logStore = logStore; public ILogger CreateLogger(string categoryName) { return new InMemoryLogger(_logStore, categoryName); } public void Dispose() { } } public class InMemoryLogger : ILogger { private readonly IInMemoryLogStore _logStore; private readonly string _categoryName; public InMemoryLogger(IInMemoryLogStore logStore, string categoryName) { _logStore = logStore; _categoryName = categoryName; } public IDisposable BeginScope<TState>(TState state) => null; public bool IsEnabled(LogLevel logLevel) => true; // 按需调整过滤级别 public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) { if (!IsEnabled(logLevel)) return; var message = formatter(state, exception); _logStore.Add(new LogEntry { Timestamp = DateTimeOffset.Now, Level = logLevel, Message = $"[{_categoryName}] {message}", Exception = exception }); } }
步骤3:整合到Host配置中
var host = Host.CreateDefaultBuilder(args) // 注册内存日志存储为单例 .ConfigureServices(services => { services.AddSingleton<IInMemoryLogStore, InMemoryLogStore>(); }) .ConfigureLogging((context, logging) => { logging.ClearProviders(); logging.AddConsole(); // 注册自定义内存日志Provider logging.Services.AddSingleton<ILoggerProvider, InMemoryLoggerProvider>(); }) // 配置Serilog实现文件日志输出 .UseSerilog((context, config) => { config .ReadFrom.Configuration(context.Configuration) .WriteTo.Console() .WriteTo.File( path: "logs/app-.log", rollingInterval: RollingInterval.Day, outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"); }) .Build(); // 你的业务逻辑执行代码 // await host.RunAsync(); 或者自行解析服务执行业务 // 程序运行结束后,获取所有日志组装邮件 var logStore = host.Services.GetRequiredService<IInMemoryLogStore>(); var allLogs = logStore.GetAll(); // 此处实现邮件发送逻辑,把allLogs拼接为邮件内容即可
补充说明
- 如果不想引入Serilog,也可以使用微软官方的
Microsoft.Extensions.Logging.File包实现文件日志,仅需在ConfigureLogging中调用logging.AddFile()即可,不过Serilog的日志格式化、滚动策略配置更灵活,更适合生产环境使用。 - 因为程序是单次运行的定时任务,内存存储日志不会有内存溢出风险,如果日志量极大,可以调整为临时写入本地文件,发邮件时再读取即可。
内容的提问来源于stack exchange,提问作者Jonathan Wood
相关产品推荐
相关产品推荐

