|
|
|
using Hangfire;
|
|
|
|
using Microsoft.AspNetCore.Builder;
|
|
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
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 OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
|
|
|
|
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
|
|
|
|
using Omu.ValueInjecter;
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Diagnostics;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Net.Http.Json;
|
|
|
|
using System.Security.Policy;
|
|
|
|
using System.Text;
|
|
|
|
using System.Text.Encodings.Web;
|
|
|
|
using System.Text.Json;
|
|
|
|
using System.Text.Json.Serialization;
|
|
|
|
using System.Threading.Channels;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using TaskManager.Contracts.Dtos;
|
|
|
|
using TaskManager.Entity;
|
|
|
|
using TaskManager.EntityFramework;
|
|
|
|
using Wood.Entity;
|
|
|
|
using Wood.Service.Controllers;
|
|
|
|
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.Type=="请求")
|
|
|
|
{
|
|
|
|
log.Path = WriteLogToFile(log.Remark);
|
|
|
|
}
|
|
|
|
log.Remark = string.Empty;
|
|
|
|
logsToSave.Add(log);
|
|
|
|
}
|
|
|
|
|
|
|
|
//foreach (var log in logsToSave)
|
|
|
|
//{
|
|
|
|
// switch (log.TaskName)
|
|
|
|
// {
|
|
|
|
// case "来料检验数据":
|
|
|
|
|
|
|
|
// //RecurringJob.AddOrUpdate<SupplierProMaterialStockService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "排产数据":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierProSchedulingService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "供应商基础信息":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierInfoService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "人员资质信息":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierEmployeeService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "BOM主数据":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierBomService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "过程控制项质量数据":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierProCpsService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "生产过程数据":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierProDataService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "产品一次合格率":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierProFirstPassyieldService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "工位一次合格率":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierProStationFirstPassyieldService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "缺陷业务数据":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierProFlawService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "环境业务数据":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierProEnvironmentService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "设备OEE达成率":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierProOeeAchievementRateService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "OEE时间明细":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierProOeeTimeDetailsService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "物料主数据":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierProMaterialDataService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "附件类数据":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierProAttachmentDataService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "工艺装备":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierProProcessEquipmentService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "工艺":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierProProcessService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
|
|
|
|
// case "整车月度生产计划1":
|
|
|
|
// var planlingResult1 = Response<SUPPLIER_PRO_PLANING, SUPPLIER_PRO_PLANING_DETIAL_DTO>(log.Remark, log.Version,log.TaskId,db);
|
|
|
|
// break;
|
|
|
|
// case "M+6月物料需求计划1":
|
|
|
|
// var monthResult = Response<SUPPLIER_MRP_MONTH, SUPPLIER_MRP_MONTH_DETAIL_DTO>(log.Remark, log.Version,log.TaskId,db);
|
|
|
|
// break;
|
|
|
|
// case "整车月度生产计划2":
|
|
|
|
// var planlingResult2=Response<SUPPLIER_PRO_PLANING, SUPPLIER_PRO_PLANING_DETIAL_DTO>(log.Remark,log.Version, log.TaskId, db);
|
|
|
|
// break;
|
|
|
|
// case "M+6月物料需求计划2":
|
|
|
|
// var monthResult2 = Response<SUPPLIER_MRP_MONTH, SUPPLIER_MRP_MONTH_DETAIL_DTO>(log.Remark, log.Version,log.TaskId,db);
|
|
|
|
// break;
|
|
|
|
// case "日物料需求计划":
|
|
|
|
// var dateResult2 = Response<SUPPLIER_MRP_DATE, SUPPLIER_MRP_DATE_DETAIL_DTO>(log.Remark, log.Version, log.TaskId, db);
|
|
|
|
// break;
|
|
|
|
// case "计划协议":
|
|
|
|
// var weekResult = Response<SUPPLIER_SA_WEEK, SUPPLIER_SA_WEEK_DETAIL_DTO>(log.Remark, log.Version, log.TaskId, db);
|
|
|
|
// break;
|
|
|
|
// case "采购订单":
|
|
|
|
// var poResult = Response<SUPPLIER_PO, SUPPLIER_PO_DETAIL_DTO>(log.Remark, log.Version, log.TaskId, db);
|
|
|
|
// break;
|
|
|
|
// case "过焊装未过总装":
|
|
|
|
// var GHResult = Response<SUPPLIER_PRO_HSCHEDUL, SUPPLIER_PO_DETAIL_DTO>(log.Remark, log.Version, log.TaskId, db);
|
|
|
|
// break;
|
|
|
|
// case "过涂装未过总装":
|
|
|
|
// var TSResult = Response<SUPPLIER_PRO_TSCHEDUL, SUPPLIER_PRO_TSCHEDUL_DETAIL_DTO>(log.Remark, log.Version, log.TaskId, db);
|
|
|
|
// break;
|
|
|
|
// case "排序供货":
|
|
|
|
// var CSResult = Response<SUPPLIER_PRO_CSCHEDUL, SUPPLIER_PRO_CSCHEDUL_DETAIL_DTO>(log.Remark, log.Version, log.TaskId, db);
|
|
|
|
// break;
|
|
|
|
// case "看板配送单":
|
|
|
|
// var DELResult = Response<SUPPLIER_DEL_STATE, SUPPLIER_DEL_STATE_DETAIL_DTO>(log.Remark, log.Version, log.TaskId, db);
|
|
|
|
// break;
|
|
|
|
// case "退货单":
|
|
|
|
// var ReturnResult = Response<SUPPLIER_RETURN, SUPPLIER_RETURN_DETAIL_DTO>(log.Remark, log.Version, log.TaskId, db);
|
|
|
|
// break;
|
|
|
|
// case "奇瑞RDC共享库存":
|
|
|
|
// var InvDataResult = Response<SUPPLIER_INV_DATA, SUPPLIER_INV_DATA_DETAIL_DTO>(log.Remark, log.Version, log.TaskId, db);
|
|
|
|
// break;
|
|
|
|
// case "日MRP状态监控":
|
|
|
|
// var MrpDateResult = Response<SUPPLIER_MRP_DATE, SUPPLIER_MRP_DATE_DETAIL_DTO>(log.Remark, log.Version, log.TaskId, db);
|
|
|
|
// break;
|
|
|
|
// case "日MRP预警推移":
|
|
|
|
// var WarningResult = Response<SUPPLIER_MRP_WARNING, SUPPLIER_MRP_WARNING_DETAIL_DTO>(log.Remark, log.Version, log.TaskId, db);
|
|
|
|
// break;
|
|
|
|
// case "M+6月物料需求计划风险确认":
|
|
|
|
|
|
|
|
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierConMmrpService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "日物料需求计划风险确认":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierConDateService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "采购订单风险确认":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierConPoService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "供应商共享库存-上午":
|
|
|
|
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierSinvDataService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// case "供应商共享库存-晚上":
|
|
|
|
// //RecurringJob.AddOrUpdate<CherySupplierSinvDataService>(
|
|
|
|
// // task.TaskName,
|
|
|
|
// // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName, client, pagesize),
|
|
|
|
// // task.Corn,
|
|
|
|
// // TimeZoneInfo.Local
|
|
|
|
// //);
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
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;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|