using OfficeOpenXml.FormulaParsing.Excel.Functions.Numeric;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
namespace WIDESEAWCS_Core.LogHelper
{
///
/// 日志等级枚举
///
public enum LogLevel
{
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3,
FATAL = 4
}
///
/// 日志条目:封装单条日志的完整信息
///
public class LogEntry
{
///
/// 日志时间
///
public DateTime Time { get; set; }
///
/// 日志等级
///
public LogLevel Level { get; set; }
///
/// 日志消息内容
///
public string Message { get; set; } = string.Empty;
///
/// 日志来源/文件名
///
public string? Source { get; set; }
///
/// 异常信息(可选)
///
public string? Exception { get; set; }
///
/// 格式化为标准日志字符串
///
public string ToFormattedString()
{
var sb = new StringBuilder();
sb.Append($"【{Time:HH:mm:ss}】【{Level}】:【{Message}】");
if (!string.IsNullOrEmpty(Exception))
{
sb.AppendLine();
sb.Append($"【异常】:{Exception}");
}
return sb.ToString();
}
}
///
/// 队列化集中日志写入器
/// 使用生产者-消费者模式,后台线程批量写入文件,提高性能
///
public class QueuedLogWriter : IDisposable
{
private static readonly Lazy _instance = new Lazy(() => new QueuedLogWriter());
public static QueuedLogWriter Instance => _instance.Value;
private readonly BlockingCollection _logQueue;
private readonly CancellationTokenSource _cts;
private readonly Task _writeTask;
private readonly ReaderWriterLockSlim _fileLock = new ReaderWriterLockSlim();
private readonly string _logFolder;
private readonly int _maxFileSize;
private readonly string _fileExt;
private bool _disposed;
///
/// 日志队列写入器单例
///
private QueuedLogWriter()
{
_logFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Log{Path.DirectorySeparatorChar}{DateTime.Now:yyyy-MM-dd}");
_maxFileSize = 10 * 1024 * 1024; // 10MB
_fileExt = ".log";
_logQueue = new BlockingCollection(new ConcurrentQueue());
_cts = new CancellationTokenSource();
// 确保日志目录存在
if (!Directory.Exists(_logFolder))
{
Directory.CreateDirectory(_logFolder);
}
// 启动后台写入线程
_writeTask = Task.Run(WriteLoop, _cts.Token);
}
///
/// 后台写入循环
///
private void WriteLoop()
{
var batch = new List();
while (!_cts.Token.IsCancellationRequested)
{
try
{
// 批量取出日志,最多100条或等待500ms
batch.Clear();
if (_logQueue.TryTake(out var entry, 500))
{
batch.Add(entry);
while (batch.Count < 100 && _logQueue.TryTake(out entry, 50))
{
batch.Add(entry);
}
WriteBatch(batch);
}
}
catch (OperationCanceledException)
{
break;
}
catch (Exception)
{
// 忽略写入异常,防止后台线程崩溃
}
}
// 取消前将剩余日志写出
while (_logQueue.TryTake(out var remainingEntry, 100))
{
batch.Add(remainingEntry);
}
if (batch.Count > 0)
{
WriteBatch(batch);
}
}
///
/// 批量写入日志到文件
///
private void WriteBatch(List entries)
{
if (entries.Count == 0) return;
try
{
_fileLock.EnterWriteLock();
foreach (var entry in entries)
{
string fileName = GetLogFileName(entry.Source);
string filePath = Path.Combine(_logFolder, fileName);
string content = entry.ToFormattedString() + Environment.NewLine;
ConsoleHelper.WriteInfoLine(content);
File.AppendAllText(filePath, content);
}
}
catch (Exception)
{
// 静默处理,防止文件IO异常影响主线程
}
finally
{
_fileLock.ExitWriteLock();
}
}
///
/// 获取或创建一个日志文件路径(按大小分文件)
///
private string GetLogFileName(string? source)
{
string prefix = string.IsNullOrEmpty(source) ? "WCS" : source;
string searchPattern = $"{prefix}*.log";
if (!Directory.Exists(_logFolder))
{
Directory.CreateDirectory(_logFolder);
}
var files = Directory.GetFiles(_logFolder, searchPattern)
.Select(f => new FileInfo(f))
.Where(f => f.Extension.Equals(_fileExt, StringComparison.OrdinalIgnoreCase))
.OrderByDescending(f => f.Name)
.ToList();
// 查找有空间的现有文件
foreach (var file in files)
{
if (file.Length < _maxFileSize)
{
return file.Name;
}
}
// 创建新文件
return $"{prefix}_{DateTime.Now:HH-mm-ss}{_fileExt}";
}
///
/// 写入日志(生产端)
///
public void Enqueue(LogEntry entry)
{
if (_disposed) return;
_logQueue.Add(entry);
}
///
/// 写入日志的便捷方法
///
public void Log(LogLevel level, string message, string? source = null, string? exception = null)
{
if (_disposed) return;
var entry = new LogEntry
{
Time = DateTime.Now,
Level = level,
Message = message,
Source = source,
Exception = exception
};
_logQueue.Add(entry);
}
///
/// 关闭日志写入器
///
public void Dispose()
{
if (_disposed) return;
_disposed = true;
_cts.Cancel();
try
{
_writeTask.Wait(3000);
}
catch (AggregateException) { }
_cts.Dispose();
_logQueue.Dispose();
_fileLock.Dispose();
}
}
///
/// 静态日志工具类(兼容原有接口)
/// 提供多种格式化方法和队列化写入
///
public class QuartzLogger
{
private static readonly QueuedLogWriter _writer = QueuedLogWriter.Instance;
///
/// 兼容旧接口:将日志写入文件
///
/// 日志文件名(作为Source)
/// 日志内容
public static void WriteLogToFile(string fileName, string log)
{
_writer.Log(LogLevel.INFO, log, fileName);
}
///
/// 写入调试日志
///
public static void Debug(string message, string? source = null)
{
_writer.Log(LogLevel.DEBUG, message, source);
}
///
/// 写入信息日志
///
public static void Info(string message, string? source = null)
{
_writer.Log(LogLevel.INFO, message, source);
}
///
/// 写入警告日志
///
public static void Warn(string message, string? source = null)
{
_writer.Log(LogLevel.WARN, message, source);
}
///
/// 写入错误日志
///
public static void Error(string message, string? source = null, Exception? exception = null)
{
_writer.Log(LogLevel.ERROR, message, source, exception?.ToString());
}
///
/// 写入致命错误日志
///
public static void Fatal(string message, string? source = null, Exception? exception = null)
{
_writer.Log(LogLevel.FATAL, message, source, exception?.ToString());
}
///
/// 使用指定格式写入日志
///
/// 格式化字符串
/// 格式化参数
public static void WriteFormatted(string format, params object[] args)
{
string message = string.Format(format, args);
_writer.Log(LogLevel.INFO, message);
}
///
/// 直接写入一个日志条目(最灵活)
///
public static void WriteLogEntry(LogEntry entry)
{
_writer.Enqueue(entry);
}
///
/// 释放资源(应用关闭时调用)
///
public static void Shutdown()
{
_writer.Dispose();
}
}
}