From 14d8e96307577809edb286b42d2789dd36db19f1 Mon Sep 17 00:00:00 2001 From: EonaCat Date: Tue, 3 Feb 2026 20:06:04 +0100 Subject: [PATCH] Updated --- .../EonaCatCoreLogger/FileLoggerProvider.cs | 31 ++++---- .../Internal/BatchingLogger.cs | 71 ++++++------------- .../Internal/BatchingLoggerProvider.cs | 23 +++--- EonaCat.Logger/Managers/LogManager.cs | 48 +++++++------ EonaCat.Logger/Managers/LoggerSettings.cs | 5 ++ 5 files changed, 80 insertions(+), 98 deletions(-) diff --git a/EonaCat.Logger/EonaCatCoreLogger/FileLoggerProvider.cs b/EonaCat.Logger/EonaCatCoreLogger/FileLoggerProvider.cs index 617e440..442b1b1 100644 --- a/EonaCat.Logger/EonaCatCoreLogger/FileLoggerProvider.cs +++ b/EonaCat.Logger/EonaCatCoreLogger/FileLoggerProvider.cs @@ -69,17 +69,17 @@ public sealed class FileLoggerProvider : BatchingLoggerProvider var file = GetFullName(group.Key); InitializeFile(file); - var sb = _buffers.GetOrAdd(file, _ => new StringBuilder(4096)); + var stringBuilder = _buffers.GetOrAdd(file, _ => new StringBuilder(4096)); - lock (sb) + lock (stringBuilder) { foreach (var message in group) { - AppendMessage(sb, message); + AppendMessage(stringBuilder, message); } } - await FlushAsync(file, sb, token).ConfigureAwait(false); + await FlushAsync(file, stringBuilder, token).ConfigureAwait(false); DeleteOldLogFiles(); } } @@ -127,9 +127,9 @@ public sealed class FileLoggerProvider : BatchingLoggerProvider _currentFileSize = File.Exists(_logFile) ? new FileInfo(_logFile).Length : 0; } - private async Task FlushAsync(string file, StringBuilder sb, CancellationToken token) + private async Task FlushAsync(string file, StringBuilder stringBuilder, CancellationToken token) { - if (sb.Length == 0) + if (stringBuilder.Length == 0) { return; } @@ -137,22 +137,25 @@ public sealed class FileLoggerProvider : BatchingLoggerProvider await _writeLock.WaitAsync(token).ConfigureAwait(false); try { - using var fs = new FileStream( + var text = stringBuilder.ToString(); + byte[] bytesToWrite = Encoding.UTF8.GetBytes(text); + + using (var fileStream = new FileStream( file, FileMode.Append, FileAccess.Write, FileShare.Read, 64 * 1024, - useAsync: true); + useAsync: true)) + { + await fileStream.WriteAsync(bytesToWrite, 0, bytesToWrite.Length, token); + } - using var writer = new StreamWriter(fs, Encoding.UTF8); - var text = sb.ToString(); - await writer.WriteAsync(text).ConfigureAwait(false); - - _fileSizes.AddOrUpdate(file, Encoding.UTF8.GetByteCount(text), (_, old) => old + Encoding.UTF8.GetByteCount(text)); + // Update current file size correctly + _fileSizes.AddOrUpdate(file, bytesToWrite.Length, (_, old) => old + bytesToWrite.Length); _currentFileSize = _fileSizes[file]; - sb.Clear(); + stringBuilder.Clear(); if (_fileSizes[file] >= _maxFileSize) { diff --git a/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLogger.cs b/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLogger.cs index 6ef69a7..dc8356d 100644 --- a/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLogger.cs +++ b/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLogger.cs @@ -3,9 +3,6 @@ using EonaCat.Logger.Extensions; using EonaCat.Logger.Managers; using Microsoft.Extensions.Logging; using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace EonaCat.Logger.EonaCatCoreLogger.Internal { @@ -25,13 +22,8 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal _settings = settings ?? throw new ArgumentNullException(nameof(settings)); } - private DateTimeOffset Now - { - get - { - return _settings.UseLocalTime ? DateTimeOffset.Now : DateTimeOffset.UtcNow; - } - } + private DateTimeOffset Now => + _settings.UseLocalTime ? DateTimeOffset.Now : DateTimeOffset.UtcNow; public IDisposable BeginScope(TState state) => NullScope.Instance; @@ -49,64 +41,41 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal return; } - string rawMessage; - if (exception != null) - { - rawMessage = exception.FormatExceptionToMessage(); - } - else - { - rawMessage = formatter != null ? formatter(state, null) : string.Empty; - } + string rawMessage = exception != null + ? exception.FormatExceptionToMessage() + : formatter?.Invoke(state, null); if (string.IsNullOrEmpty(rawMessage)) { return; } - var timestamp = Now; - LogInternalAsync(timestamp, logLevel, rawMessage, exception).ConfigureAwait(false); - } - - private async Task LogInternalAsync( - DateTimeOffset timestamp, - LogLevel logLevel, - string message, - Exception exception) - { try { + var timestamp = Now; + string formatted = LogHelper.FormatMessageWithHeader( _settings, logLevel.FromLogLevel(), - message, + rawMessage, timestamp.DateTime, _category); var writtenMessage = _provider.AddMessage(timestamp, formatted, _category); - var onLogEvent = _settings.OnLogEvent; - if (onLogEvent != null) + _settings.RaiseOnLog(new EonaCatLogMessage { - onLogEvent(new EonaCatLogMessage - { - DateTime = timestamp.DateTime, - Message = writtenMessage, - LogType = logLevel.FromLogLevel(), - Category = _category, - Exception = exception, - Origin = string.IsNullOrWhiteSpace(_settings.LogOrigin) ? "BatchingLogger" : _settings.LogOrigin - }); - } + DateTime = timestamp.DateTime, + Message = writtenMessage, + LogType = logLevel.FromLogLevel(), + Category = _category, + Exception = exception, + Origin = string.IsNullOrWhiteSpace(_settings.LogOrigin) + ? "BatchingLogger" + : _settings.LogOrigin + }); - await _provider.WriteMessagesAsync(new List - { - new LogMessage - { - Timestamp = timestamp, - Message = formatted - } - }, CancellationToken.None).ConfigureAwait(false); + } catch (Exception ex) { @@ -116,7 +85,7 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal private sealed class NullScope : IDisposable { - public static readonly NullScope Instance = new NullScope(); + public static readonly NullScope Instance = new(); public void Dispose() { } } } diff --git a/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLoggerProvider.cs b/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLoggerProvider.cs index 39c4f0b..aa6d366 100644 --- a/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLoggerProvider.cs +++ b/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLoggerProvider.cs @@ -30,7 +30,7 @@ public abstract class BatchingLoggerProvider : ILoggerProvider, IDisposable } _batchSize = currentOptions.BatchSize > 0 ? currentOptions.BatchSize : 100; - _queue = new BlockingCollection(new ConcurrentQueue()); + _queue = new BlockingCollection(Math.Max(1, _batchSize * 2)); if (currentOptions is FileLoggerOptions file) { @@ -102,23 +102,24 @@ public abstract class BatchingLoggerProvider : ILoggerProvider, IDisposable private async Task ProcessLoop() { var batch = new List(_batchSize); + var flushInterval = LoggerSettings.FileLoggerOptions.FlushPeriod; + var timeoutMs = (int)Math.Min(flushInterval.TotalMilliseconds, int.MaxValue); try { - foreach (var item in _queue.GetConsumingEnumerable(_cts.Token)) + while (!_cts.Token.IsCancellationRequested) { - batch.Add(item); + if (_queue.TryTake(out var item, timeoutMs, _cts.Token)) + { + batch.Add(item); + } - if (batch.Count >= _batchSize) + if (batch.Count >= _batchSize || + (batch.Count > 0 && !_queue.TryTake(out _, 0))) { await FlushBatchAsync(batch); } } - - if (batch.Count > 0) - { - await FlushBatchAsync(batch); - } } catch (OperationCanceledException) { @@ -127,10 +128,6 @@ public abstract class BatchingLoggerProvider : ILoggerProvider, IDisposable await FlushBatchAsync(batch); } } - catch (Exception ex) - { - Console.Error.WriteLine(ex); - } } private async Task FlushBatchAsync(List batch) diff --git a/EonaCat.Logger/Managers/LogManager.cs b/EonaCat.Logger/Managers/LogManager.cs index 69568bc..e850ebe 100644 --- a/EonaCat.Logger/Managers/LogManager.cs +++ b/EonaCat.Logger/Managers/LogManager.cs @@ -118,43 +118,45 @@ namespace EonaCat.Logger.Managers return; } - if (!IsRunning) - { - await StartNewLogAsync().ConfigureAwait(false); - } - await InternalWriteAsync(CurrentDateTime, message, logType, writeToConsole, customSplunkSourceType, grayLogFacility, grayLogSource, grayLogVersion, disableSplunkSSL) .ConfigureAwait(false); } + private readonly SemaphoreSlim _startLock = new(1, 1); public async Task StartNewLogAsync() { if (_isDisposing || _tokenSource.IsCancellationRequested) - { return; - } - if (IsRunning && CurrentDateTime.Date > _logDate.Date) + await _startLock.WaitAsync().ConfigureAwait(false); + try { - await StopLoggingAsync().ConfigureAwait(false); + if (IsRunning && CurrentDateTime.Date > _logDate.Date) + { + await StopLoggingAsync().ConfigureAwait(false); + } + + if (!IsRunning) + { + CreateLogger(); + Directory.CreateDirectory(Settings.FileLoggerOptions.LogDirectory); + if (LoggerProvider is FileLoggerProvider fileProvider) + { + fileProvider.InitializeCurrentFile(); + } + + _logDate = CurrentDateTime; + IsRunning = true; + } } - - CreateLogger(); - - // Ensure log file exists - Directory.CreateDirectory(Settings.FileLoggerOptions.LogDirectory); - if (LoggerProvider is FileLoggerProvider fileProvider) + finally { - fileProvider.InitializeCurrentFile(); + _startLock.Release(); } - - _logDate = CurrentDateTime; - IsRunning = true; } - private async Task StopLoggingAsync() { if (_isDisposing) @@ -175,6 +177,12 @@ namespace EonaCat.Logger.Managers private void CreateLogger() { + if (Logger != null) + { + // already created + return; + } + if (_isDisposing) { return; diff --git a/EonaCat.Logger/Managers/LoggerSettings.cs b/EonaCat.Logger/Managers/LoggerSettings.cs index d9415ea..5934b41 100644 --- a/EonaCat.Logger/Managers/LoggerSettings.cs +++ b/EonaCat.Logger/Managers/LoggerSettings.cs @@ -355,4 +355,9 @@ public class LoggerSettings TypesToLog.Add(ELogType.DEBUG); } } + + internal void RaiseOnLog(EonaCatLogMessage eonaCatLogMessage) + { + OnLogEvent(eonaCatLogMessage); + } } \ No newline at end of file