using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Identity.Data; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http.Json; using System.Text; using System.Text.Encodings.Web; using System.Text.Json; using System.Threading.Channels; using System.Threading.Tasks; using TaskManager.Entity; using TaskManager.EntityFramework; using Wood.Entity; using Wood.Service.SystemManage; namespace TaskManager.Controllers { public class LogConsumerService : BackgroundService { private readonly ChannelReader _logReader; private readonly ILogger _logger; private const int BatchSize = 100; // 批量写入大小 private readonly string _logDirectory; private readonly IServiceProvider _serviceProvider; public LogConsumerService( LogController logService, ILogger logger, IServiceProvider serviceProvider) { _logReader = logService.GetLogReader(); _logger = logger; _serviceProvider = serviceProvider; ; _logDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CustomLogs"); // 使用更安全的路径获取方式 EnsureDirectoryExists(_logDirectory); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation("日志消费服务已启动"); // 批量处理日志,减少数据库写入次数 while (!stoppingToken.IsCancellationRequested && await _logReader.WaitToReadAsync(stoppingToken)) { try { var logs = new List(); int count = 0; // 读取一批日志 while (_logReader.TryRead(out var log) && count < BatchSize) { logs.Add(log); count++; } if (logs.Any()) { using var scope = _serviceProvider.CreateScope(); var db = scope.ServiceProvider.GetRequiredService(); List logsToSave = new List(); foreach (var log in logs) { if (!string.IsNullOrEmpty(log.Remark)) { log.Path = WriteLogToFile(log.Remark); } log.Remark = string.Empty; logsToSave.Add(log); } await db.TaskLogs.AddRangeAsync(logsToSave, stoppingToken); await db.SaveChangesAsync(stoppingToken); _logger.LogInformation($"已写入 {logs.Count} 条日志"); } } catch (Exception ex) { _logger.LogError(ex, "日志写入数据库失败"); // 错误处理:可记录到临时文件或重试 await Task.Delay(1000, stoppingToken); // 短暂延迟后重试 } } } public override async Task StopAsync(CancellationToken stoppingToken) { _logger.LogInformation("日志消费服务正在停止"); // 处理剩余日志 await base.StopAsync(stoppingToken); } private void EnsureDirectoryExists(string directoryPath) { if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } } // 修改后的日志写入方法 private string WriteLogToFile(string jsonContent) { //if string.IsNullOrEmpty(logMessage.RawRemark)) return null; // 必须提供JSON数据 // 创建日期目录 string dateDirectory = DateTime.Now.ToString("yyyy-MM-dd"); string fullDatePath = Path.Combine(_logDirectory, dateDirectory); EnsureDirectoryExists(fullDatePath); // 生成唯一文件名(时间戳+随机数) string fileName = $"log_{DateTime.Now.Ticks}_{Random.Shared.Next(1000, 9999)}.json"; string fullPath = Path.Combine(fullDatePath, fileName); try { // 写入文件(使用UTF-8无BOM格式) File.WriteAllText(fullPath, jsonContent, new UTF8Encoding(false)); // 存储相对路径(从日志根目录开始,使用正斜杠兼容API) return Path.Combine(dateDirectory, fileName).Replace('\\', '/'); } catch (Exception ex) { Console.WriteLine($"JSON文件写入失败:{ex.Message}"); return null; } } } // 后台服务 //public class LogBackgroundService : BackgroundService //{ // private readonly Channel _logChannel; // private readonly IServiceProvider _serviceProvider; // private readonly string _logDirectory; // public LogBackgroundService(IServiceProvider serviceProvider, IConfiguration configuration) // { // Console.WriteLine("LogService 初始化"); // _serviceProvider = serviceProvider; // _logDirectory = configuration["Logging:Directory"] ?? // Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CustomLogs"); // 使用更安全的路径获取方式 // EnsureDirectoryExists(_logDirectory); // _logChannel = Channel.CreateUnbounded(); // } // public void EnqueueLog(TaskLog log) // { // _logChannel.Writer.TryWrite(log); // } // public override async Task StartAsync(CancellationToken cancellationToken) // { // // 服务启动前的准备工作 // // _logger.LogInformation("Worker starting up..."); // // 调用基类方法 // await base.StartAsync(cancellationToken); // } // public override async Task StopAsync(CancellationToken cancellationToken) // { // // 服务停止前的清理工作 // //_logger.LogInformation("Worker shutting down..."); // // 调用基类方法 // await base.StopAsync(cancellationToken); // } // public override void Dispose() // { // // 资源释放 // // _logger.LogInformation("Worker disposing resources"); // base.Dispose(); // } // protected override async Task ExecuteAsync(CancellationToken stoppingToken) // { // Console.WriteLine("LogService 开始执行后台任务"); // using PeriodicTimer timer = new(TimeSpan.FromSeconds(10)); // // 主循环 - 使用 PeriodicTimer 等待下一个触发时间 // while (await timer.WaitForNextTickAsync(stoppingToken)) // { // await foreach (var log in _logChannel.Reader.ReadAllAsync(stoppingToken)) // { // try // { // if (!string.IsNullOrEmpty(log.Remark)) // { // log.Path = WriteLogToFile(log.Remark); // } // log.Remark = string.Empty; // using var scope = _serviceProvider.CreateScope(); // var db = scope.ServiceProvider.GetRequiredService(); // await db.TaskLogs.AddAsync(log, stoppingToken); // await db.SaveChangesAsync(stoppingToken); // Console.WriteLine($"日志已保存: {log.Info}"); // } // catch (Exception ex) // { // Console.WriteLine($"日志处理失败: {ex.Message}"); // } // } // } // Console.WriteLine("LogService 后台任务已停止"); // } // private void EnsureDirectoryExists(string directoryPath) // { // if (!Directory.Exists(directoryPath)) // { // Directory.CreateDirectory(directoryPath); // } // } // // 修改后的日志写入方法 // private string WriteLogToFile(string jsonContent) // { // //if string.IsNullOrEmpty(logMessage.RawRemark)) return null; // 必须提供JSON数据 // // 创建日期目录 // string dateDirectory = DateTime.Now.ToString("yyyy-MM-dd"); // string fullDatePath = Path.Combine(_logDirectory, dateDirectory); // EnsureDirectoryExists(fullDatePath); // // 生成唯一文件名(时间戳+随机数) // string fileName = $"log_{DateTime.Now.Ticks}_{Random.Shared.Next(1000, 9999)}.json"; // string fullPath = Path.Combine(fullDatePath, fileName); // try // { // // 写入文件(使用UTF-8无BOM格式) // File.WriteAllText(fullPath, jsonContent, new UTF8Encoding(false)); // // 存储相对路径(从日志根目录开始,使用正斜杠兼容API) // return Path.Combine(dateDirectory, fileName).Replace('\\', '/'); // } // catch (Exception ex) // { // Console.WriteLine($"JSON文件写入失败:{ex.Message}"); // return null; // } // } //} }