Refactored logging to all hook into Utils.Log

Log collection moved up to MainWindow.   Since there will be many sub-VMs moving forward, a singleton based setup was desired.  RxUI's Splat was an option, but we already had Utils.Log right there.  Also now GUI printed messages will go to the log on the disk for later inspection.
This commit is contained in:
Justin Swanson 2019-10-22 23:15:42 -05:00
parent 1eafafcbec
commit 66db4e6ddd
5 changed files with 53 additions and 34 deletions

View File

@ -1,4 +1,4 @@
using Syroot.Windows.IO;
using Syroot.Windows.IO;
using System;
using ReactiveUI;
using System.Collections.Generic;
@ -104,8 +104,6 @@ namespace Wabbajack
this.Slideshow = new SlideShow(this);
}
public ObservableCollection<string> Log { get; } = new ObservableCollection<string>();
private string _Location;
public string Location { get => _Location; set => this.RaiseAndSetIfChanged(ref _Location, value); }
@ -115,8 +113,6 @@ namespace Wabbajack
private string _DownloadLocation;
public string DownloadLocation { get => _DownloadLocation; set => this.RaiseAndSetIfChanged(ref _DownloadLocation, value); }
public string LogFile { get; }
private void ExecuteChangePath()
{
switch (this.Mode)
@ -233,17 +229,12 @@ namespace Wabbajack
return validationMessage;
}
public void LogMsg(string msg)
{
Application.Current.Dispatcher.Invoke(() => Log.Add(msg));
}
private void ConfigureForBuild()
{
var profile_folder = Path.GetDirectoryName(Location);
var mo2folder = Path.GetDirectoryName(Path.GetDirectoryName(profile_folder));
if (!File.Exists(Path.Combine(mo2folder, "ModOrganizer.exe")))
LogMsg($"Error! No ModOrganizer2.exe found in {mo2folder}");
Utils.Log($"Error! No ModOrganizer2.exe found in {mo2folder}");
var profile_name = Path.GetFileName(profile_folder);
this.ModListName = profile_name;
@ -296,9 +287,9 @@ namespace Wabbajack
catch (Exception ex)
{
while (ex.InnerException != null) ex = ex.InnerException;
LogMsg(ex.StackTrace);
LogMsg(ex.ToString());
LogMsg($"{ex.Message} - Can't continue");
Utils.Log(ex.StackTrace);
Utils.Log(ex.ToString());
Utils.Log($"{ex.Message} - Can't continue");
}
finally
{
@ -335,9 +326,9 @@ namespace Wabbajack
catch (Exception ex)
{
while (ex.InnerException != null) ex = ex.InnerException;
LogMsg(ex.StackTrace);
LogMsg(ex.ToString());
LogMsg($"{ex.Message} - Can't continue");
Utils.Log(ex.StackTrace);
Utils.Log(ex.ToString());
Utils.Log($"{ex.Message} - Can't continue");
}
finally
{

View File

@ -3,17 +3,23 @@ using DynamicData.Binding;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Wabbajack.Common;
using Wabbajack.Lib;
namespace Wabbajack
{
/// <summary>
/// Main View Model for the application.
/// Keeps track of which sub view is being shown in the window, and has some singleton wiring like WorkQueue and Logging.
/// </summary>
public class MainWindowVM : ViewModel
{
public AppState AppState { get; }
@ -28,8 +34,25 @@ namespace Wabbajack
public IObservable<CPUStatus> StatusObservable => _statusSubject;
public ObservableCollectionExtended<CPUStatus> StatusList { get; } = new ObservableCollectionExtended<CPUStatus>();
private Subject<string> _logSubj = new Subject<string>();
public ObservableCollectionExtended<string> Log { get; } = new ObservableCollectionExtended<string>();
public MainWindowVM(RunMode mode)
{
// Set up logging
_logSubj
.ToObservableChangeSet()
.Buffer(TimeSpan.FromMilliseconds(250))
.Where(l => l.Count > 0)
.FlattenBufferResult()
.Top(5000)
.ObserveOn(RxApp.MainThreadScheduler)
.Bind(this.Log)
.Subscribe()
.DisposeWith(this.CompositeDisposable);
Utils.SetLoggerFn(s => _logSubj.OnNext(s));
Utils.SetStatusFn((msg, progress) => WorkQueue.Report(msg, progress));
this.AppState = new AppState(this, mode);
// Initialize work queue
@ -56,5 +79,11 @@ namespace Wabbajack
max = 1;
QueueProgress = current * 100 / max;
}
public override void Dispose()
{
base.Dispose();
Utils.SetLoggerFn(s => { });
}
}
}

View File

@ -1,4 +1,5 @@
using ReactiveUI;
using Splat;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@ -124,9 +125,9 @@ namespace Wabbajack
return image;
}
}
catch (Exception)
catch (Exception ex)
{
this.AppState.LogMsg("Error loading splash image.");
this.Log().Warn(ex, "Error loading splash image.");
}
}
return this.WabbajackLogo;

View File

@ -73,7 +73,7 @@
Grid.Row="4"
Margin="0,0,2,0"
local:AutoScrollBehavior.ScrollOnNewItem="True"
ItemsSource="{Binding Log}" />
ItemsSource="{Binding MWVM.Log}" />
<!-- End Log -->
<!-- Location -->

View File

@ -15,7 +15,7 @@ namespace Wabbajack
/// </summary>
public partial class MainWindow : Window
{
private AppState _state;
private MainWindowVM _mwvm;
public MainWindow(RunMode mode, string source)
{
@ -23,14 +23,11 @@ namespace Wabbajack
InitializeComponent();
var mainVM = new MainWindowVM(mode);
var context = mainVM.AppState;
context.LogMsg($"Wabbajack Build - {ThisAssembly.Git.Sha}");
SetupHandlers(context);
DataContext = mainVM;
Utils.SetLoggerFn(s => context.LogMsg(s));
Utils.SetStatusFn((msg, progress) => WorkQueue.Report(msg, progress));
this._mwvm = new MainWindowVM(mode);
var context = _mwvm.AppState;
Utils.Log($"Wabbajack Build - {ThisAssembly.Git.Sha}");
SetupHandlers();
DataContext = _mwvm;
new Thread(() =>
{
@ -71,25 +68,26 @@ namespace Wabbajack
}).Start();
}
private void SetupHandlers(AppState state)
private void SetupHandlers()
{
_state = state;
AppDomain.CurrentDomain.UnhandledException += AppHandler;
}
private void AppHandler(object sender, UnhandledExceptionEventArgs e)
{
_state.LogMsg("Uncaught error:");
_state.LogMsg(((Exception)e.ExceptionObject).ExceptionToString());
Utils.Log("Uncaught error:");
Utils.Log(((Exception)e.ExceptionObject).ExceptionToString());
}
internal bool ExitWhenClosing = true;
private void Window_Closing(object sender, CancelEventArgs e)
{
_mwvm.Dispose();
if (ExitWhenClosing)
{
Application.Current.Shutdown();
}
}
}
}