.NET Framework(C#)跨库错误报告与日志方案优化咨询
最优实现策略方案
一、日志记录机制:接口驱动的解耦设计
放弃静态类硬编码日志收集逻辑,改用接口抽象+依赖注入实现解耦,让类库不绑定具体日志实现:
- 定义
ILogger接口,包含基础日志方法:LogInfo、LogWarning、LogError(支持传入异常) - 类库通过静态属性注入
ILogger实例,默认提供空实现避免空引用 - 窗体项目根据自身需求实现该接口,将日志输出到UI控件或本地文件
示例代码:
// 类库中定义日志接口 public interface ILogger { void LogInfo(string message); void LogWarning(string message); void LogError(string message, Exception ex = null); } // 类库工具类依赖接口 public static class FileUtils { public static ILogger Logger { get; set; } = new NullLogger(); public static void ReadExcel(string path) { try { Logger.LogInfo($"开始读取Excel文件: {path}"); // 读取逻辑 } catch (Exception ex) { Logger.LogError("读取Excel失败", ex); throw; // 抛出异常交由上层处理终止逻辑 } } // 默认空实现,避免未注入时的空引用问题 private class NullLogger : ILogger { public void LogInfo(string message) {} public void LogWarning(string message) {} public void LogError(string message, Exception ex = null) {} } }
二、收集所有控制台日志:重定向Console输出流
窗体应用默认无控制台窗口,Console.WriteLine输出会直接丢失,通过重定向输出流即可捕获所有控制台日志:
// 窗体项目启动时初始化 public partial class MainForm : Form { private StringWriter _consoleOutput; public MainForm() { InitializeComponent(); // 重定向Console输出到内存流 _consoleOutput = new StringWriter(); Console.SetOut(_consoleOutput); // 注入自定义Logger到类库 FileUtils.Logger = new FormLogger(this); } // 窗体端Logger实现,同时处理类库日志和控制台日志 private class FormLogger : ILogger { private readonly MainForm _form; public FormLogger(MainForm form) => _form = form; public void LogInfo(string message) => WriteToLog($"[INFO] {DateTime.Now:yyyy-MM-dd HH:mm:ss} {message}"); public void LogWarning(string message) => WriteToLog($"[WARNING] {DateTime.Now:yyyy-MM-dd HH:mm:ss} {message}"); public void LogError(string message, Exception ex = null) { var errorContent = $"[ERROR] {DateTime.Now:yyyy-MM-dd HH:mm:ss} {message}"; if (ex != null) errorContent += $"\n异常详情: {ex.ToString()}"; WriteToLog(errorContent); // 触发应用终止与报告生成 _form.TerminateWithReport(errorContent); } private void WriteToLog(string content) { // 跨线程更新UI需用Invoke if (_form.logTextBox.InvokeRequired) { _form.logTextBox.Invoke(new Action(() => WriteToLog(content))); return; } _form.logTextBox.AppendText(content + Environment.NewLine); } } }
三、类库错误终止应用:异常传递+全局捕获
类库不直接终止应用,而是抛出自定义严重异常,由窗体项目全局捕获后执行终止逻辑:
// 类库中定义自定义异常 public class LibraryCriticalException : Exception { public LibraryCriticalException(string message) : base(message) {} public LibraryCriticalException(string message, Exception inner) : base(message, inner) {} } // 类库中抛出严重错误 public static void ReadExcel(string path) { if (!File.Exists(path)) { Logger.LogError($"文件不存在: {path}"); throw new LibraryCriticalException($"文件不存在: {path}"); } // 其他读取逻辑 } // 窗体项目全局捕获未处理异常 public static class Program { [STAThread] static void Main() { Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); // 捕获全局未处理异常 AppDomain.CurrentDomain.UnhandledException += (sender, e) => { if (e.ExceptionObject is LibraryCriticalException ex) { var mainForm = Application.OpenForms.OfType<MainForm>().FirstOrDefault(); mainForm?.TerminateWithReport(ex.Message); } }; Application.Run(new MainForm()); } }
四、终止后生成报告:模块化多格式支持
将报告生成逻辑封装为独立工具类,支持txt、Excel、窗体三种输出方式:
public static class ReportGenerator { // 生成TXT报告 public static void GenerateTxtReport(string content, string outputPath) { File.WriteAllText(outputPath, content); } // 生成Excel报告(需引用EPPlus NuGet包) public static void GenerateExcelReport(List<ReportElement> elements, string outputPath) { using (var package = new ExcelPackage()) { var worksheet = package.Workbook.Worksheets.Add("错误报告"); // 写入表头 worksheet.Cells[1, 1].Value = "日志类型"; worksheet.Cells[1, 2].Value = "消息内容"; worksheet.Cells[1, 3].Value = "时间"; // 写入数据 for (int i = 0; i < elements.Count; i++) { var elem = elements[i]; worksheet.Cells[i+2, 1].Value = elem.Type.ToString(); worksheet.Cells[i+2, 2].Value = elem.Message; worksheet.Cells[i+2, 3].Value = elem.Timestamp.ToString("yyyy-MM-dd HH:mm:ss"); } package.SaveAs(new FileInfo(outputPath)); } } // 弹出窗体显示报告 public static void ShowFormReport(List<ReportElement> elements) { var reportForm = new ReportForm(); reportForm.LoadReportData(elements); reportForm.ShowDialog(); } } // 窗体中的终止与报告生成方法 public void TerminateWithReport(string errorMsg) { // 收集所有日志(控制台输出+类库日志) var allConsoleLogs = _consoleOutput.ToString(); var reportElements = new List<ReportElement> { new ReportElement(ReportType.Error, errorMsg, DateTime.Now), // 可追加其他日志记录 }; // 生成报告文件 var txtPath = Path.Combine(Application.StartupPath, $"错误报告_{DateTime.Now:yyyyMMddHHmmss}.txt"); ReportGenerator.GenerateTxtReport(allConsoleLogs, txtPath); // 弹出报告窗体 ReportGenerator.ShowFormReport(reportElements); // 终止应用 Application.Exit(); }
核心优化点
- 解耦性:接口设计让类库适配任意宿主(窗体、控制台、WPF等),无需修改类库代码
- 性能:用
StringWriter替代List<string>收集日志,减少内存开销;大日志量场景可改用异步文件写入 - 可扩展性:报告生成支持新增格式(如HTML),只需扩展
ReportGenerator的方法 - 异常安全:全局捕获未处理异常,确保崩溃前能生成报告
内容的提问来源于stack exchange,提问作者Devrim Mert Yöyen
相关产品推荐
相关产品推荐

