TraceSource日志生成重复文件问题排查求助
问题定位与解决方案
问题根源
- 重复添加TraceListener实例:每次点击登录按钮时,代码都会执行
Trace.Listeners.Add(new TextWriterTraceListener(filePath, "myListener")),甚至catch块里还重复添加了一次同名监听器。当尝试添加同名但路径/实例不同的监听器时,.NET会自动给新监听器的文件名加上唯一ID后缀以避免冲突,这就是带ID的重复文件的来源。 - 配置文件与代码的双重配置冲突:配置文件的
<trace>节点下已经定义了名为myListener的监听器(路径为C:\Commission.log),但代码里又在用户ApplicationData目录下创建同名监听器,两者路径不一致,触发了.NET的文件名自动重命名逻辑。 - 监听器生命周期管理缺失:没有在使用后移除或清理监听器,导致每次点击都会新增监听器实例,重复写入日志。
修复步骤
1. 统一日志配置,避免代码与配置文件重复定义
选择要么用配置文件管理监听器,要么用代码管理,不混合使用。这里推荐保留配置文件的灵活性,同时修正代码逻辑:
修改配置文件(调整为动态路径)
移除硬编码路径,后续在代码中动态设置日志文件位置:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.diagnostics> <trace autoflush="false" indentsize="4"> <listeners> <add name="myListener" type="System.Diagnostics.TextWriterTraceListener" /> <remove name="Default" /> </listeners> </trace> <sources> <source name="TraceTest" switchName="sourceSwitch" switchType="System.Diagnostics.SourceSwitch"> <listeners> <add name="console" type="System.Diagnostics.ConsoleTraceListener"> <filter type="System.Diagnostics.EventTypeFilter" initializeData="Error"/> </add> <add name="myListener"/> <remove name="Default"/> </listeners> </source> </sources> <switches> <add name="sourceSwitch" value="Error"/> </switches> </system.diagnostics> </configuration>
2. 修正代码逻辑,仅初始化一次监听器
在应用启动时(如窗体加载事件)一次性配置监听器路径,而非每次点击按钮都添加:
private void Form1_Load(object sender, EventArgs e) { // 仅在应用启动时配置一次监听器路径 var roamingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); var filePath = Path.Combine(roamingDirectory, "Commission.log"); // 获取配置文件中定义的myListener,设置其写入路径为用户目录 if (Trace.Listeners["myListener"] is TextWriterTraceListener listener) { // 第二个参数为true表示以追加模式写入日志 listener.Writer = new StreamWriter(filePath, true); } } private void Login_Btn_Click(object sender, EventArgs e) { bool userExists = false; try { if(!userExists) { Trace.TraceInformation($"{DateTime.Now.ToShortDateString()} | {DateTime.Now.ToLongTimeString()} - User login failed. Exception: User ID not found"); } } catch(Exception ex) { Trace.TraceInformation($"{DateTime.Now.ToShortDateString()} | {DateTime.Now.ToLongTimeString()} - {ex.ToString()}"); } Trace.Flush(); }
3. 清理监听器(可选,避免资源泄漏)
在应用关闭时,关闭并移除监听器,释放文件资源:
private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (Trace.Listeners["myListener"] is TextWriterTraceListener listener) { listener.Flush(); listener.Close(); Trace.Listeners.Remove(listener); } Trace.Close(); }
关键注意事项
- 监听器应为全局单例,仅在应用启动时初始化一次,不要在事件触发时重复添加。
- 确保配置文件与代码中定义的同名监听器路径一致,避免.NET自动生成带ID的重复文件。
- 使用
StreamWriter的追加模式(第二个参数为true),确保日志内容追加到现有文件而非覆盖。
内容的提问来源于stack exchange,提问作者Thomton
相关产品推荐
相关产品推荐

