diff --git a/LogAnalyzerForWindows/LogAnalyzerForWindows.csproj b/LogAnalyzerForWindows/LogAnalyzerForWindows.csproj index 8f68546..f2f478d 100644 --- a/LogAnalyzerForWindows/LogAnalyzerForWindows.csproj +++ b/LogAnalyzerForWindows/LogAnalyzerForWindows.csproj @@ -25,9 +25,9 @@ LogAnalyzerForWindows - 1.4.0.0 - 1.4.0.0 - 1.4.0 + 1.4.1.0 + 1.4.1.0 + 1.4.1 Bohdan Harabadzhyu diff --git a/LogAnalyzerForWindows/Program.cs b/LogAnalyzerForWindows/Program.cs index be21a86..5681874 100644 --- a/LogAnalyzerForWindows/Program.cs +++ b/LogAnalyzerForWindows/Program.cs @@ -1,4 +1,6 @@ -using System.Runtime.Versioning; +using System.Diagnostics; +using System.Runtime.Versioning; +using System.Security.Principal; using Avalonia; using Avalonia.ReactiveUI; using LogAnalyzerForWindows.Services; @@ -10,13 +12,21 @@ namespace LogAnalyzerForWindows; internal sealed class Program { public static SingleInstanceService? SingleInstance { get; private set; } + private static bool IsElevated { get; set; } - // Initialization code. Don't use any Avalonia, third-party APIs or any - // SynchronizationContext-reliant code before AppMain is called: things aren't initialized - // yet and stuff might break. [STAThread] public static void Main(string[] args) { + IsElevated = IsRunningAsAdmin(); + + if (!IsElevated && !args.Contains("--no-elevate")) + { + if (TryRestartAsAdmin()) + { + return; + } + } + SingleInstance = new SingleInstanceService(); if (!SingleInstance.TryStart()) @@ -35,7 +45,51 @@ public static void Main(string[] args) } } - // Avalonia configuration, don't remove; also used by visual designer. + private static bool IsRunningAsAdmin() + { + try + { + using var identity = WindowsIdentity.GetCurrent(); + var principal = new WindowsPrincipal(identity); + return principal.IsInRole(WindowsBuiltInRole.Administrator); + } + catch + { + return false; + } + } + + private static bool TryRestartAsAdmin() + { + try + { + var exePath = Environment.ProcessPath; + if (string.IsNullOrEmpty(exePath)) + { + return false; + } + + var startInfo = new ProcessStartInfo + { + FileName = exePath, + UseShellExecute = true, + Verb = "runas", + Arguments = string.Join(" ", Environment.GetCommandLineArgs().Skip(1)) + }; + + Process.Start(startInfo); + return true; + } + catch (System.ComponentModel.Win32Exception ex) when (ex.NativeErrorCode == 1223) + { + return false; + } + catch + { + return false; + } + } + public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() diff --git a/LogAnalyzerForWindows/ViewModels/DashboardViewModel.cs b/LogAnalyzerForWindows/ViewModels/DashboardViewModel.cs index e33ad22..417dad7 100644 --- a/LogAnalyzerForWindows/ViewModels/DashboardViewModel.cs +++ b/LogAnalyzerForWindows/ViewModels/DashboardViewModel.cs @@ -34,6 +34,9 @@ internal sealed class DashboardViewModel : INotifyPropertyChanged private Axis[] _sourcesXAxes = []; private Axis[] _sourcesYAxes = []; + private Axis[] _eventIdsXAxes = []; + private Axis[] _eventIdsYAxes = []; + public DashboardViewModel(ILogRepository repository) { _repository = repository ?? throw new ArgumentNullException(nameof(repository)); @@ -114,6 +117,18 @@ public Axis[] TimelineYAxes private set => SetProperty(ref _timelineYAxes, value); } + public Axis[] EventIdsXAxes + { + get => _eventIdsXAxes; + private set => SetProperty(ref _eventIdsXAxes, value); + } + + public Axis[] EventIdsYAxes + { + get => _eventIdsYAxes; + private set => SetProperty(ref _eventIdsYAxes, value); + } + public ISeries[] TopSourcesSeries { get => _topSourcesSeries; @@ -186,6 +201,27 @@ private void InitializeChartAxes() MinLimit = 0 } ]; + + EventIdsYAxes = + [ + new Axis + { + Labels = [], + LabelsPaint = new SolidColorPaint(SKColors.LightGray), + TextSize = 12 + } + ]; + + EventIdsXAxes = + [ + new Axis + { + Name = "Count", + NamePaint = new SolidColorPaint(SKColors.White), + LabelsPaint = new SolidColorPaint(SKColors.LightGray), + MinLimit = 0 + } + ]; } public async Task LoadSessionsAsync() @@ -363,24 +399,46 @@ private void UpdateTopEventIdsChart(List<(int EventId, int Count)> topEventIds) if (topEventIds.Count == 0) { TopEventIdsSeries = []; + EventIdsYAxes = [new Axis { Labels = [] }]; return; } - var data = topEventIds - .Select(e => new { Label = $"ID: {e.EventId}", Value = e.Count }) - .ToList(); + var labels = topEventIds.Select(e => $"ID: {e.EventId}").ToArray(); + var values = topEventIds.Select(e => e.Count).ToArray(); TopEventIdsSeries = [ new RowSeries { Name = "Event Count", - Values = data.Select(d => d.Value).ToArray(), + Values = values, Fill = new SolidColorPaint(SKColors.Coral), Stroke = null, MaxBarWidth = 25, DataLabelsPaint = new SolidColorPaint(SKColors.White), - DataLabelsPosition = LiveChartsCore.Measure.DataLabelsPosition.End + DataLabelsPosition = LiveChartsCore.Measure.DataLabelsPosition.End, + DataLabelsFormatter = point => point.Coordinate.PrimaryValue.ToString(CultureInfo.InvariantCulture) + } + ]; + + EventIdsYAxes = + [ + new Axis + { + Labels = labels, + LabelsPaint = new SolidColorPaint(SKColors.LightGray), + TextSize = 11 + } + ]; + + EventIdsXAxes = + [ + new Axis + { + Name = "Count", + NamePaint = new SolidColorPaint(SKColors.White), + LabelsPaint = new SolidColorPaint(SKColors.LightGray), + MinLimit = 0 } ]; } diff --git a/LogAnalyzerForWindows/Views/DashboardView.axaml b/LogAnalyzerForWindows/Views/DashboardView.axaml index cfa1b9e..3eb2c2f 100644 --- a/LogAnalyzerForWindows/Views/DashboardView.axaml +++ b/LogAnalyzerForWindows/Views/DashboardView.axaml @@ -187,7 +187,9 @@ Foreground="White" Margin="0,0,0,10" /> + Series="{Binding TopEventIdsSeries}" + XAxes="{Binding EventIdsXAxes}" + YAxes="{Binding EventIdsYAxes}" /> diff --git a/LogAnalyzerForWindows/app.manifest b/LogAnalyzerForWindows/app.manifest index 7f44dcc..635d398 100644 --- a/LogAnalyzerForWindows/app.manifest +++ b/LogAnalyzerForWindows/app.manifest @@ -1,44 +1,25 @@  - - - + - - - - true true -