Skip to content

Commit

Permalink
Installed unhandled exception handler (#3830)
Browse files Browse the repository at this point in the history
  • Loading branch information
timkur authored Sep 11, 2024
1 parent 7ddd036 commit c40f8f3
Showing 1 changed file with 130 additions and 118 deletions.
248 changes: 130 additions & 118 deletions tools/DevDiagnostics/DevHome.DevDiagnostics/DDApp.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,118 +1,130 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using DevHome.Common.Extensions;
using DevHome.Common.Services;
using DevHome.DevDiagnostics.Helpers;
using DevHome.DevDiagnostics.Models;
using DevHome.DevDiagnostics.Pages;
using DevHome.DevDiagnostics.Services;
using DevHome.DevDiagnostics.Telemetry;
using DevHome.DevDiagnostics.TelemetryEvents;
using DevHome.DevDiagnostics.ViewModels;
using DevHome.Service;
using DevHome.Telemetry;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.UI.Xaml;
using Windows.Storage;

namespace DevHome.DevDiagnostics;

public partial class App : Application, IApp
{
// The .NET Generic Host provides dependency injection, configuration, logging, and other services.
// https://docs.microsoft.com/dotnet/core/extensions/generic-host
// https://docs.microsoft.com/dotnet/core/extensions/dependency-injection
// https://docs.microsoft.com/dotnet/core/extensions/configuration
// https://docs.microsoft.com/dotnet/core/extensions/logging
public IHost Host { get; }

public T GetService<T>()
where T : class => Host.GetService<T>();

public Microsoft.UI.Dispatching.DispatcherQueue? UIDispatcher { get; }

public App()
{
InitializeComponent();

UIDispatcher = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();

Host = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
// Services
services.AddSingleton<IPageService, DDPageService>();
services.AddSingleton<INavigationService, DDNavigationService>();
services.AddSingleton<TelemetryReporter>();
services.AddSingleton<DDAppInfoService>();
services.AddSingleton<DDInsightsService>();
services.AddSingleton<WERHelper>();
services.AddSingleton<WERAnalyzer>();
services.AddSingleton<ExternalToolsHelper>();
services.AddSingleton<InternalToolsHelper>();
services.AddSingleton<IDevHomeService>(CommonHelper.GetDevHomeService());
services.AddSingleton<LoaderSnapAssistantTool>();
// Window
services.AddSingleton<PrimaryWindow>();
// Views and ViewModels
services.AddSingleton<AppDetailsPage>();
services.AddSingleton<AppDetailsPageViewModel>();
services.AddSingleton<InsightsPage>();
services.AddSingleton<InsightsPageViewModel>();
services.AddSingleton<ModulesPage>();
services.AddSingleton<ModulesPageViewModel>();
services.AddSingleton<ProcessListPage>();
services.AddSingleton<ProcessListPageViewModel>();
services.AddSingleton<ResourceUsagePage>();
services.AddSingleton<ResourceUsagePageViewModel>();
services.AddSingleton<WERPage>();
services.AddSingleton<WERPageViewModel>();
services.AddSingleton<WinLogsPage>();
services.AddSingleton<WinLogsPageViewModel>();
services.AddSingleton<SettingsPage>();
services.AddSingleton<SettingsPageViewModel>();
// Settings sub-pages and viewmodels.
services.AddTransient<PreferencesViewModel>();
services.AddTransient<PreferencesPage>();
services.AddTransient<AdditionalToolsViewModel>();
services.AddTransient<AdditionalToolsPage>();
services.AddTransient<AdvancedSettingsViewModel>();
services.AddTransient<AdvancedSettingsPage>();
services.AddTransient<AboutViewModel>();
services.AddTransient<AboutPage>();
}).Build();

// Provide an explicit implementationInstance otherwise AddSingleton does not create a new instance immediately.
// It will lazily init when the first component requires it but the hotkey helper needs to be registered immediately.
Application.Current.GetService<PrimaryWindow>();

// And start up the listener for process load failures immediately
Application.Current.GetService<LoaderSnapAssistantTool>();
}

internal static ITelemetry Logger => TelemetryFactory.Get<ITelemetry>();

internal static void LogTimeTaken(string eventName, uint timeTakenMilliseconds, Guid? relatedActivityId = null) => Logger.LogTimeTaken(eventName, timeTakenMilliseconds, relatedActivityId);

internal static void LogCritical(string eventName, bool isError = false, Guid? relatedActivityId = null) => Logger.LogCritical(eventName, isError, relatedActivityId);

internal static void Log<T>(string eventName, LogLevel level, T data, Guid? relatedActivityId = null)
where T : EventBase
{
Logger.Log<T>(eventName, level, data, relatedActivityId ?? null);
}

internal static void LogError<T>(string eventName, LogLevel level, T data, Guid? relatedActivityId = null)
where T : EventBase
{
Logger.LogError<T>(eventName, level, data, relatedActivityId);
}

