From 8f1502244346e2596e1d670f68bdea8127509559 Mon Sep 17 00:00:00 2001 From: problematicconsumer Date: Tue, 3 Oct 2023 21:12:14 +0330 Subject: [PATCH] Fix log and analytics bugs --- lib/bootstrap.dart | 7 +----- .../repository/profiles_repository_impl.dart | 14 +++++------ lib/domain/app/app_failure.dart | 1 + .../connectivity/connection_failure.dart | 1 + lib/domain/core_service_failure.dart | 5 ++-- lib/domain/failures.dart | 5 ++++ lib/domain/profiles/profiles_failure.dart | 1 + lib/features/common/app_update_notifier.dart | 6 ++--- .../connectivity/connectivity_controller.dart | 18 +++++++------- .../notifier/profile_detail_notifier.dart | 6 ++--- .../profiles/notifier/profiles_notifier.dart | 24 +++++++++---------- .../proxies/notifier/proxies_notifier.dart | 18 +++++++------- .../settings/view/per_app_proxy_page.dart | 12 +++++----- lib/utils/sentry_loggy_integration.dart | 3 +++ lib/utils/sentry_utils.dart | 21 ++++++++++++++++ lib/utils/utils.dart | 1 + 16 files changed, 86 insertions(+), 57 deletions(-) create mode 100644 lib/utils/sentry_utils.dart diff --git a/lib/bootstrap.dart b/lib/bootstrap.dart index 7cd4a9f9..8c6d717b 100644 --- a/lib/bootstrap.dart +++ b/lib/bootstrap.dart @@ -67,12 +67,7 @@ Future lazyBootstrap( options.tracesSampleRate = 0.25; options.enableUserInteractionTracing = true; options.addIntegration(sentryLogger); - options.beforeSend = (event, {hint}) { - return switch (event.throwable) { - ExpectedException _ => null, - _ => event, - }; - }; + options.beforeSend = sentryBeforeSend; options.logger = (level, message, {exception, logger, stackTrace}) { if (level == SentryLevel.fatal) { _logger.debug(message); diff --git a/lib/data/repository/profiles_repository_impl.dart b/lib/data/repository/profiles_repository_impl.dart index b414f448..d05ba757 100644 --- a/lib/data/repository/profiles_repository_impl.dart +++ b/lib/data/repository/profiles_repository_impl.dart @@ -73,7 +73,7 @@ class ProfilesRepositoryImpl () async { final existingProfile = await profilesDao.getProfileByUrl(url); if (existingProfile case RemoteProfile()) { - loggy.info("profile with url[$url] already exists, updating"); + loggy.info("profile with same url already exists, updating"); final baseProfile = markAsActive ? existingProfile.copyWith(active: true) : existingProfile; @@ -120,9 +120,9 @@ class ProfilesRepositoryImpl final parseResult = await singbox.parseConfig(path, tempPath, false).run(); return parseResult.fold( - (l) async { - loggy.warning("error parsing config: $l"); - return left(ProfileFailure.invalidConfig(l.msg)); + (err) async { + loggy.warning("error parsing config", err); + return left(ProfileFailure.invalidConfig(err.msg)); }, (_) async { final profile = LocalProfile( @@ -267,9 +267,9 @@ class ProfilesRepositoryImpl final parseResult = await singbox.parseConfig(path, tempPath, false).run(); return parseResult.fold( - (l) async { - loggy.warning("error parsing config: $l"); - return left(ProfileFailure.invalidConfig(l.msg)); + (err) async { + loggy.warning("error parsing config", err); + return left(ProfileFailure.invalidConfig(err.msg)); }, (_) async { final profile = Profile.fromResponse(url, headers); diff --git a/lib/domain/app/app_failure.dart b/lib/domain/app/app_failure.dart index 4f37126e..b340cbbb 100644 --- a/lib/domain/app/app_failure.dart +++ b/lib/domain/app/app_failure.dart @@ -8,6 +8,7 @@ part 'app_failure.freezed.dart'; sealed class AppFailure with _$AppFailure, Failure { const AppFailure._(); + @With() const factory AppFailure.unexpected([ Object? error, StackTrace? stackTrace, diff --git a/lib/domain/connectivity/connection_failure.dart b/lib/domain/connectivity/connection_failure.dart index 1c08e443..0004a1b9 100644 --- a/lib/domain/connectivity/connection_failure.dart +++ b/lib/domain/connectivity/connection_failure.dart @@ -9,6 +9,7 @@ part 'connection_failure.freezed.dart'; sealed class ConnectionFailure with _$ConnectionFailure, Failure { const ConnectionFailure._(); + @With() const factory ConnectionFailure.unexpected([ Object? error, StackTrace? stackTrace, diff --git a/lib/domain/core_service_failure.dart b/lib/domain/core_service_failure.dart index f288ac98..894ba578 100644 --- a/lib/domain/core_service_failure.dart +++ b/lib/domain/core_service_failure.dart @@ -8,9 +8,10 @@ part 'core_service_failure.freezed.dart'; sealed class CoreServiceFailure with _$CoreServiceFailure, Failure { const CoreServiceFailure._(); + @With() const factory CoreServiceFailure.unexpected( - Object error, - StackTrace stackTrace, + Object? error, + StackTrace? stackTrace, ) = UnexpectedCoreServiceFailure; @With() diff --git a/lib/domain/failures.dart b/lib/domain/failures.dart index b8a8ea8e..155c03a4 100644 --- a/lib/domain/failures.dart +++ b/lib/domain/failures.dart @@ -5,6 +5,11 @@ mixin Failure { ({String type, String? message}) present(TranslationsEn t); } +mixin UnexpectedFailure { + Object? get error; + StackTrace? get stackTrace; +} + /// failures ignored by analytics service etc. mixin ExpectedException {} diff --git a/lib/domain/profiles/profiles_failure.dart b/lib/domain/profiles/profiles_failure.dart index c564995e..fdb26cb4 100644 --- a/lib/domain/profiles/profiles_failure.dart +++ b/lib/domain/profiles/profiles_failure.dart @@ -8,6 +8,7 @@ part 'profiles_failure.freezed.dart'; sealed class ProfileFailure with _$ProfileFailure, Failure { const ProfileFailure._(); + @With() const factory ProfileFailure.unexpected([ Object? error, StackTrace? stackTrace, diff --git a/lib/features/common/app_update_notifier.dart b/lib/features/common/app_update_notifier.dart index 6742ac2f..d55c3b9f 100644 --- a/lib/features/common/app_update_notifier.dart +++ b/lib/features/common/app_update_notifier.dart @@ -50,16 +50,16 @@ class AppUpdateNotifier extends _$AppUpdateNotifier with AppLogger { ) .match( (err) { - loggy.warning("failed to get latest version, $err"); + loggy.warning("failed to get latest version", err); return state = AppUpdateState.error(err); }, (remote) { if (remote.version.compareTo(currentVersion) > 0) { - loggy.info("new version available: $remote"); + loggy.debug("new version available: $remote"); return state = AppUpdateState.available(remote); } loggy.info( - "already using latest version[$currentVersion], remote: $remote", + "already using latest version[$currentVersion], remote: [${remote.version}]", ); return state = const AppUpdateState.notAvailable(); }, diff --git a/lib/features/common/connectivity/connectivity_controller.dart b/lib/features/common/connectivity/connectivity_controller.dart index 23df1282..63e287a7 100644 --- a/lib/features/common/connectivity/connectivity_controller.dart +++ b/lib/features/common/connectivity/connectivity_controller.dart @@ -47,9 +47,9 @@ class ConnectivityController extends _$ConnectivityController with AppLogger { return _disconnect(); } loggy.debug("reconnecting, profile: [$profileId]"); - await _core.restart(profileId).mapLeft((l) { - loggy.warning("error reconnecting: $l"); - state = AsyncError(l, StackTrace.current); + await _core.restart(profileId).mapLeft((err) { + loggy.warning("error reconnecting", err); + state = AsyncError(err, StackTrace.current); }).run(); } } @@ -67,16 +67,16 @@ class ConnectivityController extends _$ConnectivityController with AppLogger { Future _connect() async { final activeProfile = await ref.read(activeProfileProvider.future); - await _core.start(activeProfile!.id).mapLeft((l) { - loggy.warning("error connecting: $l"); - state = AsyncError(l, StackTrace.current); + await _core.start(activeProfile!.id).mapLeft((err) { + loggy.warning("error connecting", err); + state = AsyncError(err, StackTrace.current); }).run(); } Future _disconnect() async { - await _core.stop().mapLeft((l) { - loggy.warning("error disconnecting: $l"); - state = AsyncError(l, StackTrace.current); + await _core.stop().mapLeft((err) { + loggy.warning("error disconnecting", err); + state = AsyncError(err, StackTrace.current); }).run(); } } diff --git a/lib/features/profile_detail/notifier/profile_detail_notifier.dart b/lib/features/profile_detail/notifier/profile_detail_notifier.dart index 67c81706..6397164e 100644 --- a/lib/features/profile_detail/notifier/profile_detail_notifier.dart +++ b/lib/features/profile_detail/notifier/profile_detail_notifier.dart @@ -30,9 +30,9 @@ class ProfileDetailNotifier extends _$ProfileDetailNotifier with AppLogger { } final failureOrProfile = await _profilesRepo.get(id).run(); return failureOrProfile.match( - (l) { - loggy.warning('failed to load profile, $l'); - throw l; + (err) { + loggy.warning('failed to load profile', err); + throw err; }, (profile) { if (profile == null) { diff --git a/lib/features/profiles/notifier/profiles_notifier.dart b/lib/features/profiles/notifier/profiles_notifier.dart index a6feefa2..e4425562 100644 --- a/lib/features/profiles/notifier/profiles_notifier.dart +++ b/lib/features/profiles/notifier/profiles_notifier.dart @@ -43,9 +43,9 @@ class ProfilesNotifier extends _$ProfilesNotifier with AppLogger { Future selectActiveProfile(String id) async { loggy.debug('changing active profile to: [$id]'); - return _profilesRepo.setAsActive(id).getOrElse((f) { - loggy.warning('failed to set [$id] as active profile, $f'); - throw f; + return _profilesRepo.setAsActive(id).getOrElse((err) { + loggy.warning('failed to set [$id] as active profile', err); + throw err; }).run(); } @@ -58,9 +58,9 @@ class ProfilesNotifier extends _$ProfilesNotifier with AppLogger { return ref .read(profilesRepositoryProvider) .addByUrl(link.url, markAsActive: markAsActive) - .getOrElse((l) { - loggy.warning("failed to add profile: $l"); - throw l; + .getOrElse((err) { + loggy.warning("failed to add profile", err); + throw err; }).run(); } else if (LinkParser.protocol(rawInput) case (final parsed)?) { loggy.debug("adding profile, content"); @@ -71,9 +71,9 @@ class ProfilesNotifier extends _$ProfilesNotifier with AppLogger { name: parsed.name, markAsActive: markAsActive, ) - .getOrElse((l) { - loggy.warning("failed to add profile: $l"); - throw l; + .getOrElse((err) { + loggy.warning("failed to add profile", err); + throw err; }).run(); } else { loggy.debug("invalid content"); @@ -93,9 +93,9 @@ class ProfilesNotifier extends _$ProfilesNotifier with AppLogger { Future deleteProfile(Profile profile) async { loggy.debug('deleting profile: ${profile.name}'); await _profilesRepo.delete(profile.id).mapLeft( - (f) { - loggy.warning('failed to delete profile, $f'); - throw f; + (err) { + loggy.warning('failed to delete profile', err); + throw err; }, ).run(); } diff --git a/lib/features/proxies/notifier/proxies_notifier.dart b/lib/features/proxies/notifier/proxies_notifier.dart index 53d3a5c0..abbd8912 100644 --- a/lib/features/proxies/notifier/proxies_notifier.dart +++ b/lib/features/proxies/notifier/proxies_notifier.dart @@ -60,9 +60,9 @@ class ProxiesNotifier extends _$ProxiesNotifier with AppLogger { .watchOutbounds() .map( (event) => event.getOrElse( - (f) { - loggy.warning("error receiving proxies: $f"); - throw f; + (err) { + loggy.warning("error receiving proxies", err); + throw err; }, ), ) @@ -105,9 +105,9 @@ class ProxiesNotifier extends _$ProxiesNotifier with AppLogger { await ref .read(coreFacadeProvider) .selectOutbound(groupTag, outboundTag) - .getOrElse((l) { - loggy.warning("error selecting outbound", l); - throw l; + .getOrElse((err) { + loggy.warning("error selecting outbound", err); + throw err; }).run(); state = AsyncData( [ @@ -122,9 +122,9 @@ class ProxiesNotifier extends _$ProxiesNotifier with AppLogger { Future urlTest(String groupTag) async { loggy.debug("testing group: [$groupTag]"); if (state case AsyncData()) { - await ref.read(coreFacadeProvider).urlTest(groupTag).getOrElse((l) { - loggy.warning("error testing group", l); - throw l; + await ref.read(coreFacadeProvider).urlTest(groupTag).getOrElse((err) { + loggy.warning("error testing group", err); + throw err; }).run(); } } diff --git a/lib/features/settings/view/per_app_proxy_page.dart b/lib/features/settings/view/per_app_proxy_page.dart index c1027c80..afcebe82 100644 --- a/lib/features/settings/view/per_app_proxy_page.dart +++ b/lib/features/settings/view/per_app_proxy_page.dart @@ -25,9 +25,9 @@ Future> installedPackagesInfo( return ref .watch(platformSettingsProvider) .getInstalledPackages() - .getOrElse((l) { - _logger.warning("error getting installed packages: $l"); - throw l; + .getOrElse((err) { + _logger.warning("error getting installed packages", err); + throw err; }).run(); } @@ -40,9 +40,9 @@ Future packageIcon( final bytes = await ref .watch(platformSettingsProvider) .getPackageIcon(packageName) - .getOrElse((l) { - _logger.warning("error getting package icon: $l"); - throw l; + .getOrElse((err) { + _logger.warning("error getting package icon", err); + throw err; }).run(); return MemoryImage(bytes); } diff --git a/lib/utils/sentry_loggy_integration.dart b/lib/utils/sentry_loggy_integration.dart index d30f74b4..de4c4a0f 100644 --- a/lib/utils/sentry_loggy_integration.dart +++ b/lib/utils/sentry_loggy_integration.dart @@ -1,3 +1,4 @@ +import 'package:hiddify/utils/sentry_utils.dart'; import 'package:loggy/loggy.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; @@ -33,6 +34,8 @@ class SentryLoggyIntegration extends LoggyPrinter @override Future onLog(LogRecord record) async { + if (!canSendEvent(record.error)) return; + if (_shouldLog(record.level, _minEventLevel)) { await _hub.captureEvent( record.toEvent(), diff --git a/lib/utils/sentry_utils.dart b/lib/utils/sentry_utils.dart new file mode 100644 index 00000000..b83b82d3 --- /dev/null +++ b/lib/utils/sentry_utils.dart @@ -0,0 +1,21 @@ +import 'dart:io'; + +import 'package:dio/dio.dart'; +import 'package:hiddify/domain/failures.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; + +FutureOr sentryBeforeSend(SentryEvent event, {Hint? hint}) { + if (canSendEvent(event.throwable)) return event; + return null; +} + +bool canSendEvent(dynamic throwable) { + return switch (throwable) { + UnexpectedFailure(:final error) => canSendEvent(error), + DioException _ => false, + SocketException _ => false, + ExpectedException _ => false, + _ => true, + }; +} diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index d7a91f3c..de5fe51f 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -13,6 +13,7 @@ export 'placeholders.dart'; export 'platform_utils.dart'; export 'sentry_loggy_integration.dart'; export 'sentry_riverpod_observer.dart'; +export 'sentry_utils.dart'; export 'text_utils.dart'; export 'uri_utils.dart'; export 'validators.dart';