2025-11-14
SQLite
00

目录

为什么选择SQLite?
系统设计
基础结构定义
数据库管理
使用Spectre.Console美化控制台输出
总结

在工业自动化、物联网和设备监控领域,记录设备运行日志是保障系统稳定和问题追踪的关键环节。本文将详细介绍如何使用C#和SQLite数据库构建一个轻量级但功能强大的设备日志记录系统,并使用流行的Spectre.Console库为控制台输出添加美观的视觉效果。

为什么选择SQLite?

SQLite作为一个嵌入式数据库,具有以下优势:

  • 零配置,无需安装独立数据库服务
  • 单文件存储,便于备份和迁移
  • 跨平台兼容性强
  • 资源占用少,适合嵌入式设备
  • 支持SQL标准查询

系统设计

我们的设备日志系统包含以下核心组件:

  1. 日志类型枚举(LogType)
  2. 设备日志实体类(DeviceLog)
  3. 日志管理器(DeviceLogManager)
  4. 控制台展示界面(使用Spectre.Console)

基础结构定义

首先,让我们定义日志类型枚举和设备日志实体类:

C#
// 日志类型枚举 public enum LogType { Info, // 一般信息 Warning, // 警告信息 Error, // 错误信息 Critical // 严重错误 } // 设备日志实体类 public class DeviceLog { public int Id { get; set; } // 日志唯一标识 public DateTime Timestamp { get; set; } // 时间戳 public string DeviceId { get; set; } // 设备标识 public LogType LogLevel { get; set; } // 日志级别 public string Message { get; set; } // 日志消息 public double? Temperature { get; set; } // 温度(可选) public double? Voltage { get; set; } // 电压(可选) }

数据库管理

日志管理器负责与SQLite数据库交互,实现日志的存储和检索:

