You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在多个类中使用Serilog写入同一个日志文件

问题根因

日志无法跨类写入同一个文件是两个核心配置错误导致的:

  • Serilog全局Logger初始化时机完全错误。你把Log.Logger配置、启动日志写入的代码放在了Application.Run(new Form1())之后,这行方法会持续阻塞直到主窗体关闭,也就是说整个应用运行周期里Serilog都没完成初始化,等你执行Logger配置代码时程序已经准备退出了。其他类调用日志方法时,全局Logger还是未配置的空默认实例,自然不会写入任何内容。
  • 错误在业务类中调用了全局资源释放方法。你在SqlRead类的finally块里写了Log.CloseAndFlush(),这个方法是程序完全退出前才需要全局调用一次的资源回收方法,你在单次数据库操作结束就调用它,会直接销毁全局Logger实例、释放日志文件句柄,后续所有类的日志写入操作都会失效。
正确配置方案

1. 调整Program类的初始化顺序

必须在应用启动、窗体创建之前完成Serilog全局Logger初始化,Application.Run放在所有初始化逻辑之后,应用退出前再统一执行日志缓冲刷新和资源释放。
修正后的Program代码:

internal static class Program
{
    /// <summary>
    ///  应用程序主入口点
    /// </summary>
    [STAThread]
    static void Main()
    {
        // 最先初始化Serilog全局Logger
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.File("logs/ConverterLog.txt", rollingInterval: RollingInterval.Day)
            .CreateLogger();
        
        // 初始化完成后写入启动日志
        Log.Information("Program Startup");

        // 再执行应用配置、启动主窗体
        ApplicationConfiguration.Initialize();
        Application.Run(new Form1()); // 此处阻塞直到主窗体关闭

        // 程序退出前全局仅调用一次,确保所有缓冲日志写入磁盘
        Log.CloseAndFlush();
    }
}

2. 移除业务类中的错误释放调用

删除SqlRead类finally块里的Log.CloseAndFlush(),业务流程中绝对不能调用这个全局销毁方法。另外补充一个日志写法的优化:记录异常时优先传入完整异常对象,不要只传Message,否则会丢失堆栈跟踪、内部异常等关键排查信息。
修正后的SqlRead代码片段:

class SqlRead
{
    public void Password(string sqlConnectionString, List<SqlInformation> sqlInformationList)
    {
        string sqlQuerySelect = "SELECT Login, Password FROM Users Order by Login";
        using var sqlConn = new SqlConnection(sqlConnectionString);
        using var sqlCmdSelect = new SqlCommand(sqlQuerySelect, sqlConn);
        try
        {
            sqlConn.Open();
            using SqlDataReader sqlReader = sqlCmdSelect.ExecuteReader();
            while (sqlReader.Read())
            {
                sqlInformationList.Add(new SqlInformation() { Username = sqlReader[0].ToString(), Password = sqlReader[1].ToString() });
            }
            sqlReader.Close();
            Log.Information("SQL data successfully read");
        }
        catch (SqlException e)
        {
            MessageBox.Show(e.Message);
            // 传入完整异常对象,保留全量错误信息
            Log.Error(e, "读取SQL数据失败");
        }
        // 移除此处的Log.CloseAndFlush()调用
    }
}
补充说明
  • Serilog的静态Log实例是进程级单例,只要在程序入口最开始初始化一次,应用内所有类都可以直接调用Log.Information/Log.Error等静态方法,所有日志会自动写入配置好的同一个文件目标,不需要每个类单独配置Logger。
  • 文件写入默认会带少量缓冲,不需要每次写日志手动调用刷新,全局退出时调用一次CloseAndFlush()就能保证所有日志落盘不丢失。

内容的提问来源于stack exchange,提问作者Fabian228

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 03:06:37