277 lines
10 KiB
C#
277 lines
10 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Threading.Tasks;
|
||
using Microsoft.Extensions.Configuration;
|
||
using Microsoft.Extensions.Logging;
|
||
using Serilog;
|
||
using Serilog.Extensions.Logging;
|
||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||
|
||
namespace JiShe.CollectBus.PluginFileWatcher
|
||
{
|
||
/// <summary>
|
||
/// 数据库操作工具类,用于命令行测试数据库功能
|
||
/// </summary>
|
||
public class DbUtility
|
||
{
|
||
private readonly EventDatabaseManager _dbManager;
|
||
private readonly ILogger _logger;
|
||
private readonly FileMonitorConfig _config;
|
||
|
||
/// <summary>
|
||
/// 初始化数据库工具类
|
||
/// </summary>
|
||
/// <param name="configPath">配置文件路径</param>
|
||
public DbUtility(string configPath = "appsettings.json")
|
||
{
|
||
// 从配置文件加载配置
|
||
var configuration = new ConfigurationBuilder()
|
||
.AddJsonFile(configPath, optional: false, reloadOnChange: true)
|
||
.Build();
|
||
|
||
// 初始化日志
|
||
var serilogLogger = new LoggerConfiguration()
|
||
.ReadFrom.Configuration(configuration)
|
||
.CreateLogger();
|
||
|
||
// 将Serilog适配为Microsoft.Extensions.Logging.ILogger
|
||
_logger = new SerilogLoggerFactory(serilogLogger).CreateLogger("DbUtility");
|
||
|
||
// 创建配置对象
|
||
_config = new FileMonitorConfig();
|
||
configuration.GetSection("FileMonitor").Bind(_config);
|
||
|
||
// 确保SQLite存储已启用
|
||
_config.EventStorage.EnableEventStorage = true;
|
||
_config.EventStorage.StorageType = "SQLite";
|
||
|
||
// 创建数据库管理器
|
||
_dbManager = new EventDatabaseManager(_config, _logger);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行数据库维护操作
|
||
/// </summary>
|
||
/// <param name="args">命令行参数</param>
|
||
public async Task ExecuteAsync(string[] args)
|
||
{
|
||
if (args.Length == 0)
|
||
{
|
||
PrintUsage();
|
||
return;
|
||
}
|
||
|
||
string command = args[0].ToLower();
|
||
|
||
switch (command)
|
||
{
|
||
case "stats":
|
||
await ShowStatisticsAsync();
|
||
break;
|
||
|
||
case "cleanup":
|
||
int days = args.Length > 1 && int.TryParse(args[1], out int d) ? d : _config.EventStorage.DataRetentionDays;
|
||
await _dbManager.CleanupOldDataAsync(days);
|
||
Console.WriteLine($"已清理 {days} 天前的旧数据");
|
||
break;
|
||
|
||
case "query":
|
||
await QueryEventsAsync(args);
|
||
break;
|
||
|
||
case "test":
|
||
await GenerateTestDataAsync(args);
|
||
break;
|
||
|
||
default:
|
||
Console.WriteLine($"未知命令: {command}");
|
||
PrintUsage();
|
||
break;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示帮助信息
|
||
/// </summary>
|
||
private void PrintUsage()
|
||
{
|
||
Console.WriteLine("数据库工具使用方法:");
|
||
Console.WriteLine(" stats - 显示数据库统计信息");
|
||
Console.WriteLine(" cleanup [days] - 清理指定天数之前的数据(默认使用配置值)");
|
||
Console.WriteLine(" query [limit] - 查询最近的事件(默认10条)");
|
||
Console.WriteLine(" query type:X ext:Y - 按类型和扩展名查询事件");
|
||
Console.WriteLine(" test [count] - 生成测试数据(默认100条)");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示数据库统计信息
|
||
/// </summary>
|
||
private async Task ShowStatisticsAsync()
|
||
{
|
||
try
|
||
{
|
||
var stats = await _dbManager.GetDatabaseStatsAsync();
|
||
|
||
Console.WriteLine("数据库统计信息:");
|
||
Console.WriteLine($"事件总数: {stats.TotalEvents}");
|
||
Console.WriteLine($"最早事件时间: {stats.OldestEventTime?.ToLocalTime()}");
|
||
Console.WriteLine($"最新事件时间: {stats.NewestEventTime?.ToLocalTime()}");
|
||
|
||
Console.WriteLine("\n事件类型分布:");
|
||
if (stats.EventTypeCounts != null)
|
||
{
|
||
foreach (var item in stats.EventTypeCounts)
|
||
{
|
||
Console.WriteLine($" {item.Key}: {item.Value}");
|
||
}
|
||
}
|
||
|
||
Console.WriteLine("\n扩展名分布 (Top 10):");
|
||
if (stats.TopExtensions != null)
|
||
{
|
||
foreach (var item in stats.TopExtensions)
|
||
{
|
||
Console.WriteLine($" {item.Key}: {item.Value}");
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"获取统计信息出错: {ex.Message}");
|
||
_logger.LogError(ex, "获取数据库统计信息时发生错误");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询事件
|
||
/// </summary>
|
||
private async Task QueryEventsAsync(string[] args)
|
||
{
|
||
try
|
||
{
|
||
var queryParams = new EventQueryParams
|
||
{
|
||
PageSize = 10,
|
||
PageIndex = 0
|
||
};
|
||
|
||
// 解析查询参数
|
||
if (args.Length > 1)
|
||
{
|
||
foreach (var arg in args.Skip(1))
|
||
{
|
||
if (int.TryParse(arg, out int limit))
|
||
{
|
||
queryParams.PageSize = limit;
|
||
}
|
||
else if (arg.StartsWith("type:", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
string typeValue = arg.Substring(5);
|
||
if (Enum.TryParse<FileEventType>(typeValue, true, out var eventType))
|
||
{
|
||
queryParams.EventType = eventType;
|
||
}
|
||
}
|
||
else if (arg.StartsWith("ext:", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
queryParams.ExtensionFilter = arg.Substring(4);
|
||
if (!queryParams.ExtensionFilter.StartsWith("."))
|
||
{
|
||
queryParams.ExtensionFilter = "." + queryParams.ExtensionFilter;
|
||
}
|
||
}
|
||
else if (arg.StartsWith("path:", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
queryParams.PathFilter = arg.Substring(5);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 执行查询
|
||
var result = await _dbManager.QueryEventsAsync(queryParams);
|
||
|
||
Console.WriteLine($"查询结果 (总数: {result.TotalCount}):");
|
||
foreach (var evt in result.Events)
|
||
{
|
||
string typeStr = evt.EventType.ToString();
|
||
string timestamp = evt.Timestamp.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss");
|
||
Console.WriteLine($"[{timestamp}] {typeStr,-10} {evt.FileName} ({evt.Extension})");
|
||
}
|
||
|
||
if (result.HasMore)
|
||
{
|
||
Console.WriteLine($"... 还有更多结果,共 {result.TotalCount} 条");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"查询事件出错: {ex.Message}");
|
||
_logger.LogError(ex, "查询事件时发生错误");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成测试数据
|
||
/// </summary>
|
||
private async Task GenerateTestDataAsync(string[] args)
|
||
{
|
||
try
|
||
{
|
||
int count = args.Length > 1 && int.TryParse(args[1], out int c) ? c : 100;
|
||
|
||
var events = new List<FileEvent>();
|
||
var rnd = new Random();
|
||
string[] extensions = { ".dll", ".exe", ".txt", ".cs", ".xml", ".json", ".png", ".jpg" };
|
||
string[] directories = { "C:\\Temp", "D:\\Work", "C:\\Program Files", "D:\\Projects", "E:\\Data" };
|
||
|
||
DateTime startTime = DateTime.Now.AddHours(-24);
|
||
|
||
for (int i = 0; i < count; i++)
|
||
{
|
||
var eventType = (FileEventType)rnd.Next(0, 5);
|
||
var ext = extensions[rnd.Next(extensions.Length)];
|
||
var dir = directories[rnd.Next(directories.Length)];
|
||
var fileName = $"TestFile_{i:D5}{ext}";
|
||
var timestamp = startTime.AddMinutes(i);
|
||
|
||
var fileEvent = new FileEvent
|
||
{
|
||
Id = Guid.NewGuid(),
|
||
Timestamp = timestamp,
|
||
EventType = eventType,
|
||
FullPath = $"{dir}\\{fileName}",
|
||
FileName = fileName,
|
||
Directory = dir,
|
||
Extension = ext,
|
||
FileSize = rnd.Next(1024, 1024 * 1024)
|
||
};
|
||
|
||
// 如果是重命名事件,添加旧文件名
|
||
if (eventType == FileEventType.Renamed)
|
||
{
|
||
fileEvent.OldFileName = $"OldFile_{i:D5}{ext}";
|
||
fileEvent.OldFullPath = $"{dir}\\{fileEvent.OldFileName}";
|
||
}
|
||
|
||
// 添加一些元数据
|
||
fileEvent.Metadata["CreationTime"] = timestamp.AddMinutes(-rnd.Next(1, 60)).ToString("o");
|
||
fileEvent.Metadata["LastWriteTime"] = timestamp.ToString("o");
|
||
fileEvent.Metadata["IsReadOnly"] = (rnd.Next(10) < 2).ToString();
|
||
fileEvent.Metadata["TestData"] = $"测试数据 {i}";
|
||
|
||
events.Add(fileEvent);
|
||
}
|
||
|
||
Console.WriteLine($"正在生成 {count} 条测试数据...");
|
||
await _dbManager.SaveEventsAsync(events);
|
||
Console.WriteLine("测试数据生成完成!");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"生成测试数据出错: {ex.Message}");
|
||
_logger.LogError(ex, "生成测试数据时发生错误");
|
||
}
|
||
}
|
||
}
|
||
} |