diff --git a/EonaCat.Logger.Server/EonaCat.Logger.Server.csproj b/EonaCat.Logger.Server/EonaCat.Logger.Server.csproj
new file mode 100644
index 0000000..21b0c44
--- /dev/null
+++ b/EonaCat.Logger.Server/EonaCat.Logger.Server.csproj
@@ -0,0 +1,28 @@
+
+
+
+ netstandard2.1
+ enable
+ True
+ EonaCat.Logger.Server
+ EonaCat (Jeroen Saey)
+ EonaCat.Logger.Server is a server for the logging library
+ EonaCat (Jeroen Saey)
+ https://www.nuget.org/packages/EonaCat.Logger.Server/
+ icon.png
+ README.md
+ EonaCat;Logger;EonaCatLogger;server;Log;Writer;Jeroen;Saey
+
+
+
+
+ True
+ \
+
+
+ True
+ \
+
+
+
+
diff --git a/EonaCat.Logger.Server/Server.cs b/EonaCat.Logger.Server/Server.cs
new file mode 100644
index 0000000..bb36864
--- /dev/null
+++ b/EonaCat.Logger.Server/Server.cs
@@ -0,0 +1,287 @@
+using System.IO;
+using System.Net.Sockets;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+using System.Threading;
+using System;
+using System.Linq;
+
+namespace EonaCat.Logger.Server
+{
+ // This file is part of the EonaCat project(s) which is released under the Apache License.
+ // See the LICENSE file or go to https://EonaCat.com/License for full license details.
+ public class Server
+ {
+ private TcpListener _tcpListener;
+ private UdpClient _udpListener;
+ private CancellationTokenSource _cts;
+ private bool _isRunning;
+ private readonly bool _useUdp;
+ private const long MaxLogFileSize = 200 * 1024 * 1024; // 200MB log rollover limit
+ private readonly int _logRetentionDays; // Number of days to retain logs
+ private readonly long _maxLogDirectorySize; // Maximum allowed size of the logs directory
+ private const int UdpBufferSize = 65507; // Maximum UDP packet size (65507 bytes for UDP payload)
+
+ ///
+ /// EonaCat Log Server
+ ///
+ /// Determine if we need to start a udp server (default: true)
+ /// Max log retention days (default: 30)
+ /// Max log directory size (default: 10GB)
+ public Server(bool useUdp = true, int logRetentionDays = 30, long maxLogDirectorySize = 10L * 1024 * 1024 * 1024) // Default 10GB max directory size
+ {
+ _useUdp = useUdp;
+ _logRetentionDays = logRetentionDays;
+ _maxLogDirectorySize = maxLogDirectorySize;
+ }
+
+ protected virtual Task ProcessLogAsync(string logData)
+ {
+ string logsRootDirectory = "logs";
+
+ // Create root log directory if it doesn't exist
+ if (!Directory.Exists(logsRootDirectory))
+ {
+ Directory.CreateDirectory(logsRootDirectory);
+ }
+
+ // Create a daily directory for logs
+ string dailyLogsDirectory = Path.Combine(logsRootDirectory, DateTime.Now.ToString("yyyyMMdd"));
+ if (!Directory.Exists(dailyLogsDirectory))
+ {
+ Directory.CreateDirectory(dailyLogsDirectory);
+ }
+
+ // Base log file name
+ string baseLogFilePath = Path.Combine(dailyLogsDirectory, "EonaCatLogs");
+ string logFilePath = baseLogFilePath + ".log";
+
+ int fileIndex = 1;
+ while (File.Exists(logFilePath) && new FileInfo(logFilePath).Length > MaxLogFileSize)
+ {
+ logFilePath = baseLogFilePath + $"_{fileIndex}.log";
+ fileIndex++;
+ }
+
+ // After processing log, check directory size and clean up if needed
+ CleanUpOldLogs();
+
+ return File.AppendAllTextAsync(logFilePath, logData + Environment.NewLine);
+ }
+
+ private void CleanUpOldLogs()
+ {
+ string logsRootDirectory = "logs";
+ if (!Directory.Exists(logsRootDirectory))
+ {
+ return;
+ }
+
+ // Delete old directories
+ foreach (var directory in Directory.GetDirectories(logsRootDirectory))
+ {
+ try
+ {
+ DirectoryInfo dirInfo = new DirectoryInfo(directory);
+ if (dirInfo.CreationTime < DateTime.Now.AddDays(-_logRetentionDays))
+ {
+ Console.WriteLine($"Deleting old log directory: {directory}");
+ Directory.Delete(directory, true); // Delete directory and its contents
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error deleting old directory {directory}: {ex.Message}");
+ }
+ }
+
+ // Ensure total size of log directory doesn't exceed max limit
+ long totalDirectorySize = GetDirectorySize(logsRootDirectory);
+ if (totalDirectorySize > _maxLogDirectorySize)
+ {
+ Console.WriteLine("Log directory size exceeded limit, cleaning up...");
+
+ // Delete the oldest directories until the size limit is met
+ foreach (var directory in Directory.GetDirectories(logsRootDirectory).OrderBy(d => new DirectoryInfo(d).CreationTime))
+ {
+ try
+ {
+ DirectoryInfo dirInfo = new DirectoryInfo(directory);
+ long dirSize = GetDirectorySize(directory);
+ totalDirectorySize -= dirSize;
+
+ // Delete the directory if the total size exceeds the limit
+ Directory.Delete(directory, true);
+ Console.WriteLine($"Deleted directory: {directory}");
+
+ // Stop deleting if we are under the size limit
+ if (totalDirectorySize <= _maxLogDirectorySize)
+ {
+ break;
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error deleting directory {directory}: {ex.Message}");
+ }
+ }
+ }
+ }
+
+ private long GetDirectorySize(string directory)
+ {
+ long size = 0;
+ try
+ {
+ // Add size of files in the directory
+ size += Directory.GetFiles(directory).Sum(file => new FileInfo(file).Length);
+
+ // Add size of files in subdirectories
+ foreach (var subdirectory in Directory.GetDirectories(directory))
+ {
+ size += GetDirectorySize(subdirectory);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error calculating size for directory {directory}: {ex.Message}");
+ }
+ return size;
+ }
+
+ public async Task Start(IPAddress ipAddress = null, int port = 5555)
+ {
+ if (ipAddress == null)
+ {
+ ipAddress = IPAddress.Any;
+ }
+
+ _cts = new CancellationTokenSource();
+ _isRunning = true;
+
+ if (_useUdp)
+ {
+ _udpListener = new UdpClient(port);
+ Console.WriteLine($"EonaCat UDP Log Server started on port {port}...");
+ await ListenUdpAsync();
+ }
+ else
+ {
+ _tcpListener = new TcpListener(ipAddress, port);
+ _tcpListener.Start();
+ Console.WriteLine($"EonaCat TCP Log Server started on port {port}...");
+ await ListenTcpAsync();
+ }
+ }
+
+ private async Task ListenTcpAsync()
+ {
+ try
+ {
+ while (!_cts.Token.IsCancellationRequested)
+ {
+ TcpClient client = await _tcpListener.AcceptTcpClientAsync();
+ _ = Task.Run(() => HandleTcpClient(client));
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ Console.WriteLine("TCP Server stopping...");
+ }
+ }
+
+ private async Task ListenUdpAsync()
+ {
+ try
+ {
+ while (!_cts.Token.IsCancellationRequested)
+ {
+ // Increased buffer size for UDP
+ UdpReceiveResult result = await _udpListener.ReceiveAsync();
+ string logData = Encoding.UTF8.GetString(result.Buffer);
+
+ // If the received data is too large, process it in chunks
+ if (result.Buffer.Length > UdpBufferSize)
+ {
+ // Handle fragmentation and reassembly (this is a basic placeholder logic)
+ Console.WriteLine("Received large UDP data. Handling fragmentation.");
+ await ProcessLargeDataAsync(result.Buffer);
+ }
+ else
+ {
+ Console.WriteLine($"Received UDP Log: {logData}");
+ await ProcessLogAsync(logData);
+ }
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ Console.WriteLine("UDP Server stopping...");
+ }
+ }
+
+ private async Task ProcessLargeDataAsync(byte[] data)
+ {
+ // You can implement your own logic here for processing large UDP data, such as fragmentation handling
+ string largeDataString = Encoding.UTF8.GetString(data);
+ await ProcessLogAsync(largeDataString);
+ }
+
+ public void Stop()
+ {
+ if (_isRunning)
+ {
+ _cts.Cancel();
+
+ // Proper cleanup of resources
+ _cts.Dispose();
+ if (_useUdp)
+ {
+ _udpListener?.Close();
+ _udpListener?.Dispose();
+ }
+ else
+ {
+ _tcpListener?.Stop();
+ _tcpListener?.Server?.Dispose(); // Dispose of the socket (if any)
+ }
+
+ _isRunning = false;
+ Console.WriteLine("EonaCat Log Server stopped.");
+ }
+ }
+
+ private async Task HandleTcpClient(TcpClient client)
+ {
+ try
+ {
+ using (NetworkStream stream = client.GetStream())
+ using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
+ {
+ char[] buffer = new char[8192]; // 8KB buffer size for large data
+ int bytesRead;
+ StringBuilder logData = new StringBuilder();
+
+ while ((bytesRead = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0)
+ {
+ logData.Append(new string(buffer, 0, bytesRead));
+ }
+
+ Console.WriteLine($"Received TCP Log: {logData.ToString()}");
+ await ProcessLogAsync(logData.ToString());
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error: {ex.Message}");
+ }
+ finally
+ {
+ // Ensure client is properly disposed
+ client.Close();
+ client.Dispose();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/EonaCat.Logger.sln b/EonaCat.Logger.sln
index 9375bee..80caf80 100644
--- a/EonaCat.Logger.sln
+++ b/EonaCat.Logger.sln
@@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EonaCat.Logger", "EonaCat.L
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EonaCat.Logger.Test.Web", "Testers\EonaCat.Logger.Test.Web\EonaCat.Logger.Test.Web.csproj", "{DBEEF0B0-68AF-4A98-80B9-17FFCDB96E38}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EonaCat.Logger.Server", "EonaCat.Logger.Server\EonaCat.Logger.Server.csproj", "{5A5B4709-C2D9-4AD6-BF7F-A97B8BC98255}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -41,6 +43,18 @@ Global
{DBEEF0B0-68AF-4A98-80B9-17FFCDB96E38}.Release|x64.Build.0 = Release|Any CPU
{DBEEF0B0-68AF-4A98-80B9-17FFCDB96E38}.Release|x86.ActiveCfg = Release|Any CPU
{DBEEF0B0-68AF-4A98-80B9-17FFCDB96E38}.Release|x86.Build.0 = Release|Any CPU
+ {5A5B4709-C2D9-4AD6-BF7F-A97B8BC98255}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5A5B4709-C2D9-4AD6-BF7F-A97B8BC98255}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5A5B4709-C2D9-4AD6-BF7F-A97B8BC98255}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5A5B4709-C2D9-4AD6-BF7F-A97B8BC98255}.Debug|x64.Build.0 = Debug|Any CPU
+ {5A5B4709-C2D9-4AD6-BF7F-A97B8BC98255}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5A5B4709-C2D9-4AD6-BF7F-A97B8BC98255}.Debug|x86.Build.0 = Debug|Any CPU
+ {5A5B4709-C2D9-4AD6-BF7F-A97B8BC98255}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5A5B4709-C2D9-4AD6-BF7F-A97B8BC98255}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5A5B4709-C2D9-4AD6-BF7F-A97B8BC98255}.Release|x64.ActiveCfg = Release|Any CPU
+ {5A5B4709-C2D9-4AD6-BF7F-A97B8BC98255}.Release|x64.Build.0 = Release|Any CPU
+ {5A5B4709-C2D9-4AD6-BF7F-A97B8BC98255}.Release|x86.ActiveCfg = Release|Any CPU
+ {5A5B4709-C2D9-4AD6-BF7F-A97B8BC98255}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/EonaCat.Logger/Managers/LogManager.cs b/EonaCat.Logger/Managers/LogManager.cs
index 113a8ae..dcb6e5c 100644
--- a/EonaCat.Logger/Managers/LogManager.cs
+++ b/EonaCat.Logger/Managers/LogManager.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
using EonaCat.Logger.EonaCatCoreLogger;