This commit is contained in:
2026-02-03 20:06:04 +01:00
parent d9454280b9
commit 14d8e96307
5 changed files with 80 additions and 98 deletions

View File

@@ -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)
{

View File

@@ -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>(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<LogMessage>
{
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() { }
}
}

View File

@@ -30,7 +30,7 @@ public abstract class BatchingLoggerProvider : ILoggerProvider, IDisposable
}
_batchSize = currentOptions.BatchSize > 0 ? currentOptions.BatchSize : 100;
_queue = new BlockingCollection<LogMessage>(new ConcurrentQueue<LogMessage>());
_queue = new BlockingCollection<LogMessage>(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<LogMessage>(_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<LogMessage> batch)

View File

@@ -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;

View File

@@ -355,4 +355,9 @@ public class LoggerSettings
TypesToLog.Add(ELogType.DEBUG);
}
}
internal void RaiseOnLog(EonaCatLogMessage eonaCatLogMessage)
{
OnLogEvent(eonaCatLogMessage);
}
}