C#
// 日志管理器 public class DeviceLogManager { private string _connectionString; // 构造函数,接收数据库文件路径 public DeviceLogManager(string dbPath) { _connectionString = $"Data Source={dbPath};Version=3;"; InitializeDatabase(); } // 初始化数据库,如果表不存在则创建 private void InitializeDatabase() { using (var connection = new SQLiteConnection(_connectionString)) { connection.Open(); using (var command = new SQLiteCommand(connection)) { command.CommandText = @" CREATE TABLE IF NOT EXISTS DeviceLogs ( Id INTEGER PRIMARY KEY AUTOINCREMENT, Timestamp DATETIME NOT NULL, DeviceId TEXT NOT NULL, LogLevel INTEGER NOT NULL, Message TEXT NOT NULL, Temperature REAL, Voltage REAL )"; command.ExecuteNonQuery(); } } } // 记录日志方法 public void LogEvent(DeviceLog log) { using (var connection = new SQLiteConnection(_connectionString)) { connection.Open(); using (var command = new SQLiteCommand(connection)) { command.CommandText = @" INSERT INTO DeviceLogs (Timestamp, DeviceId, LogLevel, Message, Temperature, Voltage) VALUES (@Timestamp, @DeviceId, @LogLevel, @Message, @Temperature, @Voltage)"; command.Parameters.AddWithValue("@Timestamp", log.Timestamp); command.Parameters.AddWithValue("@DeviceId", log.DeviceId); command.Parameters.AddWithValue("@LogLevel", (int)log.LogLevel); command.Parameters.AddWithValue("@Message", log.Message); // 对可能为空的数值使用DBNull.Value command.Parameters.AddWithValue("@Temperature", log.Temperature ?? (object)DBNull.Value); command.Parameters.AddWithValue("@Voltage", log.Voltage ?? (object)DBNull.Value); command.ExecuteNonQuery(); } } } // 查询日志方法,支持多种过滤条件 public List<DeviceLog> GetLogs( string deviceId = null, LogType? logLevel = null, DateTime? startTime = null, DateTime? endTime = null) { var logs = new List<DeviceLog>(); using (var connection = new SQLiteConnection(_connectionString)) { connection.Open(); using (var command = new SQLiteCommand(connection)) { // 构建WHERE子句 var whereConditions = new List<string>(); if (!string.IsNullOrEmpty(deviceId)) whereConditions.Add("DeviceId = @DeviceId"); if (logLevel.HasValue) whereConditions.Add("LogLevel = @LogLevel"); if (startTime.HasValue) whereConditions.Add("Timestamp >= @StartTime"); if (endTime.HasValue) whereConditions.Add("Timestamp <= @EndTime"); string whereClause = whereConditions.Any() ? $"WHERE {string.Join(" AND ", whereConditions)}" : ""; // 构建SQL查询 command.CommandText = $@" SELECT * FROM DeviceLogs {whereClause} ORDER BY Timestamp DESC"; // 添加参数 if (!string.IsNullOrEmpty(deviceId)) command.Parameters.AddWithValue("@DeviceId", deviceId); if (logLevel.HasValue) command.Parameters.AddWithValue("@LogLevel", (int)logLevel.Value); if (startTime.HasValue) command.Parameters.AddWithValue("@StartTime", startTime.Value); if (endTime.HasValue) command.Parameters.AddWithValue("@EndTime", endTime.Value); // 读取结果 using (var reader = command.ExecuteReader()) { while (reader.Read()) { logs.Add(new DeviceLog { Id = Convert.ToInt32(reader["Id"]), Timestamp = Convert.ToDateTime(reader["Timestamp"]), DeviceId = reader["DeviceId"].ToString(), LogLevel = (LogType)Convert.ToInt32(reader["LogLevel"]), Message = reader["Message"].ToString(), Temperature = reader["Temperature"] == DBNull.Value ? null : Convert.ToDouble(reader["Temperature"]), Voltage = reader["Voltage"] == DBNull.Value ? null : Convert.ToDouble(reader["Voltage"]) }); } } } } return logs; } // 删除过期日志 public void DeleteOldLogs(int daysToKeep) { using (var connection = new SQLiteConnection(_connectionString)) { connection.Open(); using (var command = new SQLiteCommand(connection)) { command.CommandText = @" DELETE FROM DeviceLogs WHERE Timestamp < @OldDate"; command.Parameters.AddWithValue("@OldDate", DateTime.Now.AddDays(-daysToKeep)); command.ExecuteNonQuery(); } } } }

使用Spectre.Console美化控制台输出

Spectre.Console是一个现代化的.NET库,能够为控制台应用程序创建美观、交互式的用户界面。下面,我们将使用Spectre.Console提升我们的设备日志系统的可视化效果:

image.png

