1 安装包
两个包:
- log4net
- System.Data.SQLite
第二个包也可以利用Microsoft.Data.Sqlite,查到的资料显示假如情况利用的是 .NET Core 或 .NET 5+,则建议利用Microsoft.Data.Sqlite。但是我并没有测试第二个包,可能利用上有区别。
2 下载Sqlite
假如本地没有sqlite情况的话,需要先下载。官网下载链接
进去之后直接找各自情况对应的版本,假如是windows情况的话,直接下载下图中标记的tool,中间那个下载链接是下载sqlite3.dll,不过我并不清楚如何利用。
tool解压之后有如下几个文件,双击打开sqlite3.exe即可。
3 Sqlite常用命令
打开是一个命令行界面,可以利用.help查看常用的命令及解释。
创建数据库文件利用.open xxx,这条语句,假如发现数据库文件存在,就会直接打开,假如不存在,就会先创建再打开。在目录内可以看到创建的数据库文件。
.databases可以查询所有数据库文件
.tables可以查询所有表(我还未创建,所以现在还没有表)
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配置
- [assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
复制代码
具体步伐如下:- private static readonly ILog log = LogManager.GetLogger(typeof(Form1));
- log.Info("这是一条info语句");
- log.Warn("这是一条warn语句");
- log.Error("这是一条错误语句", new Exception("测试异常"));
复制代码 查看日志是否正常写入数据库。
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[lvwLog.Items.Count - 1].ForeColor = Color.Red;
- }
- }
复制代码 另外,控件换成了listview,因为这个可以很方便地“高亮”错误日志。相干listview的设置如下:- lvwLog.View = View.Details; // 设置为竖向排列
- lvwLog.Scrollable = true; // 确保滚动条可用
- lvwLog.Columns.Add("日志信息", -2); //添加一列数据,并占满全行
- lvwLog.DoubleBuffered(true); //使用双缓冲,避免闪烁
复制代码 结果如下:
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |