From 921636a0912990173c0d312f4da3092ad87b95bc Mon Sep 17 00:00:00 2001 From: problematicconsumer Date: Mon, 18 Sep 2023 14:01:44 +0330 Subject: [PATCH] fix: minor bugs --- lib/bootstrap.dart | 40 +++++--- lib/core/router/app_router.dart | 4 + lib/data/data_providers.dart | 3 +- lib/data/repository/config_options_store.dart | 5 +- lib/utils/alerts.dart | 4 +- lib/utils/custom_log_printer.dart | 15 ++- lib/utils/sentry_loggy_integration.dart | 95 +++++++++++++++++++ lib/utils/utils.dart | 1 + pubspec.lock | 8 ++ pubspec.yaml | 3 + 10 files changed, 157 insertions(+), 21 deletions(-) create mode 100644 lib/utils/sentry_loggy_integration.dart diff --git a/lib/bootstrap.dart b/lib/bootstrap.dart index 4a0e26b8..9cd2dbd8 100644 --- a/lib/bootstrap.dart +++ b/lib/bootstrap.dart @@ -23,8 +23,9 @@ import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:window_manager/window_manager.dart'; -final _loggy = Loggy('bootstrap'); +final _logger = Loggy('bootstrap'); const _testCrashReport = false; +final _loggers = MultiLogPrinter(const PrettyPrinter(), []); Future lazyBootstrap( WidgetsBinding widgetsBinding, @@ -32,6 +33,7 @@ Future lazyBootstrap( ) async { FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); if (PlatformUtils.isDesktop) await windowManager.ensureInitialized(); + Loggy.initLoggy(); final appInfo = await AppRepositoryImpl.getAppInfo(env); final sharedPreferences = await SharedPreferences.getInstance(); @@ -43,6 +45,8 @@ Future lazyBootstrap( ); final enableAnalytics = container.read(enableAnalyticsProvider); + final sentryLogger = SentryLoggyIntegration(); + _loggers.addPrinter(sentryLogger); await SentryFlutter.init( (options) { @@ -52,8 +56,14 @@ Future lazyBootstrap( options.dsn = ""; } - options.environment = env.toString(); + options.environment = env.name; + options.dist = appInfo.release.name; options.debug = kDebugMode; + options.enableNativeCrashHandling = true; + options.enableNdkScopeSync = true; + options.attachThreads = true; + options.tracesSampleRate = 0.25; + options.addIntegration(sentryLogger); }, appRunner: () => _lazyBootstrap(widgetsBinding, container, env), ); @@ -70,7 +80,7 @@ Future _lazyBootstrap( await filesEditor.init(); initLoggers(container.read, debug); - _loggy.info( + _logger.info( "os: [${Platform.operatingSystem}](${Platform.operatingSystemVersion}), processor count [${Platform.numberOfProcessors}]", ); @@ -89,7 +99,9 @@ Future _lazyBootstrap( runApp( ProviderScope( parent: container, - child: const AppView(), + child: SentryUserInteractionWidget( + child: const AppView(), + ), ), ); @@ -102,13 +114,13 @@ void initLoggers( ) { final logLevel = debug ? LogLevel.all : LogLevel.info; final logToFile = debug || (!Platform.isAndroid && !Platform.isIOS); + if (logToFile) { + _loggers.addPrinter( + FileLogPrinter(read(filesEditorServiceProvider).appLogsPath), + ); + } Loggy.initLoggy( - logPrinter: MultiLogPrinter( - const PrettyPrinter(), - logToFile - ? FileLogPrinter(read(filesEditorServiceProvider).appLogsPath) - : null, - ), + logPrinter: _loggers, logOptions: LogOptions(logLevel), ); } @@ -116,19 +128,19 @@ void initLoggers( Future initAppServices( Result Function(ProviderListenable) read, ) async { - _loggy.debug("initializing app services"); + _logger.debug("initializing app services"); await Future.wait( [ read(singboxServiceProvider).init(), ], ); - _loggy.debug('initialized app services'); + _logger.debug('initialized app services'); } Future initControllers( Result Function(ProviderListenable) read, ) async { - _loggy.debug("initializing controllers"); + _logger.debug("initializing controllers"); await Future.wait( [ read(activeProfileProvider.future), @@ -136,5 +148,5 @@ Future initControllers( if (PlatformUtils.isDesktop) read(systemTrayControllerProvider.future), ], ); - _loggy.debug("initialized base controllers"); + _logger.debug("initialized base controllers"); } diff --git a/lib/core/router/app_router.dart b/lib/core/router/app_router.dart index 81b76860..f8bd47bd 100644 --- a/lib/core/router/app_router.dart +++ b/lib/core/router/app_router.dart @@ -4,6 +4,7 @@ import 'package:hiddify/core/prefs/prefs.dart'; import 'package:hiddify/core/router/routes/routes.dart'; import 'package:hiddify/services/deep_link_service.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; part 'app_router.g.dart'; @@ -30,6 +31,9 @@ GoRouter router(RouterRef ref) { initialLocation: initialLocation, debugLogDiagnostics: true, routes: $routes, + observers: [ + SentryNavigatorObserver(), + ], redirect: (context, state) { if (!introCompleted && state.uri.path != const IntroRoute().location) { return const IntroRoute().location; diff --git a/lib/data/data_providers.dart b/lib/data/data_providers.dart index 4e669dba..6d81974b 100644 --- a/lib/data/data_providers.dart +++ b/lib/data/data_providers.dart @@ -12,6 +12,7 @@ import 'package:hiddify/domain/core_facade.dart'; import 'package:hiddify/domain/profiles/profiles.dart'; import 'package:hiddify/services/service_providers.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:sentry_dio/sentry_dio.dart'; import 'package:shared_preferences/shared_preferences.dart'; part 'data_providers.g.dart'; @@ -31,7 +32,7 @@ Dio dio(DioRef ref) => Dio( "User-Agent": ref.watch(appInfoProvider).userAgent, }, ), - ); + )..addSentry(); @Riverpod(keepAlive: true) ProfilesDao profilesDao(ProfilesDaoRef ref) => ProfilesDao( diff --git a/lib/data/repository/config_options_store.dart b/lib/data/repository/config_options_store.dart index 5cc6e763..8249ecb2 100644 --- a/lib/data/repository/config_options_store.dart +++ b/lib/data/repository/config_options_store.dart @@ -1,3 +1,4 @@ +import 'package:hiddify/core/prefs/prefs.dart'; import 'package:hiddify/domain/singbox/config_options.dart'; import 'package:hiddify/utils/pref_notifier.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -67,7 +68,9 @@ final setSystemProxyStore = @riverpod ConfigOptions configOptions(ConfigOptionsRef ref) => ConfigOptions( - executeConfigAsIs: ref.watch(executeConfigAsIs), + executeConfigAsIs: ref.watch(debugModeNotifierProvider) + ? ref.watch(executeConfigAsIs) + : false, logLevel: ref.watch(logLevelStore), resolveDestination: ref.watch(resolveDestinationStore), ipv6Mode: ref.watch(ipv6ModeStore), diff --git a/lib/utils/alerts.dart b/lib/utils/alerts.dart index b5b7b59a..e9a7add2 100644 --- a/lib/utils/alerts.dart +++ b/lib/utils/alerts.dart @@ -104,8 +104,8 @@ class CustomToast extends StatelessWidget { } void show(BuildContext context) { - FToast().init(context); - FToast().showToast( + final fToast = FToast().init(context); + fToast.showToast( child: this, gravity: ToastGravity.BOTTOM, toastDuration: duration, diff --git a/lib/utils/custom_log_printer.dart b/lib/utils/custom_log_printer.dart index ecbd04f8..cee5ba24 100644 --- a/lib/utils/custom_log_printer.dart +++ b/lib/utils/custom_log_printer.dart @@ -3,15 +3,24 @@ import 'dart:io'; import 'package:loggy/loggy.dart'; class MultiLogPrinter extends LoggyPrinter { - MultiLogPrinter(this.consolePrinter, this.filePrinter); + MultiLogPrinter( + this.consolePrinter, + this.otherPrinters, + ); final LoggyPrinter consolePrinter; - final LoggyPrinter? filePrinter; + List otherPrinters; + + void addPrinter(LoggyPrinter printer) { + otherPrinters.add(printer); + } @override void onLog(LogRecord record) { consolePrinter.onLog(record); - filePrinter?.onLog(record); + for (final printer in otherPrinters) { + printer.onLog(record); + } } } diff --git a/lib/utils/sentry_loggy_integration.dart b/lib/utils/sentry_loggy_integration.dart new file mode 100644 index 00000000..445cacb6 --- /dev/null +++ b/lib/utils/sentry_loggy_integration.dart @@ -0,0 +1,95 @@ +import 'package:loggy/loggy.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; + +// modified version of https://github.com/getsentry/sentry-dart/tree/main/logging +class SentryLoggyIntegration extends LoggyPrinter + implements Integration { + SentryLoggyIntegration({ + LogLevel minBreadcrumbLevel = LogLevel.info, + LogLevel minEventLevel = LogLevel.error, + }) : _minBreadcrumbLevel = minBreadcrumbLevel, + _minEventLevel = minEventLevel; + + final LogLevel _minBreadcrumbLevel; + final LogLevel _minEventLevel; + + late Hub _hub; + + @override + void call(Hub hub, SentryOptions options) { + _hub = hub; + options.sdk.addIntegration('LoggyIntegration'); + } + + @override + Future close() async {} + + bool _shouldLog(LogLevel logLevel, LogLevel minLevel) { + if (logLevel == LogLevel.off) { + return false; + } + return logLevel.priority >= minLevel.priority; + } + + @override + Future onLog(LogRecord record) async { + if (_shouldLog(record.level, _minEventLevel)) { + await _hub.captureEvent( + record.toEvent(), + stackTrace: record.stackTrace, + hint: Hint.withMap({TypeCheckHint.record: record}), + ); + } + + if (_shouldLog(record.level, _minBreadcrumbLevel)) { + await _hub.addBreadcrumb( + record.toBreadcrumb(), + hint: Hint.withMap({TypeCheckHint.record: record}), + ); + } + } +} + +extension LogRecordX on LogRecord { + Breadcrumb toBreadcrumb() { + return Breadcrumb( + category: 'log', + type: 'debug', + timestamp: time.toUtc(), + level: level.toSentryLevel(), + message: message, + data: { + if (object != null) 'LogRecord.object': object!, + if (error != null) 'LogRecord.error': error!, + if (stackTrace != null) 'LogRecord.stackTrace': stackTrace!, + 'LogRecord.loggerName': loggerName, + 'LogRecord.sequenceNumber': sequenceNumber, + }, + ); + } + + SentryEvent toEvent() { + return SentryEvent( + timestamp: time.toUtc(), + logger: loggerName, + level: level.toSentryLevel(), + message: SentryMessage(message), + throwable: error, + // ignore: deprecated_member_use + extra: { + if (object != null) 'LogRecord.object': object!, + 'LogRecord.sequenceNumber': sequenceNumber, + }, + ); + } +} + +extension LogLevelX on LogLevel { + SentryLevel? toSentryLevel() => switch (this) { + LogLevel.all || LogLevel.debug => SentryLevel.debug, + LogLevel.info => SentryLevel.info, + LogLevel.warning => SentryLevel.warning, + LogLevel.error => SentryLevel.error, + _ => null, + }; +} diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index f1d68690..3e28a1fa 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -10,6 +10,7 @@ export 'mutation_state.dart'; export 'number_formatters.dart'; export 'placeholders.dart'; export 'platform_utils.dart'; +export 'sentry_loggy_integration.dart'; export 'text_utils.dart'; export 'uri_utils.dart'; export 'validators.dart'; diff --git a/pubspec.lock b/pubspec.lock index 0c3767c3..c1858afd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1053,6 +1053,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.10.1" + sentry_dio: + dependency: "direct main" + description: + name: sentry_dio + sha256: "4455340dce8abf0790155fd0f6a8bcd84ab505417f2106fdc9582efe4fb4f350" + url: "https://pub.dev" + source: hosted + version: "7.10.1" sentry_flutter: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 6ddadd64..75f137b3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -54,7 +54,10 @@ dependencies: url_launcher: ^6.1.14 vclibs: ^0.1.0 launch_at_startup: ^0.2.2 + + # analytics sentry_flutter: ^7.10.1 + sentry_dio: ^7.10.1 # utils combine: ^0.5.6