You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

286 lines
10 KiB

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<TaskLog> _logReader;
private readonly ILogger<LogConsumerService> _logger;
private const int BatchSize = 100; // 批量写入大小
private readonly string _logDirectory;
private readonly IServiceProvider _serviceProvider;
public LogConsumerService(
LogController logService,
ILogger<LogConsumerService> 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<TaskLog>();
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<JobDbContext>();
List<TaskLog> logsToSave = new List<TaskLog>();
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<TaskLog> _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<TaskLog>();
// }
// 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<JobDbContext>();
// 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;
// }
// }
//}
}