添加后台日志系统 - (第四讲)
视频讲解如下:
工程源码下载:GPS定位系统系列教程源码下载
今天这个章节给大家讲讲如何实现一个简单的日志系统,日志的存储方式一般分为两种,一种是文本文件的方式,另一种则是数据库的方式。今天要讲的是如何将系统的运行日志存储到文件中。
日志系统的原理其实也很简单,就是采用ConcurrentQueue队列将所有需要存储的日志进行缓存,在每次往队列里面添加日志时,都发送一个消息告诉线程需要写文件了,线程一旦接收到消息,就不停的从队列中提取出日志信息,并写到文件,当然了,你也可以把它写到数据库里面,都是可以的。
日志系统的类文件我们取名为:LogHelper.cs,我们新建一个comm目录,将我们的LogHelper.cs文件放在该目录下面,LogHelper.cs文件代码如下:
using System.Collections.Concurrent;
namespace WebApplicationGPS.comm
{
public static class LogHelper
{
/// <summary>
/// 添加并发队列,存储所有的日志信息
/// </summary>
private static readonly ConcurrentQueue<string> _que = new ConcurrentQueue<string>();
/// <summary>
/// 设置线程同步事件,通知线程进行日志写操作
/// </summary>
private static readonly ManualResetEvent _mre = new ManualResetEvent(false);
/// <summary>
/// 启动线程
/// </summary>
public static void Start()
{
new Thread(new ThreadStart(ThreadLog)) { IsBackground = false }.Start();
}
/// <summary>
/// 外部调用,往队列里面写日志信息,同时发出信号,通知线程开始写文件
/// </summary>
/// <param name="data"></param>
public static void WriteLog(string data)
{
try
{
if (data == null || data == "") return;
// debug
System.Diagnostics.Debug.WriteLine(data);
// 往队列写数据
_que.Enqueue($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}:{data}\r\n");
// 发出信号,通知线程开始写文件
_mre.Set();
}
catch { }
}
/// <summary>
/// 日志文件写线程
/// </summary>
private static void ThreadLog()
{
while (true)
{
try
{
// 创建目录,放循环里面,如果目录被意外删除了,也能恢复
string path = AppDomain.CurrentDomain.BaseDirectory + @"\logs";
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
while (true)
{
// 按每小时一个文件的周期进行日志存储
string filePath = Path.Combine(path, DateTime.Now.ToString("yyyy-MM-dd HH") + " log.txt");
_mre.WaitOne(); // 阻塞线程,直到调用Set方法才能继续执行
while (_que.Count > 0 && _que.TryDequeue(out string msg))
{
// 不停的写文件
File.AppendAllText(filePath, msg);
}
_mre.Reset(); // 释放信号,等待下次信号到达
Thread.Sleep(1);
}
}
catch { }
}
}
}
}
日志系统的方法文件已经有了,这时就需要测试我们的日志了。
首先我们需要新建两个文件:
ServerInit.cs:用于初始化整个系统的后台程序,包括日志系统、数据库、TCP通讯等。
APP/Service.cs:位于APP目录下,主要为我们的后台线程应用程序,在当前项目中其实是用不到它的,我们这里用它来演示我们的日志功能。
新增App目录结构和Service.cs、ServerInit.cs文件内容如下:

Service.cs 代码如下,实现的效果就是每秒写一次日志。
using WebApplicationGPS.comm;
namespace WebApplicationGPS.APP
{
public class Service
{
/// <summary>
/// 后台应用程序入口
/// </summary>
public void TaskService()
{
try
{
while (true)
{
Thread.Sleep(1000);
LogHelper.WriteLog($"写日志:{DateTime.Now.ToString()}");
}
}
catch { }
}
}
}
ServerInit.cs 代码如下:
using WebApplicationGPS.APP;
using WebApplicationGPS.comm;
namespace WebApplicationGPS
{
public class ServerInit
{
public ServerInit()
{
// 启动日志系统
LogHelper.Start();
// 启动后台应用程序
AppStart();
}
/// <summary>
/// 启动后台应用
/// </summary>
private void AppStart()
{
new Thread(() =>
{
Service app = new Service();
while (true)
{
app.TaskService();
Thread.Sleep(1000);
}
})
{ IsBackground = true }.Start();
}
}
}
ServerInit文件目前还不能被系统调用,所以我们需要在Program.cs中添加对ServerInit的调用,起到初始化的作用。
添加方法也很简单,直接在Program.cs的app.Run();前面追加如下代码,并补上相应的引用即可。
注意:一定要加在app.Run();的前面,系统启动时会停在app.Run();位置,并不会继续往下执行。
new ServerInit();
运行效果如下,我们会发现在debug目录下会自动生成一个日志文件:2022-09-14 14 log.txt


到这里,我们的一个简易log系统就完成了。