在工业自动化、物联网和设备监控领域,记录设备运行日志是保障系统稳定和问题追踪的关键环节。本文将详细介绍如何使用C#和SQLite数据库构建一个轻量级但功能强大的设备日志记录系统,并使用流行的Spectre.Console库为控制台输出添加美观的视觉效果。
SQLite作为一个嵌入式数据库,具有以下优势:
我们的设备日志系统包含以下核心组件:
首先,让我们定义日志类型枚举和设备日志实体类:
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是一个现代化的.NET库,能够为控制台应用程序创建美观、交互式的用户界面。下面,我们将使用Spectre.Console提升我们的设备日志系统的可视化效果:

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]旧日志清理完成![/]");
}
}
}
}


本文介绍了如何使用C#和SQLite构建一个功能完整的设备日志记录系统,并借助Spectre.Console库打造美观的控制台界面。该系统具有以下优势:
无论是在工业控制、智能家居还是物联网应用领域,这套系统都能为设备运行状态的监控和问题诊断提供有力支持。通过SQLite的高效存储和Spectre.Console的精美展示,让设备数据管理既实用又赏心悦目。
您可以根据实际需求进一步扩展这个系统,例如添加数据导出功能、实现远程日志收集、开发Web管理界面等。希望本文对您的项目开发有所启发和帮助!
#C#开发 #SQLite #设备监控 #日志系统 #Spectre控制台 #数据可视化 #工业物联网
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!