C#利用log4net和sqlite数据库记载日志
1 安装包两个包:
[*]log4net
[*]System.Data.SQLite
第二个包也可以利用Microsoft.Data.Sqlite,查到的资料显示假如情况利用的是 .NET Core 或 .NET 5+,则建议利用Microsoft.Data.Sqlite。但是我并没有测试第二个包,可能利用上有区别。
2 下载Sqlite
假如本地没有sqlite情况的话,需要先下载。官网下载链接
进去之后直接找各自情况对应的版本,假如是windows情况的话,直接下载下图中标记的tool,中间那个下载链接是下载sqlite3.dll,不过我并不清楚如何利用。
https://cdn.nlark.com/yuque/0/2024/png/28628673/1729673529583-c1e7108f-45d3-4b5b-bf61-ad8177647dd2.png
tool解压之后有如下几个文件,双击打开sqlite3.exe即可。
https://cdn.nlark.com/yuque/0/2024/png/28628673/1729673685541-2d4d0ee9-72bb-4455-bc87-78f21afd0b85.png
3 Sqlite常用命令
打开是一个命令行界面,可以利用.help查看常用的命令及解释。
.helphttps://cdn.nlark.com/yuque/0/2024/png/28628673/1729673803046-4157a11a-2c8a-4a9e-89bf-7fba6d518b75.png
创建数据库文件利用.open xxx,这条语句,假如发现数据库文件存在,就会直接打开,假如不存在,就会先创建再打开。
.open test.db在目录内可以看到创建的数据库文件。
https://cdn.nlark.com/yuque/0/2024/png/28628673/1729673977210-0d20f810-5802-475e-bb83-b78ecb8f5122.png
.databases可以查询所有数据库文件
https://cdn.nlark.com/yuque/0/2024/png/28628673/1729674034639-c8eeb583-fbfd-499c-ac3e-7a03798ee1ab.png
.tables可以查询所有表(我还未创建,所以现在还没有表)
https://cdn.nlark.com/yuque/0/2024/png/28628673/1729674068565-6e85ab38-8e27-45f8-b33e-71fbec255851.png
sql语句的话可以查询相干资料。
查询的数据以标准格式显示。
.header on
.mode column
SELECT * FROM COMPANY;当然sqlite也有可视化的软件,但是我现在没用到,所以没有下载安装,需要的话可以自行查询。
4 创建日志相干基本表
利用命令创建日志表,包含id(利用自增,当然可以换成uuid或者其它形式)、日期、线程号、级别(info、error这些)、记载者、具体记载的信息、异常信息。具体内容要对应log4net的设置。
CREATE TABLE Log (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Date DATETIME,
Thread VARCHAR(255),
Level VARCHAR(50),
Logger VARCHAR(255),
Message TEXT,
Exception TEXT
);5 log4net设置
更换数据库连接。sql语句的内容对应数据库基本表的字段。
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="1" />
<connectionType value="System.Data.SQLite.SQLiteConnection, System.Data.SQLite" />
<connectionString value="Data Source=./database/logs.db;Version=3;" />
<commandText value="INSERT INTO Log (Date, Thread, Level, Logger, Message, Exception) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)" />
<parameter>
<parameterName value="@log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="@thread" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%thread" />
</layout>
</parameter>
<parameter>
<parameterName value="@log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="@logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<parameter>
<parameterName value="@message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="@exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="AdoNetAppender" />
</root>
</log4net>
</configuration>6 日志记载
把生成的db文件拷到步伐里,这个文件就是记载文件的数据库了,其它的都不告急。当然,假如想查看数据库的话,也可以把sqlite3.exe拷过来。
读取log4net的设置建议写在AssemblyInfo.cs,这样步伐启动时会默认加载设置文件。
//Log4net配置
https://cdn.nlark.com/yuque/0/2024/png/28628673/1729675803360-1b39de2f-9360-409f-abd5-e0676d6de74e.png
具体步伐如下:
private static readonly ILog log = LogManager.GetLogger(typeof(Form1));
log.Info("这是一条info语句");
log.Warn("这是一条warn语句");
log.Error("这是一条错误语句", new Exception("测试异常"));查看日志是否正常写入数据库。
https://cdn.nlark.com/yuque/0/2024/png/28628673/1729675894685-c3c47e8a-f4b9-478c-be4f-7a8604dccf01.png
7 利用C#步伐查询sqlite
步伐如下:
// 构建连接字符串
string connectionString = $"Data Source=./database/SoftWareBaseLog.db;Version=3;";
// 创建 SQLite 连接
using (var connection = new SQLiteConnection(connectionString))
{
connection.Open();
// 创建 SQL 命令
string sql = "SELECT Message FROM Log where Level='ERROR'";
using (var command = new SQLiteCommand(sql, connection))
{
// 执行命令并读取数据
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
string msg = reader.GetString(0);
Console.WriteLine(msg);
}
}
}
}8 实时显示日志
现在所有日志都写到数据库里了,那要是还想实时显示到界面上,当然也有很多方式实现,不过我这里建议实时显示可以利用log4net的自有功能。
好比我想利用winform中的listbox来实时显示日志,可以建立一个Appender(附加),继承于log4net的AppenderSkeleton,这是一个抽象类,有一个抽象方法。
具体的,可以参考以下步伐,这里会显示所有的日志,假如需要过滤的话,可以在这个基础上改。另外,一定一定一定要给this.Layout赋值,这是日志在界面上的显示方式,假如没有写的话,就会劳绩一个报错:“A layout must be set”,去网上搜这条内容,不一定能找到办理方案。
public class ListBoxAppender : AppenderSkeleton
{
private ListBox _ListBox;
public ListBoxAppender(ListBox box)
{
_ListBox = box;
this.Layout = new PatternLayout("%date [%thread] %-5level %logger - %message%newline");
}
protected override void Append(LoggingEvent loggingEvent)
{
// 获取日志信息
string logMessage = RenderLoggingEvent(loggingEvent);
// 更新 UI 控件
if (_ListBox.InvokeRequired)
{
_ListBox.Invoke(new Action(() => AppendText(logMessage)));
}
else
{
AppendText(logMessage);
}
}
private void AppendText(string text)
{
_ListBox.Items.Add(text);
}
}只需要给log4net设置一次就可以利用,这样,每次调用日志记载,界面上的lbxLog控件就可以一直显示最新的日志信息。
// 添加自定义 Appender
var listBoxAppender = new ListBoxAppender(lbxLog);
log4net.Config.BasicConfigurator.Configure(listBoxAppender);但是,测试出现了标题,在多线程、短时间添加多条日志的情况下会导致界面卡死,猜测是多条日志抢一个listbox的索引出现的标题,更好的方案是添加缓存机制,生产者-消耗者模式。
生产者只记载到队列里即可,这里为了避免队列堆积,利用了定长的一个概念,太多的日志堆积会丢掉一部份数据。
public class LogQueueAppender : AppenderSkeleton
{
/// <summary>
/// 锁对象
/// </summary>
private static readonly object _lock = new object();
private static LogQueueAppender Instance { get; set; }
/// <summary>
/// 日志队列
/// 不再直接更新控件,在日志频繁时会出现控件卡死的情况
/// </summary>
private ConcurrentQueue<string> LogQueue { get; } = new ConcurrentQueue<string>();
private LogQueueAppender()
{
//Layout必须赋值,否则会报错
this.Layout = new PatternLayout("%date [%thread] %-5level %logger - %message%newline");
}
/// <summary>
/// 获取实体对象
/// </summary>
/// <returns></returns>
public static LogQueueAppender GetInstance()
{
if (Instance == null)
{
lock (_lock)
{
if (Instance == null)
{
Instance = new LogQueueAppender();
}
}
}
return Instance;
}
/// <summary>
/// 获取日志队列
/// </summary>
/// <returns></returns>
public ConcurrentQueue<string> GetLogQueue()
{
return LogQueue;
}
/// <summary>
/// 覆写Append方法
/// </summary>
/// <param name="loggingEvent"></param>
protected override void Append(LoggingEvent loggingEvent)
{
// 获取日志信息
string logMessage = RenderLoggingEvent(loggingEvent);
AppendText(logMessage);
}
/// <summary>
/// 添加日志信息
/// </summary>
/// <param name="text"></param>
private void AppendText(string text)
{
//最多存储200条日志,多余的会直接丢弃
if (LogQueue.Count >= 200)
{
LogQueue.TryDequeue(out string message);
}
LogQueue.Enqueue(text);
}而消耗者负责将日志信息更新到界面上,这里每次只更新一条日志信息,我认为足够了,当然这可以改成一次更新多条信息,避免日志堆积。
/// <summary>
/// 读取日志信息
/// </summary>
private void LoadLog()
{
LogThreadRunFlag = true;
Task.Factory.StartNew(() => {
while (LogThreadRunFlag == true)
{
bool flag = LogQueueAppender.GetInstance().GetLogQueue().TryDequeue(out string log);
if (flag)
{
lvwLog.Invoke(new Action(() => AppendText(log)));
}
Thread.Sleep(50);
}
}, TaskCreationOptions.LongRunning);
}
/// <summary>
/// 添加到界面中
/// </summary>
/// <param name="text">日志信息</param>
private void AppendText(string text)
{
if (lvwLog.Items.Count == 100)
{
lvwLog.Items.Clear();
}
lvwLog.Items.Add(text);
if (text.Contains("ERROR"))
{
lvwLog.Items.ForeColor = Color.Red;
}
}另外,控件换成了listview,因为这个可以很方便地“高亮”错误日志。相干listview的设置如下:
lvwLog.View = View.Details; // 设置为竖向排列
lvwLog.Scrollable = true; // 确保滚动条可用
lvwLog.Columns.Add("日志信息", -2); //添加一列数据,并占满全行
lvwLog.DoubleBuffered(true); //使用双缓冲,避免闪烁结果如下:
https://cdn.nlark.com/yuque/0/2024/png/28628673/1729826981565-424439b6-890d-400a-94e2-7f9c1443e8d5.png
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]