diff --git a/src/Android/Autofill/AutofillService.cs b/src/Android/Autofill/AutofillService.cs index c339794bc..07171eb9e 100644 --- a/src/Android/Autofill/AutofillService.cs +++ b/src/Android/Autofill/AutofillService.cs @@ -1,4 +1,7 @@ -using Android; +using System; +using System.Collections.Generic; +using System.Linq; +using Android; using Android.App; using Android.Content; using Android.OS; @@ -9,12 +12,6 @@ using Bit.Core; using Bit.Core.Abstractions; using Bit.Core.Enums; using Bit.Core.Utilities; -#if !FDROID -using Microsoft.AppCenter.Crashes; -#endif -using System; -using System.Collections.Generic; -using System.Linq; namespace Bit.Droid.Autofill { @@ -28,6 +25,7 @@ namespace Bit.Droid.Autofill private IVaultTimeoutService _vaultTimeoutService; private IPolicyService _policyService; private IStateService _stateService; + private LazyResolve _logger = new LazyResolve("logger"); public async override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback) @@ -84,9 +82,7 @@ namespace Bit.Droid.Autofill } catch (Exception e) { -#if !FDROID - Crashes.TrackError(e); -#endif + _logger.Value.Exception(e); } } @@ -160,9 +156,7 @@ namespace Bit.Droid.Autofill } catch (Exception e) { -#if !FDROID - Crashes.TrackError(e); -#endif + _logger.Value.Exception(e); } } } diff --git a/src/Android/MainActivity.cs b/src/Android/MainActivity.cs index c11f8b9f7..4018dd734 100644 --- a/src/Android/MainActivity.cs +++ b/src/Android/MainActivity.cs @@ -69,7 +69,7 @@ namespace Bit.Droid Window.AddFlags(Android.Views.WindowManagerFlags.Secure); } -#if !FDROID +#if !DEBUG && !FDROID var appCenterHelper = new AppCenterHelper(_appIdService, _stateService); var appCenterTask = appCenterHelper.InitAsync(); #endif diff --git a/src/Android/MainApplication.cs b/src/Android/MainApplication.cs index ff2fd307a..aadd11564 100644 --- a/src/Android/MainApplication.cs +++ b/src/Android/MainApplication.cs @@ -53,7 +53,8 @@ namespace Bit.Droid ServiceContainer.Resolve("apiService"), ServiceContainer.Resolve("messagingService"), ServiceContainer.Resolve("platformUtilsService"), - ServiceContainer.Resolve("deviceActionService")); + ServiceContainer.Resolve("deviceActionService"), + ServiceContainer.Resolve("logger")); ServiceContainer.Register("deleteAccountActionFlowExecutioner", deleteAccountActionFlowExecutioner); var verificationActionsFlowHelper = new VerificationActionsFlowHelper( @@ -87,7 +88,14 @@ namespace Bit.Droid private void RegisterLocalServices() { - ServiceContainer.Register("logService", new AndroidLogService()); + ServiceContainer.Register("nativeLogService", new AndroidLogService()); +#if FDROID + ServiceContainer.Register("logger", new StubLogger()); +#elif DEBUG + ServiceContainer.Register("logger", DebugLogger.Instance); +#else + ServiceContainer.Register("logger", Logger.Instance); +#endif // Note: This might cause a race condition. Investigate more. Task.Run(() => diff --git a/src/Android/Services/AndroidLogService.cs b/src/Android/Services/AndroidLogService.cs index ead61510d..8d7cdac54 100644 --- a/src/Android/Services/AndroidLogService.cs +++ b/src/Android/Services/AndroidLogService.cs @@ -3,7 +3,7 @@ using System; namespace Bit.Core.Services { - public class AndroidLogService : ILogService + public class AndroidLogService : INativeLogService { private static readonly string _tag = "BITWARDEN"; diff --git a/src/App/Controls/AccountSwitchingOverlay/AccountSwitchingOverlayView.xaml.cs b/src/App/Controls/AccountSwitchingOverlay/AccountSwitchingOverlayView.xaml.cs index 8f213dcba..b4af21f98 100644 --- a/src/App/Controls/AccountSwitchingOverlay/AccountSwitchingOverlayView.xaml.cs +++ b/src/App/Controls/AccountSwitchingOverlay/AccountSwitchingOverlayView.xaml.cs @@ -1,9 +1,8 @@ using System; using System.Threading.Tasks; using System.Windows.Input; -#if !FDROID -using Microsoft.AppCenter.Crashes; -#endif +using Bit.Core.Abstractions; +using Bit.Core.Utilities; using Xamarin.CommunityToolkit.ObjectModel; using Xamarin.Forms; @@ -23,14 +22,14 @@ namespace Bit.App.Controls set => SetValue(MainFabProperty, value); } + readonly LazyResolve _logger = new LazyResolve("logger"); + public AccountSwitchingOverlayView() { InitializeComponent(); ToggleVisibililtyCommand = new AsyncCommand(ToggleVisibilityAsync, -#if !FDROID - onException: ex => Crashes.TrackError(ex), -#endif + onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false); } @@ -110,9 +109,7 @@ namespace Bit.App.Controls } catch (Exception ex) { -#if !FDROID - Crashes.TrackError(ex); -#endif + _logger.Value.Exception(ex); } } @@ -133,9 +130,7 @@ namespace Bit.App.Controls } catch (Exception ex) { -#if !FDROID - Crashes.TrackError(ex); -#endif + _logger.Value.Exception(ex); } } } diff --git a/src/App/Controls/AccountSwitchingOverlay/AccountSwitchingOverlayViewModel.cs b/src/App/Controls/AccountSwitchingOverlay/AccountSwitchingOverlayViewModel.cs index bc15fe96a..ed6f521ca 100644 --- a/src/App/Controls/AccountSwitchingOverlay/AccountSwitchingOverlayViewModel.cs +++ b/src/App/Controls/AccountSwitchingOverlay/AccountSwitchingOverlayViewModel.cs @@ -4,7 +4,6 @@ using System.Windows.Input; using Bit.Core.Abstractions; using Bit.Core.Models.View; using Bit.Core.Utilities; -using Microsoft.AppCenter.Crashes; using Xamarin.CommunityToolkit.ObjectModel; using Xamarin.Forms; @@ -16,15 +15,14 @@ namespace Bit.App.Controls private readonly IMessagingService _messagingService; public AccountSwitchingOverlayViewModel(IStateService stateService, - IMessagingService messagingService) + IMessagingService messagingService, + ILogger logger) { _stateService = stateService; _messagingService = messagingService; SelectAccountCommand = new AsyncCommand(SelectAccountAsync, -#if !FDROID - onException: ex => Crashes.TrackError(ex), -#endif + onException: ex => logger.Exception(ex), allowsMultipleExecutions: false); } diff --git a/src/App/Pages/Accounts/DeleteAccountViewModel.cs b/src/App/Pages/Accounts/DeleteAccountViewModel.cs index cab70bd38..6705e1949 100644 --- a/src/App/Pages/Accounts/DeleteAccountViewModel.cs +++ b/src/App/Pages/Accounts/DeleteAccountViewModel.cs @@ -5,9 +5,6 @@ using Bit.App.Utilities; using Bit.Core.Abstractions; using Bit.Core.Exceptions; using Bit.Core.Utilities; -#if !FDROID -using Microsoft.AppCenter.Crashes; -#endif namespace Bit.App.Pages { @@ -15,11 +12,13 @@ namespace Bit.App.Pages { readonly IPlatformUtilsService _platformUtilsService; readonly IVerificationActionsFlowHelper _verificationActionsFlowHelper; + readonly ILogger _logger; public DeleteAccountViewModel() { _platformUtilsService = ServiceContainer.Resolve("platformUtilsService"); _verificationActionsFlowHelper = ServiceContainer.Resolve("verificationActionsFlowHelper"); + _logger = ServiceContainer.Resolve("logger"); PageTitle = AppResources.DeleteAccount; } @@ -44,9 +43,7 @@ namespace Bit.App.Pages } catch (System.Exception ex) { -#if !FDROID - Crashes.TrackError(ex); -#endif + _logger.Exception(ex); await _platformUtilsService.ShowDialogAsync(AppResources.AnErrorHasOccurred); } } @@ -60,16 +57,19 @@ namespace Bit.App.Pages readonly IMessagingService _messagingService; readonly IPlatformUtilsService _platformUtilsService; readonly IDeviceActionService _deviceActionService; + readonly ILogger _logger; public DeleteAccountActionFlowExecutioner(IApiService apiService, IMessagingService messagingService, IPlatformUtilsService platformUtilsService, - IDeviceActionService deviceActionService) + IDeviceActionService deviceActionService, + ILogger logger) { _apiService = apiService; _messagingService = messagingService; _platformUtilsService = platformUtilsService; _deviceActionService = deviceActionService; + _logger = logger; } public async Task Execute(IActionFlowParmeters parameters) @@ -102,9 +102,7 @@ namespace Bit.App.Pages catch (System.Exception ex) { await _deviceActionService.HideLoadingAsync(); -#if !FDROID - Crashes.TrackError(ex); -#endif + _logger.Exception(ex); await _platformUtilsService.ShowDialogAsync(AppResources.AnErrorHasOccurred); } } diff --git a/src/App/Pages/Accounts/HomePageViewModel.cs b/src/App/Pages/Accounts/HomePageViewModel.cs index d0f951962..bd44d5567 100644 --- a/src/App/Pages/Accounts/HomePageViewModel.cs +++ b/src/App/Pages/Accounts/HomePageViewModel.cs @@ -17,10 +17,11 @@ namespace Bit.App.Pages { _stateService = ServiceContainer.Resolve("stateService"); _messagingService = ServiceContainer.Resolve("messagingService"); + var logger = ServiceContainer.Resolve("logger"); PageTitle = AppResources.Bitwarden; - AccountSwitchingOverlayViewModel = new AccountSwitchingOverlayViewModel(_stateService, _messagingService) + AccountSwitchingOverlayViewModel = new AccountSwitchingOverlayViewModel(_stateService, _messagingService, logger) { AllowActiveAccountSelection = true }; diff --git a/src/App/Pages/Accounts/LockPageViewModel.cs b/src/App/Pages/Accounts/LockPageViewModel.cs index 59ca8c69d..a4515c01b 100644 --- a/src/App/Pages/Accounts/LockPageViewModel.cs +++ b/src/App/Pages/Accounts/LockPageViewModel.cs @@ -11,9 +11,6 @@ using Bit.Core.Models.Domain; using Bit.Core.Models.Request; using Bit.Core.Utilities; using Xamarin.Forms; -#if !FDROID -using Microsoft.AppCenter.Crashes; -#endif namespace Bit.App.Pages { @@ -29,6 +26,7 @@ namespace Bit.App.Pages private readonly IStateService _stateService; private readonly IBiometricService _biometricService; private readonly IKeyConnectorService _keyConnectorService; + private readonly ILogger _logger; private string _email; private bool _showPassword; @@ -55,12 +53,13 @@ namespace Bit.App.Pages _stateService = ServiceContainer.Resolve("stateService"); _biometricService = ServiceContainer.Resolve("biometricService"); _keyConnectorService = ServiceContainer.Resolve("keyConnectorService"); + _logger = ServiceContainer.Resolve("logger"); PageTitle = AppResources.VerifyMasterPassword; TogglePasswordCommand = new Command(TogglePassword); SubmitCommand = new Command(async () => await SubmitAsync()); - AccountSwitchingOverlayViewModel = new AccountSwitchingOverlayViewModel(_stateService, _messagingService) + AccountSwitchingOverlayViewModel = new AccountSwitchingOverlayViewModel(_stateService, _messagingService, _logger) { AllowAddAccountRow = true, AllowActiveAccountSelection = true @@ -151,9 +150,7 @@ namespace Bit.App.Pages if (string.IsNullOrWhiteSpace(_email)) { await _vaultTimeoutService.LogOutAsync(); -#if !FDROID - Crashes.TrackError(new NullReferenceException("Email not found in storage")); -#endif + _logger.Exception(new NullReferenceException("Email not found in storage")); return; } var webVault = _environmentService.GetWebVaultUrl(true); diff --git a/src/App/Pages/Accounts/LoginPageViewModel.cs b/src/App/Pages/Accounts/LoginPageViewModel.cs index 7514e9047..709d7cc80 100644 --- a/src/App/Pages/Accounts/LoginPageViewModel.cs +++ b/src/App/Pages/Accounts/LoginPageViewModel.cs @@ -8,9 +8,6 @@ using Bit.Core; using Bit.Core.Abstractions; using Bit.Core.Exceptions; using Bit.Core.Utilities; -#if !FDROID -using Microsoft.AppCenter.Crashes; -#endif using Xamarin.Forms; namespace Bit.App.Pages @@ -25,6 +22,7 @@ namespace Bit.App.Pages private readonly IEnvironmentService _environmentService; private readonly II18nService _i18nService; private readonly IMessagingService _messagingService; + private readonly ILogger _logger; private bool _showPassword; private bool _showCancelButton; @@ -41,12 +39,13 @@ namespace Bit.App.Pages _environmentService = ServiceContainer.Resolve("environmentService"); _i18nService = ServiceContainer.Resolve("i18nService"); _messagingService = ServiceContainer.Resolve("messagingService"); + _logger = ServiceContainer.Resolve("logger"); PageTitle = AppResources.Bitwarden; TogglePasswordCommand = new Command(TogglePassword); LogInCommand = new Command(async () => await LogInAsync()); - AccountSwitchingOverlayViewModel = new AccountSwitchingOverlayViewModel(_stateService, _messagingService) + AccountSwitchingOverlayViewModel = new AccountSwitchingOverlayViewModel(_stateService, _messagingService, _logger) { AllowAddAccountRow = true, AllowActiveAccountSelection = true @@ -221,9 +220,7 @@ namespace Bit.App.Pages } catch (Exception e) { -#if !FDROID - Crashes.TrackError(e); -#endif + _logger.Exception(e); } } diff --git a/src/App/Pages/Accounts/VerificationCodeViewModel.cs b/src/App/Pages/Accounts/VerificationCodeViewModel.cs index e160a535d..7f1c62bbb 100644 --- a/src/App/Pages/Accounts/VerificationCodeViewModel.cs +++ b/src/App/Pages/Accounts/VerificationCodeViewModel.cs @@ -1,19 +1,16 @@ using System; +using System.Threading.Tasks; +using System.Windows.Input; using Bit.App.Abstractions; using Bit.App.Resources; -using Bit.Core.Abstractions; -using Bit.Core.Utilities; -using System.Threading.Tasks; -using Bit.Core.Exceptions; -using Xamarin.Forms; -using Xamarin.CommunityToolkit.ObjectModel; -using System.Windows.Input; using Bit.App.Utilities; using Bit.Core; +using Bit.Core.Abstractions; using Bit.Core.Enums; -#if !FDROID -using Microsoft.AppCenter.Crashes; -#endif +using Bit.Core.Exceptions; +using Bit.Core.Utilities; +using Xamarin.CommunityToolkit.ObjectModel; +using Xamarin.Forms; namespace Bit.App.Pages { @@ -24,6 +21,7 @@ namespace Bit.App.Pages private readonly IUserVerificationService _userVerificationService; private readonly IApiService _apiService; private readonly IVerificationActionsFlowHelper _verificationActionsFlowHelper; + private readonly ILogger _logger; private bool _showPassword; private string _secret, _mainActionText, _sendCodeStatus; @@ -35,6 +33,7 @@ namespace Bit.App.Pages _userVerificationService = ServiceContainer.Resolve("userVerificationService"); _apiService = ServiceContainer.Resolve("apiService"); _verificationActionsFlowHelper = ServiceContainer.Resolve("verificationActionsFlowHelper"); + _logger = ServiceContainer.Resolve("logger"); PageTitle = AppResources.VerificationCode; @@ -118,9 +117,7 @@ namespace Bit.App.Pages } catch (Exception ex) { -#if !FDROID - Crashes.TrackError(ex); -#endif + _logger.Exception(ex); await _deviceActionService.HideLoadingAsync(); SendCodeStatus = AppResources.AnErrorOccurredWhileSendingAVerificationCodeToYourEmailPleaseTryAgain; } @@ -171,9 +168,7 @@ namespace Bit.App.Pages } catch (Exception ex) { -#if !FDROID - Crashes.TrackError(ex); -#endif + _logger.Exception(ex); await _deviceActionService.HideLoadingAsync(); } } diff --git a/src/App/Pages/Generator/GeneratorHistoryPageViewModel.cs b/src/App/Pages/Generator/GeneratorHistoryPageViewModel.cs index e92aedde4..ab63c81b0 100644 --- a/src/App/Pages/Generator/GeneratorHistoryPageViewModel.cs +++ b/src/App/Pages/Generator/GeneratorHistoryPageViewModel.cs @@ -4,9 +4,6 @@ using Bit.App.Resources; using Bit.Core.Abstractions; using Bit.Core.Models.Domain; using Bit.Core.Utilities; -#if !FDROID -using Microsoft.AppCenter.Crashes; -#endif using Xamarin.Forms; namespace Bit.App.Pages @@ -16,6 +13,7 @@ namespace Bit.App.Pages private readonly IPlatformUtilsService _platformUtilsService; private readonly IPasswordGenerationService _passwordGenerationService; private readonly IClipboardService _clipboardService; + private readonly ILogger _logger; private bool _showNoData; @@ -24,6 +22,7 @@ namespace Bit.App.Pages _platformUtilsService = ServiceContainer.Resolve("platformUtilsService"); _passwordGenerationService = ServiceContainer.Resolve("passwordGenerationService"); _clipboardService = ServiceContainer.Resolve("clipboardService"); + _logger = ServiceContainer.Resolve("logger"); PageTitle = AppResources.PasswordHistory; History = new ExtendedObservableCollection(); @@ -70,9 +69,7 @@ namespace Bit.App.Pages } catch (System.Exception ex) { -#if !FDROID - Crashes.TrackError(ex); -#endif + _logger.Exception(ex); } } } diff --git a/src/App/Pages/Send/SendAddEditPage.xaml.cs b/src/App/Pages/Send/SendAddEditPage.xaml.cs index a0b1aa2d8..3121acf0e 100644 --- a/src/App/Pages/Send/SendAddEditPage.xaml.cs +++ b/src/App/Pages/Send/SendAddEditPage.xaml.cs @@ -7,9 +7,6 @@ using Bit.App.Utilities; using Bit.Core.Abstractions; using Bit.Core.Enums; using Bit.Core.Utilities; -#if !FDROID -using Microsoft.AppCenter.Crashes; -#endif using Xamarin.Forms; using Xamarin.Forms.PlatformConfiguration; using Xamarin.Forms.PlatformConfiguration.iOSSpecific; @@ -21,6 +18,7 @@ namespace Bit.App.Pages { private readonly IBroadcasterService _broadcasterService; private readonly IVaultTimeoutService _vaultTimeoutService; + private readonly LazyResolve _logger = new LazyResolve("logger"); private AppOptions _appOptions; private SendAddEditPageViewModel _vm; @@ -132,9 +130,7 @@ namespace Bit.App.Pages } catch (Exception ex) { -#if !FDROID - Crashes.TrackError(ex); -#endif + _logger.Value.Exception(ex); await CloseAsync(); } } diff --git a/src/App/Pages/Send/SendAddEditPageViewModel.cs b/src/App/Pages/Send/SendAddEditPageViewModel.cs index 4a213a1b1..78642e362 100644 --- a/src/App/Pages/Send/SendAddEditPageViewModel.cs +++ b/src/App/Pages/Send/SendAddEditPageViewModel.cs @@ -10,9 +10,6 @@ using Bit.Core.Enums; using Bit.Core.Exceptions; using Bit.Core.Models.View; using Bit.Core.Utilities; -#if !FDROID -using Microsoft.AppCenter.Crashes; -#endif using Xamarin.Essentials; using Xamarin.Forms; @@ -25,6 +22,7 @@ namespace Bit.App.Pages private readonly IMessagingService _messagingService; private readonly IStateService _stateService; private readonly ISendService _sendService; + private readonly ILogger _logger; private bool _sendEnabled; private bool _canAccessPremium; private bool _emailVerified; @@ -58,6 +56,8 @@ namespace Bit.App.Pages _messagingService = ServiceContainer.Resolve("messagingService"); _stateService = ServiceContainer.Resolve("stateService"); _sendService = ServiceContainer.Resolve("sendService"); + _logger = ServiceContainer.Resolve("logger"); + TogglePasswordCommand = new Command(TogglePassword); TypeOptions = new List> @@ -455,9 +455,7 @@ namespace Bit.App.Pages catch (Exception ex) { await _deviceActionService.HideLoadingAsync(); -#if !FDROID - Crashes.TrackError(ex); -#endif + _logger.Exception(ex); await _platformUtilsService.ShowDialogAsync(AppResources.AnErrorHasOccurred); } return false; diff --git a/src/App/Pages/Settings/ExportVaultPageViewModel.cs b/src/App/Pages/Settings/ExportVaultPageViewModel.cs index 80218b834..de84447ba 100644 --- a/src/App/Pages/Settings/ExportVaultPageViewModel.cs +++ b/src/App/Pages/Settings/ExportVaultPageViewModel.cs @@ -1,17 +1,14 @@ using System; -using Bit.App.Abstractions; -using Bit.App.Resources; -using Bit.Core.Abstractions; -using Bit.Core.Utilities; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; +using Bit.App.Abstractions; +using Bit.App.Resources; +using Bit.Core.Abstractions; using Bit.Core.Enums; using Bit.Core.Exceptions; +using Bit.Core.Utilities; using Bit.Core; -#if !FDROID -using Microsoft.AppCenter.Crashes; -#endif using Xamarin.Forms; namespace Bit.App.Pages @@ -26,6 +23,7 @@ namespace Bit.App.Pages private readonly IKeyConnectorService _keyConnectorService; private readonly IUserVerificationService _userVerificationService; private readonly IApiService _apiService; + private readonly ILogger _logger; private int _fileFormatSelectedIndex; private string _exportWarningMessage; @@ -48,6 +46,7 @@ namespace Bit.App.Pages _keyConnectorService = ServiceContainer.Resolve("keyConnectorService"); _userVerificationService = ServiceContainer.Resolve("userVerificationService"); _apiService = ServiceContainer.Resolve("apiService"); + _logger = ServiceContainer.Resolve("logger"); PageTitle = AppResources.ExportVault; TogglePasswordCommand = new Command(TogglePassword); @@ -189,9 +188,7 @@ namespace Bit.App.Pages ClearResult(); await _platformUtilsService.ShowDialogAsync(_i18nService.T("ExportVaultFailure")); System.Diagnostics.Debug.WriteLine(">>> {0}: {1}", ex.GetType(), ex.StackTrace); -#if !FDROID - Crashes.TrackError(ex); -#endif + _logger.Exception(ex); } } diff --git a/src/App/Pages/Vault/AddEditPageViewModel.cs b/src/App/Pages/Vault/AddEditPageViewModel.cs index 9ca606a06..f71c7ced9 100644 --- a/src/App/Pages/Vault/AddEditPageViewModel.cs +++ b/src/App/Pages/Vault/AddEditPageViewModel.cs @@ -1,21 +1,18 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Bit.App.Abstractions; +using Bit.App.Controls; using Bit.App.Models; using Bit.App.Resources; +using Bit.Core; using Bit.Core.Abstractions; using Bit.Core.Enums; using Bit.Core.Exceptions; using Bit.Core.Models.View; using Bit.Core.Utilities; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Bit.App.Controls; -using Bit.Core; using Xamarin.Forms; -#if !FDROID -using Microsoft.AppCenter.Crashes; -#endif namespace Bit.App.Pages { @@ -32,6 +29,8 @@ namespace Bit.App.Pages private readonly IMessagingService _messagingService; private readonly IEventService _eventService; private readonly IPolicyService _policyService; + private readonly ILogger _logger; + private CipherView _cipher; private bool _showNotesSeparator; private bool _showPassword; @@ -68,7 +67,7 @@ namespace Bit.App.Pages new KeyValuePair(UriMatchType.Exact, AppResources.Exact), new KeyValuePair(UriMatchType.Never, AppResources.Never) }; - + public AddEditPageViewModel() { _deviceActionService = ServiceContainer.Resolve("deviceActionService"); @@ -82,6 +81,8 @@ namespace Bit.App.Pages _collectionService = ServiceContainer.Resolve("collectionService"); _eventService = ServiceContainer.Resolve("eventService"); _policyService = ServiceContainer.Resolve("policyService"); + _logger = ServiceContainer.Resolve("logger"); + GeneratePasswordCommand = new Command(GeneratePassword); TogglePasswordCommand = new Command(TogglePassword); ToggleCardNumberCommand = new Command(ToggleCardNumber); @@ -538,9 +539,7 @@ namespace Bit.App.Pages } catch(Exception genex) { -#if !FDROID - Crashes.TrackError(genex); -#endif + _logger.Exception(genex); await _deviceActionService.HideLoadingAsync(); } return false; diff --git a/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs b/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs index 20e4ddafd..941660b37 100644 --- a/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs +++ b/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs @@ -45,6 +45,7 @@ namespace Bit.App.Pages private readonly IMessagingService _messagingService; private readonly IStateService _stateService; private readonly IPasswordRepromptService _passwordRepromptService; + private readonly ILogger _logger; public GroupingsPageViewModel() { @@ -58,6 +59,7 @@ namespace Bit.App.Pages _messagingService = ServiceContainer.Resolve("messagingService"); _stateService = ServiceContainer.Resolve("stateService"); _passwordRepromptService = ServiceContainer.Resolve("passwordRepromptService"); + _logger = ServiceContainer.Resolve("logger"); Loading = true; PageTitle = AppResources.MyVault; @@ -69,7 +71,7 @@ namespace Bit.App.Pages }); CipherOptionsCommand = new Command(CipherOptionsAsync); - AccountSwitchingOverlayViewModel = new AccountSwitchingOverlayViewModel(_stateService, _messagingService) + AccountSwitchingOverlayViewModel = new AccountSwitchingOverlayViewModel(_stateService, _messagingService, _logger) { AllowAddAccountRow = true }; diff --git a/src/App/Pages/Vault/ScanPage.xaml.cs b/src/App/Pages/Vault/ScanPage.xaml.cs index 30d6fb09f..cf7e7a68e 100644 --- a/src/App/Pages/Vault/ScanPage.xaml.cs +++ b/src/App/Pages/Vault/ScanPage.xaml.cs @@ -2,7 +2,8 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Microsoft.AppCenter.Crashes; +using Bit.Core.Abstractions; +using Bit.Core.Utilities; using Xamarin.Forms; namespace Bit.App.Pages @@ -14,6 +15,8 @@ namespace Bit.App.Pages private CancellationTokenSource _autofocusCts; private Task _continuousAutofocusTask; + private readonly LazyResolve _logger = new LazyResolve("logger"); + public ScanPage(Action callback) { _callback = callback; @@ -61,9 +64,7 @@ namespace Bit.App.Pages catch (TaskCanceledException) { } catch (Exception ex) { -#if !FDROID - Crashes.TrackError(ex); -#endif + _logger.Value.Exception(ex); } }, autofocusCts.Token); } diff --git a/src/App/Utilities/ThemeManager.cs b/src/App/Utilities/ThemeManager.cs index 7bc50788b..3dabf093d 100644 --- a/src/App/Utilities/ThemeManager.cs +++ b/src/App/Utilities/ThemeManager.cs @@ -1,14 +1,12 @@ using System; +using System.Linq; +using System.Threading.Tasks; using Bit.App.Models; using Bit.App.Styles; using Bit.Core.Abstractions; +using Bit.Core.Services; using Bit.Core.Utilities; using Xamarin.Forms; -using System.Linq; -using System.Threading.Tasks; -#if !FDROID -using Microsoft.AppCenter.Crashes; -#endif namespace Bit.App.Utilities { @@ -76,9 +74,7 @@ namespace Bit.App.Utilities } catch (Exception ex) { -#if !FDROID - Crashes.TrackError(ex); -#endif + LoggerHelper.LogEvenIfCantBeResolved(ex); } } @@ -168,9 +164,7 @@ namespace Bit.App.Utilities } catch (Exception ex) { -#if !FDROID - Crashes.TrackError(ex); -#endif + LoggerHelper.LogEvenIfCantBeResolved(ex); } } } diff --git a/src/Core/Abstractions/ILogger.cs b/src/Core/Abstractions/ILogger.cs new file mode 100644 index 000000000..704fca758 --- /dev/null +++ b/src/Core/Abstractions/ILogger.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace Bit.Core.Abstractions +{ + public interface ILogger + { + /// + /// Logs something that is not in itself an exception, e.g. a wrong flow or value that needs to be reported + /// and looked into. + /// + /// A text to be used as the issue's title + /// Additional data + void Error(string message, + IDictionary extraData = null, + [CallerMemberName] string memberName = "", + [CallerFilePath] string sourceFilePath = "", + [CallerLineNumber] int sourceLineNumber = 0); + + /// + /// Logs an exception + /// + void Exception(Exception ex); + } +} diff --git a/src/Core/Abstractions/ILogService.cs b/src/Core/Abstractions/INativeLogService.cs similarity index 83% rename from src/Core/Abstractions/ILogService.cs rename to src/Core/Abstractions/INativeLogService.cs index 8af1a806a..fdadcca37 100644 --- a/src/Core/Abstractions/ILogService.cs +++ b/src/Core/Abstractions/INativeLogService.cs @@ -1,6 +1,6 @@ namespace Bit.Core.Abstractions { - public interface ILogService + public interface INativeLogService { void Debug(string message); void Error(string message); diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index 09129dec5..6aceb3c57 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -15,6 +15,8 @@ + + @@ -31,4 +33,7 @@ + + + diff --git a/src/Core/Services/ConsoleLogService.cs b/src/Core/Services/ConsoleLogService.cs index baa292f76..492891834 100644 --- a/src/Core/Services/ConsoleLogService.cs +++ b/src/Core/Services/ConsoleLogService.cs @@ -3,7 +3,7 @@ using System; namespace Bit.Core.Services { - public class ConsoleLogService : ILogService + public class ConsoleLogService : INativeLogService { public void Debug(string message) { diff --git a/src/Core/Services/Logging/DebugLogger.cs b/src/Core/Services/Logging/DebugLogger.cs new file mode 100644 index 000000000..e70fbda80 --- /dev/null +++ b/src/Core/Services/Logging/DebugLogger.cs @@ -0,0 +1,50 @@ +#if !FDROID +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; +using Bit.Core.Abstractions; + +namespace Bit.Core.Services +{ + public class DebugLogger : ILogger + { + static ILogger _instance; + public static ILogger Instance + { + get + { + if (_instance is null) + { + _instance = new DebugLogger(); + } + return _instance; + } + } + + protected DebugLogger() + { + } + + public void Error(string message, IDictionary extraData = null, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) + { + var classAndMethod = $"{Path.GetFileNameWithoutExtension(sourceFilePath)}.{memberName}"; + var filePathAndLineNumber = $"{Path.GetFileName(sourceFilePath)}:{sourceLineNumber}"; + + if (string.IsNullOrEmpty(message)) + { + Debug.WriteLine($"Error found in: {classAndMethod})"); + return; + } + + Debug.WriteLine($"File: {filePathAndLineNumber}"); + Debug.WriteLine($"Method: {memberName}"); + Debug.WriteLine($"Message: {message}"); + + } + + public void Exception(Exception ex) => Debug.WriteLine(ex); + } +} +#endif diff --git a/src/Core/Services/Logging/Logger.cs b/src/Core/Services/Logging/Logger.cs new file mode 100644 index 000000000..69f781435 --- /dev/null +++ b/src/Core/Services/Logging/Logger.cs @@ -0,0 +1,71 @@ +#if !FDROID +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using Bit.Core.Abstractions; +using Microsoft.AppCenter.Crashes; + +namespace Bit.Core.Services +{ + public class Logger : ILogger + { + static ILogger _instance; + public static ILogger Instance + { + get + { + if (_instance is null) + { + _instance = new Logger(); + } + return _instance; + } + } + + protected Logger() + { + } + + public void Error(string message, + IDictionary extraData = null, + [CallerMemberName] string memberName = "", + [CallerFilePath] string sourceFilePath = "", + [CallerLineNumber] int sourceLineNumber = 0) + { + var classAndMethod = $"{Path.GetFileNameWithoutExtension(sourceFilePath)}.{memberName}"; + var filePathAndLineNumber = $"{Path.GetFileName(sourceFilePath)}:{sourceLineNumber}"; + var properties = new Dictionary + { + ["File"] = filePathAndLineNumber, + ["Method"] = memberName + }; + + var exception = new Exception(message ?? $"Error found in: {classAndMethod}"); + if (extraData == null) + { + Crashes.TrackError(exception, properties); + } + else + { + var data = properties.Concat(extraData).ToDictionary(x => x.Key, x => x.Value); + Crashes.TrackError(exception, data); + } + } + + public void Exception(Exception exception) + { + try + { + Crashes.TrackError(exception); + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + } + } + } +} +#endif diff --git a/src/Core/Services/Logging/LoggerHelper.cs b/src/Core/Services/Logging/LoggerHelper.cs new file mode 100644 index 000000000..cfce40af6 --- /dev/null +++ b/src/Core/Services/Logging/LoggerHelper.cs @@ -0,0 +1,33 @@ +using System; +using Bit.Core.Abstractions; +using Bit.Core.Utilities; +#if !FDROID +using Microsoft.AppCenter.Crashes; +#endif + +namespace Bit.Core.Services +{ + public static class LoggerHelper + { + /// + /// Logs the exception even if the service can't be resolved. + /// Useful when we need to log an exception in situations where the ServiceContainer may not be initialized. + /// + /// + public static void LogEvenIfCantBeResolved(Exception ex) + { + if (ServiceContainer.Resolve("logger", true) is ILogger logger) + { + logger.Exception(ex); + } + else + { +#if !FDROID + // just in case the caller throws the exception in a moment where the logger can't be resolved + // we need to track the error as well + Crashes.TrackError(ex); +#endif + } + } + } +} diff --git a/src/Core/Services/Logging/StubLogger.cs b/src/Core/Services/Logging/StubLogger.cs new file mode 100644 index 000000000..aa3db6aff --- /dev/null +++ b/src/Core/Services/Logging/StubLogger.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Bit.Core.Abstractions; + +namespace Bit.Core.Services +{ + /// + /// A logger that does nothing, this is useful on e.g. FDroid, where we cannot use logging through AppCenter + /// + public class StubLogger : ILogger + { + public void Error(string message, IDictionary extraData = null, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) + { + } + + public void Exception(Exception ex) + { + } + } +} diff --git a/src/Core/Utilities/TaskExtensions.cs b/src/Core/Utilities/TaskExtensions.cs index 8e3eb8a6f..2400671f6 100644 --- a/src/Core/Utilities/TaskExtensions.cs +++ b/src/Core/Utilities/TaskExtensions.cs @@ -1,8 +1,6 @@ using System; using System.Threading.Tasks; -#if !FDROID -using Microsoft.AppCenter.Crashes; -#endif +using Bit.Core.Services; namespace Bit.Core.Utilities { @@ -22,9 +20,7 @@ namespace Bit.Core.Utilities } catch (Exception ex) { -#if !FDROID - Crashes.TrackError(ex); -#endif + LoggerHelper.LogEvenIfCantBeResolved(ex); onException?.Invoke(ex); } } diff --git a/src/iOS.Core/Utilities/iOSCoreHelpers.cs b/src/iOS.Core/Utilities/iOSCoreHelpers.cs index be8034106..26190c20b 100644 --- a/src/iOS.Core/Utilities/iOSCoreHelpers.cs +++ b/src/iOS.Core/Utilities/iOSCoreHelpers.cs @@ -27,17 +27,28 @@ namespace Bit.iOS.Core.Utilities public static void RegisterAppCenter() { +#if !DEBUG var appCenterHelper = new AppCenterHelper( ServiceContainer.Resolve("appIdService"), ServiceContainer.Resolve("stateService")); var appCenterTask = appCenterHelper.InitAsync(); +#endif } public static void RegisterLocalServices() { - if (ServiceContainer.Resolve("logService", true) == null) + if (ServiceContainer.Resolve("nativeLogService", true) == null) { - ServiceContainer.Register("logService", new ConsoleLogService()); + ServiceContainer.Register("nativeLogService", new ConsoleLogService()); + } + + if (ServiceContainer.Resolve("logger", true) == null) + { +#if DEBUG + ServiceContainer.Register("logger", DebugLogger.Instance); +#else + ServiceContainer.Register("logger", Logger.Instance); +#endif } var preferencesStorage = new PreferencesStorageService(AppGroupId); @@ -156,7 +167,8 @@ namespace Bit.iOS.Core.Utilities ServiceContainer.Resolve("apiService"), ServiceContainer.Resolve("messagingService"), ServiceContainer.Resolve("platformUtilsService"), - ServiceContainer.Resolve("deviceActionService")); + ServiceContainer.Resolve("deviceActionService"), + ServiceContainer.Resolve("logger")); ServiceContainer.Register("deleteAccountActionFlowExecutioner", deleteAccountActionFlowExecutioner); var verificationActionsFlowHelper = new VerificationActionsFlowHelper( diff --git a/src/iOS.Core/Utilities/iOSHelpers.cs b/src/iOS.Core/Utilities/iOSHelpers.cs index 7bb32057e..d10cf7403 100644 --- a/src/iOS.Core/Utilities/iOSHelpers.cs +++ b/src/iOS.Core/Utilities/iOSHelpers.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; using Bit.App.Utilities; -using Microsoft.AppCenter.Crashes; +using Bit.Core.Services; using UIKit; using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; @@ -39,7 +39,7 @@ namespace Bit.iOS.Core.Utilities } catch (Exception e) { - Crashes.TrackError(e); + Logger.Instance.Exception(e); } finally { diff --git a/src/iOS/AppDelegate.cs b/src/iOS/AppDelegate.cs index a426a6a3b..aeedeec98 100644 --- a/src/iOS/AppDelegate.cs +++ b/src/iOS/AppDelegate.cs @@ -287,7 +287,7 @@ namespace Bit.iOS } // Migration services - ServiceContainer.Register("logService", new ConsoleLogService()); + ServiceContainer.Register("nativeLogService", new ConsoleLogService()); // Note: This might cause a race condition. Investigate more. Task.Run(() => diff --git a/src/iOS/Services/iOSPushNotificationHandler.cs b/src/iOS/Services/iOSPushNotificationHandler.cs index bfa982432..197a7fe1a 100644 --- a/src/iOS/Services/iOSPushNotificationHandler.cs +++ b/src/iOS/Services/iOSPushNotificationHandler.cs @@ -1,8 +1,8 @@ using System; using System.Diagnostics; using Bit.App.Abstractions; +using Bit.Core.Services; using Foundation; -using Microsoft.AppCenter.Crashes; using Newtonsoft.Json.Linq; using UserNotifications; using Xamarin.Forms; @@ -45,7 +45,7 @@ namespace Bit.iOS.Services } catch (Exception ex) { - Crashes.TrackError(ex); + Logger.Instance.Exception(ex); } }