Phase 4.1: Basis-Infrastruktur in den Core (Logging, JobManager)
- TerminalLogger, JobManager, JobStatusRow nach Core verschoben (Namespaces PolyTraderSharp.Services/.Models beibehalten). - TerminalLogger: ungenutzte DB-Usings entfernt. - Toten Stub services/logging.cs (internal class Logging) gelöscht. - Build 0 Fehler. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
using System.ComponentModel;
|
||||
using PolyTraderSharp.Models;
|
||||
|
||||
namespace PolyTraderSharp.Services
|
||||
{
|
||||
public class JobManager
|
||||
{
|
||||
public BindingList<JobStatusRow> Jobs { get; } = new BindingList<JobStatusRow>();
|
||||
|
||||
public void RegisterJob(JobStatusRow job)
|
||||
{
|
||||
Jobs.Add(job);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Channels;
|
||||
|
||||
namespace PolyTraderSharp.Services
|
||||
{
|
||||
public enum LogLevel { Debug, Info, Warning, Error, Trade, TradeReasoning }
|
||||
|
||||
public class LogMessageEventArgs : EventArgs
|
||||
{
|
||||
public string Message { get; }
|
||||
public LogLevel Level { get; }
|
||||
public DateTime Timestamp { get; }
|
||||
|
||||
public LogMessageEventArgs(string message, LogLevel level)
|
||||
{
|
||||
Message = message;
|
||||
Level = level;
|
||||
Timestamp = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
public class TerminalLogger
|
||||
{
|
||||
public event EventHandler<LogMessageEventArgs>? OnLogMessage;
|
||||
private readonly List<LogMessageEventArgs> _history = new();
|
||||
private readonly object _lock = new();
|
||||
|
||||
private readonly string _logsDirectory;
|
||||
private readonly Channel<LogMessageEventArgs> _logChannel;
|
||||
|
||||
public TerminalLogger()
|
||||
{
|
||||
_logsDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
|
||||
if (!Directory.Exists(_logsDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(_logsDirectory);
|
||||
}
|
||||
|
||||
_logChannel = Channel.CreateUnbounded<LogMessageEventArgs>(new UnboundedChannelOptions
|
||||
{
|
||||
SingleReader = true
|
||||
});
|
||||
Task.Run(ProcessLogQueueAsync);
|
||||
}
|
||||
|
||||
private async Task ProcessLogQueueAsync()
|
||||
{
|
||||
await foreach (var e in _logChannel.Reader.ReadAllAsync())
|
||||
{
|
||||
try
|
||||
{
|
||||
string dateStr = e.Timestamp.ToString("dd-MM-yyyy");
|
||||
string fileName = $"{dateStr}-{e.Level}.log";
|
||||
string fullPath = Path.Combine(_logsDirectory, fileName);
|
||||
|
||||
// Remove Emojis (Surrogate pairs and common symbols)
|
||||
string safeMsg = System.Text.RegularExpressions.Regex.Replace(e.Message, @"\p{Cs}|[✅❌🌐📈🔴🧪ℹ️🚨🏆💰⬇️⬆️🔹🔸✨🔥📊📝🔄⏸️]", "");
|
||||
safeMsg = safeMsg.Replace("\r\n", " | ").Replace("\n", " | ").Replace(" ", " ").Trim();
|
||||
|
||||
string logLine = $"[{e.Timestamp:HH:mm:ss}] {safeMsg}{Environment.NewLine}";
|
||||
|
||||
await File.AppendAllTextAsync(fullPath, logLine);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignored to prevent cascading lockups
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Log(string message, LogLevel level = LogLevel.Info)
|
||||
{
|
||||
var e = new LogMessageEventArgs(message, level);
|
||||
lock (_lock)
|
||||
{
|
||||
_history.Add(e);
|
||||
// Optimize list pruning to avoid heavy O(N) operations per log
|
||||
if (_history.Count > 10500)
|
||||
{
|
||||
// Remove older items efficiently in a batch
|
||||
int itemsToRemove = _history.Count - 9000;
|
||||
_history.RemoveRange(0, itemsToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
OnLogMessage?.Invoke(this, e);
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Standard Console output as fallback/debug
|
||||
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] [{level}] {message}");
|
||||
|
||||
_logChannel.Writer.TryWrite(e);
|
||||
}
|
||||
|
||||
public void Info(string message) => Log(message, LogLevel.Info);
|
||||
public void Debug(string message) => Log(message, LogLevel.Debug);
|
||||
public void Warning(string message) => Log(message, LogLevel.Warning);
|
||||
public void Error(string message) => Log(message, LogLevel.Error);
|
||||
public void Trade(string message) => Log(message, LogLevel.Trade);
|
||||
public void TradeReasoning(string message) => Log(message, LogLevel.TradeReasoning);
|
||||
|
||||
public List<LogMessageEventArgs> GetHistory(TimeSpan maxAge)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
var cutoff = DateTime.Now - maxAge;
|
||||
return _history.Where(x => x.Timestamp >= cutoff).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user