Added max folder capacity

Added some methods in the EncryptedFileFlow
Added filters for FileFlow
This commit is contained in:
Jeroen Saey
2026-04-29 07:19:52 +02:00
parent 8db1a6a556
commit 9e7ad2237b
7 changed files with 1393 additions and 94 deletions
@@ -25,7 +25,7 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Net.Http.Json" Version="10.0.3" />
<PackageReference Include="System.Net.Http.Json" Version="10.0.7" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EonaCat.LogStack\EonaCat.LogStack.csproj" />
@@ -35,8 +35,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Diagnostics.EventLog" Version="10.0.3" />
<PackageReference Include="System.Threading.AccessControl" Version="10.0.3" />
<PackageReference Include="System.Diagnostics.EventLog" Version="10.0.7" />
<PackageReference Include="System.Threading.AccessControl" Version="10.0.7" />
</ItemGroup>
<ItemGroup>
+9 -9
View File
@@ -14,7 +14,7 @@ It features a rich fluent API for routing log events to dozens of destinations f
<Copyright>EonaCat (Jeroen Saey)</Copyright>
<PackageTags>EonaCat;Logger;EonaCatLogStack;Log;Writer;Flows;LogStack;Memory;Speed;Jeroen;Saey</PackageTags>
<PackageIconUrl />
<FileVersion>0.0.3</FileVersion>
<FileVersion>0.0.4</FileVersion>
<PackageReadmeFile>README.md</PackageReadmeFile>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
@@ -25,7 +25,7 @@ It features a rich fluent API for routing log events to dozens of destinations f
</PropertyGroup>
<PropertyGroup>
<EVRevisionFormat>0.0.3+{chash:10}.{c:ymd}</EVRevisionFormat>
<EVRevisionFormat>0.0.4+{chash:10}.{c:ymd}</EVRevisionFormat>
<EVDefault>true</EVDefault>
<EVInfo>true</EVInfo>
<EVTagMatch>v[0-9]*</EVTagMatch>
@@ -36,7 +36,7 @@ It features a rich fluent API for routing log events to dozens of destinations f
</PropertyGroup>
<PropertyGroup>
<Version>0.0.3</Version>
<Version>0.0.4</Version>
<PackageId>EonaCat.LogStack</PackageId>
<Product>EonaCat.LogStack</Product>
<RepositoryUrl>https://git.saey.me/EonaCat/EonaCat.LogStack</RepositoryUrl>
@@ -66,18 +66,18 @@ It features a rich fluent API for routing log events to dozens of destinations f
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="EonaCat.Json" Version="2.2.0" />
<PackageReference Include="EonaCat.Versioning" Version="1.2.8">
<PackageReference Include="EonaCat.Json" Version="2.2.2" />
<PackageReference Include="EonaCat.Versioning" Version="1.2.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="EonaCat.Versioning.Helpers" Version="1.0.2" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.7" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.7" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.7" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Threading.Channels" Version="10.0.3" />
<PackageReference Include="System.Threading.Channels" Version="10.0.7" />
</ItemGroup>
<ItemGroup>
<None Update="LICENSE.md">
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,4 @@
using EonaCat.Json;
using EonaCat.LogStack.Core;
using EonaCat.LogStack.Core;
using EonaCat.LogStack.EonaCatLogStackCore;
using EonaCat.LogStack.EonaCatLogStackCore.Policies;
using System;
@@ -42,6 +41,10 @@ namespace EonaCat.LogStack.Flows
{ LogLevel.Critical, "CRITICAL" },
};
private static readonly char[] CsvSpecialChars = { ',', '"', '\n', '\r' };
private static readonly string CachedMachineName = Environment.MachineName;
private static readonly int CachedPid = Process.GetCurrentProcess().Id;
private const string CsvHeader = "timestamp,level,category,message,exception,properties\r\n";
private readonly BlockingCollection<LogEvent> _queue;
@@ -57,6 +60,7 @@ namespace EonaCat.LogStack.Flows
private readonly string _directory;
private readonly string _filePrefix;
private readonly long _maxFileSize;
private readonly long _maxDirectorySize;
private readonly FileRetentionPolicy _retention;
private readonly TimestampMode _timestampMode;
private readonly TimeSpan _flushInterval;
@@ -74,11 +78,38 @@ namespace EonaCat.LogStack.Flows
private readonly object _secondaryWritersLock = new object();
private int _correlationSeed;
private readonly List<Func<LogEvent, bool>> _filters = new List<Func<LogEvent, bool>>();
private readonly object _filtersLock = new object();
private readonly ConcurrentDictionary<string, long> _deduplicationCache
= new ConcurrentDictionary<string, long>(StringComparer.Ordinal);
private TimeSpan _deduplicationWindow = TimeSpan.Zero;
private volatile bool _deduplicationEnabled;
private string _dateFormat = "yyyyMMdd";
private volatile Exception _lastError;
private long _lastErrorTimestamp;
private long _totalErrors;
private readonly List<KeyValuePair<string, Func<LogEvent, object>>> _enrichers
= new List<KeyValuePair<string, Func<LogEvent, object>>>();
private long _currentMemoryBytes;
// Rate limiting
private int _maxEventsPerSecond;
private bool _rateLimitEnabled => _maxEventsPerSecond > 0;
private long _rateLimitWindowStart;
private int _rateLimitCounter;
private readonly object _rateLimitLock = new object();
// Auto-flush on error
private volatile bool _autoFlushOnError;
// Scoped properties (AsyncLocal for ambient context)
private static readonly AsyncLocal<Dictionary<string, object>> _scopeProperties
= new AsyncLocal<Dictionary<string, object>>();
private long _totalBytesWritten;
private long _totalRotations;
@@ -121,6 +152,7 @@ namespace EonaCat.LogStack.Flows
string directory,
string filePrefix = "log",
long maxFileSize = 200 * 1024 * 1024,
long maxDirectorySize = 2L * 1024 * 1024 * 1024,
FileRetentionPolicy retention = null,
int flushIntervalMs = 2000,
int batchSize = 1,
@@ -157,6 +189,7 @@ namespace EonaCat.LogStack.Flows
_filePrefix = filePrefix;
_template = template;
_maxFileSize = maxFileSize;
_maxDirectorySize = maxDirectorySize > 0 ? maxDirectorySize : 10L * maxFileSize;
_retention = retention ?? new FileRetentionPolicy();
_timestampMode = timestampMode;
_useCategoryRouting = useCategoryRouting;
@@ -318,6 +351,176 @@ namespace EonaCat.LogStack.Flows
MinimumLevel = level;
}
/// <summary>Add a custom filter predicate. Events are logged only if ALL filters return true.</summary>
public FileFlow WithFilter(Func<LogEvent, bool> predicate)
{
if (predicate == null)
{
throw new ArgumentNullException("predicate");
}
lock (_filtersLock)
{
_filters.Add(predicate);
}
return this;
}
/// <summary>Enable deduplication: suppress identical messages within the given time window.</summary>
public FileFlow WithDeduplication(TimeSpan window)
{
if (window <= TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException("window", "Deduplication window must be positive.");
}
_deduplicationWindow = window;
_deduplicationEnabled = true;
return this;
}
/// <summary>Configure a custom date format for log file names (default: yyyyMMdd).</summary>
public FileFlow WithDateFormat(string dateFormat)
{
if (string.IsNullOrWhiteSpace(dateFormat))
{
throw new ArgumentNullException("dateFormat");
}
_dateFormat = dateFormat;
return this;
}
/// <summary>Limit the flow to a maximum number of events per second. Events exceeding the limit are dropped.</summary>
public FileFlow WithRateLimit(int maxEventsPerSecond)
{
_maxEventsPerSecond = maxEventsPerSecond;
return this;
}
/// <summary>When enabled, the file stream is flushed immediately after writing Error or Critical level events.</summary>
public FileFlow WithAutoFlushOnError(bool enabled = true)
{
_autoFlushOnError = enabled;
return this;
}
/// <summary>Push scoped properties that will be included in all log events written on the current async context.</summary>
public IDisposable BeginScope(params KeyValuePair<string, object>[] properties)
{
var previous = _scopeProperties.Value;
var merged = previous != null
? new Dictionary<string, object>(previous)
: new Dictionary<string, object>();
foreach (var kv in properties)
{
merged[kv.Key] = kv.Value;
}
_scopeProperties.Value = merged;
return new ScopeDisposable(previous);
}
/// <summary>Push a single scoped property.</summary>
public IDisposable BeginScope(string key, object value)
{
return BeginScope(new KeyValuePair<string, object>(key, value));
}
/// <summary>Returns the current queue depth (number of pending events).</summary>
public int GetQueueDepth()
{
return _queue.Count;
}
/// <summary>Returns the current estimated memory usage of the queue in bytes.</summary>
public long GetMemoryPressureBytes()
{
return Interlocked.Read(ref _currentMemoryBytes);
}
/// <summary>Generates a fingerprint hash for an exception to assist with grouping.</summary>
public static string GetExceptionFingerprint(Exception ex)
{
if (ex == null)
{
return null;
}
string source = string.Concat(
ex.GetType().FullName, "|",
ex.TargetSite?.Name ?? string.Empty, "|",
ex.StackTrace != null && ex.StackTrace.Length > 0
? ex.StackTrace.Substring(0, Math.Min(200, ex.StackTrace.Length))
: string.Empty);
// Simple FNV-1a hash
unchecked
{
uint hash = 2166136261;
foreach (char c in source)
{
hash ^= c;
hash *= 16777619;
}
return hash.ToString("x8");
}
}
private sealed class ScopeDisposable : IDisposable
{
private readonly Dictionary<string, object> _previous;
public ScopeDisposable(Dictionary<string, object> previous)
{
_previous = previous;
}
public void Dispose()
{
_scopeProperties.Value = _previous;
}
}
/// <summary>Returns true if the flow is healthy (no recent errors and writer thread alive).</summary>
public bool IsHealthy()
{
if (!IsEnabled)
{
return false;
}
if (!_writerThread.IsAlive)
{
return false;
}
long lastErr = Interlocked.Read(ref _lastErrorTimestamp);
if (lastErr > 0)
{
TimeSpan since = TimeSpan.FromTicks(DateTime.UtcNow.Ticks - lastErr);
if (since < TimeSpan.FromMinutes(1))
{
return false;
}
}
return true;
}
/// <summary>Returns the last error encountered by the writer, or null if none.</summary>
public Exception GetLastError()
{
return _lastError;
}
/// <summary>Returns the total number of write errors encountered.</summary>
public long GetTotalErrors()
{
return Interlocked.Read(ref _totalErrors);
}
/// <summary>Returns live throughput and health metrics.</summary>
public LogStats GetStats()
{
@@ -347,6 +550,28 @@ namespace EonaCat.LogStack.Flows
return Task.FromResult(WriteResult.LevelFiltered);
}
if (!PassesFilters(logEvent))
{
return Task.FromResult(WriteResult.LevelFiltered);
}
if (_deduplicationEnabled && IsDuplicate(logEvent))
{
return Task.FromResult(WriteResult.LevelFiltered);
}
if (_rateLimitEnabled && !TryPassRateLimit())
{
Interlocked.Increment(ref DroppedCount);
Action<LogEvent> drop = _onDrop;
if (drop != null)
{
drop(logEvent);
}
return Task.FromResult(WriteResult.Dropped);
}
return Task.FromResult(TryEnqueue(logEvent));
}
@@ -361,9 +586,11 @@ namespace EonaCat.LogStack.Flows
WriteResult result = WriteResult.Success;
SamplingPolicy sp = _samplingPolicy;
ReadOnlySpan<LogEvent> span = logEvents.Span;
foreach (LogEvent e in logEvents.ToArray())
for (int i = 0; i < span.Length; i++)
{
LogEvent e = span[i];
if (e.Level < MinimumLevel)
{
continue;
@@ -374,6 +601,29 @@ namespace EonaCat.LogStack.Flows
continue;
}
if (!PassesFilters(e))
{
continue;
}
if (_deduplicationEnabled && IsDuplicate(e))
{
continue;
}
if (_rateLimitEnabled && !TryPassRateLimit())
{
Interlocked.Increment(ref DroppedCount);
Action<LogEvent> drop = _onDrop;
if (drop != null)
{
drop(e);
}
result = WriteResult.Dropped;
continue;
}
if (TryEnqueue(e) == WriteResult.Dropped)
{
result = WriteResult.Dropped;
@@ -418,6 +668,88 @@ namespace EonaCat.LogStack.Flows
return WriteResult.Success;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool TryPassRateLimit()
{
long now = DateTime.UtcNow.Ticks;
lock (_rateLimitLock)
{
long elapsed = now - _rateLimitWindowStart;
if (elapsed >= TimeSpan.TicksPerSecond)
{
_rateLimitWindowStart = now;
_rateLimitCounter = 1;
return true;
}
if (_rateLimitEnabled && _rateLimitCounter >= _maxEventsPerSecond)
{
return false;
}
_rateLimitCounter++;
return true;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool PassesFilters(LogEvent log)
{
lock (_filtersLock)
{
for (int i = 0; i < _filters.Count; i++)
{
if (!_filters[i](log))
{
return false;
}
}
}
return true;
}
private bool IsDuplicate(LogEvent log)
{
string key = string.Concat(
log.Level.ToString(), "|",
log.Category ?? string.Empty, "|",
log.Message.Length > 0 ? log.Message.ToString() : string.Empty);
long nowTicks = DateTime.UtcNow.Ticks;
long windowTicks = _deduplicationWindow.Ticks;
long existing;
if (_deduplicationCache.TryGetValue(key, out existing))
{
if (nowTicks - existing < windowTicks)
{
return true;
}
}
_deduplicationCache[key] = nowTicks;
// Periodic cleanup: remove expired entries when cache grows large
if (_deduplicationCache.Count > 10000)
{
CleanDeduplicationCache(nowTicks, windowTicks);
}
return false;
}
private void CleanDeduplicationCache(long nowTicks, long windowTicks)
{
foreach (var kvp in _deduplicationCache)
{
if (nowTicks - kvp.Value >= windowTicks)
{
long removed;
_deduplicationCache.TryRemove(kvp.Key, out removed);
}
}
}
public override Task FlushAsync(CancellationToken cancellationToken = default(CancellationToken))
{
@@ -642,6 +974,9 @@ namespace EonaCat.LogStack.Flows
}
catch (Exception ex)
{
_lastError = ex;
Interlocked.Increment(ref _totalErrors);
Interlocked.Exchange(ref _lastErrorTimestamp, DateTime.UtcNow.Ticks);
try
{
WriteToConsoleError("[FileFlow] Write error for '" + path + "': " + ex.Message);
@@ -651,6 +986,19 @@ namespace EonaCat.LogStack.Flows
}
Interlocked.Add(ref _totalBytesWritten, line.Length + 1);
// Auto-flush on error/critical
if (_autoFlushOnError && (log.Level >= LogLevel.Error))
{
lock (_fileLock)
{
OpenFile autoFlushOf;
if (_openFiles.TryGetValue(path, out autoFlushOf))
{
try { autoFlushOf.Writer.Flush(); } catch { /* ignore */ }
}
}
}
}
catch (Exception ex)
{
@@ -719,11 +1067,30 @@ namespace EonaCat.LogStack.Flows
sb.Append("\",");
sb.Append("\"host\":\"");
AppendJsonEscaped(Environment.MachineName, sb);
AppendJsonEscaped(CachedMachineName, sb);
sb.Append("\",");
sb.Append("\"pid\":");
sb.Append(Process.GetCurrentProcess().Id);
sb.Append(CachedPid);
sb.Append(',');
// Distributed tracing
if (log.TraceId != default(ActivityTraceId))
{
sb.Append("\"traceId\":\"");
sb.Append(log.TraceId.ToHexString());
sb.Append("\",");
}
if (log.SpanId != default(ActivitySpanId))
{
sb.Append("\"spanId\":\"");
sb.Append(log.SpanId.ToHexString());
sb.Append("\",");
}
sb.Append("\"threadId\":");
sb.Append(log.ThreadId);
sb.Append(',');
}
@@ -777,7 +1144,7 @@ namespace EonaCat.LogStack.Flows
sb.Append('"');
}
foreach (var property in log.Properties.ToArray())
foreach (var property in log.Properties)
{
if (!first)
{
@@ -927,7 +1294,7 @@ namespace EonaCat.LogStack.Flows
sb.Append("</property>");
}
foreach (var property in log.Properties.ToArray())
foreach (var property in log.Properties)
{
if (string.IsNullOrEmpty(property.Key))
{
@@ -1025,7 +1392,7 @@ namespace EonaCat.LogStack.Flows
object val = kv.Value(log);
AppendCsvInner(val != null ? val.ToString() : "null", sb);
}
foreach (var property in log.Properties.ToArray())
foreach (var property in log.Properties)
{
if (!first)
{
@@ -1047,7 +1414,7 @@ namespace EonaCat.LogStack.Flows
value = string.Empty;
}
bool needsQuote = value.IndexOfAny(new[] { ',', '"', '\n', '\r' }) >= 0;
bool needsQuote = value.IndexOfAny(CsvSpecialChars) >= 0;
if (needsQuote)
{
sb.Append('"');
@@ -1253,7 +1620,20 @@ namespace EonaCat.LogStack.Flows
for (int i = maxFiles - 1; i >= 1; i--)
{
string src = Path.Combine(dir, baseName + "_" + i + _fileExtension);
string srcGz = src + ".gz";
string dst = Path.Combine(dir, baseName + "_" + (i + 1) + _fileExtension);
string dstGz = dst + ".gz";
// Move .gz variant if it exists
if (File.Exists(srcGz))
{
if (File.Exists(dstGz))
{
File.Delete(dstGz);
}
File.Move(srcGz, dstGz);
}
if (!File.Exists(src))
{
continue;
@@ -1261,8 +1641,6 @@ namespace EonaCat.LogStack.Flows
if (File.Exists(dst))
{
_compressionQueue.Enqueue(dst);
_compressionSignal.Release(1);
File.Delete(dst);
}
File.Move(src, dst);
@@ -1275,6 +1653,14 @@ namespace EonaCat.LogStack.Flows
}
File.Move(filePath, archive);
// Queue the archived file for compression
if (_compressionFormat != CompressionFormat.None)
{
_compressionQueue.Enqueue(archive);
_compressionSignal.Release(1);
}
return archive;
}
catch (Exception ex)
@@ -1343,6 +1729,9 @@ namespace EonaCat.LogStack.Flows
gz.Write(buffer, 0, read);
}
}
// Delete the original uncompressed file after successful compression
try { File.Delete(path); } catch { /* ignore */ }
}
private void PeriodicFlushLoop()
@@ -1361,18 +1750,14 @@ namespace EonaCat.LogStack.Flows
break;
}
OpenFile[] snapshot;
lock (_fileLock)
{
snapshot = new OpenFile[_openFiles.Count];
_openFiles.Values.CopyTo(snapshot, 0);
}
foreach (OpenFile of in snapshot)
foreach (OpenFile of in _openFiles.Values)
{
try { of.Writer.Flush(); } catch { /* ignore */ }
}
}
}
catch (ThreadInterruptedException) { break; }
catch (Exception ex)
{
@@ -1405,6 +1790,7 @@ namespace EonaCat.LogStack.Flows
}
FileInfo[] files = dir.GetFiles("*" + _fileExtension)
.Concat(dir.GetFiles("*" + _fileExtension + ".gz"))
.OrderByDescending(f => f.LastWriteTimeUtc)
.ToArray();
@@ -1418,8 +1804,9 @@ namespace EonaCat.LogStack.Flows
bool tooMany = _retention.MaxRolledFiles > 0 && kept >= _retention.MaxRolledFiles;
bool tooLarge = _retention.MaxTotalArchiveBytes > 0
&& totalBytes + f.Length > _retention.MaxTotalArchiveBytes;
bool directoryTooLarge = totalBytes + f.Length > _maxDirectorySize;
if (tooOld || tooMany || tooLarge)
if (tooOld || tooMany || tooLarge || directoryTooLarge)
{
try { f.Delete(); } catch { /* ignore */ }
}
@@ -1460,7 +1847,7 @@ namespace EonaCat.LogStack.Flows
return Path.Combine(
_directory,
prefix + "_" + Environment.MachineName + "_" + date.ToString("yyyyMMdd") + _fileExtension);
string.Concat(prefix, "_", CachedMachineName, "_", date.ToString(_dateFormat), _fileExtension));
}
private void SetFileExtension(FileOutputFormat fmt)
@@ -1488,7 +1875,7 @@ namespace EonaCat.LogStack.Flows
+ log.Properties.Count * 40;
if (log.Exception != null)
{
s += log.Exception.ToString().Length * 2;
s += 2048; // Avoid calling Exception.ToString() just for size estimation
}
return s;
@@ -1541,7 +1928,7 @@ namespace EonaCat.LogStack.Flows
sb.Append(_timestampMode == TimestampMode.Local
? TimeZoneInfo.Local.StandardName : "UTC");
case "host":
return (log, sb) => sb.Append(Environment.MachineName);
return (log, sb) => sb.Append(CachedMachineName);
case "category":
return (log, sb) => { if (log.Category != null) { sb.Append(log.Category); } };
case "thread":
@@ -1573,7 +1960,23 @@ namespace EonaCat.LogStack.Flows
case "newline":
return (log, sb) => sb.AppendLine();
case "pid":
return (log, sb) => sb.Append(Process.GetCurrentProcess().Id);
return (log, sb) => sb.Append(CachedPid);
case "traceid":
return (log, sb) =>
{
if (log.TraceId != default(ActivityTraceId))
{
sb.Append(log.TraceId.ToHexString());
}
};
case "spanid":
return (log, sb) =>
{
if (log.SpanId != default(ActivitySpanId))
{
sb.Append(log.SpanId.ToHexString());
}
};
default:
return BuildCustomOrLiteralToken(token);
}
@@ -1598,9 +2001,11 @@ namespace EonaCat.LogStack.Flows
private void AppendProperties(LogEvent log, StringBuilder sb)
{
var scopeProps = _scopeProperties.Value;
bool hasEnrichers = _enrichers.Count > 0;
bool hasProps = log.Properties.Count > 0;
if (!hasEnrichers && !hasProps)
bool hasScope = scopeProps != null && scopeProps.Count > 0;
if (!hasEnrichers && !hasProps && !hasScope)
{
return;
}
@@ -1620,7 +2025,7 @@ namespace EonaCat.LogStack.Flows
sb.Append(kv.Key).Append('=').Append(val != null ? val.ToString() : "null");
}
foreach (var property in log.Properties.ToArray())
foreach (var property in log.Properties)
{
if (!first)
{
@@ -1632,6 +2037,21 @@ namespace EonaCat.LogStack.Flows
.Append(property.Value != null ? property.Value.ToString() : "null");
}
if (hasScope)
{
foreach (var kv in scopeProps)
{
if (!first)
{
sb.Append(", ");
}
first = false;
sb.Append(kv.Key).Append('=')
.Append(kv.Value != null ? kv.Value.ToString() : "null");
}
}
sb.Append('}');
}
}
+10 -3
View File
@@ -95,6 +95,7 @@ public sealed class LogBuilder
string directory,
string filePrefix = "log",
long maxFileSize = 100 * 1024 * 1024,
long maxDirectorySize = 2L * 1024 * 1024 * 1024,
FileRetentionPolicy fileRetentionPolicy = null,
int flushIntervalInMilliSeconds = 2000,
bool useCategoryRouting = false,
@@ -110,6 +111,7 @@ public sealed class LogBuilder
directory,
filePrefix,
maxFileSize,
maxDirectorySize,
fileRetentionPolicy,
flushIntervalInMilliSeconds,
batchSize,
@@ -140,9 +142,14 @@ public sealed class LogBuilder
password,
filePrefix,
maxFileSize,
flushIntervalInMilliSeconds,
minimumLevel,
_timestampMode));
maxDirectorySize: 2L * 1024 * 1024 * 1024,
retention: fileRetentionPolicy,
flushIntervalMs: flushIntervalInMilliSeconds,
batchSize: 1,
minimumLevel: minimumLevel,
useCategoryRouting: useCategoryRouting,
logLevelsForSeparateFiles: logLevelsForSeparateFiles,
tsMode: _timestampMode));
return this;
}
@@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EonaCat.Versioning" Version="1.2.8">
<PackageReference Include="EonaCat.Versioning" Version="1.2.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>