C#
using Spectre.Console; using System; using System.Data.SQLite; using System.Linq; namespace DeviceLoggerSystem { class Program { static void Main(string[] args) { // 创建标题 AnsiConsole.Write( new FigletText("设备日志系统") .LeftJustified() .Color(Color.Green)); // 创建日志管理器 var dbPath = "device_logs.db"; var logManager = new DeviceLogManager(dbPath); // 使用进度条显示系统初始化 AnsiConsole.Progress() .Start(ctx => { var task = ctx.AddTask("[green]初始化系统[/]"); for (int i = 0; i < 100; i++) { task.Increment(1); System.Threading.Thread.Sleep(20); } }); // 记录一些示例日志 AddSampleLogs(logManager); // 主循环 bool running = true; while (running) { var choice = AnsiConsole.Prompt( new SelectionPrompt<string>() .Title("[yellow]请选择操作:[/]") .PageSize(10) .AddChoices(new[] { "添加新日志", "查询设备日志", "查看统计信息", "清理旧日志", "退出" })); switch (choice) { case "添加新日志": AddNewLog(logManager); break; case "查询设备日志": QueryLogs(logManager); break; case "查看统计信息": ShowStatistics(logManager); break; case "清理旧日志": CleanupOldLogs(logManager); break; case "退出": running = false; break; } } } // 添加示例日志数据 static void AddSampleLogs(DeviceLogManager logManager) { var deviceIds = new[] { "DEVICE_001", "DEVICE_002", "DEVICE_003" }; var random = new Random(); foreach (var deviceId in deviceIds) { // 添加一些随机的历史数据 for (int i = 0; i < 5; i++) { var timestamp = DateTime.Now.AddHours(-random.Next(1, 48)); var logType = (LogType)random.Next(0, 4); var temp = 20.0 + random.NextDouble() * 30.0; var voltage = 200.0 + random.NextDouble() * 40.0; string message = logType switch { LogType.Info => "定期检查正常", LogType.Warning => "温度偏高,请注意", LogType.Error => "电压异常,需要检查", LogType.Critical => "设备紧急停机", _ => "系统记录" }; logManager.LogEvent(new DeviceLog { Timestamp = timestamp, DeviceId = deviceId, LogLevel = logType, Message = message, Temperature = temp, Voltage = voltage }); } } AnsiConsole.MarkupLine("[green]示例数据已创建![/]"); } // 添加新日志 static void AddNewLog(DeviceLogManager logManager) { var deviceId = AnsiConsole.Ask<string>("输入设备ID:"); var logLevel = AnsiConsole.Prompt( new SelectionPrompt<LogType>() .Title("选择日志级别:") .AddChoices(Enum.GetValues(typeof(LogType)).Cast<LogType>())); var message = AnsiConsole.Ask<string>("输入日志消息:"); // 可选参数 double? temperature = null; double? voltage = null; if (AnsiConsole.Confirm("是否记录温度?")) { temperature = AnsiConsole.Ask<double>("输入温度值:"); } if (AnsiConsole.Confirm("是否记录电压?")) { voltage = AnsiConsole.Ask<double>("输入电压值:"); } logManager.LogEvent(new DeviceLog { Timestamp = DateTime.Now, DeviceId = deviceId, LogLevel = logLevel, Message = message, Temperature = temperature, Voltage = voltage }); AnsiConsole.MarkupLine("[green]日志已添加成功![/]"); } // 查询日志 static void QueryLogs(DeviceLogManager logManager) { // 构建查询条件 string deviceId = null; if (AnsiConsole.Confirm("是否按设备ID筛选?")) { deviceId = AnsiConsole.Ask<string>("请输入设备ID:"); } LogType? logLevel = null; if (AnsiConsole.Confirm("是否按日志级别筛选?")) { logLevel = AnsiConsole.Prompt( new SelectionPrompt<LogType>() .Title("选择日志级别:") .AddChoices(Enum.GetValues(typeof(LogType)).Cast<LogType>())); } DateTime? startTime = null; if (AnsiConsole.Confirm("是否设置开始时间?")) { string dateStr = AnsiConsole.Ask<string>("请输入开始时间 (yyyy-MM-dd HH:mm:ss):"); if (DateTime.TryParse(dateStr, out var dt)) startTime = dt; } DateTime? endTime = null; if (AnsiConsole.Confirm("是否设置结束时间?")) { string dateStr = AnsiConsole.Ask<string>("请输入结束时间 (yyyy-MM-dd HH:mm:ss):"); if (DateTime.TryParse(dateStr, out var dt)) endTime = dt; } // 执行查询 var logs = logManager.GetLogs(deviceId, logLevel, startTime, endTime); if (logs.Count == 0) { AnsiConsole.MarkupLine("[yellow]未找到符合条件的日志记录[/]"); return; } // 创建表格显示结果 var table = new Table(); table.Border(TableBorder.Rounded); table.Expand(); // 添加列 table.AddColumn("ID"); table.AddColumn("时间"); table.AddColumn("设备ID"); table.AddColumn("级别"); table.AddColumn("消息"); table.AddColumn("温度"); table.AddColumn("电压"); // 添加数据行 foreach (var log in logs) { string tempStr = log.Temperature.HasValue ? $"{log.Temperature:F1}°C" : "-"; string voltStr = log.Voltage.HasValue ? $"{log.Voltage:F1}V" : "-"; // 根据日志级别设置行颜色 var style = log.LogLevel switch { LogType.Info => "green", LogType.Warning => "yellow", LogType.Error => "red", LogType.Critical => "red bold", _ => "white" }; table.AddRow( $"[{style}]{log.Id}[/]", $"[{style}]{log.Timestamp}[/]", $"[{style}]{log.DeviceId}[/]", $"[{style}]{log.LogLevel}[/]", $"[{style}]{log.Message}[/]", $"[{style}]{tempStr}[/]", $"[{style}]{voltStr}[/]" ); } AnsiConsole.Write(table); AnsiConsole.MarkupLine($"[blue]共找到 {logs.Count} 条记录[/]"); } // 显示统计信息 static void ShowStatistics(DeviceLogManager logManager) { // 获取所有日志 var allLogs = logManager.GetLogs(); // 按设备统计 var deviceCounts = allLogs .GroupBy(l => l.DeviceId) .Select(g => (DeviceId: g.Key, Count: g.Count())) .ToList(); // 按日志级别统计 var levelCounts = allLogs .GroupBy(l => l.LogLevel) .Select(g => (Level: g.Key, Count: g.Count())) .ToList(); // 创建统计图表 AnsiConsole.Write(new Rule("[yellow]设备日志统计[/]")); // 设备柱状图 var deviceChart = new BarChart() .Width(60) .Label("[green bold]按设备统计[/]") .CenterLabel(); foreach (var item in deviceCounts) { deviceChart.AddItem(item.DeviceId, item.Count, Color.Blue); } AnsiConsole.Write(deviceChart); // 日志级别饼图 var levelChart = new BarChart() .Width(60) .Label("[red bold]按日志级别统计[/]") .CenterLabel(); foreach (var item in levelCounts) { var color = item.Level switch { LogType.Info => Color.Green, LogType.Warning => Color.Yellow, LogType.Error => Color.Red, LogType.Critical => Color.Purple, _ => Color.White }; levelChart.AddItem(item.Level.ToString(), item.Count, color); } AnsiConsole.Write(levelChart); // 时间分布 if (allLogs.Any()) { AnsiConsole.MarkupLine($"[blue]最早记录时间: {allLogs.Min(l => l.Timestamp)}[/]"); AnsiConsole.MarkupLine($"[blue]最新记录时间: {allLogs.Max(l => l.Timestamp)}[/]"); AnsiConsole.MarkupLine($"[blue]总记录数: {allLogs.Count}[/]"); } } // 清理旧日志 static void CleanupOldLogs(DeviceLogManager logManager) { var days = AnsiConsole.Ask("保留最近几天的日志?", 30); if (AnsiConsole.Confirm($"确定要删除 {days} 天前的所有日志记录?")) { AnsiConsole.Status() .Start("正在清理旧日志...", ctx => { logManager.DeleteOldLogs(days); System.Threading.Thread.Sleep(1000); // 模拟操作 }); AnsiConsole.MarkupLine("[green]旧日志清理完成![/]"); } } } }

image.png

image.png

总结

本文介绍了如何使用C#和SQLite构建一个功能完整的设备日志记录系统,并借助Spectre.Console库打造美观的控制台界面。该系统具有以下优势:

  1. 轻量级:无需复杂的数据库配置,单文件存储
  2. 高效性:快速的读写操作,支持批量处理
  3. 可扩展:易于添加新的设备参数和日志类型
  4. 用户友好:直观的界面设计,丰富的可视化效果
  5. 实用功能:完整的CRUD操作,灵活的查询和管理能力

无论是在工业控制、智能家居还是物联网应用领域,这套系统都能为设备运行状态的监控和问题诊断提供有力支持。通过SQLite的高效存储和Spectre.Console的精美展示,让设备数据管理既实用又赏心悦目。

您可以根据实际需求进一步扩展这个系统,例如添加数据导出功能、实现远程日志收集、开发Web管理界面等。希望本文对您的项目开发有所启发和帮助!


#C#开发 #SQLite #设备监控 #日志系统 #Spectre控制台 #数据可视化 #工业物联网

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!