From f3be41a848a7dfb4fb23c9ba924d06e7bf11e477 Mon Sep 17 00:00:00 2001 From: bezzad Date: Sat, 2 Dec 2023 00:16:17 +0330 Subject: [PATCH] added ILogger pattern to main downloader class --- src/Downloader.Test/Helper/FileLogger.cs | 122 +++++++++++++++++++ src/Downloader/AbstractDownloadService.cs | 9 +- src/Downloader/Extensions/Logging/ILogger.cs | 18 +++ src/Downloader/FileHelper.cs | 4 +- 4 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 src/Downloader.Test/Helper/FileLogger.cs create mode 100644 src/Downloader/Extensions/Logging/ILogger.cs diff --git a/src/Downloader.Test/Helper/FileLogger.cs b/src/Downloader.Test/Helper/FileLogger.cs new file mode 100644 index 00000000..3382c667 --- /dev/null +++ b/src/Downloader.Test/Helper/FileLogger.cs @@ -0,0 +1,122 @@ +using Downloader.Extensions.Logging; +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Downloader.Test.Helper; + +internal class FileLogger : ILogger, IDisposable +{ + private volatile bool _disposed = false; + private SemaphoreSlim _semaphore = new SemaphoreSlim(0); + protected readonly ConcurrentQueue LogQueue; + protected string LogPath; + protected StreamWriter LogStream; + + public FileLogger(string logPath) + { + LogQueue = new ConcurrentQueue(); + LogPath = logPath; + LogStream = new StreamWriter(FileHelper.CreateFile(logPath)); + + Task task = Task.Factory.StartNew( + function: Writer, + cancellationToken: default, + creationOptions: TaskCreationOptions.LongRunning, + scheduler: TaskScheduler.Default); + + task.Unwrap(); + } + + public void Debug(string message) + { + Log(nameof(Debug), message); + } + + public void Info(string message) + { + Log(nameof(Info), message); + } + + public void Warning(string message) + { + Log(nameof(Warning), message); + } + + public void Warning(string message, Exception exception) + { + Log(nameof(Warning), message, exception); + } + + public void Error(string message) + { + Log(nameof(Error), message); + } + + public void Error(string message, Exception exception) + { + Log(nameof(Error), message, exception); + } + + public void Fatal(string message) + { + Log(nameof(Fatal), message); + } + + public void Fatal(string message, Exception exception) + { + Log(nameof(Fatal), message, exception); + } + + protected void Log(string logType, string message, Exception exception = null) + { + if (!_disposed) + { + LogQueue.Enqueue(Formatter(logType, message, exception)); + _semaphore.Release(); + } + } + + public virtual string Formatter(string logType, string message, Exception exception) + { + var log = $"{DateTime.Now:s} | {logType} | {message}"; + if (exception is not null) + { + log += " | " + exception.Message + ": " + exception.StackTrace; + } + + return log; + } + + private async Task Writer() + { + while (!_disposed) + { + await _semaphore.WaitAsync().ConfigureAwait(false); + if (LogQueue.TryDequeue(out var log)) + { + await LogStream.WriteLineAsync(log).ConfigureAwait(false); + } + } + } + + public void Dispose() + { + _disposed = true; + LogQueue.Clear(); + LogStream?.Dispose(); + LogStream = null; + } + + public async Task FlushAsync() + { + while (!_disposed && _semaphore.CurrentCount > 0) + { + await Task.Delay(100); + } + + await (LogStream?.FlushAsync() ?? Task.CompletedTask).ConfigureAwait(false); + } +} diff --git a/src/Downloader/AbstractDownloadService.cs b/src/Downloader/AbstractDownloadService.cs index 734902f2..23e6e1ea 100644 --- a/src/Downloader/AbstractDownloadService.cs +++ b/src/Downloader/AbstractDownloadService.cs @@ -1,3 +1,4 @@ +using Downloader.Extensions.Logging; using System; using System.Collections.Generic; using System.ComponentModel; @@ -12,6 +13,7 @@ namespace Downloader { public abstract class AbstractDownloadService : IDownloadService, IDisposable { + protected ILogger _logger; protected SemaphoreSlim _parallelSemaphore; protected readonly SemaphoreSlim _singleInstanceSemaphore = new SemaphoreSlim(1, 1); protected CancellationTokenSource _globalCancellationTokenSource; @@ -206,8 +208,6 @@ protected void OnDownloadStarted(DownloadStartedEventArgs e) protected void OnDownloadFileCompleted(AsyncCompletedEventArgs e) { - // flush streams - Package.Flush(); Package.IsSaving = false; if (e.Cancelled) @@ -261,6 +261,11 @@ protected void OnChunkDownloadProgressChanged(object sender, DownloadProgressCha DownloadProgressChanged?.Invoke(this, totalProgressArg); } + public void AddLogger(ILogger logger) + { + _logger = logger; + } + public virtual void Dispose() { Clear().Wait(); diff --git a/src/Downloader/Extensions/Logging/ILogger.cs b/src/Downloader/Extensions/Logging/ILogger.cs new file mode 100644 index 00000000..d969b552 --- /dev/null +++ b/src/Downloader/Extensions/Logging/ILogger.cs @@ -0,0 +1,18 @@ +using System; +using System.Threading.Tasks; + +namespace Downloader.Extensions.Logging; + +public interface ILogger +{ + void Debug(string message); + void Info(string message); + void Warning(string message); + void Warning(string message, Exception exception); + void Error(string message); + void Error(string message, Exception exception); + void Fatal(string message); + void Fatal(string message, Exception exception); + string Formatter(string logType, string message, Exception exception); + Task FlushAsync(); +} diff --git a/src/Downloader/FileHelper.cs b/src/Downloader/FileHelper.cs index 0a4db164..0c889116 100644 --- a/src/Downloader/FileHelper.cs +++ b/src/Downloader/FileHelper.cs @@ -5,12 +5,12 @@ namespace Downloader { internal static class FileHelper { - public static Stream CreateFile(string filename) + public static FileStream CreateFile(string filename) { string directory = Path.GetDirectoryName(filename); if (string.IsNullOrWhiteSpace(directory)) { - return Stream.Null; + return null; } if (Directory.Exists(directory) == false)