forked from sim0n00ps/OF-DL
Use a logging sync to ensure GUI users are aware of any errors that occur while downloading
This commit is contained in:
parent
49cddd0608
commit
f1d3ac7ea3
@ -939,7 +939,8 @@ public class DownloadService(
|
||||
using HttpClient client = new();
|
||||
HttpRequestMessage request = new() { Method = HttpMethod.Get, RequestUri = new Uri(url) };
|
||||
|
||||
using HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, progressReporter.CancellationToken);
|
||||
using HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead,
|
||||
progressReporter.CancellationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
Stream body = await response.Content.ReadAsStreamAsync(progressReporter.CancellationToken);
|
||||
|
||||
|
||||
@ -7,8 +7,11 @@ namespace OF_DL.Services;
|
||||
|
||||
public class LoggingService : ILoggingService
|
||||
{
|
||||
public LoggingService()
|
||||
private readonly ILogEventSink? _optionalErrorSink;
|
||||
|
||||
public LoggingService(ILogEventSink? optionalErrorSink = null)
|
||||
{
|
||||
_optionalErrorSink = optionalErrorSink;
|
||||
LevelSwitch = new LoggingLevelSwitch();
|
||||
InitializeLogger();
|
||||
}
|
||||
@ -38,10 +41,17 @@ public class LoggingService : ILoggingService
|
||||
// Set the initial level to Error (until we've read from config)
|
||||
LevelSwitch.MinimumLevel = LogEventLevel.Error;
|
||||
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
LoggerConfiguration loggerConfiguration = new LoggerConfiguration()
|
||||
.MinimumLevel.ControlledBy(LevelSwitch)
|
||||
.WriteTo.File("logs/OFDL.txt", rollingInterval: RollingInterval.Day)
|
||||
.CreateLogger();
|
||||
.WriteTo.File("logs/OFDL.txt", rollingInterval: RollingInterval.Day);
|
||||
|
||||
if (_optionalErrorSink != null)
|
||||
{
|
||||
loggerConfiguration = loggerConfiguration.WriteTo.Sink(_optionalErrorSink,
|
||||
LogEventLevel.Error);
|
||||
}
|
||||
|
||||
Log.Logger = loggerConfiguration.CreateLogger();
|
||||
|
||||
Log.Debug("Logging service initialized");
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OF_DL.Helpers;
|
||||
using OF_DL.Services;
|
||||
using Serilog;
|
||||
@ -20,13 +19,10 @@ public static class Program
|
||||
// Parse command line arguments
|
||||
HidePrivateInfo = args.Contains("--hide-private-info", StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
ServiceCollection services = new();
|
||||
services.AddSingleton<ILoggingService, LoggingService>();
|
||||
ServiceProvider tempProvider = services.BuildServiceProvider();
|
||||
ILoggingService loggingService = tempProvider.GetRequiredService<ILoggingService>();
|
||||
// Initialize the logging service to ensure that logs are written before Avalonia starts (with a new logging service)
|
||||
LoggingService _ = new();
|
||||
|
||||
RegisterGlobalExceptionHandlers();
|
||||
Log.Information("Starting OF DL GUI");
|
||||
|
||||
// Check if running in Docker and print a message
|
||||
if (EnvironmentHelper.IsRunningInDocker())
|
||||
@ -40,7 +36,7 @@ public static class Program
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleUnhandledException(ex, "Program.Main", isTerminating: true);
|
||||
HandleUnhandledException(ex, "Program.Main", true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -65,7 +61,7 @@ public static class Program
|
||||
TaskScheduler.UnobservedTaskException += (_, eventArgs) =>
|
||||
{
|
||||
HandleUnhandledException(eventArgs.Exception, "TaskScheduler.UnobservedTaskException",
|
||||
isTerminating: false);
|
||||
false);
|
||||
eventArgs.SetObserved();
|
||||
};
|
||||
}
|
||||
|
||||
45
OF DL.Gui/Services/DownloadErrorLogTracking.cs
Normal file
45
OF DL.Gui/Services/DownloadErrorLogTracking.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using Serilog.Core;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace OF_DL.Gui.Services;
|
||||
|
||||
public sealed class DownloadErrorLogTracker
|
||||
{
|
||||
private int _sessionActive;
|
||||
private int _errorLoggedInSession;
|
||||
|
||||
public bool IsSessionActive => Volatile.Read(ref _sessionActive) == 1;
|
||||
|
||||
public void StartSession()
|
||||
{
|
||||
Interlocked.Exchange(ref _errorLoggedInSession, 0);
|
||||
Interlocked.Exchange(ref _sessionActive, 1);
|
||||
}
|
||||
|
||||
public bool StopSession()
|
||||
{
|
||||
Interlocked.Exchange(ref _sessionActive, 0);
|
||||
return Volatile.Read(ref _errorLoggedInSession) == 1;
|
||||
}
|
||||
|
||||
public void RecordError()
|
||||
{
|
||||
if (!IsSessionActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Interlocked.Exchange(ref _errorLoggedInSession, 1);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DownloadErrorTrackingSink(DownloadErrorLogTracker tracker) : ILogEventSink
|
||||
{
|
||||
public void Emit(LogEvent logEvent)
|
||||
{
|
||||
if (logEvent.Level >= LogEventLevel.Error)
|
||||
{
|
||||
tracker.RecordError();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using OF_DL.Gui.ViewModels;
|
||||
using OF_DL.Gui.Views;
|
||||
using OF_DL.Services;
|
||||
using Serilog.Core;
|
||||
|
||||
namespace OF_DL.Gui.Services;
|
||||
|
||||
@ -11,6 +12,8 @@ internal static class ServiceCollectionFactory
|
||||
{
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
|
||||
services.AddSingleton<DownloadErrorLogTracker>();
|
||||
services.AddSingleton<ILogEventSink, DownloadErrorTrackingSink>();
|
||||
services.AddSingleton<ILoggingService, LoggingService>();
|
||||
services.AddSingleton<IConfigService, ConfigService>();
|
||||
services.AddSingleton<IAuthService, AuthService>();
|
||||
|
||||
@ -26,7 +26,8 @@ public partial class MainWindowViewModel(
|
||||
IConfigService configService,
|
||||
IAuthService authService,
|
||||
IStartupService startupService,
|
||||
IDownloadOrchestrationService downloadOrchestrationService) : ViewModelBase
|
||||
IDownloadOrchestrationService downloadOrchestrationService,
|
||||
DownloadErrorLogTracker downloadErrorLogTracker) : ViewModelBase
|
||||
{
|
||||
private enum SingleDownloadType
|
||||
{
|
||||
@ -946,6 +947,7 @@ public partial class MainWindowViewModel(
|
||||
return;
|
||||
}
|
||||
|
||||
downloadErrorLogTracker.StartSession();
|
||||
IsDownloading = true;
|
||||
_workCancellationSource?.Dispose();
|
||||
_workCancellationSource = new CancellationTokenSource();
|
||||
@ -1000,18 +1002,39 @@ public partial class MainWindowViewModel(
|
||||
}
|
||||
|
||||
ThrowIfStopRequested();
|
||||
if (downloadErrorLogTracker.StopSession())
|
||||
{
|
||||
AppendLog(
|
||||
"Errors were encountered during the download. Check the logs saved to the logs folder for details.");
|
||||
}
|
||||
|
||||
eventHandler.OnScrapeComplete(DateTime.Now - start);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (downloadErrorLogTracker.IsSessionActive)
|
||||
{
|
||||
downloadErrorLogTracker.StopSession();
|
||||
}
|
||||
|
||||
AppendLog("Operation canceled.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (downloadErrorLogTracker.IsSessionActive)
|
||||
{
|
||||
downloadErrorLogTracker.StopSession();
|
||||
}
|
||||
|
||||
AppendLog($"Download failed: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (downloadErrorLogTracker.IsSessionActive)
|
||||
{
|
||||
downloadErrorLogTracker.StopSession();
|
||||
}
|
||||
|
||||
IsDownloading = false;
|
||||
_workCancellationSource?.Dispose();
|
||||
_workCancellationSource = null;
|
||||
@ -1228,6 +1251,7 @@ public partial class MainWindowViewModel(
|
||||
return;
|
||||
}
|
||||
|
||||
downloadErrorLogTracker.StartSession();
|
||||
IsDownloading = true;
|
||||
_workCancellationSource?.Dispose();
|
||||
_workCancellationSource = new CancellationTokenSource();
|
||||
@ -1306,18 +1330,39 @@ public partial class MainWindowViewModel(
|
||||
}
|
||||
|
||||
ThrowIfStopRequested();
|
||||
if (downloadErrorLogTracker.StopSession())
|
||||
{
|
||||
AppendLog(
|
||||
"Errors were encountered during the download. Check the logs saved to the logs folder for details.");
|
||||
}
|
||||
|
||||
eventHandler.OnScrapeComplete(DateTime.Now - start);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (downloadErrorLogTracker.IsSessionActive)
|
||||
{
|
||||
downloadErrorLogTracker.StopSession();
|
||||
}
|
||||
|
||||
AppendLog("Operation canceled.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (downloadErrorLogTracker.IsSessionActive)
|
||||
{
|
||||
downloadErrorLogTracker.StopSession();
|
||||
}
|
||||
|
||||
AppendLog($"Download failed: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (downloadErrorLogTracker.IsSessionActive)
|
||||
{
|
||||
downloadErrorLogTracker.StopSession();
|
||||
}
|
||||
|
||||
IsDownloading = false;
|
||||
_workCancellationSource?.Dispose();
|
||||
_workCancellationSource = null;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user