mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Debugger - Added logs to logs tab ☜(゚ヮ゚☜)
Core - Added logs store giving access to the last 500 logs
This commit is contained in:
parent
f836c2b700
commit
cb5d2cc8fa
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ninject.Activation;
|
||||
using Serilog;
|
||||
using Serilog.Core;
|
||||
@ -17,6 +18,7 @@ namespace Artemis.Core.Ninject
|
||||
rollingInterval: RollingInterval.Day,
|
||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}")
|
||||
.WriteTo.Debug()
|
||||
.WriteTo.Sink<ArtemisSink>()
|
||||
.MinimumLevel.ControlledBy(LoggingLevelSwitch)
|
||||
.CreateLogger();
|
||||
|
||||
@ -28,4 +30,13 @@ namespace Artemis.Core.Ninject
|
||||
return Logger;
|
||||
}
|
||||
}
|
||||
|
||||
internal class ArtemisSink : ILogEventSink
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void Emit(LogEvent logEvent)
|
||||
{
|
||||
LogStore.Emit(logEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
src/Artemis.Core/Stores/LogStore.cs
Normal file
55
src/Artemis.Core/Stores/LogStore.cs
Normal file
@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A static store containing the last 500 logging events
|
||||
/// </summary>
|
||||
public static class LogStore
|
||||
{
|
||||
private static readonly LinkedList<LogEvent> LinkedList = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list containing the last 500 log events.
|
||||
/// </summary>
|
||||
public static List<LogEvent> Events => LinkedList.ToList();
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a new <see cref="LogEvent" /> was received.
|
||||
/// </summary>
|
||||
public static event EventHandler<LogEventEventArgs>? EventAdded;
|
||||
|
||||
internal static void Emit(LogEvent logEvent)
|
||||
{
|
||||
LinkedList.AddLast(logEvent);
|
||||
if (LinkedList.Count > 500)
|
||||
LinkedList.RemoveFirst();
|
||||
|
||||
OnEventAdded(new LogEventEventArgs(logEvent));
|
||||
}
|
||||
|
||||
private static void OnEventAdded(LogEventEventArgs e)
|
||||
{
|
||||
EventAdded?.Invoke(null, e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains log event related data
|
||||
/// </summary>
|
||||
public class LogEventEventArgs : EventArgs
|
||||
{
|
||||
internal LogEventEventArgs(LogEvent logEvent)
|
||||
{
|
||||
LogEvent = logEvent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the log event
|
||||
/// </summary>
|
||||
public LogEvent LogEvent { get; }
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
"profiles": {
|
||||
"Artemis.UI": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "--force-elevation --logging=debug"
|
||||
"commandLineArgs": "--force-elevation"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15,70 +15,74 @@
|
||||
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
|
||||
UseLayoutRounding="True"
|
||||
FadeContentIfInactive="False"
|
||||
Width="800"
|
||||
Width="1200"
|
||||
Height="800"
|
||||
d:DesignHeight="800" d:DesignWidth="800" d:DataContext="{d:DesignInstance debug:DebugViewModel}"
|
||||
Icon="/Resources/Images/Logo/logo-512.png"
|
||||
Topmost="{Binding StayOnTopSetting.Value}">
|
||||
<DockPanel>
|
||||
<mde:AppBar Type="Dense"
|
||||
Title="Debugger"
|
||||
DockPanel.Dock="Top"
|
||||
Margin="-18 0 0 0">
|
||||
<mde:AppBar.AppIcon>
|
||||
<materialDesign:PackIcon Kind="Matrix" Width="20" Height="28" />
|
||||
</mde:AppBar.AppIcon>
|
||||
<materialDesign:DialogHost IsTabStop="False"
|
||||
Focusable="False"
|
||||
Identifier="DebuggerDialog"
|
||||
DialogTheme="Inherit">
|
||||
<DockPanel>
|
||||
<mde:AppBar Type="Dense"
|
||||
Title="Debugger"
|
||||
DockPanel.Dock="Top"
|
||||
Margin="-18 0 0 0">
|
||||
<mde:AppBar.AppIcon>
|
||||
<materialDesign:PackIcon Kind="Matrix" Width="20" Height="28" />
|
||||
</mde:AppBar.AppIcon>
|
||||
|
||||
<materialDesign:PopupBox DockPanel.Dock="Right" PlacementMode="BottomAndAlignRightEdges" StaysOpen="False">
|
||||
<StackPanel>
|
||||
<Button Command="{s:Action ToggleStayOnTop}">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}"
|
||||
Margin="0 0 10 0"
|
||||
IsChecked="{Binding StayOnTopSetting.Value}"/>
|
||||
<TextBlock>Stay on top</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action ForceGarbageCollection}">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<materialDesign:PackIcon Kind="DeleteEmpty"/>
|
||||
<TextBlock Margin="10 0">Force garbage collection</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action Elevate}">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<materialDesign:PackIcon Kind="ShieldHalfFull" />
|
||||
<TextBlock Margin="10 0">Elevate permissions</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action Drop}">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<materialDesign:PackIcon Kind="ChevronDoubleDown" />
|
||||
<TextBlock Margin="10 0">Drop permissions</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action Restart}">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<materialDesign:PackIcon Kind="Restart" />
|
||||
<TextBlock Margin="10 0">Restart</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</materialDesign:PopupBox>
|
||||
</mde:AppBar>
|
||||
|
||||
<TabControl ItemsSource="{Binding Items}"
|
||||
SelectedItem="{Binding ActiveItem}"
|
||||
DisplayMemberPath="DisplayName"
|
||||
Style="{StaticResource MaterialDesignTabControl}">
|
||||
<TabControl.ContentTemplate>
|
||||
<DataTemplate>
|
||||
<materialDesign:TransitioningContent OpeningEffect="{materialDesign:TransitionEffect FadeIn}">
|
||||
<ContentControl s:View.Model="{Binding}" TextElement.Foreground="{DynamicResource MaterialDesignBody}" Margin="10" />
|
||||
</materialDesign:TransitioningContent>
|
||||
</DataTemplate>
|
||||
</TabControl.ContentTemplate>
|
||||
</TabControl>
|
||||
</DockPanel>
|
||||
<materialDesign:PopupBox DockPanel.Dock="Right" PlacementMode="BottomAndAlignRightEdges" StaysOpen="False">
|
||||
<StackPanel>
|
||||
<Button Command="{s:Action ToggleStayOnTop}">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}"
|
||||
Margin="0 0 10 0"
|
||||
IsChecked="{Binding StayOnTopSetting.Value}" />
|
||||
<TextBlock>Stay on top</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action ForceGarbageCollection}">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<materialDesign:PackIcon Kind="DeleteEmpty" />
|
||||
<TextBlock Margin="10 0">Force garbage collection</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action Elevate}">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<materialDesign:PackIcon Kind="ShieldHalfFull" />
|
||||
<TextBlock Margin="10 0">Elevate permissions</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action Drop}">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<materialDesign:PackIcon Kind="ChevronDoubleDown" />
|
||||
<TextBlock Margin="10 0">Drop permissions</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action Restart}">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<materialDesign:PackIcon Kind="Restart" />
|
||||
<TextBlock Margin="10 0">Restart</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</materialDesign:PopupBox>
|
||||
</mde:AppBar>
|
||||
|
||||
<TabControl ItemsSource="{Binding Items}"
|
||||
SelectedItem="{Binding ActiveItem}"
|
||||
DisplayMemberPath="DisplayName"
|
||||
Style="{StaticResource MaterialDesignTabControl}">
|
||||
<TabControl.ContentTemplate>
|
||||
<DataTemplate>
|
||||
<materialDesign:TransitioningContent OpeningEffect="{materialDesign:TransitionEffect FadeIn}">
|
||||
<ContentControl s:View.Model="{Binding}" TextElement.Foreground="{DynamicResource MaterialDesignBody}" Margin="10" />
|
||||
</materialDesign:TransitioningContent>
|
||||
</DataTemplate>
|
||||
</TabControl.ContentTemplate>
|
||||
</TabControl>
|
||||
</DockPanel>
|
||||
</materialDesign:DialogHost>
|
||||
</mde:MaterialWindow>
|
||||
@ -24,11 +24,11 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
|
||||
|
||||
public DataModelDebugViewModel(IDataModelUIService dataModelUIService, IPluginManagementService pluginManagementService)
|
||||
{
|
||||
DisplayName = "DATA MODEL";
|
||||
_dataModelUIService = dataModelUIService;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
_updateTimer = new Timer(25);
|
||||
|
||||
DisplayName = "Data model";
|
||||
Modules = new BindableCollection<Module>();
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,44 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Settings.Debug.Tabs"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance local:LogsDebugViewModel}">
|
||||
<Grid />
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<materialDesign:Card Grid.Row="0" Grid.ColumnSpan="2" Margin="0 0 0 5" Background="#FF424242">
|
||||
<FlowDocumentScrollViewer Document="{Binding LogsDocument}" FontFamily="Consolas" HorizontalScrollBarVisibility="Auto">
|
||||
<FlowDocumentScrollViewer.Resources>
|
||||
<Style TargetType="FlowDocument">
|
||||
<Setter Property="TextElement.FontFamily" Value="Consolas" />
|
||||
<Setter Property="TextElement.FontSize" Value="12" />
|
||||
<Setter Property="PageWidth" Value="2024" />
|
||||
</Style>
|
||||
<Style TargetType="Paragraph">
|
||||
<Setter Property="Margin" Value="0 1" />
|
||||
</Style>
|
||||
</FlowDocumentScrollViewer.Resources>
|
||||
</FlowDocumentScrollViewer>
|
||||
</materialDesign:Card>
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" TextWrapping="Wrap" Margin="0 0 5 0" VerticalAlignment="Center">
|
||||
<materialDesign:PackIcon Kind="Text" Margin="0 0 0 -3"></materialDesign:PackIcon>
|
||||
When reporting errors please don't take a screenshot of the logs, instead upload the full log or select & copy a part of it, thanks!
|
||||
</TextBlock>
|
||||
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 5">
|
||||
<Button Style="{StaticResource MaterialDesignRaisedButton}" Command="{s:Action UploadLogs}" Width="150" Margin="0 0 5 0">
|
||||
UPLOAD LOGS
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignOutlinedButton}" Command="{s:Action ShowLogsFolder}" Width="150" Margin="5 0 0 0">
|
||||
SHOW LOGS
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -1,12 +1,127 @@
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Serilog.Events;
|
||||
using Serilog.Formatting.Display;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Settings.Debug.Tabs
|
||||
{
|
||||
public class LogsDebugViewModel : Screen
|
||||
{
|
||||
public LogsDebugViewModel()
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly MessageTemplateTextFormatter _formatter;
|
||||
private ScrollViewer _scrollViewer;
|
||||
|
||||
public LogsDebugViewModel(IDialogService dialogService)
|
||||
{
|
||||
DisplayName = "Logs";
|
||||
DisplayName = "LOGS";
|
||||
_dialogService = dialogService;
|
||||
_formatter = new MessageTemplateTextFormatter(
|
||||
"{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}"
|
||||
);
|
||||
}
|
||||
|
||||
public FlowDocument LogsDocument { get; } = new();
|
||||
|
||||
public void ShowLogsFolder()
|
||||
{
|
||||
Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Path.Combine(Constants.DataFolder, "Logs"));
|
||||
}
|
||||
|
||||
public async Task UploadLogs()
|
||||
{
|
||||
bool confirmed = await _dialogService.ShowConfirmDialogAt(
|
||||
"DebuggerDialog",
|
||||
"Upload logs",
|
||||
"Automatically uploading logs is not yet implemented.\r\n\r\n" +
|
||||
"To manually upload a log simply drag the log file from the logs folder\r\n" +
|
||||
"into Discord or the GitHub issue textbox, depending on what you're using.",
|
||||
"OPEN LOGS FOLDER",
|
||||
"CANCEL");
|
||||
|
||||
if (confirmed)
|
||||
ShowLogsFolder();
|
||||
}
|
||||
|
||||
private Paragraph CreateLogEventParagraph(LogEvent logEvent)
|
||||
{
|
||||
Paragraph paragraph = new(new Run(RenderLogEvent(logEvent)))
|
||||
{
|
||||
// But mah MVVM
|
||||
Foreground = logEvent.Level switch
|
||||
{
|
||||
LogEventLevel.Verbose => new SolidColorBrush(Colors.White),
|
||||
LogEventLevel.Debug => new SolidColorBrush(Color.FromRgb(216, 216, 216)),
|
||||
LogEventLevel.Information => new SolidColorBrush(Color.FromRgb(93, 201, 255)),
|
||||
LogEventLevel.Warning => new SolidColorBrush(Color.FromRgb(255, 177, 53)),
|
||||
LogEventLevel.Error => new SolidColorBrush(Color.FromRgb(255, 63, 63)),
|
||||
LogEventLevel.Fatal => new SolidColorBrush(Colors.Red),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
}
|
||||
};
|
||||
|
||||
return paragraph;
|
||||
}
|
||||
|
||||
private string RenderLogEvent(LogEvent logEvent)
|
||||
{
|
||||
using StringWriter writer = new();
|
||||
_formatter.Format(logEvent, writer);
|
||||
return writer.ToString().Trim();
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnActivate()
|
||||
{
|
||||
LogsDocument.Blocks.AddRange(LogStore.Events.Select(e => CreateLogEventParagraph(e)));
|
||||
LogStore.EventAdded += LogStoreOnEventAdded;
|
||||
|
||||
base.OnActivate();
|
||||
}
|
||||
|
||||
private void LogStoreOnEventAdded(object sender, LogEventEventArgs e)
|
||||
{
|
||||
Execute.PostToUIThread(() =>
|
||||
{
|
||||
LogsDocument.Blocks.Add(CreateLogEventParagraph(e.LogEvent));
|
||||
while (LogsDocument.Blocks.Count > 500)
|
||||
LogsDocument.Blocks.Remove(LogsDocument.Blocks.FirstBlock);
|
||||
|
||||
if (_scrollViewer != null && Math.Abs(_scrollViewer.VerticalOffset - _scrollViewer.ScrollableHeight) < 10)
|
||||
_scrollViewer.ScrollToBottom();
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnDeactivate()
|
||||
{
|
||||
LogStore.EventAdded -= LogStoreOnEventAdded;
|
||||
LogsDocument.Blocks.Clear();
|
||||
|
||||
base.OnDeactivate();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
ScrollViewer scrollViewer = VisualTreeUtilities.FindChild<ScrollViewer>(View, null);
|
||||
_scrollViewer = scrollViewer;
|
||||
_scrollViewer?.ScrollToBottom();
|
||||
|
||||
base.OnViewLoaded();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -10,10 +10,10 @@
|
||||
d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance local:RenderDebugViewModel}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" TextWrapping="Wrap">
|
||||
In this window you can view the inner workings of Artemis.
|
||||
@ -30,19 +30,20 @@
|
||||
This image shows what is being rendered and dispatched to RGB.NET
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Column="1" HorizontalAlignment="Right" Margin="0,0,5,0">
|
||||
<Run Text="FPS: "></Run>
|
||||
<Run FontWeight="Bold" Text="{Binding CurrentFps}"></Run>
|
||||
<Run Text=" at "></Run>
|
||||
<Run Text="{Binding RenderWidth}"/><Run Text="x"></Run><Run Text="{Binding RenderHeight}"/>
|
||||
<Run Text="FPS: " />
|
||||
<Run FontWeight="Bold" Text="{Binding CurrentFps}" />
|
||||
<Run Text=" at " />
|
||||
<Run Text="{Binding RenderWidth}" /><Run Text="x" />
|
||||
<Run Text="{Binding RenderHeight}" />
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<materialDesign:Card Grid.Row="2" Margin="0,5,0,0" Background="{StaticResource Checkerboard}">
|
||||
<Image Source="{Binding CurrentFrame}" />
|
||||
<materialDesign:Card Grid.Row="2" Margin="0 5" Background="{StaticResource Checkerboard}">
|
||||
<Image Source="{Binding CurrentFrame}" />
|
||||
</materialDesign:Card>
|
||||
|
||||
<StackPanel Grid.Row="3" Margin="0 5 0 0">
|
||||
<Button HorizontalAlignment="Left" Command="{s:Action SaveFrame}">SAVE FRAME</Button>
|
||||
<StackPanel Grid.Row="3" HorizontalAlignment="Right" Margin="0 5">
|
||||
<Button Style="{StaticResource MaterialDesignOutlinedButton}" Command="{s:Action SaveFrame}">SAVE FRAME</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -23,8 +23,8 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
|
||||
|
||||
public RenderDebugViewModel(ICoreService coreService)
|
||||
{
|
||||
DisplayName = "RENDERING";
|
||||
_coreService = coreService;
|
||||
DisplayName = "Rendering";
|
||||
}
|
||||
|
||||
public ImageSource CurrentFrame
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user