Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
│ WB Packages │
╰──────────────────────────────────────────────────────────────────────╯ -->
<ItemGroup>
<PackageVersion Include="WB.Logging.Base" Version="[1.0.0-preview.12, 2.0.0)" />
<PackageVersion Include="WB.Logging.Base" Version="[1.0.0-preview.14, 2.0.0)" />
</ItemGroup>

<!-- ╭──────────────────────────────────────────────────────────────────────╮
Expand Down
67 changes: 11 additions & 56 deletions src/AsyncLogSinkBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,31 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace WB.Logging.LogSinks.Base;

/// <summary>
/// A base implementation of <see cref="IAsyncLogSink"/> that manages log message writers for different payload types.
/// </summary>
/// <param name="defaultLogMessageWriter">The default <see cref="IAsyncLogMessageWriter{TPayload, TWriter}"/> to use when no
/// <param name="defaultLogMessageWriter">The default <see cref="IAsyncLogMessageWriter{TAsyncLogSink, TPayload}"/> to use when no
/// specific writer is registered for a payload type.</param>
/// <param name="writer">The initial writer of type <typeparamref name="TWriter"/> that the log message writers will use to write log messages.</param>
public abstract class AsyncLogSinkBase<TWriter>(IAsyncLogMessageWriter<object, TWriter> defaultLogMessageWriter, TWriter writer) : IAsyncLogSink
public abstract class AsyncLogSinkBase<TLogSinkBase>(IAsyncLogMessageWriter<TLogSinkBase, object> defaultLogMessageWriter) : IAsyncLogSink
where TLogSinkBase : AsyncLogSinkBase<TLogSinkBase>
{
// ┌─────────────────────────────────────────────────────────────────────────────┐
// │ Private Fields │
// └─────────────────────────────────────────────────────────────────────────────┘
private readonly ConcurrentDictionary<Type, object> logMessageWriters = new();

private readonly ConcurrentBag<ILogMessageFilter> filters = [];

// ┌─────────────────────────────────────────────────────────────────────────────┐
// │ Public Properties │
// └─────────────────────────────────────────────────────────────────────────────┘

/// <summary>
/// Gets the default <see cref="IAsyncLogMessageWriter{TPayload, TWriter}"/> to use when no specific writer is registered for a payload type.
/// Gets the default <see cref="IAsyncLogMessageWriter{TAsyncLogSink, TPayload}"/> to use when no specific writer is registered for a payload type.
/// </summary>
public IAsyncLogMessageWriter<object, TWriter> DefaultLogMessageWriter => defaultLogMessageWriter;
public IAsyncLogMessageWriter<TLogSinkBase, object> DefaultLogMessageWriter => defaultLogMessageWriter;

/// <summary>
/// Gets the registered log message writers.
Expand All @@ -40,48 +36,17 @@ public abstract class AsyncLogSinkBase<TWriter>(IAsyncLogMessageWriter<object, T
/// </remarks>
public IReadOnlyList<object> LogMessageWriters => (IReadOnlyList<object>)logMessageWriters.Values;

/// <summary>
/// Gets or sets the writer of type <typeparamref name="TWriter"/> that this log message writer uses to write log messages.
/// </summary>
/// <remarks>
/// When setting the writer, it will update the writer of all registered log message writers that
/// implement <see cref="IAsyncLogMessageWriter{TPayload, TWriter}"/>.
/// </remarks>
public TWriter Writer
{
get;
set
{
field = value;

object[] logMessageWriters = [DefaultLogMessageWriter, .. this.logMessageWriters.Values];

foreach (object writer in logMessageWriters)
{
if (writer is IHasWriter<TWriter> asyncLogMessageWriter)
{
asyncLogMessageWriter.Writer = value;
}
}
}
} = writer;

// ┌─────────────────────────────────────────────────────────────────────────────┐
// │ Public Methods │
// └─────────────────────────────────────────────────────────────────────────────┘

/// <inheritdoc/>
public async ValueTask SubmitAsync<TPayload>(ILogMessage<TPayload> logMessage)
public virtual async ValueTask SubmitAsync<TPayload>(ILogMessage<TPayload> logMessage)
where TPayload : notnull
{
if (!filters.All(filter => filter.IsMatch(logMessage)))
{
return;
}

ArgumentNullException.ThrowIfNull(logMessage, nameof(logMessage));

if (TryGetLogMessageWriter(out IAsyncLogMessageWriter<TPayload, TWriter>? logMessageWriter))
if (TryGetLogMessageWriter(out IAsyncLogMessageWriter<TLogSinkBase, TPayload>? logMessageWriter))
{
await logMessageWriter.WriteAsync(logMessage.Timestamp, logMessage.LogLevel, logMessage.Senders, logMessage.Payload).ConfigureAwait(false);
}
Expand All @@ -100,37 +65,27 @@ public async ValueTask SubmitAsync<TPayload>(ILogMessage<TPayload> logMessage)
/// <param name="logMessageWriter">The log message writer to register.</param>
/// <returns>A <see cref="IDisposable"/> that, when disposed, unregisters the log message writer.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="logMessageWriter"/> is <c>null</c>.</exception>
public IDisposable RegisterLogMessageWriter<TPayload>(IAsyncLogMessageWriter<TPayload, TWriter> logMessageWriter)
public IDisposable RegisterLogMessageWriter<TPayload>(IAsyncLogMessageWriter<TLogSinkBase, TPayload> logMessageWriter)
where TPayload : notnull
{
ArgumentNullException.ThrowIfNull(logMessageWriter);

logMessageWriter.LogSink = this;
logMessageWriter.LogSink = (TLogSinkBase)this;

logMessageWriters[typeof(TPayload)] = logMessageWriter;

return new DelegateDisposable(() => logMessageWriters.TryRemove(typeof(TPayload), out _));
}

/// <inheritdoc/>
public IDisposable AddFilter(ILogMessageFilter filter)
{
ArgumentNullException.ThrowIfNull(filter);

filters.Add(filter);

return new DelegateDisposable(() => filters.TryTake(out _));
}

// ┌─────────────────────────────────────────────────────────────────────────────┐
// │ Private Methods │
// └─────────────────────────────────────────────────────────────────────────────┘
private bool TryGetLogMessageWriter<TPayload>([NotNullWhen(true)] out IAsyncLogMessageWriter<TPayload, TWriter>? logMessageWriter)
private bool TryGetLogMessageWriter<TPayload>([NotNullWhen(true)] out IAsyncLogMessageWriter<TLogSinkBase, TPayload>? logMessageWriter)
where TPayload : notnull
{
if (logMessageWriters.TryGetValue(typeof(TPayload), out var writer))
{
logMessageWriter = (IAsyncLogMessageWriter<TPayload, TWriter>)writer;
logMessageWriter = (IAsyncLogMessageWriter<TLogSinkBase, TPayload>)writer;

return true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;

namespace WB.Logging.LogSinks.Base;
Expand All @@ -8,9 +9,10 @@ namespace WB.Logging.LogSinks.Base;
/// Defines an asynchronous log message writer for <see cref="ILogMessage{TPayload}"/> with a specific
/// payload type <typeparamref name="TPayload"/>.
/// </summary>
/// <typeparam name="TAsyncLogSink">The type of the log sink that this log message writer belongs to.</typeparam>
/// <typeparam name="TPayload">The type of the payload of the log messages that this writer can write.</typeparam>
/// <typeparam name="TWriter">The type of the writer that this log message writer uses to write log messages.</typeparam>
public interface IAsyncLogMessageWriter<TPayload, TWriter> : IHasWriter<TWriter>
public interface IAsyncLogMessageWriter<TAsyncLogSink, TPayload>
where TAsyncLogSink : IAsyncLogSink
where TPayload : notnull
{
// ┌─────────────────────────────────────────────────────────────────────────────┐
Expand All @@ -20,7 +22,8 @@ public interface IAsyncLogMessageWriter<TPayload, TWriter> : IHasWriter<TWriter>
/// <summary>
/// Gets or sets the <see cref="IAsyncLogSink"/> that this log message writer belongs to.
/// </summary>
public IAsyncLogSink? LogSink { get; set; }
[NotNull]
public TAsyncLogSink? LogSink { get; set; }

// ┌─────────────────────────────────────────────────────────────────────────────┐
// │ Public Methods │
Expand Down
17 changes: 0 additions & 17 deletions src/LogMessageWriter/IHasWriter.cs

This file was deleted.

9 changes: 6 additions & 3 deletions src/LogMessageWriter/ILogMessageWriter{TPayload}.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace WB.Logging.LogSinks.Base;

/// <summary>
/// Defines a log message writer for <see cref="ILogMessage{TPayload}"/> with a specific
/// payload type <typeparamref name="TPayload"/>.
/// </summary>
/// <typeparam name="TLogSink">The type of the log sink that this log message writer belongs to.</typeparam>
/// <typeparam name="TPayload">The type of the payload of the log messages that this writer can write.</typeparam>
/// <typeparam name="TWriter">The type of the writer that this log message writer uses to write log messages.</typeparam>
public interface ILogMessageWriter<TPayload, TWriter> : IHasWriter<TWriter>
public interface ILogMessageWriter<TLogSink, TPayload>
where TLogSink : ILogSink
where TPayload : notnull
{
// ┌─────────────────────────────────────────────────────────────────────────────┐
Expand All @@ -19,7 +21,8 @@ public interface ILogMessageWriter<TPayload, TWriter> : IHasWriter<TWriter>
/// <summary>
/// Gets or sets the <see cref="IAsyncLogSink"/> that this log message writer belongs to.
/// </summary>
public ILogSink? LogSink { get; set; }
[NotNull]
public TLogSink? LogSink { get; set; }

// ┌─────────────────────────────────────────────────────────────────────────────┐
// │ Public Methods │
Expand Down
Loading
Loading