云计算百科
云计算领域专业知识百科平台

【C#】 高效日志打印 Logger代码实现【串口通信日志,服务器日志,异常记录,系统状态监控,程序崩溃 日志也不会丢失】

文章目录

  • 1 问题引入 及 分析
  • 1.1 特点
  • 2 高效日志写入 (多个线程同时调用)
  • 3 .代码优化(避免lock对主线程的影响)
    • 3.1 优化后的源码
    • 3.2 化后代码的优势
    • 3.3 日志调用示例
    • 3.4 如果不调用 StopLogger() 会发生什么?
    • 3.5 如何确保 StopLogger() 被调用
  • 4 AutoFlush = true 和 Flush() 适用场景
  • 5 降低磁盘负担,提高写入性能
    • 5.1 完整代码
    • 5.2 多线程日志写入示例

1 问题引入 及 分析

程序在运行过程中,偶发性的出现故障,时有时无。

为了对运行过程以及程序故障的跟踪,我们对串口数据监控事件的和TCP监控事件中的数据及状态都写入日志记录。

下面串口事件和tcp事件TcpClientHelper.getMsgInvoked += TcpClientHelper_getMsgInvoked;和 SP.ReceivedBytesEventHandler += SP_ReceivedBytesEventHandler; ,对于事件可以理解为线程,这里同时启动两个事件,就相当于开了两个线程。

那么既然那是 对运行过程以及程序故障的跟踪,我们的日志需要具备以下特点:

1.1 特点

  • 1 .使用 StreamWriter 并开启 AutoFlush = true:避免频繁打开/关闭文件,提高写入效率。

  • 2.使用 File.AppendText():高效地追加写入,不需要每次打开新文件。

  • 3.多个线程同时调用:在高并发场景下优化写入性能。

  • 4.日志按日期分类存储:每天生成一个新的日志文件,避免单个文件过大影响性能。

  • 5.不能能影响 事件处理函数(主线程)的执行效率,尤其是在高频调用的情况下。

  • 6 日志不会丢失 ,即使程序崩溃,日志数据也会写入文件。

2 高效日志写入 (多个线程同时调用)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace Helper
{

public static class Logger
{

// **日志文件存储目录**
private static readonly string LogDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, \”Log\”);

// **当前日志文件的路径(按日期命名)**
private static string logFile = GetLogFilePath();

// **记录上一次写日志的日期**
private static DateTime lastLogDate = DateTime.Now.Date;

// **线程锁,确保多线程环境下的安全写入**
private static readonly object lockObj = new object();

/// <summary>
/// 计算并返回当前日期对应的日志文件路径
/// </summary>
private static string GetLogFilePath()
{

return Path.Combine(LogDirectory, DateTime.Now.ToString(\”yyyy-MM-dd\”) + \”.log\”);
}

/// <summary>
/// 写日志(高效方式)
/// </summary>
/// <param name=\”message\”>要记录的日志信息</param>
public static void WriteLog(string message,bool bNormal)
{

lock (lockObj) // 确保多线程写入安全
{

// **检查日期是否变更**
if (DateTime.Now.Date > lastLogDate)
{

lastLogDate = DateTime.Now.Date; // 更新日期
logFile = GetLogFilePath(); // 重新计算日志文件路径
}

try
{

// **确保日志文件夹存在**
if (!Directory.Exists(LogDirectory))
{

Directory.CreateDirectory(LogDirectory);
}

// **使用 StreamWriter 进行高效日志写入**
using (StreamWriter writer = new StreamWriter(logFile, true, Encoding.UTF8))
{

writer.AutoFlush = true;//数据立即写入磁盘,日志不会丢失,即使程序崩溃,日志数据也会写入文件。

// **写入日志内容**
if (bNormal)
writer.WriteLine($\”[{
DateTime.Now:yyyy-MM-dd HH:mm:ss}
]–[NORMAL]: {
message}
\”
);
else
writer.WriteLine($\”[{
DateTime.Now:yyyy-MM-dd HH:mm:ss}
]–[ERROR]: {
message}
\”
);

//writer.Flush(); // 手动刷新缓冲区,仅在需要时调用,减少磁盘频繁刷新负担
}
}
catch (Exception ex)
{

**异常处理(防止日志写入异常影响程序运行)**
//Console.WriteLine(\”日志写入失败:\” + ex.Message);
}
}
}
}

}

足实时性和多线程安全性的需求,但 lock 作用域内打开文件并写入日志,会阻塞主线程,这可能会影响 事件处理函数 的执行效率 尤其是在高频调用的情况下。

所以进一步改进

3 .代码优化(避免lock对主线程的影响)

上面的代码已经 满足实时性和多线程安全性的需求,但 lock 作用域内打开文件并写入日志,会阻塞主线程,这可能会影响 事件处理函数 的执行效率 尤其是在高频调用的情况下。

解决方案:

  • 1.使用 ConcurrentQueue 作为日志缓冲区,并在单独的后台线程中写入日志,减少对主线程的影响。

  • 2.使用 Task.Run()异步 或 后台线程 处理日志写入,减少 事件处理函数 受到的影响。

3.1 优化后的源码

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Helper
{

public static class Logger
{

// **日志存储目录**
private static readonly string

赞(0)
未经允许不得转载:网硕互联帮助中心 » 【C#】 高效日志打印 Logger代码实现【串口通信日志,服务器日志,异常记录,系统状态监控,程序崩溃 日志也不会丢失】
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!