using Microsoft.AspNetCore.Mvc; using LTEMvcApp.Models; using LTEMvcApp.Services; using Microsoft.Extensions.Logging; using System.Threading.Tasks; using System.Threading; using System.IO; using System.Text; namespace LTEMvcApp.Controllers { /// /// 日志管理控制器 - 负责日志相关的管理功能 /// [ApiController] [Route("api/[controller]")] public class LogController : ControllerBase { private readonly WebSocketManagerService _webSocketManager; private readonly ILogger _logger; private readonly string _logsDirectory = "ClientMessageLogs"; public LogController(WebSocketManagerService webSocketManager, ILogger logger) { _webSocketManager = webSocketManager; _logger = logger; // 确保日志目录存在 if (!Directory.Exists(_logsDirectory)) { Directory.CreateDirectory(_logsDirectory); } } /// /// 获取日志缓存统计信息 /// /// 统计信息 [HttpGet("stats")] public ActionResult GetLogCacheStats() { try { var stats = new { totalLogs = _webSocketManager.GetLogCacheCount(), cacheSize = 10000, // LogCacheSize timestamp = DateTime.UtcNow }; return Ok(stats); } catch (Exception ex) { _logger.LogError(ex, "获取日志缓存统计信息时发生错误"); return StatusCode(500, new { message = "获取统计信息失败", error = ex.Message }); } } /// /// 清空全局日志缓存 /// /// 操作结果 [HttpPost("clear")] public ActionResult ClearLogCache() { try { _webSocketManager.ClearLogCache(); return Ok(new { message = "日志缓存已清空" }); } catch (Exception ex) { _logger.LogError(ex, "清空日志缓存时发生错误"); return StatusCode(500, new { message = "清空日志缓存失败", error = ex.Message }); } } /// /// 重置全局日志缓存 /// /// 操作结果 [HttpPost("reset")] public ActionResult ResetLogCache() { try { _webSocketManager.ResetLogCache(); return Ok(new { message = "日志缓存已重置" }); } catch (Exception ex) { _logger.LogError(ex, "重置日志缓存时发生错误"); return StatusCode(500, new { message = "重置日志缓存失败", error = ex.Message }); } } /// /// 添加测试日志数据 /// /// 操作结果 [HttpPost("add-test-data")] public ActionResult AddTestLogData() { try { var testLogs = new List(); _webSocketManager.AddLogsToCache(testLogs); return Ok(new { message = $"已添加 {testLogs.Count} 条测试日志" }); } catch (Exception ex) { _logger.LogError(ex, "添加测试日志数据时发生错误"); return StatusCode(500, new { message = "添加测试日志失败", error = ex.Message }); } } /// /// 使用 Server-Sent Events (SSE) 实时推送全局日志 /// [HttpGet("stream")] public async Task StreamLogs(CancellationToken cancellationToken) { try { Response.ContentType = "text/event-stream"; Response.Headers.Append("Cache-Control", "no-cache"); Response.Headers.Append("Connection", "keep-alive"); Response.Headers.Append("Access-Control-Allow-Origin", "*"); // 发送连接成功事件 await SendSseEvent("connected", new { message = "日志流连接已建立", timestamp = DateTime.UtcNow }); await Response.Body.FlushAsync(cancellationToken); int lastLogCount = 0; var lastLogs = new List(); var lastLogHash = string.Empty; // 首先,一次性推送所有已缓存的日志 try { var initialLogs = _webSocketManager.GetLogCache()?.ToList() ?? new List(); _logger.LogInformation("StreamLogs: 获取到初始日志 {Count} 条", initialLogs.Count); if (initialLogs.Any()) { _logger.LogInformation("StreamLogs: 发送历史日志事件,日志数量: {Count}", initialLogs.Count); await SendSseEvent("history", new { logs = initialLogs, totalCount = initialLogs.Count }); await Response.Body.FlushAsync(cancellationToken); lastLogCount = initialLogs.Count; lastLogs = initialLogs.ToList(); lastLogHash = CalculateLogsHash(initialLogs); } else { _logger.LogInformation("StreamLogs: 没有历史日志数据"); } } catch (Exception ex) { _logger.LogError(ex, "获取初始日志时发生错误"); await SendSseEvent("error", new { message = "获取初始日志失败", error = ex.Message }); await Response.Body.FlushAsync(cancellationToken); } while (!cancellationToken.IsCancellationRequested) { try { var currentLogs = _webSocketManager.GetLogCache()?.ToList() ?? new List(); var currentLogHash = CalculateLogsHash(currentLogs); bool hasNewLogs = false; List newLogs = new List(); if (currentLogs.Count > lastLogCount) { newLogs = currentLogs.Skip(lastLogCount).ToList(); hasNewLogs = newLogs.Any(); } else if (currentLogs.Count == lastLogCount && currentLogHash != lastLogHash) { newLogs = GetChangedLogs(lastLogs, currentLogs); hasNewLogs = newLogs.Any(); } else if (currentLogs.Count < lastLogCount) { _logger.LogInformation("检测到日志缓存被重置,重新同步"); await SendSseEvent("reset", new { message = "日志缓存已重置", totalCount = currentLogs.Count }); await Response.Body.FlushAsync(cancellationToken); lastLogCount = currentLogs.Count; lastLogs = currentLogs.ToList(); lastLogHash = currentLogHash; continue; } if (hasNewLogs && newLogs.Any()) { _logger.LogInformation("StreamLogs: 发送新日志事件,新增日志数量: {NewCount}, 总日志数量: {TotalCount}", newLogs.Count, currentLogs.Count); var eventData = new { logs = newLogs, totalCount = currentLogs.Count, newCount = newLogs.Count }; await SendSseEvent("new_logs", eventData); await Response.Body.FlushAsync(cancellationToken); lastLogCount = currentLogs.Count; lastLogs = currentLogs.ToList(); lastLogHash = currentLogHash; } await Task.Delay(250, cancellationToken); } catch (OperationCanceledException) { break; } catch (Exception ex) { _logger.LogError(ex, "StreamLogs 循环中发生错误"); await SendSseEvent("error", new { message = "处理日志流时发生错误", error = ex.Message, timestamp = DateTime.UtcNow }); await Response.Body.FlushAsync(cancellationToken); await Task.Delay(1000, cancellationToken); } } await SendSseEvent("disconnected", new { message = "日志流连接已断开", timestamp = DateTime.UtcNow }); await Response.Body.FlushAsync(cancellationToken); } catch (OperationCanceledException) { _logger.LogInformation("StreamLogs 连接被客户端取消"); } catch (Exception ex) { _logger.LogError(ex, "StreamLogs 方法执行时发生未处理的异常"); try { await SendSseEvent("fatal_error", new { message = "服务器内部错误", error = ex.Message, timestamp = DateTime.UtcNow }); await Response.Body.FlushAsync(); } catch { // 忽略发送错误事件时的异常 } } } /// /// 获取日志缓存详细状态(调试用) /// /// 日志缓存详细状态 [HttpGet("debug")] public ActionResult GetLogCacheDebugInfo() { try { var logs = _webSocketManager.GetLogCache()?.ToList() ?? new List(); var logCount = _webSocketManager.GetLogCacheCount(); var cacheStatus = _webSocketManager.GetLogCacheStatus(); var debugInfo = new { totalLogs = logCount, actualLogsCount = logs.Count, cacheSize = 10000, timestamp = DateTime.UtcNow, sampleLogs = logs.TakeLast(5).Select(log => new { timestamp = log.Timestamp, layer = log.Layer, message = log.Message?.Substring(0, Math.Min(100, log.Message?.Length ?? 0)) + "..." }).ToList(), logHash = CalculateLogsHash(logs), cacheStatus = cacheStatus }; return Ok(debugInfo); } catch (Exception ex) { _logger.LogError(ex, "获取日志缓存调试信息时发生错误"); return StatusCode(500, new { message = "获取调试信息失败", error = ex.Message }); } } /// /// 获取SSE连接状态(调试用) /// /// 连接状态信息 [HttpGet("connection-status")] public ActionResult GetSseConnectionStatus() { try { var status = new { timestamp = DateTime.UtcNow, requestHeaders = Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToString()), userAgent = Request.Headers["User-Agent"].ToString(), accept = Request.Headers["Accept"].ToString(), cacheControl = Request.Headers["Cache-Control"].ToString(), connection = Request.Headers["Connection"].ToString(), isHttps = Request.IsHttps, host = Request.Host.ToString(), path = Request.Path.ToString(), queryString = Request.QueryString.ToString(), method = Request.Method, contentType = Request.ContentType, contentLength = Request.ContentLength }; return Ok(status); } catch (Exception ex) { _logger.LogError(ex, "获取SSE连接状态时发生错误"); return StatusCode(500, new { message = "获取连接状态失败", error = ex.Message }); } } /// /// 测试SSE连接(调试用) /// /// 测试结果 [HttpGet("test-connection")] public ActionResult TestSseConnection() { try { var testResult = new { message = "SSE连接测试成功", timestamp = DateTime.UtcNow, serverTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), logCacheCount = _webSocketManager.GetLogCacheCount(), testData = new { test = true, message = "这是一个测试消息" } }; return Ok(testResult); } catch (Exception ex) { _logger.LogError(ex, "测试SSE连接时发生错误"); return StatusCode(500, new { message = "测试连接失败", error = ex.Message }); } } /// /// 强制推送测试日志(调试用) /// /// 操作结果 [HttpPost("force-push-test")] public ActionResult ForcePushTestLogs() { try { var testLogs = new List(); _webSocketManager.AddLogsToCache(testLogs); _logger.LogInformation("强制推送测试日志: {Message}", testLogs[0].Message); return Ok(new { message = $"已强制推送测试日志: {testLogs[0].Message}", timestamp = testLogs[0].Timestamp }); } catch (Exception ex) { _logger.LogError(ex, "强制推送测试日志时发生错误"); return StatusCode(500, new { message = "强制推送失败", error = ex.Message }); } } private async Task SendSseEvent(string eventName, object data) { try { if (string.IsNullOrEmpty(eventName)) { _logger.LogWarning("尝试发送空事件名称的SSE事件"); return; } if (data == null) { _logger.LogWarning("尝试发送空数据的SSE事件: {EventName}", eventName); return; } var json = Newtonsoft.Json.JsonConvert.SerializeObject(data); var eventData = $"event: {eventName}\ndata: {json}\n\n"; await Response.WriteAsync(eventData); } catch (Exception ex) { _logger.LogError(ex, "发送SSE事件时发生错误: {EventName}", eventName); } } /// /// 计算日志列表的哈希值,用于检测内容变化 /// /// 日志列表 /// 哈希值字符串 private string CalculateLogsHash(List logs) { if (logs == null || !logs.Any()) return string.Empty; try { var hashInput = string.Join("|", logs.Select(log => $"{log.Timestamp}_{log.Layer}_{log.Message}")); using (var sha256 = System.Security.Cryptography.SHA256.Create()) { var bytes = System.Text.Encoding.UTF8.GetBytes(hashInput); var hash = sha256.ComputeHash(bytes); return Convert.ToBase64String(hash); } } catch (Exception ex) { _logger.LogError(ex, "计算日志哈希值时发生错误"); return string.Empty; } } /// /// 获取变化的日志项 /// /// 旧日志列表 /// 新日志列表 /// 变化的日志列表 private List GetChangedLogs(List oldLogs, List newLogs) { var changedLogs = new List(); if (oldLogs.Count != newLogs.Count) { return newLogs; } for (int i = 0; i < newLogs.Count; i++) { if (i < oldLogs.Count) { var oldLog = oldLogs[i]; var newLog = newLogs[i]; if (oldLog.Timestamp != newLog.Timestamp || oldLog.Layer != newLog.Layer || oldLog.Message != newLog.Message) { changedLogs.Add(newLog); } } else { changedLogs.Add(newLogs[i]); } } return changedLogs; } } }