LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

C#与SQLite打造高效设备运行日志记录系统

admin
2025年5月26日 8:43 本文热度 196

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

为什么选择SQLite?

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

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

系统设计

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

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

基础结构定义

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

// 日志类型枚举
publicenum LogType 
{
    Info,     // 一般信息
    Warning,  // 警告信息
    Error,    // 错误信息
    Critical  // 严重错误
}

// 设备日志实体类
publicclass DeviceLog 
{

    publicint Id { get; set; }                // 日志唯一标识
    public DateTime Timestamp { get; set; }    // 时间戳
    publicstring DeviceId { get; set; }       // 设备标识
    public LogType LogLevel { get; set; }      // 日志级别
    publicstring Message { get; set; }        // 日志消息
    publicdouble? Temperature { get; set; }   // 温度(可选)
    publicdouble? Voltage { get; set; }       // 电压(可选)
}

数据库管理

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

// 日志管理器
publicclass DeviceLogManager 
{

    privatestring _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提升我们的设备日志系统的可视化效果:

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(148));
                    var logType = (LogType)random.Next(04);
                    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库打造美观的控制台界面。该系统具有以下优势:

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

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

您可以根据实际需求进一步扩展这个系统,例如添加数据导出功能、实现远程日志收集、开发Web管理界面等。


阅读原文:原文链接


该文章在 2025/5/26 11:08:33 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved