Skip to content

Instantly share code, notes, and snippets.

@gusarov
Last active March 18, 2025 00:17
Show Gist options
  • Save gusarov/5f1ee1adc3d4228fb6b83e424bdd2002 to your computer and use it in GitHub Desktop.
Save gusarov/5f1ee1adc3d4228fb6b83e424bdd2002 to your computer and use it in GitHub Desktop.
public class CustomLog : IDisposable, IAsyncDisposable
{
StreamWriter _log;
Channel<string> _channel = Channel.CreateUnbounded<string>();
Task _writer;
CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
Timer _flusher;
SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
public CustomLog(string logName)
{
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Todo");
Directory.CreateDirectory(path);
var file = Path.Combine(path, logName + ".log");
try
{
_log = new StreamWriter(file, true);
}
catch
{
file = Path.Combine(path, logName + Guid.NewGuid().ToString("N") + ".log");
_log = new StreamWriter(file, true);
}
_writer = WriterWorker(_cancellationTokenSource.Token);
_flusher = new Timer(async _ =>
{
await _semaphore.WaitAsync();
try
{
await _log.FlushAsync();
}
finally
{
_semaphore.Release();
}
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
}
async Task WriterWorker(CancellationToken cancellationToken)
{
await foreach (var line in _channel.Reader.ReadAllAsync(cancellationToken))
{
await _semaphore.WaitAsync();
try
{
await _log.WriteLineAsync(line);
}
finally
{
_semaphore.Release();
}
}
}
public void Log(string line)
{
_channel.Writer.TryWrite(line);
}
public void Dispose()
{
_cancellationTokenSource.Cancel();
_writer.Wait();
}
public async ValueTask DisposeAsync()
{
_cancellationTokenSource.Cancel();
await _writer;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment