diff --git a/lib/backend/database/firebase/firestore_caching_data_interface.dart b/lib/backend/database/firebase/firestore_caching_data_interface.dart index d4222b8..eb67e24 100644 --- a/lib/backend/database/firebase/firestore_caching_data_interface.dart +++ b/lib/backend/database/firebase/firestore_caching_data_interface.dart @@ -58,7 +58,7 @@ class FirestoreCachingDataInterface Future> get() async { if (await Hive.boxExists(name)) { final profiler = - await FredericProfiler.trackFirebase('Load cached $name from Box'); + await FredericProfiler.track('Load cached $name from Box'); if (_box == null) _box = await Hive.openBox(name); if (_box!.isEmpty) { // If the stored box is empty it is possible that the box was corrupted @@ -69,7 +69,7 @@ class FirestoreCachingDataInterface return reload(); } } - profiler?.stop(); + profiler.stop(); return _box!.values.toList(); } else { return reload(); diff --git a/lib/backend/sets/set_time_series_data_representation.dart b/lib/backend/sets/set_time_series_data_representation.dart index 8d99baf..319b1af 100644 --- a/lib/backend/sets/set_time_series_data_representation.dart +++ b/lib/backend/sets/set_time_series_data_representation.dart @@ -50,8 +50,8 @@ class SetTimeSeriesDataRepresentation implements SetDataRepresentation { } if (_box!.isEmpty) { - profiler = await FredericProfiler.trackFirebase( - 'Calculate SetVolumeDataRepresentation'); + profiler = + await FredericProfiler.track('Calculate SetVolumeDataRepresentation'); DateTime earliestSet = DateTime.now(); DateTime latestSet = DateTime.fromMillisecondsSinceEpoch(0); @@ -118,8 +118,8 @@ class SetTimeSeriesDataRepresentation implements SetDataRepresentation { // await _box!.put(1, Map>.of(_optimizedBestSetData)); // await _box!.put(2, {1: _optimizedBestSetDataLastDate}); } else { - profiler = await FredericProfiler.trackFirebase( - 'Load SetVolumeDataRepresentation'); + profiler = + await FredericProfiler.track('Load SetVolumeDataRepresentation'); final data = _box!.getAt(0); if (data == null) { return initialize(clearCachedData: true); diff --git a/lib/backend/util/frederic_profiler.dart b/lib/backend/util/frederic_profiler.dart index cea3ae4..3fbe7db 100644 --- a/lib/backend/util/frederic_profiler.dart +++ b/lib/backend/util/frederic_profiler.dart @@ -1,19 +1,16 @@ import 'dart:collection'; import 'package:easy_localization/easy_localization.dart'; -import 'package:firebase_performance/firebase_performance.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; class FredericProfiler { static final bool profilerDisabled = false; - static final FirebasePerformance firebasePerformance = - FirebasePerformance.instance; + final ISentrySpan transaction; - Trace? _trace; - - FredericProfiler.track(this.component, {this.description}) { + FredericProfiler.track(this.component, {this.description}) + : transaction = Sentry.startTransaction(component, 'FredericProfiler') { if (profilerDisabled) return; _stopwatch = Stopwatch(); @@ -24,20 +21,6 @@ class FredericProfiler { _profilers[component]!.add(this); } - static Future? trackFirebase(String name, - [String? description]) async { - final profiler = FredericProfiler.track(name, description: description); - profiler._trace = - firebasePerformance.newTrace(kReleaseMode ? name : '[D]: $name'); - profiler._trace?.start(); - - return profiler; - } - - void setMetric(String name, int value) { - _trace?.setMetric(name, value); - } - static HashMap> _profilers = HashMap>(); @@ -151,7 +134,7 @@ class FredericProfiler { void stop() { if (profilerDisabled) return; _stopwatch!.stop(); - _trace?.stop(); + transaction.finish(); } static final timeFormat = diff --git a/lib/main.dart b/lib/main.dart index 4ec30cd..86b7d11 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,10 +1,7 @@ import 'dart:io'; -import 'dart:isolate'; import 'package:easy_localization/easy_localization.dart'; import 'package:firebase_core/firebase_core.dart'; -import 'package:firebase_crashlytics/firebase_crashlytics.dart'; -import 'package:firebase_performance/firebase_performance.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -24,6 +21,7 @@ import 'package:frederic/frederic_main_app.dart'; import 'package:frederic/theme/frederic_theme.dart'; import 'package:get_it/get_it.dart'; import 'package:hive_flutter/hive_flutter.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:sheet/route.dart'; import 'package:system_theme/system_theme.dart'; @@ -43,8 +41,7 @@ void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); - startupTimeProfiler = - await FredericProfiler.trackFirebase('App Startup Time'); + startupTimeProfiler = await FredericProfiler.track('App Startup Time'); final timeUntilRunApp = FredericProfiler.track('time until runApp()'); // TODO: may be a race condition @@ -59,28 +56,8 @@ void main() async { yield LicenseEntryWithLineBreaks(['google_fonts'], license); }); - // == Record all errors outside a Flutter context == - Isolate.current.addErrorListener(RawReceivePort((pair) async { - final List errorAndStacktrace = pair; - print('ERROR IN CURRENT/MAIN ISOLATE'); - print(errorAndStacktrace.first); - print(errorAndStacktrace.last); - - await FirebaseCrashlytics.instance.recordError( - errorAndStacktrace.first, - errorAndStacktrace.last, - ); - }).sendPort); - await EasyLocalization.ensureInitialized(); - // == Crashlytics & Performance == - if (kReleaseMode) { - FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterError; - } - - // == Crashlytics & Performance == End == - // == Hive == Register Adapters == await Hive.initFlutter(); if (!Hive.isAdapterRegistered(1)) @@ -114,21 +91,21 @@ void main() async { // == Load Startup Preferences == End == - // == Disable Crashlytics in debug mode - if (kDebugMode) { - await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(false); - } else { - await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); - } - await FirebasePerformance.instance.setPerformanceCollectionEnabled(true); - timeUntilRunApp.stop(); - runApp(EasyLocalization( - supportedLocales: [Locale('en'), Locale('de')], - fallbackLocale: Locale('en'), - useOnlyLangCode: true, - path: 'assets/translations', - child: FredericBase())); + + SentryFlutter.init( + (options) => options + ..dsn = + 'https://e0c3b76f6f3d43cc99ed5043389ae4fa@performance.neverskipfitness.com/1' + ..tracesSampleRate = 1 //0.01 // Performance trace 1% of events + ..enableAutoSessionTracking = false + ..environment = (kReleaseMode ? 'production' : 'development'), + appRunner: () => runApp(EasyLocalization( + supportedLocales: [Locale('en'), Locale('de')], + fallbackLocale: Locale('en'), + useOnlyLangCode: true, + path: 'assets/translations', + child: FredericBase()))); } class FredericBase extends StatefulWidget { diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 7d6bc49..693f7a3 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -1,5 +1,4 @@ import 'package:easy_localization/easy_localization.dart'; -import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -124,11 +123,6 @@ class SettingsScreen extends StatelessWidget { icon: Icons.admin_panel_settings_outlined, onTap: () => Navigator.of(context).pushNamed('/admin'), ), - SettingsElement( - text: 'Crash the app', - icon: Icons.fire_extinguisher, - onTap: () => FirebaseCrashlytics.instance.crash(), - ), ]), if (kDebugMode || user.isDeveloper) SliverPadding(padding: const EdgeInsets.symmetric(vertical: 16)), diff --git a/lib/widgets/activity_screen/activity_filter_segment.dart b/lib/widgets/activity_screen/activity_filter_segment.dart index eff86d4..33d15b0 100644 --- a/lib/widgets/activity_screen/activity_filter_segment.dart +++ b/lib/widgets/activity_screen/activity_filter_segment.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:frederic/backend/util/frederic_profiler.dart'; import 'package:frederic/main.dart'; import 'package:frederic/widgets/activity_screen/activity_musclegroup_button.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; import '../../state/activity_filter_controller.dart'; import '../standard_elements/frederic_heading.dart'; @@ -143,9 +144,11 @@ class _ActivityFilterSegmentState extends State { ), ), ); - } catch (e) { + } catch (e, stackTrace) { print(e); FredericProfiler.log('muscle group filter segment: ' + e.toString()); + Sentry.captureException(e, stackTrace: stackTrace); + return SliverToBoxAdapter( child: Container( child: kDebugMode ? Text(e.toString()) : Container(height: 16), diff --git a/pubspec.yaml b/pubspec.yaml index c6f63cf..c94bc45 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,8 +27,6 @@ dependencies: cloud_firestore: ^4.11.0 firebase_storage: ^11.3.1 firebase_app_check: ^0.2.1+1 - firebase_crashlytics: ^3.4.1 - firebase_performance: ^0.9.3+1 google_sign_in: ^6.1.5 sign_in_with_apple: ^5.0.0 @@ -74,6 +72,7 @@ dependencies: easy_localization_loader: ^2.0.0 date_format: ^2.0.7 + sentry_flutter: ^7.17.0 dev_dependencies: