From c1336428dc9546e44dc9c5588f5fe5368b8d82ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Sun, 16 Feb 2025 01:44:41 +0100 Subject: [PATCH] AppCenter to AppInsights migration. (#562) * Remove AppCenter usage and libraries. * Remove redundant pacakges and add the app insights sink. * Diagnostic id support and manipulating telemetries. * Handling of appdomain unhandled exceptions. * Remove unused package identity package from mail project. * Fixing printing. --- Directory.Packages.props | 3 +- .../Interfaces/IApplicationConfiguration.cs | 5 ++ .../Interfaces/IPreferencesService.cs | 1 + .../Translations/en_US/resources.json | 2 + Wino.Core.UWP/Services/PreferencesService.cs | 6 +++ Wino.Core.UWP/Styles/Colors.xaml | 1 + Wino.Core.UWP/Wino.Core.UWP.csproj | 1 - Wino.Core.UWP/WinoApplication.cs | 48 ++++++------------- Wino.Core.ViewModels/AboutPageViewModel.cs | 19 ++++++++ .../Wino.Core.ViewModels.csproj | 1 - Wino.Core/Wino.Core.csproj | 4 -- Wino.Core/WinoErrors.cs | 42 ---------------- .../AccountManagementViewModel.cs | 5 +- Wino.Mail.ViewModels/AppShellViewModel.cs | 8 ++-- Wino.Mail.ViewModels/MailListPageViewModel.cs | 8 +--- .../MailRenderingPageViewModel.cs | 22 ++++----- .../Wino.Mail.ViewModels.csproj | 7 ++- Wino.Mail/App.xaml.cs | 2 - Wino.Mail/Views/AboutPage.xaml | 26 ++++++++++ Wino.Mail/Wino.Mail.csproj | 8 +--- Wino.Server/App.xaml.cs | 5 +- Wino.Services/ApplicationConfiguration.cs | 2 + Wino.Services/LogInitializer.cs | 14 +++++- Wino.Services/Misc/WinoTelemetryConverter.cs | 38 +++++++++++++++ Wino.Services/ServicesContainerSetup.cs | 2 + Wino.Services/Wino.Services.csproj | 13 ++--- WinoMail.Packaging/WinoMail.Packaging.wapproj | 1 + 27 files changed, 160 insertions(+), 134 deletions(-) delete mode 100644 Wino.Core/WinoErrors.cs create mode 100644 Wino.Services/Misc/WinoTelemetryConverter.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index 3bca99a9..15bf141d 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -20,8 +20,6 @@ - - @@ -42,6 +40,7 @@ + diff --git a/Wino.Core.Domain/Interfaces/IApplicationConfiguration.cs b/Wino.Core.Domain/Interfaces/IApplicationConfiguration.cs index f2efb5d7..b87c0a56 100644 --- a/Wino.Core.Domain/Interfaces/IApplicationConfiguration.cs +++ b/Wino.Core.Domain/Interfaces/IApplicationConfiguration.cs @@ -23,5 +23,10 @@ /// Files here are short-lived and can be deleted by system. /// string ApplicationTempFolderPath { get; set; } + + /// + /// Application insights instrumentation key. + /// + string ApplicationInsightsInstrumentationKey { get; } } } diff --git a/Wino.Core.Domain/Interfaces/IPreferencesService.cs b/Wino.Core.Domain/Interfaces/IPreferencesService.cs index 9ef30635..afb0c515 100644 --- a/Wino.Core.Domain/Interfaces/IPreferencesService.cs +++ b/Wino.Core.Domain/Interfaces/IPreferencesService.cs @@ -187,6 +187,7 @@ namespace Wino.Core.Domain.Interfaces DayOfWeek WorkingDayStart { get; set; } DayOfWeek WorkingDayEnd { get; set; } double HourHeight { get; set; } + string DiagnosticId { get; set; } CalendarSettings GetCurrentCalendarSettings(); diff --git a/Wino.Core.Domain/Translations/en_US/resources.json b/Wino.Core.Domain/Translations/en_US/resources.json index 5a70fd4d..e46ac92d 100644 --- a/Wino.Core.Domain/Translations/en_US/resources.json +++ b/Wino.Core.Domain/Translations/en_US/resources.json @@ -451,6 +451,8 @@ "SettingsDeleteProtection_Title": "Permanent Delete Protection", "SettingsDiagnostics_Description": "For developers", "SettingsDiagnostics_Title": "Diagnostics", + "SettingsDiagnostics_DiagnosticId_Title": "Diagnostic Id", + "SettingsDiagnostics_DiagnosticId_Description": "Share this Id with the developers when asked to get help for the issues you experience in Wino Mail.", "SettingsDiscord_Description": "Get regular development updates, join roadmap discussions and provide feedback.", "SettingsDiscord_Title": "Discord Channel", "SettingsElementThemeSelectionDisabled": "Element theme selection is disabled when application theme is selected other than Default.", diff --git a/Wino.Core.UWP/Services/PreferencesService.cs b/Wino.Core.UWP/Services/PreferencesService.cs index 535e2f5e..fdcf13bf 100644 --- a/Wino.Core.UWP/Services/PreferencesService.cs +++ b/Wino.Core.UWP/Services/PreferencesService.cs @@ -229,6 +229,12 @@ namespace Wino.Core.UWP.Services set => SaveProperty(propertyName: nameof(ServerTerminationBehavior), value); } + public string DiagnosticId + { + get => _configurationService.Get(nameof(DiagnosticId), Guid.NewGuid().ToString()); + set => SaveProperty(propertyName: nameof(DiagnosticId), value); + } + public DayOfWeek FirstDayOfWeek { get => _configurationService.Get(nameof(FirstDayOfWeek), DayOfWeek.Monday); diff --git a/Wino.Core.UWP/Styles/Colors.xaml b/Wino.Core.UWP/Styles/Colors.xaml index 853aba49..e60ea73c 100644 --- a/Wino.Core.UWP/Styles/Colors.xaml +++ b/Wino.Core.UWP/Styles/Colors.xaml @@ -9,6 +9,7 @@ #1abc9c + #ff7675 #ff7675 #1abc9c diff --git a/Wino.Core.UWP/Wino.Core.UWP.csproj b/Wino.Core.UWP/Wino.Core.UWP.csproj index 88bd8c3e..1bb7391b 100644 --- a/Wino.Core.UWP/Wino.Core.UWP.csproj +++ b/Wino.Core.UWP/Wino.Core.UWP.csproj @@ -98,7 +98,6 @@ - diff --git a/Wino.Core.UWP/WinoApplication.cs b/Wino.Core.UWP/WinoApplication.cs index ddeb52a0..ad492e29 100644 --- a/Wino.Core.UWP/WinoApplication.cs +++ b/Wino.Core.UWP/WinoApplication.cs @@ -3,9 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using Microsoft.AppCenter; -using Microsoft.AppCenter.Analytics; -using Microsoft.AppCenter.Crashes; using Microsoft.Extensions.DependencyInjection; using Nito.AsyncEx; using Serilog; @@ -40,24 +37,16 @@ namespace Wino.Core.UWP protected IDatabaseService DatabaseService { get; } protected ITranslationService TranslationService { get; } - // Order matters. - private List initializeServices => new List() - { - DatabaseService, - TranslationService, - ThemeService, - }; - - public abstract string AppCenterKey { get; } - protected WinoApplication() { - ConfigureAppCenter(); ConfigurePrelaunch(); Services = ConfigureServices(); + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + TaskScheduler.UnobservedTaskException += OnUnobservedTaskException; UnhandledException += OnAppUnhandledException; + Resuming += OnResuming; Suspending += OnSuspending; @@ -77,6 +66,18 @@ namespace Wino.Core.UWP ConfigureLogging(); } + private void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs e) + => Log.Fatal(e.ExceptionObject as Exception, "AppDomain Unhandled Exception"); + + private void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) + => Log.Error(e.Exception, "Unobserved Task Exception"); + + private void OnAppUnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e) + { + Log.Fatal(e.Exception, "Unhandled Exception"); + e.Handled = true; + } + protected abstract void OnApplicationCloseRequested(object sender, SystemNavigationCloseRequestedPreviewEventArgs e); protected abstract IEnumerable GetActivationHandlers(); protected abstract ActivationHandler GetDefaultActivationHandler(); @@ -208,29 +209,12 @@ namespace Wino.Core.UWP catch { } } - - private void ConfigurePrelaunch() { if (ApiInformation.IsMethodPresent("Windows.ApplicationModel.Core.CoreApplication", "EnablePrelaunch")) CoreApplication.EnablePrelaunch(true); } - private void OnAppUnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e) - { - var parameters = new Dictionary() - { - { "BaseMessage", e.Exception.GetBaseException().Message }, - { "BaseStackTrace", e.Exception.GetBaseException().StackTrace }, - { "StackTrace", e.Exception.StackTrace }, - { "Message", e.Exception.Message }, - }; - - Log.Error(e.Exception, "[Wino Crash]"); - - Crashes.TrackError(e.Exception, parameters); - Analytics.TrackEvent("Wino Crashed", parameters); - } public virtual async void OnResuming(object sender, object e) @@ -255,8 +239,6 @@ namespace Wino.Core.UWP public virtual void OnSuspending(object sender, SuspendingEventArgs e) { } public abstract IServiceProvider ConfigureServices(); - public void ConfigureAppCenter() - => AppCenter.Start(AppCenterKey, typeof(Analytics), typeof(Crashes)); public void ConfigureLogging() { diff --git a/Wino.Core.ViewModels/AboutPageViewModel.cs b/Wino.Core.ViewModels/AboutPageViewModel.cs index c235089f..4eb70af3 100644 --- a/Wino.Core.ViewModels/AboutPageViewModel.cs +++ b/Wino.Core.ViewModels/AboutPageViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using CommunityToolkit.Mvvm.Input; +using Serilog; using Wino.Core.Domain; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; @@ -13,6 +14,7 @@ namespace Wino.Core.ViewModels private readonly IMailDialogService _dialogService; private readonly INativeAppService _nativeAppService; private readonly IApplicationConfiguration _appInitializerService; + private readonly IClipboardService _clipboardService; private readonly IFileService _fileService; private readonly ILogInitializer _logInitializer; @@ -29,6 +31,7 @@ namespace Wino.Core.ViewModels INativeAppService nativeAppService, IPreferencesService preferencesService, IApplicationConfiguration appInitializerService, + IClipboardService clipboardService, IFileService fileService, ILogInitializer logInitializer) { @@ -37,6 +40,7 @@ namespace Wino.Core.ViewModels _nativeAppService = nativeAppService; _logInitializer = logInitializer; _appInitializerService = appInitializerService; + _clipboardService = clipboardService; _fileService = fileService; PreferencesService = preferencesService; @@ -65,6 +69,21 @@ namespace Wino.Core.ViewModels } } + [RelayCommand] + private async Task CopyDiagnosticId() + { + try + { + await _clipboardService.CopyClipboardAsync(PreferencesService.DiagnosticId); + _dialogService.InfoBarMessage(Translator.Buttons_Copy, string.Format(Translator.ClipboardTextCopied_Message, "Id"), InfoBarMessageType.Success); + } + catch (Exception ex) + { + _dialogService.InfoBarMessage(Translator.GeneralTitle_Error, string.Format(Translator.ClipboardTextCopyFailed_Message, "Id"), InfoBarMessageType.Error); + Log.Error(ex, "Failed to copy diagnostic id to clipboard."); + } + } + [RelayCommand] private async Task ShareWinoLogAsync() { diff --git a/Wino.Core.ViewModels/Wino.Core.ViewModels.csproj b/Wino.Core.ViewModels/Wino.Core.ViewModels.csproj index 33fdcc6a..00c2b2ab 100644 --- a/Wino.Core.ViewModels/Wino.Core.ViewModels.csproj +++ b/Wino.Core.ViewModels/Wino.Core.ViewModels.csproj @@ -7,7 +7,6 @@ true - diff --git a/Wino.Core/Wino.Core.csproj b/Wino.Core/Wino.Core.csproj index cc67afcd..1b7ec732 100644 --- a/Wino.Core/Wino.Core.csproj +++ b/Wino.Core/Wino.Core.csproj @@ -26,10 +26,6 @@ - - - - diff --git a/Wino.Core/WinoErrors.cs b/Wino.Core/WinoErrors.cs deleted file mode 100644 index 1ef74d87..00000000 --- a/Wino.Core/WinoErrors.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace Wino.Core -{ - /// - /// Error codes for Wino application. - /// Pretty outdated. - /// - public static class WinoErrors - { - public const string AccountStructureRender = nameof(AccountStructureRender); - public const string MimeRendering = nameof(MimeRendering); - public const string MailRendering = nameof(MailRendering); - public const string FolderOperationExecution = nameof(FolderOperationExecution); - public const string StartupAccountExtendFail = nameof(StartupAccountExtendFail); - public const string AccountNavigateInboxFail = nameof(AccountNavigateInboxFail); - public const string AccountCreation = nameof(AccountCreation); - - public const string OutlookIntegratorFolderSync = nameof(OutlookIntegratorFolderSync); - public const string GoogleSynchronizerAccountSync = nameof(GoogleSynchronizerAccountSync); - public const string ImapFolderSync = nameof(ImapFolderSync); - - public const string RendererCommandMailOperation = nameof(RendererCommandMailOperation); - public const string MailListingMailOperation = nameof(MailListingMailOperation); - - public const string AutoMarkAsRead = nameof(AutoMarkAsRead); - public const string MailListGetItem = nameof(MailListGetItem); - public const string MailListCollectionUpdate = nameof(MailListCollectionUpdate); - public const string MailListRefreshFolder = nameof(MailListRefreshFolder); - public const string ProcessorTaskFailed = nameof(ProcessorTaskFailed); - public const string SearchFailed = nameof(SearchFailed); - - public const string BatchExecutionFailed = nameof(BatchExecutionFailed); - public const string SingleBatchExecutionFailedGoogle = nameof(SingleBatchExecutionFailedGoogle); - - public const string SynchronizationWorkerException = nameof(SynchronizationWorkerException); - public const string StoreRatingSubmission = nameof(StoreRatingSubmission); - - public const string OpenAttachment = nameof(OpenAttachment); - public const string SaveAttachment = nameof(SaveAttachment); - - public const string OutlookMimeSaveFailure = nameof(OutlookMimeSaveFailure); - } -} diff --git a/Wino.Mail.ViewModels/AccountManagementViewModel.cs b/Wino.Mail.ViewModels/AccountManagementViewModel.cs index 4495cd37..0f0f69b4 100644 --- a/Wino.Mail.ViewModels/AccountManagementViewModel.cs +++ b/Wino.Mail.ViewModels/AccountManagementViewModel.cs @@ -5,9 +5,7 @@ using System.Threading; using System.Threading.Tasks; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; -using Microsoft.AppCenter.Crashes; using Serilog; -using Wino.Core; using Wino.Core.Domain; using Wino.Core.Domain.Entities.Mail; using Wino.Core.Domain.Entities.Shared; @@ -274,8 +272,7 @@ namespace Wino.Mail.ViewModels } catch (Exception ex) { - Log.Error(ex, WinoErrors.AccountCreation); - Crashes.TrackError(ex); + Log.Error(ex, "Failed to create account."); DialogService.InfoBarMessage(Translator.Info_AccountCreationFailedTitle, ex.Message, InfoBarMessageType.Error); diff --git a/Wino.Mail.ViewModels/AppShellViewModel.cs b/Wino.Mail.ViewModels/AppShellViewModel.cs index 6cfd027b..82d5a1cc 100644 --- a/Wino.Mail.ViewModels/AppShellViewModel.cs +++ b/Wino.Mail.ViewModels/AppShellViewModel.cs @@ -6,11 +6,9 @@ using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; -using Microsoft.AppCenter.Crashes; using MoreLinq; using MoreLinq.Extensions; using Serilog; -using Wino.Core; using Wino.Core.Domain; using Wino.Core.Domain.Entities.Mail; using Wino.Core.Domain.Entities.Shared; @@ -301,7 +299,7 @@ namespace Wino.Mail.ViewModels } catch (Exception ex) { - Crashes.TrackError(ex); + Log.Error(ex, "Failed to configure background tasks."); _dialogService.InfoBarMessage(Translator.Info_BackgroundExecutionUnknownErrorTitle, Translator.Info_BackgroundExecutionUnknownErrorMessage, InfoBarMessageType.Error); } @@ -373,7 +371,7 @@ namespace Wino.Mail.ViewModels } catch (Exception ex) { - Log.Error(ex, WinoErrors.StartupAccountExtendFail); + Log.Error(ex, "Failed to process launch options."); } } @@ -474,7 +472,7 @@ namespace Wino.Mail.ViewModels } catch (Exception ex) { - Log.Error(ex, WinoErrors.AccountNavigateInboxFail); + Log.Error(ex, "Failed to navigate to Inbox."); } } diff --git a/Wino.Mail.ViewModels/MailListPageViewModel.cs b/Wino.Mail.ViewModels/MailListPageViewModel.cs index 10e3dac7..af180369 100644 --- a/Wino.Mail.ViewModels/MailListPageViewModel.cs +++ b/Wino.Mail.ViewModels/MailListPageViewModel.cs @@ -10,11 +10,9 @@ using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; -using Microsoft.AppCenter.Crashes; using MoreLinq; using Nito.AsyncEx; using Serilog; -using Wino.Core; using Wino.Core.Domain; using Wino.Core.Domain.Entities.Mail; using Wino.Core.Domain.Entities.Shared; @@ -844,11 +842,9 @@ namespace Wino.Mail.ViewModels Debugger.Break(); if (IsInSearchMode) - Log.Error(ex, WinoErrors.SearchFailed); + Log.Error(ex, "Failed to perform search."); else - Log.Error(ex, WinoErrors.MailListRefreshFolder); - - Crashes.TrackError(ex); + Log.Error(ex, "Failed to refresh listed mails."); } finally { diff --git a/Wino.Mail.ViewModels/MailRenderingPageViewModel.cs b/Wino.Mail.ViewModels/MailRenderingPageViewModel.cs index 96f428f0..5e0fdd84 100644 --- a/Wino.Mail.ViewModels/MailRenderingPageViewModel.cs +++ b/Wino.Mail.ViewModels/MailRenderingPageViewModel.cs @@ -9,10 +9,9 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using MailKit; -using Microsoft.AppCenter.Crashes; + using MimeKit; using Serilog; -using Wino.Core; using Wino.Core.Domain; using Wino.Core.Domain.Entities.Mail; using Wino.Core.Domain.Entities.Shared; @@ -345,8 +344,7 @@ namespace Wino.Mail.ViewModels { _dialogService.InfoBarMessage(Translator.Info_MailRenderingFailedTitle, string.Format(Translator.Info_MailRenderingFailedMessage, ex.Message), InfoBarMessageType.Error); - Crashes.TrackError(ex); - Log.Error(ex, "Render Failed"); + Log.Error(ex, "Failed to render mail."); } } @@ -616,8 +614,7 @@ namespace Wino.Mail.ViewModels } catch (Exception ex) { - Log.Error(ex, WinoErrors.OpenAttachment); - Crashes.TrackError(ex); + Log.Error(ex, "Failed to open attachment."); _dialogService.InfoBarMessage(Translator.Info_AttachmentOpenFailedTitle, Translator.Info_AttachmentOpenFailedMessage, InfoBarMessageType.Error); } @@ -643,8 +640,7 @@ namespace Wino.Mail.ViewModels } catch (Exception ex) { - Log.Error(ex, WinoErrors.SaveAttachment); - Crashes.TrackError(ex); + Log.Error(ex, "Failed to save attachment."); _dialogService.InfoBarMessage(Translator.Info_AttachmentSaveFailedTitle, Translator.Info_AttachmentSaveFailedMessage, InfoBarMessageType.Error); } @@ -673,8 +669,7 @@ namespace Wino.Mail.ViewModels } catch (Exception ex) { - Log.Error(ex, WinoErrors.SaveAttachment); - Crashes.TrackError(ex); + Log.Error(ex, "Failed to save attachment."); _dialogService.InfoBarMessage(Translator.Info_AttachmentSaveFailedTitle, Translator.Info_AttachmentSaveFailedMessage, InfoBarMessageType.Error); } @@ -709,8 +704,8 @@ namespace Wino.Mail.ViewModels } catch (Exception ex) { + Log.Error(ex, "Failed to print mail."); _dialogService.InfoBarMessage(string.Empty, ex.Message, InfoBarMessageType.Error); - Crashes.TrackError(ex); } } @@ -735,8 +730,8 @@ namespace Wino.Mail.ViewModels } catch (Exception ex) { + Log.Error(ex, "Failed to save as PDF."); _dialogService.InfoBarMessage(Translator.Info_PDFSaveFailedTitle, ex.Message, InfoBarMessageType.Error); - Crashes.TrackError(ex); } } @@ -786,8 +781,7 @@ namespace Wino.Mail.ViewModels { _dialogService.InfoBarMessage(Translator.Info_MailRenderingFailedTitle, string.Format(Translator.Info_MailRenderingFailedMessage, ex.Message), InfoBarMessageType.Error); - Crashes.TrackError(ex); - Log.Error(ex, "Render Failed"); + Log.Error(ex, "Failed to render mail."); } } } diff --git a/Wino.Mail.ViewModels/Wino.Mail.ViewModels.csproj b/Wino.Mail.ViewModels/Wino.Mail.ViewModels.csproj index b44f763c..72e32d96 100644 --- a/Wino.Mail.ViewModels/Wino.Mail.ViewModels.csproj +++ b/Wino.Mail.ViewModels/Wino.Mail.ViewModels.csproj @@ -7,10 +7,9 @@ true - - - - + + + diff --git a/Wino.Mail/App.xaml.cs b/Wino.Mail/App.xaml.cs index ec72397d..c7e3039a 100644 --- a/Wino.Mail/App.xaml.cs +++ b/Wino.Mail/App.xaml.cs @@ -31,8 +31,6 @@ namespace Wino { public sealed partial class App : WinoApplication, IRecipient { - public override string AppCenterKey { get; } = "90deb1d0-a77f-47d0-8a6b-7eaf111c6b72"; - private BackgroundTaskDeferral connectionBackgroundTaskDeferral; private BackgroundTaskDeferral toastActionBackgroundTaskDeferral; diff --git a/Wino.Mail/Views/AboutPage.xaml b/Wino.Mail/Views/AboutPage.xaml index 3f87887e..f67fc9f6 100644 --- a/Wino.Mail/Views/AboutPage.xaml +++ b/Wino.Mail/Views/AboutPage.xaml @@ -139,6 +139,31 @@ + + + + + + + @@ -148,3 +173,4 @@ + diff --git a/Wino.Mail/Wino.Mail.csproj b/Wino.Mail/Wino.Mail.csproj index ffe1f917..957f80c8 100644 --- a/Wino.Mail/Wino.Mail.csproj +++ b/Wino.Mail/Wino.Mail.csproj @@ -11,7 +11,6 @@ win-$(Platform).pubxml true true - True True SHA256 @@ -90,15 +89,12 @@ - - - + - - + diff --git a/Wino.Server/App.xaml.cs b/Wino.Server/App.xaml.cs index 08c8affe..fe1cabf1 100644 --- a/Wino.Server/App.xaml.cs +++ b/Wino.Server/App.xaml.cs @@ -192,6 +192,7 @@ namespace Wino.Server AppDomain.CurrentDomain.UnhandledException += ServerCrashed; Application.Current.DispatcherUnhandledException += UIThreadCrash; TaskScheduler.UnobservedTaskException += TaskCrashed; + // Ensure proper encodings are available for MimeKit System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); @@ -241,9 +242,9 @@ namespace Wino.Server } } - private void TaskCrashed(object sender, UnobservedTaskExceptionEventArgs e) => Log.Error(e.Exception, "Task crashed."); + private void TaskCrashed(object sender, UnobservedTaskExceptionEventArgs e) => Log.Error(e.Exception, "Server task crashed."); - private void UIThreadCrash(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) => Log.Error(e.Exception, "UI thread crashed."); + private void UIThreadCrash(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) => Log.Error(e.Exception, "Server UI thread crashed."); private void ServerCrashed(object sender, UnhandledExceptionEventArgs e) => Log.Error((Exception)e.ExceptionObject, "Server crashed."); diff --git a/Wino.Services/ApplicationConfiguration.cs b/Wino.Services/ApplicationConfiguration.cs index f03369c4..3edda53f 100644 --- a/Wino.Services/ApplicationConfiguration.cs +++ b/Wino.Services/ApplicationConfiguration.cs @@ -9,5 +9,7 @@ namespace Wino.Services public string ApplicationDataFolderPath { get; set; } public string PublisherSharedFolderPath { get; set; } public string ApplicationTempFolderPath { get; set; } + + public string ApplicationInsightsInstrumentationKey => "a5a07c2f-6e24-4055-bfc9-88e87eef873a"; } } diff --git a/Wino.Services/LogInitializer.cs b/Wino.Services/LogInitializer.cs index a4dae199..50898d49 100644 --- a/Wino.Services/LogInitializer.cs +++ b/Wino.Services/LogInitializer.cs @@ -1,7 +1,9 @@ -using Serilog; +using Microsoft.ApplicationInsights.Extensibility; +using Serilog; using Serilog.Core; using Serilog.Exceptions; using Wino.Core.Domain.Interfaces; +using Wino.Services.Misc; namespace Wino.Services { @@ -9,10 +11,15 @@ namespace Wino.Services { private readonly LoggingLevelSwitch _levelSwitch = new LoggingLevelSwitch(); private readonly IPreferencesService _preferencesService; + private readonly IApplicationConfiguration _applicationConfiguration; + private readonly TelemetryConfiguration _telemetryConfiguration; - public LogInitializer(IPreferencesService preferencesService) + public LogInitializer(IPreferencesService preferencesService, IApplicationConfiguration applicationConfiguration) { _preferencesService = preferencesService; + _applicationConfiguration = applicationConfiguration; + + _telemetryConfiguration = new TelemetryConfiguration(applicationConfiguration.ApplicationInsightsInstrumentationKey); RefreshLoggingLevel(); } @@ -28,10 +35,13 @@ namespace Wino.Services public void SetupLogger(string fullLogFilePath) { + var insightsTelemetryConverter = new WinoTelemetryConverter(_preferencesService.DiagnosticId); + Log.Logger = new LoggerConfiguration() .MinimumLevel.ControlledBy(_levelSwitch) .WriteTo.File(fullLogFilePath, retainedFileCountLimit: 3, rollOnFileSizeLimit: true, rollingInterval: RollingInterval.Day) .WriteTo.Debug() + .WriteTo.ApplicationInsights(_telemetryConfiguration, insightsTelemetryConverter, restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Error) .Enrich.FromLogContext() .Enrich.WithExceptionDetails() .CreateLogger(); diff --git a/Wino.Services/Misc/WinoTelemetryConverter.cs b/Wino.Services/Misc/WinoTelemetryConverter.cs new file mode 100644 index 00000000..adb300d2 --- /dev/null +++ b/Wino.Services/Misc/WinoTelemetryConverter.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Microsoft.ApplicationInsights.Channel; +using Microsoft.ApplicationInsights.DataContracts; +using Serilog.Events; +using Serilog.Sinks.ApplicationInsights.TelemetryConverters; + +namespace Wino.Services.Misc +{ + internal class WinoTelemetryConverter : EventTelemetryConverter + { + private readonly string _userDiagnosticId; + + public WinoTelemetryConverter(string userDiagnosticId) + { + _userDiagnosticId = userDiagnosticId; + } + + public override IEnumerable Convert(LogEvent logEvent, IFormatProvider formatProvider) + { + foreach (ITelemetry telemetry in base.Convert(logEvent, formatProvider)) + { + // Assign diagnostic id as user id. + telemetry.Context.User.Id = _userDiagnosticId; + + yield return telemetry; + } + } + + public override void ForwardPropertiesToTelemetryProperties(LogEvent logEvent, ISupportProperties telemetryProperties, IFormatProvider formatProvider) + { + ForwardPropertiesToTelemetryProperties(logEvent, telemetryProperties, formatProvider, + includeLogLevel: true, + includeRenderedMessage: true, + includeMessageTemplate: false); + } + } +} diff --git a/Wino.Services/ServicesContainerSetup.cs b/Wino.Services/ServicesContainerSetup.cs index 89bf8b33..6ecb1941 100644 --- a/Wino.Services/ServicesContainerSetup.cs +++ b/Wino.Services/ServicesContainerSetup.cs @@ -29,6 +29,8 @@ namespace Wino.Services services.AddTransient(); services.AddTransient(); services.AddTransient(); + + } } } diff --git a/Wino.Services/Wino.Services.csproj b/Wino.Services/Wino.Services.csproj index 8117e81f..089e7eec 100644 --- a/Wino.Services/Wino.Services.csproj +++ b/Wino.Services/Wino.Services.csproj @@ -7,12 +7,13 @@ - - - - - - + + + + + + + diff --git a/WinoMail.Packaging/WinoMail.Packaging.wapproj b/WinoMail.Packaging/WinoMail.Packaging.wapproj index a6cc0375..36188528 100644 --- a/WinoMail.Packaging/WinoMail.Packaging.wapproj +++ b/WinoMail.Packaging/WinoMail.Packaging.wapproj @@ -141,6 +141,7 @@ +