diff --git a/lib/app/screens/settings_source_screen.dart b/lib/app/screens/settings_source_screen.dart index 6c381fa..3fc9045 100644 --- a/lib/app/screens/settings_source_screen.dart +++ b/lib/app/screens/settings_source_screen.dart @@ -7,6 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import '../../database/dao/sources_dao.dart'; import '../../database/database.dart'; import '../../l10n/generated/app_localizations.dart'; +import '../../util/logger.dart'; import '../state/database.dart'; import '../util/padding.dart'; @@ -216,6 +217,7 @@ class _SettingsSourceScreen extends HookConsumerWidget { } catch (e, _) { // showErrorSnackbar(context, e.toString()); // log.severe('Saving source', e, st); + logger.w('fuck'); error = true; } finally { isSaving.value = false; diff --git a/lib/app/state/database.dart b/lib/app/state/database.dart index e476f67..ce5b1d2 100644 --- a/lib/app/state/database.dart +++ b/lib/app/state/database.dart @@ -6,44 +6,40 @@ import '../../database/database.dart'; final databaseInitializer = FutureProvider((ref) async { final db = SubtracksDatabase(); - await db - .batch((batch) { - batch.insertAll( - db.sources, - [ - SourcesCompanion.insert( - id: Value(1), - name: 'test subsonic', - isActive: Value(true), - ), - SourcesCompanion.insert( - id: Value(2), - name: 'test navidrome', - isActive: Value(null), - ), - ], - mode: InsertMode.insertOrIgnore, - ); - batch.insertAllOnConflictUpdate(db.subsonicSettings, [ - SubsonicSettingsCompanion.insert( - sourceId: Value(1), - address: Uri.parse('http://demo.subsonic.org'), - username: 'guest1', - password: 'guest', - useTokenAuth: Value(true), - ), - SubsonicSettingsCompanion.insert( - sourceId: Value(2), - address: Uri.parse('http://10.0.2.2:4533'), - username: 'admin', - password: 'password', - useTokenAuth: Value(true), - ), - ]); - }) - .onError((error, stack) { - print(error); - }); + await db.batch((batch) { + batch.insertAll( + db.sources, + [ + SourcesCompanion.insert( + id: Value(1), + name: 'test subsonic', + isActive: Value(true), + ), + SourcesCompanion.insert( + id: Value(2), + name: 'test navidrome', + isActive: Value(null), + ), + ], + mode: InsertMode.insertOrIgnore, + ); + batch.insertAllOnConflictUpdate(db.subsonicSettings, [ + SubsonicSettingsCompanion.insert( + sourceId: Value(1), + address: Uri.parse('http://demo.subsonic.org'), + username: 'guest1', + password: 'guest', + useTokenAuth: Value(true), + ), + SubsonicSettingsCompanion.insert( + sourceId: Value(2), + address: Uri.parse('http://10.0.2.2:4533'), + username: 'admin', + password: 'password', + useTokenAuth: Value(true), + ), + ]); + }); return db; }); diff --git a/lib/app/ui/cover_art_theme.dart b/lib/app/ui/cover_art_theme.dart index 8fb58f8..156c7e9 100644 --- a/lib/app/ui/cover_art_theme.dart +++ b/lib/app/ui/cover_art_theme.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import '../../util/logger.dart'; import '../state/source.dart'; import '../util/color_scheme.dart'; import 'theme.dart'; @@ -36,8 +37,12 @@ class CoverArtTheme extends HookConsumerWidget { : 'https://placehold.net/400x400.png', ), ); - } catch (err) { - print(err); + } catch (error, stackTrace) { + logger.w( + 'Could not create color scheme from image provider', + error: error, + stackTrace: stackTrace, + ); return null; } }, diff --git a/lib/database/database.dart b/lib/database/database.dart index 290fdee..b9511a2 100644 --- a/lib/database/database.dart +++ b/lib/database/database.dart @@ -7,6 +7,7 @@ import '../sources/models.dart' as models; import 'converters.dart'; import 'dao/library_dao.dart'; import 'dao/sources_dao.dart'; +import 'log_interceptor.dart'; part 'database.g.dart'; @@ -27,14 +28,14 @@ class SubtracksDatabase extends _$SubtracksDatabase { static QueryExecutor _openConnection() { return driftDatabase( - name: 'my_database', + name: 'subtracks_database', native: DriftNativeOptions( databasePath: () async { final directory = await getApplicationSupportDirectory(); return path.join(directory.absolute.path, 'subtracks.sqlite'); }, ), - ); + ).interceptWith(LogInterceptor()); } @override diff --git a/lib/database/log_interceptor.dart b/lib/database/log_interceptor.dart new file mode 100644 index 0000000..c156874 --- /dev/null +++ b/lib/database/log_interceptor.dart @@ -0,0 +1,120 @@ +import 'dart:async'; + +import 'package:drift/drift.dart'; +import 'package:logger/logger.dart'; + +import '../util/logger.dart'; + +/// https://drift.simonbinder.eu/examples/tracing/ +class LogInterceptor extends QueryInterceptor { + Future _run( + String description, + FutureOr Function() operation, + ) async { + final trace = logger.level >= Level.trace; + final stopwatch = trace ? (Stopwatch()..start()) : null; + + logger.t('Running $description'); + + try { + final result = await operation(); + if (trace) { + logger.t(' => succeeded after ${stopwatch!.elapsedMilliseconds}ms'); + } + return result; + } on Object catch (e, st) { + if (trace) { + logger.t(' => failed after ${stopwatch!.elapsedMilliseconds}ms'); + } + logger.e('Query failed', error: e, stackTrace: st); + rethrow; + } + } + + @override + TransactionExecutor beginTransaction(QueryExecutor parent) { + logger.t('begin'); + return super.beginTransaction(parent); + } + + @override + Future commitTransaction(TransactionExecutor inner) { + return _run('commit', () => inner.send()); + } + + @override + Future rollbackTransaction(TransactionExecutor inner) { + return _run('rollback', () => inner.rollback()); + } + + @override + Future runBatched( + QueryExecutor executor, + BatchedStatements statements, + ) { + return _run( + 'batch with $statements', + () => executor.runBatched(statements), + ); + } + + @override + Future runInsert( + QueryExecutor executor, + String statement, + List args, + ) { + return _run( + '$statement with $args', + () => executor.runInsert(statement, args), + ); + } + + @override + Future runUpdate( + QueryExecutor executor, + String statement, + List args, + ) { + return _run( + '$statement with $args', + () => executor.runUpdate(statement, args), + ); + } + + @override + Future runDelete( + QueryExecutor executor, + String statement, + List args, + ) { + return _run( + '$statement with $args', + () => executor.runDelete(statement, args), + ); + } + + @override + Future runCustom( + QueryExecutor executor, + String statement, + List args, + ) { + return _run( + '$statement with $args', + () => executor.runCustom(statement, args), + ); + } + + @override + Future>> runSelect( + QueryExecutor executor, + String statement, + List args, + ) { + return _run( + '$statement with $args', + () => executor.runSelect(statement, args), + ); + } +} diff --git a/lib/util/logger.dart b/lib/util/logger.dart new file mode 100644 index 0000000..66aa8fb --- /dev/null +++ b/lib/util/logger.dart @@ -0,0 +1,48 @@ +import 'package:logger/logger.dart'; + +class LogLevelFilter extends LogFilter { + @override + bool shouldLog(LogEvent event) { + return event.level >= level!; + } +} + +class SubtracksLogger extends Logger { + SubtracksLogger({ + super.filter, + super.printer, + super.output, + required Level level, + }) : _level = level, + super(level: level); + + final Level _level; + Level get level => _level; +} + +SubtracksLogger createLogger() { + var isDebug = false; + assert(() { + isDebug = true; + return true; + }()); + + if (isDebug) { + return SubtracksLogger( + filter: DevelopmentFilter(), + printer: PrettyPrinter(), + output: ConsoleOutput(), + level: Level.debug, + ); + } + + // TODO: production logger + return SubtracksLogger( + filter: DevelopmentFilter(), + printer: PrettyPrinter(), + output: ConsoleOutput(), + level: Level.debug, + ); +} + +final logger = createLogger(); diff --git a/pubspec.lock b/pubspec.lock index 00bd8d6..1fbb550 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -565,6 +565,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.0" + logger: + dependency: "direct main" + description: + name: logger + sha256: a7967e31b703831a893bbc3c3dd11db08126fe5f369b5c648a36f821979f5be3 + url: "https://pub.dev" + source: hosted + version: "2.6.2" logging: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 81551b2..840dbeb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -26,6 +26,7 @@ dependencies: infinite_scroll_pagination: ^5.1.1 intl: any json_annotation: ^4.9.0 + logger: ^2.6.2 material_color_utilities: ^0.11.1 material_symbols_icons: ^4.2874.0 octo_image: ^2.1.0