mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Update logging
This commit is contained in:
parent
92a2195ccf
commit
e7b7350e76
@ -3,11 +3,13 @@ using System.Windows;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.App.Blazor.Models;
|
||||
using NLog;
|
||||
using NLog.Extensions.Logging;
|
||||
using NLog.Targets;
|
||||
using Wabbajack.App.Blazor.State;
|
||||
using Wabbajack.App.Blazor.Utility;
|
||||
using Wabbajack.DTOs;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
||||
|
||||
namespace Wabbajack.App.Blazor;
|
||||
|
||||
@ -18,23 +20,41 @@ public partial class App
|
||||
public App()
|
||||
{
|
||||
_serviceProvider = Host.CreateDefaultBuilder(Array.Empty<string>())
|
||||
.ConfigureLogging(loggingBuilder =>
|
||||
{
|
||||
loggingBuilder.ClearProviders();
|
||||
})
|
||||
.ConfigureLogging(SetupLogging)
|
||||
.ConfigureServices(services => ConfigureServices(services))
|
||||
.Build()
|
||||
.Services;
|
||||
}
|
||||
|
||||
private static void SetupLogging(ILoggingBuilder loggingBuilder)
|
||||
{
|
||||
var config = new NLog.Config.LoggingConfiguration();
|
||||
|
||||
var fileTarget = new FileTarget("file")
|
||||
{
|
||||
FileName = "log.log"
|
||||
};
|
||||
|
||||
var consoleTarget = new ConsoleTarget("console");
|
||||
|
||||
var uiTarget = new MemoryTarget("ui");
|
||||
|
||||
config.AddRuleForAllLevels(fileTarget);
|
||||
config.AddRuleForAllLevels(consoleTarget);
|
||||
config.AddRuleForAllLevels(uiTarget);
|
||||
|
||||
loggingBuilder.ClearProviders();
|
||||
loggingBuilder.SetMinimumLevel(LogLevel.Trace);
|
||||
loggingBuilder.AddNLog(config);
|
||||
}
|
||||
|
||||
private static IServiceCollection ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddOSIntegrated();
|
||||
services.AddBlazorWebView();
|
||||
services.AddAllSingleton<ILoggerProvider, LoggerProvider>();
|
||||
services.AddTransient<MainWindow>();
|
||||
services.AddSingleton<SystemParametersConstructor>();
|
||||
services.AddSingleton(typeof(IStateContainer), typeof(StateContainer));
|
||||
services.AddSingleton<IStateContainer, StateContainer>();
|
||||
return services;
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
@using Wabbajack.App.Blazor.Models
|
||||
|
||||
@using NLog
|
||||
@using NLog.Targets
|
||||
@namespace Wabbajack.App.Blazor.Components
|
||||
|
||||
<div id="virtual-logger">
|
||||
<Virtualize Items="@_consoleLog" Context="logItem" OverscanCount="3">
|
||||
<span @key="logItem.MessageId">@logItem.LongMessage</span>
|
||||
<Virtualize Items="@Logs" Context="logItem" OverscanCount="3">
|
||||
<span @key="logItem">@logItem</span>
|
||||
</Virtualize>
|
||||
</div>
|
||||
|
||||
@ -13,16 +13,11 @@
|
||||
// TODO: [Low] More parameters to customise the logger. E.g. Reverse order.
|
||||
// TODO: [High] Find a way to auto-scroll. (JS interop?)
|
||||
|
||||
[Parameter]
|
||||
public IObservable<LoggerProvider.ILogMessage> Messages { get; set; }
|
||||
private MemoryTarget? _memoryTarget;
|
||||
private ICollection<string> Logs => _memoryTarget?.Logs ?? Array.Empty<string>();
|
||||
|
||||
private List<LoggerProvider.ILogMessage> _consoleLog = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
Messages.Subscribe(_consoleLog.Add);
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_memoryTarget = LogManager.Configuration.FindTargetByName<MemoryTarget>("ui");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,31 +1,13 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.App.Blazor.Models;
|
||||
using Wabbajack.App.Blazor.State;
|
||||
using Wabbajack.App.Blazor.Utility;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Installer;
|
||||
using Wabbajack.Paths.IO;
|
||||
|
||||
namespace Wabbajack.App.Blazor;
|
||||
|
||||
public partial class MainWindow
|
||||
{
|
||||
private readonly ILogger<MainWindow> _logger;
|
||||
private readonly LoggerProvider _loggerProvider;
|
||||
private readonly SystemParametersConstructor _systemParams;
|
||||
private readonly IStateContainer _stateContainer;
|
||||
|
||||
public MainWindow(ILogger<MainWindow> logger, IServiceProvider serviceProvider, LoggerProvider loggerProvider,
|
||||
SystemParametersConstructor systemParams, IStateContainer stateContainer)
|
||||
public MainWindow(IServiceProvider serviceProvider, IStateContainer stateContainer)
|
||||
{
|
||||
_logger = logger;
|
||||
_loggerProvider = loggerProvider;
|
||||
_systemParams = systemParams;
|
||||
_stateContainer = stateContainer;
|
||||
|
||||
_stateContainer.TaskBarStateObservable.Subscribe(state =>
|
||||
stateContainer.TaskBarStateObservable.Subscribe(state =>
|
||||
{
|
||||
Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
|
@ -1,3 +0,0 @@
|
||||
namespace Wabbajack.App.Blazor.Models;
|
||||
|
||||
public class Install { }
|
@ -1,149 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using DynamicData;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.Paths;
|
||||
using Wabbajack.Paths.IO;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
|
||||
namespace Wabbajack.App.Blazor.Models;
|
||||
|
||||
public class LoggerProvider : ILoggerProvider
|
||||
{
|
||||
private readonly RelativePath _appName;
|
||||
private readonly Configuration _configuration;
|
||||
private readonly CompositeDisposable _disposables;
|
||||
private readonly Stream _logFile;
|
||||
private readonly StreamWriter _logStream;
|
||||
|
||||
public readonly ReadOnlyObservableCollection<ILogMessage> _messagesFiltered;
|
||||
private readonly DateTime _startupTime;
|
||||
|
||||
private long _messageId;
|
||||
private readonly SourceCache<ILogMessage, long> _messageLog = new(m => m.MessageId);
|
||||
private readonly Subject<ILogMessage> _messages = new();
|
||||
|
||||
public LoggerProvider(Configuration configuration)
|
||||
{
|
||||
_startupTime = DateTime.UtcNow;
|
||||
_configuration = configuration;
|
||||
_configuration.LogLocation.CreateDirectory();
|
||||
|
||||
_disposables = new CompositeDisposable();
|
||||
|
||||
// Messages
|
||||
// .ObserveOnGuiThread()
|
||||
// .Subscribe(m => _messageLog.AddOrUpdate(m));
|
||||
|
||||
Messages.Subscribe(LogToFile);
|
||||
|
||||
_messageLog.Connect()
|
||||
.Bind(out _messagesFiltered)
|
||||
.Subscribe();
|
||||
|
||||
_appName = typeof(LoggerProvider).Assembly.Location.ToAbsolutePath().FileName;
|
||||
LogPath = _configuration.LogLocation.Combine($"{_appName}.current.log");
|
||||
_logFile = LogPath.Open(FileMode.Append, FileAccess.Write);
|
||||
|
||||
_logStream = new StreamWriter(_logFile, Encoding.UTF8);
|
||||
}
|
||||
|
||||
public IObservable<ILogMessage> Messages => _messages;
|
||||
public AbsolutePath LogPath { get; }
|
||||
public ReadOnlyObservableCollection<ILogMessage> MessageLog => _messagesFiltered;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_disposables.Dispose();
|
||||
}
|
||||
|
||||
public ILogger CreateLogger(string categoryName)
|
||||
{
|
||||
return new Logger(this, categoryName);
|
||||
}
|
||||
|
||||
private void LogToFile(ILogMessage logMessage)
|
||||
{
|
||||
var line = $"[{logMessage.TimeStamp - _startupTime}] {logMessage.LongMessage}";
|
||||
lock (_logStream)
|
||||
{
|
||||
_logStream.Write(line);
|
||||
_logStream.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
private long NextMessageId()
|
||||
{
|
||||
return Interlocked.Increment(ref _messageId);
|
||||
}
|
||||
|
||||
public class Logger : ILogger
|
||||
{
|
||||
private readonly string _categoryName;
|
||||
private readonly LoggerProvider _provider;
|
||||
private ImmutableList<object> Scopes = ImmutableList<object>.Empty;
|
||||
|
||||
public Logger(LoggerProvider provider, string categoryName)
|
||||
{
|
||||
_categoryName = categoryName;
|
||||
_provider = provider;
|
||||
}
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
|
||||
Func<TState, Exception?, string> formatter)
|
||||
{
|
||||
Debug.WriteLine($"{logLevel} - {formatter(state, exception)}");
|
||||
_provider._messages.OnNext(new LogMessage<TState>(DateTime.UtcNow, _provider.NextMessageId(), logLevel,
|
||||
eventId, state, exception, formatter));
|
||||
}
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public IDisposable BeginScope<TState>(TState state)
|
||||
{
|
||||
Scopes = Scopes.Add(state);
|
||||
return Disposable.Create(() => Scopes = Scopes.Remove(state));
|
||||
}
|
||||
}
|
||||
|
||||
public interface ILogMessage
|
||||
{
|
||||
long MessageId { get; }
|
||||
|
||||
string ShortMessage { get; }
|
||||
DateTime TimeStamp { get; }
|
||||
string LongMessage { get; }
|
||||
}
|
||||
|
||||
private record LogMessage<TState>(DateTime TimeStamp, long MessageId, LogLevel LogLevel, EventId EventId,
|
||||
TState State, Exception? Exception, Func<TState, Exception?, string> Formatter) : ILogMessage
|
||||
{
|
||||
public string ShortMessage => Formatter(State, Exception);
|
||||
|
||||
public string LongMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(ShortMessage);
|
||||
if (Exception != null)
|
||||
{
|
||||
sb.Append("Exception: ");
|
||||
sb.Append(Exception);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -41,7 +41,7 @@
|
||||
@if (InstallState == InstallState.Installing)
|
||||
{
|
||||
<div class="logger-container">
|
||||
<VirtualLogger Messages="LoggerProvider.Messages"/>
|
||||
<VirtualLogger/>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
|
@ -12,7 +12,6 @@ using Wabbajack.Services.OSIntegrated;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.JSInterop;
|
||||
using Wabbajack.App.Blazor.Models;
|
||||
using Wabbajack.App.Blazor.State;
|
||||
|
||||
namespace Wabbajack.App.Blazor.Pages;
|
||||
@ -26,7 +25,6 @@ public partial class Configure
|
||||
[Inject] private SystemParametersConstructor ParametersConstructor { get; set; } = default!;
|
||||
[Inject] private IGameLocator GameLocator { get; set; } = default!;
|
||||
[Inject] private SettingsManager SettingsManager { get; set; } = default!;
|
||||
[Inject] private LoggerProvider LoggerProvider { get; set; } = default!;
|
||||
[Inject] private JSRuntime JSRuntime { get; set; } = default!;
|
||||
|
||||
private ModList? Modlist => StateContainer.Modlist;
|
||||
|
@ -20,6 +20,8 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Wpf" Version="6.0.101-preview.11.2349" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.1" />
|
||||
<PackageReference Include="NLog" Version="4.7.13" />
|
||||
<PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" />
|
||||
<PackageReference Include="PInvoke.User32" Version="0.7.104" />
|
||||
<PackageReference Include="Silk.NET.DXGI" Version="2.12.0" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user