Skip to content

Commit

Permalink
Merge pull request #10 from walterlv/t/walterlv/logger
Browse files Browse the repository at this point in the history
改进日志 1. 允许强行等待日志写完 2. 线程安全 3. 允许设置日志最大大小
  • Loading branch information
walterlv authored Jun 30, 2020
2 parents ee04c2d + 9ccdb2e commit c341901
Show file tree
Hide file tree
Showing 10 changed files with 548 additions and 94 deletions.
2 changes: 1 addition & 1 deletion build/Version.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project>
<PropertyGroup>
<Version>5.2.1</Version>
<Version>5.3.0</Version>
</PropertyGroup>
</Project>
6 changes: 6 additions & 0 deletions src/Utils/Walterlv.Collections/Threading/AsyncQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ public AsyncQueue()
_queue = new ConcurrentQueue<T>();
}

/// <summary>
/// 获取此刻队列中剩余元素的个数。
/// 请注意:因为线程安全问题,此值获取后值即过时,所以获取此值的代码需要自行处理线程安全。
/// </summary>
public int Count => _queue.Count;

/// <summary>
/// 入队。
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public AsyncQueue()
_queue = new ConcurrentQueue<T>();
}

public int Count => _queue.Count;

public void Enqueue(T item)
{
_queue.Enqueue(item);
Expand All @@ -40,7 +42,6 @@ public async Task<T> DequeueAsync(CancellationToken cancellationToken = default)
while (true)
{
await _semaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(false);

if (_queue.TryDequeue(out var item))
{
return item;
Expand Down
62 changes: 61 additions & 1 deletion src/Utils/Walterlv.Logger/Core/AsyncOutputLogger.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

namespace Walterlv.Logging.Core
Expand All @@ -11,6 +12,9 @@ public abstract partial class AsyncOutputLogger : ILogger
{
private readonly AsyncQueue<LogContext> _queue;
private bool _isInitialized;
private CancellationTokenSource _waitForEmptyCancellationTokenSource = new CancellationTokenSource();
private TaskCompletionSource<object?>? _waitForEmptyTaskCompletionSource;
private object _waitForEmptyLocker = new object();

/// <summary>
/// 创建 Markdown 格式的日志记录实例。
Expand Down Expand Up @@ -108,7 +112,32 @@ private async void StartLogging()
{
while (true)
{
var context = await _queue.DequeueAsync().ConfigureAwait(false);
LogContext context;

try
{
context = await _queue.DequeueAsync(_waitForEmptyCancellationTokenSource.Token).ConfigureAwait(false);
await Write(context).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
while (_queue.Count > 0)
{
context = await _queue.DequeueAsync().ConfigureAwait(false);
await Write(context).ConfigureAwait(false);
}
}

if (_queue.Count == 0)
{
_waitForEmptyCancellationTokenSource.Dispose();
_waitForEmptyCancellationTokenSource = new CancellationTokenSource();
_waitForEmptyTaskCompletionSource?.SetResult(null);
}
}

async Task Write(LogContext context)
{
if (!_isInitialized)
{
_isInitialized = true;
Expand All @@ -128,5 +157,36 @@ private async void StartLogging()
/// </summary>
/// <param name="context">包含一条日志的所有上下文信息。</param>
protected abstract void OnLogReceived(in LogContext context);

/// <summary>
/// 如果派生类需要等待当前尚未完成日志输出的日志全部完成输出,则调用此方法。
/// 但请注意:因为并发问题,如果等待期间还有新写入的日志,那么也会一并等待。
/// </summary>
/// <returns>可等待对象。</returns>
protected async Task WaitFlushingAsync()
{
if (_waitForEmptyTaskCompletionSource is null)
{
lock (_waitForEmptyLocker)
{
if (_waitForEmptyTaskCompletionSource is null)
{
_waitForEmptyTaskCompletionSource = new TaskCompletionSource<object?>();
_waitForEmptyCancellationTokenSource.Cancel();
}
else if (_waitForEmptyTaskCompletionSource.Task.IsCompleted)
{
return;
}
}
}

await _waitForEmptyTaskCompletionSource.Task.ConfigureAwait(false);

lock (_waitForEmptyLocker)
{
_waitForEmptyTaskCompletionSource = null;
}
}
}
}
Loading

0 comments on commit c341901

Please sign in to comment.