Files
EonaCat.LogStack/EonaCat.LogStack/EonaCatLoggerCore/IFlow.cs
T
2026-04-06 08:15:54 +02:00

126 lines
3.8 KiB
C#

using EonaCat.LogStack.Core;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace EonaCat.LogStack.Flows;
// 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.
/// <summary>
/// Flows are output destinations for log events (replacement for "sinks").
/// Each flow handles writing log events to a specific destination with optimized batching.
/// </summary>
public interface IFlow : IAsyncDisposable
{
/// <summary>
/// Gets the name of this flow for identification
/// </summary>
string Name { get; }
/// <summary>
/// Minimum log level this flow will process
/// </summary>
LogLevel MinimumLevel { get; }
/// <summary>
/// Whether this flow is currently enabled
/// </summary>
bool IsEnabled { get; }
/// <summary>
/// Blast a single log event to this flow
/// </summary>
Task<WriteResult> BlastAsync(LogEvent logEvent, CancellationToken cancellationToken = default);
/// <summary>
/// Blast a batch of log events to this flow (more efficient than single blasts)
/// </summary>
Task<WriteResult> BlastBatchAsync(ReadOnlyMemory<LogEvent> logEvents, CancellationToken cancellationToken = default);
/// <summary>
/// Flush any buffered log events immediately
/// </summary>
Task FlushAsync(CancellationToken cancellationToken = default);
}
/// <summary>
/// Base class for flows with common functionality
/// </summary>
public abstract class FlowBase : IFlow
{
protected FlowBase(string name, LogLevel minimumLevel = LogLevel.Trace)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
MinimumLevel = minimumLevel;
IsEnabled = true;
}
public string Name { get; }
public LogLevel MinimumLevel { get; protected set; }
public bool IsEnabled { get; protected set; }
protected long DroppedCount;
protected long BlastedCount;
protected bool IsLogLevelEnabled(LogEvent logEvent)
{
return logEvent.Level >= MinimumLevel;
}
public abstract Task<WriteResult> BlastAsync(LogEvent logEvent, CancellationToken cancellationToken = default);
public virtual async Task<WriteResult> BlastBatchAsync(ReadOnlyMemory<LogEvent> logEvents, CancellationToken cancellationToken = default)
{
var result = WriteResult.Success;
var eventsArray = logEvents.ToArray();
foreach (var logEvent in eventsArray)
{
var singleResult = await BlastAsync(logEvent, cancellationToken).ConfigureAwait(false);
if (singleResult != WriteResult.Success)
{
result = singleResult;
}
}
return result;
}
public abstract Task FlushAsync(CancellationToken cancellationToken = default);
public virtual async ValueTask DisposeAsync()
{
IsEnabled = false;
await FlushAsync(default).ConfigureAwait(false);
GC.SuppressFinalize(this);
}
/// <summary>
/// Gets diagnostic information about this flow
/// </summary>
public virtual FlowDiagnostics GetDiagnostics()
{
return new FlowDiagnostics
{
Name = Name,
IsEnabled = IsEnabled,
MinimumLevel = MinimumLevel,
BlastedCount = Interlocked.Read(ref BlastedCount),
DroppedCount = Interlocked.Read(ref DroppedCount)
};
}
}
/// <summary>
/// Diagnostic information about a flow
/// </summary>
public sealed class FlowDiagnostics
{
public string Name { get; set; }
public bool IsEnabled { get; set; }
public LogLevel MinimumLevel { get; set; }
public long BlastedCount { get; set; }
public long DroppedCount { get; set; }
}