internal static void Log(string eventName, LogLevel level, Guid? relatedActivityId = null) => Logger.Log(eventName, level, new UsageEventData(), relatedActivityId);
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using DevHome.Common.Extensions;
using DevHome.Common.Services;
using DevHome.DevDiagnostics.Helpers;
using DevHome.DevDiagnostics.Models;
using DevHome.DevDiagnostics.Pages;
using DevHome.DevDiagnostics.Services;
using DevHome.DevDiagnostics.Telemetry;
using DevHome.DevDiagnostics.TelemetryEvents;
using DevHome.DevDiagnostics.ViewModels;
using DevHome.Service;
using DevHome.Telemetry;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.UI.Xaml;
using Windows.Storage;

namespace DevHome.DevDiagnostics;

public partial class App : Application, IApp
{
// The .NET Generic Host provides dependency injection, configuration, logging, and other services.
// https://docs.microsoft.com/dotnet/core/extensions/generic-host
// https://docs.microsoft.com/dotnet/core/extensions/dependency-injection
// https://docs.microsoft.com/dotnet/core/extensions/configuration
// https://docs.microsoft.com/dotnet/core/extensions/logging
public IHost Host { get; }

public T GetService<T>()
where T : class => Host.GetService<T>();

public Microsoft.UI.Dispatching.DispatcherQueue? UIDispatcher { get; }

public App()
{
UnhandledException += App_UnhandledException;

InitializeComponent();

UIDispatcher = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();

Host = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
// Services
services.AddSingleton<IPageService, DDPageService>();
services.AddSingleton<INavigationService, DDNavigationService>();
services.AddSingleton<TelemetryReporter>();
services.AddSingleton<DDAppInfoService>();
services.AddSingleton<DDInsightsService>();
services.AddSingleton<WERHelper>();
services.AddSingleton<WERAnalyzer>();
services.AddSingleton<ExternalToolsHelper>();
services.AddSingleton<InternalToolsHelper>();
services.AddSingleton<IDevHomeService>(CommonHelper.GetDevHomeService());
services.AddSingleton<LoaderSnapAssistantTool>();
// Window
services.AddSingleton<PrimaryWindow>();
// Views and ViewModels
services.AddSingleton<AppDetailsPage>();
services.AddSingleton<AppDetailsPageViewModel>();
services.AddSingleton<InsightsPage>();
services.AddSingleton<InsightsPageViewModel>();
services.AddSingleton<ModulesPage>();
services.AddSingleton<ModulesPageViewModel>();
services.AddSingleton<ProcessListPage>();
services.AddSingleton<ProcessListPageViewModel>();
services.AddSingleton<ResourceUsagePage>();
services.AddSingleton<ResourceUsagePageViewModel>();
services.AddSingleton<WERPage>();
services.AddSingleton<WERPageViewModel>();
services.AddSingleton<WinLogsPage>();
services.AddSingleton<WinLogsPageViewModel>();
services.AddSingleton<SettingsPage>();
services.AddSingleton<SettingsPageViewModel>();
// Settings sub-pages and viewmodels.
services.AddTransient<PreferencesViewModel>();
services.AddTransient<PreferencesPage>();
services.AddTransient<AdditionalToolsViewModel>();
services.AddTransient<AdditionalToolsPage>();
services.AddTransient<AdvancedSettingsViewModel>();
services.AddTransient<AdvancedSettingsPage>();
services.AddTransient<AboutViewModel>();
services.AddTransient<AboutPage>();
}).Build();

// Provide an explicit implementationInstance otherwise AddSingleton does not create a new instance immediately.
// It will lazily init when the first component requires it but the hotkey helper needs to be registered immediately.
Application.Current.GetService<PrimaryWindow>();

// And start up the listener for process load failures immediately
Application.Current.GetService<LoaderSnapAssistantTool>();
}

private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
{
// https://docs.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.application.unhandledexception.
Serilog.Log.Fatal(e.Exception, $"Unhandled exception: {e.Message}");
Serilog.Log.CloseAndFlush();

// We are very likely in a bad and unrecoverable state, so ensure we crash w/ the exception info.
Environment.FailFast(e.Message, e.Exception);
}

internal static ITelemetry Logger => TelemetryFactory.Get<ITelemetry>();

internal static void LogTimeTaken(string eventName, uint timeTakenMilliseconds, Guid? relatedActivityId = null) => Logger.LogTimeTaken(eventName, timeTakenMilliseconds, relatedActivityId);

internal static void LogCritical(string eventName, bool isError = false, Guid? relatedActivityId = null) => Logger.LogCritical(eventName, isError, relatedActivityId);

internal static void Log<T>(string eventName, LogLevel level, T data, Guid? relatedActivityId = null)
where T : EventBase
{
Logger.Log<T>(eventName, level, data, relatedActivityId ?? null);
}

internal static void LogError<T>(string eventName, LogLevel level, T data, Guid? relatedActivityId = null)
where T : EventBase
{
Logger.LogError<T>(eventName, level, data, relatedActivityId);
}

internal static void Log(string eventName, LogLevel level, Guid? relatedActivityId = null) => Logger.Log(eventName, level, new UsageEventData(), relatedActivityId);
}

0 comments on commit c40f8f3

Please sign in to comment.