From bc3979029de78edcf3be2c41e558003544e470b0 Mon Sep 17 00:00:00 2001 From: Robert Vollmer Date: Sat, 24 Feb 2024 04:38:57 +0100 Subject: [PATCH] refactor(mobile): move error details to separate DB column (#6898) * Add "details" column to LoggerMessage * Include error details in log details page * Move error details out of log message * Add error message to mixin * Create extension for HTTP Response logging * Fix analyze errors * format * fix analyze errors, format again --- .../lib/extensions/asyncvalue_extensions.dart | 2 +- .../lib/extensions/response_extensions.dart | 5 ++ mobile/lib/main.dart | 7 +- mobile/lib/mixins/error_logger.mixin.dart | 6 +- .../activities/services/activity.service.dart | 38 ++++---- .../services/image_viewer.service.dart | 10 +-- .../asset_viewer/ui/description_input.dart | 2 +- .../backup/providers/backup.provider.dart | 2 +- .../providers/authentication.provider.dart | 6 +- .../modules/login/services/oauth.service.dart | 2 +- .../map/providers/map_state.provider.dart | 8 +- .../lib/modules/map/services/map.service.dart | 1 + mobile/lib/modules/map/utils/map_utils.dart | 6 +- .../modules/map/widgets/map_asset_grid.dart | 2 +- .../memories/services/memory.service.dart | 2 +- .../partner/services/partner.service.dart | 8 +- .../services/shared_link.service.dart | 8 +- .../providers/trashed_asset.provider.dart | 8 +- .../modules/trash/services/trash.service.dart | 6 +- .../shared/models/logger_message.model.dart | 2 + .../shared/models/logger_message.model.g.dart | Bin 31017 -> 36914 bytes mobile/lib/shared/services/asset.service.dart | 4 +- .../services/immich_logger.service.dart | 3 +- mobile/lib/shared/services/share.service.dart | 6 +- mobile/lib/shared/services/sync.service.dart | 22 +++-- mobile/lib/shared/services/user.service.dart | 4 +- .../lib/shared/views/app_log_detail_page.dart | 84 +++--------------- mobile/lib/shared/views/splash_screen.dart | 6 +- 28 files changed, 106 insertions(+), 154 deletions(-) create mode 100644 mobile/lib/extensions/response_extensions.dart diff --git a/mobile/lib/extensions/asyncvalue_extensions.dart b/mobile/lib/extensions/asyncvalue_extensions.dart index c616835a81..af02ff13c2 100644 --- a/mobile/lib/extensions/asyncvalue_extensions.dart +++ b/mobile/lib/extensions/asyncvalue_extensions.dart @@ -30,7 +30,7 @@ extension LogOnError on AsyncValue { } if (hasError && !hasValue) { - _asyncErrorLogger.severe("$error", error, stackTrace); + _asyncErrorLogger.severe('Could not load value', error, stackTrace); return onError?.call(error, stackTrace) ?? ScaffoldErrorBody(errorMsg: error?.toString()); } diff --git a/mobile/lib/extensions/response_extensions.dart b/mobile/lib/extensions/response_extensions.dart new file mode 100644 index 0000000000..7fec41d07c --- /dev/null +++ b/mobile/lib/extensions/response_extensions.dart @@ -0,0 +1,5 @@ +import 'package:http/http.dart'; + +extension LoggerExtension on Response { + String toLoggerString() => "Status: $statusCode $reasonPhrase\n\n$body"; +} diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index 293867fb32..f20cf7ecc6 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -73,15 +73,14 @@ Future initApp() async { FlutterError.onError = (details) { FlutterError.presentError(details); log.severe( - 'FlutterError - Catch all error: ${details.toString()} - ${details.exception} - ${details.library} - ${details.context} - ${details.stack}', - details, + 'FlutterError - Catch all', + "${details.toString()}\nException: ${details.exception}\nLibrary: ${details.library}\nContext: ${details.context}", details.stack, ); }; PlatformDispatcher.instance.onError = (error, stack) { - log.severe('PlatformDispatcher - Catch all error: $error', error, stack); - debugPrint("PlatformDispatcher - Catch all error: $error $stack"); + log.severe('PlatformDispatcher - Catch all', error, stack); return true; }; diff --git a/mobile/lib/mixins/error_logger.mixin.dart b/mobile/lib/mixins/error_logger.mixin.dart index 38837a716f..9b2bc6f98e 100644 --- a/mobile/lib/mixins/error_logger.mixin.dart +++ b/mobile/lib/mixins/error_logger.mixin.dart @@ -10,13 +10,14 @@ mixin ErrorLoggerMixin { /// Else, logs the error to the overrided logger and returns an AsyncError<> AsyncFuture guardError( Future Function() fn, { + required String errorMessage, Level logLevel = Level.SEVERE, }) async { try { final result = await fn(); return AsyncData(result); } catch (error, stackTrace) { - logger.log(logLevel, "$error", error, stackTrace); + logger.log(logLevel, errorMessage, error, stackTrace); return AsyncError(error, stackTrace); } } @@ -26,12 +27,13 @@ mixin ErrorLoggerMixin { Future logError( Future Function() fn, { required T defaultValue, + required String errorMessage, Level logLevel = Level.SEVERE, }) async { try { return await fn(); } catch (error, stackTrace) { - logger.log(logLevel, "$error", error, stackTrace); + logger.log(logLevel, errorMessage, error, stackTrace); } return defaultValue; } diff --git a/mobile/lib/modules/activities/services/activity.service.dart b/mobile/lib/modules/activities/services/activity.service.dart index db35c17aee..cde98f73ae 100644 --- a/mobile/lib/modules/activities/services/activity.service.dart +++ b/mobile/lib/modules/activities/services/activity.service.dart @@ -24,6 +24,7 @@ class ActivityService with ErrorLoggerMixin { return list != null ? list.map(Activity.fromDto).toList() : []; }, defaultValue: [], + errorMessage: "Failed to get all activities for album $albumId", ); } @@ -35,6 +36,7 @@ class ActivityService with ErrorLoggerMixin { return dto?.comments ?? 0; }, defaultValue: 0, + errorMessage: "Failed to statistics for album $albumId", ); } @@ -45,6 +47,7 @@ class ActivityService with ErrorLoggerMixin { return true; }, defaultValue: false, + errorMessage: "Failed to delete activity", ); } @@ -54,21 +57,24 @@ class ActivityService with ErrorLoggerMixin { String? assetId, String? comment, }) async { - return guardError(() async { - final dto = await _apiService.activityApi.createActivity( - ActivityCreateDto( - albumId: albumId, - type: type == ActivityType.comment - ? ReactionType.comment - : ReactionType.like, - assetId: assetId, - comment: comment, - ), - ); - if (dto != null) { - return Activity.fromDto(dto); - } - throw NoResponseDtoError(); - }); + return guardError( + () async { + final dto = await _apiService.activityApi.createActivity( + ActivityCreateDto( + albumId: albumId, + type: type == ActivityType.comment + ? ReactionType.comment + : ReactionType.like, + assetId: assetId, + comment: comment, + ), + ); + if (dto != null) { + return Activity.fromDto(dto); + } + throw NoResponseDtoError(); + }, + errorMessage: "Failed to create $type for album $albumId", + ); } } diff --git a/mobile/lib/modules/asset_viewer/services/image_viewer.service.dart b/mobile/lib/modules/asset_viewer/services/image_viewer.service.dart index db527c6e23..54682fdeeb 100644 --- a/mobile/lib/modules/asset_viewer/services/image_viewer.service.dart +++ b/mobile/lib/modules/asset_viewer/services/image_viewer.service.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/extensions/response_extensions.dart'; import 'package:immich_mobile/shared/models/asset.dart'; import 'package:immich_mobile/shared/providers/api.provider.dart'; import 'package:immich_mobile/shared/services/api.service.dart'; @@ -39,7 +40,8 @@ class ImageViewerService { final failedResponse = imageResponse.statusCode != 200 ? imageResponse : motionReponse; _log.severe( - "Motion asset download failed with status - ${failedResponse.statusCode} and response - ${failedResponse.body}", + "Motion asset download failed", + failedResponse.toLoggerString(), ); return false; } @@ -75,9 +77,7 @@ class ImageViewerService { .downloadFileWithHttpInfo(asset.remoteId!); if (res.statusCode != 200) { - _log.severe( - "Asset download failed with status - ${res.statusCode} and response - ${res.body}", - ); + _log.severe("Asset download failed", res.toLoggerString()); return false; } @@ -98,7 +98,7 @@ class ImageViewerService { return entity != null; } } catch (error, stack) { - _log.severe("Error saving file ${error.toString()}", error, stack); + _log.severe("Error saving downloaded asset", error, stack); return false; } finally { // Clear temp files diff --git a/mobile/lib/modules/asset_viewer/ui/description_input.dart b/mobile/lib/modules/asset_viewer/ui/description_input.dart index c5972a822d..c5bae07cde 100644 --- a/mobile/lib/modules/asset_viewer/ui/description_input.dart +++ b/mobile/lib/modules/asset_viewer/ui/description_input.dart @@ -48,7 +48,7 @@ class DescriptionInput extends HookConsumerWidget { ); } catch (error, stack) { hasError.value = true; - _log.severe("Error updating description $error", error, stack); + _log.severe("Error updating description", error, stack); ImmichToast.show( context: context, msg: "description_input_submit_error".tr(), diff --git a/mobile/lib/modules/backup/providers/backup.provider.dart b/mobile/lib/modules/backup/providers/backup.provider.dart index a175a17de1..68c6bf9e66 100644 --- a/mobile/lib/modules/backup/providers/backup.provider.dart +++ b/mobile/lib/modules/backup/providers/backup.provider.dart @@ -245,7 +245,7 @@ class BackupNotifier extends StateNotifier { } catch (e, stack) { log.severe( "Failed to get thumbnail for album ${album.name}", - e.toString(), + e, stack, ); } diff --git a/mobile/lib/modules/login/providers/authentication.provider.dart b/mobile/lib/modules/login/providers/authentication.provider.dart index 23dcd50533..e010024332 100644 --- a/mobile/lib/modules/login/providers/authentication.provider.dart +++ b/mobile/lib/modules/login/providers/authentication.provider.dart @@ -108,7 +108,7 @@ class AuthenticationNotifier extends StateNotifier { .then((_) => log.info("Logout was successful for $userEmail")) .onError( (error, stackTrace) => - log.severe("Error logging out $userEmail", error, stackTrace), + log.severe("Logout failed for $userEmail", error, stackTrace), ); await Future.wait([ @@ -129,8 +129,8 @@ class AuthenticationNotifier extends StateNotifier { shouldChangePassword: false, isAuthenticated: false, ); - } catch (e) { - log.severe("Error logging out $e"); + } catch (e, stack) { + log.severe('Logout failed', e, stack); } } diff --git a/mobile/lib/modules/login/services/oauth.service.dart b/mobile/lib/modules/login/services/oauth.service.dart index 8f34c968eb..952c6fa8d6 100644 --- a/mobile/lib/modules/login/services/oauth.service.dart +++ b/mobile/lib/modules/login/services/oauth.service.dart @@ -36,7 +36,7 @@ class OAuthService { ), ); } catch (e, stack) { - log.severe("Error performing oAuthLogin: ${e.toString()}", e, stack); + log.severe("OAuth login failed", e, stack); return null; } } diff --git a/mobile/lib/modules/map/providers/map_state.provider.dart b/mobile/lib/modules/map/providers/map_state.provider.dart index de6265c233..f1d1a4dde4 100644 --- a/mobile/lib/modules/map/providers/map_state.provider.dart +++ b/mobile/lib/modules/map/providers/map_state.provider.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:immich_mobile/extensions/response_extensions.dart'; import 'package:immich_mobile/modules/map/models/map_state.model.dart'; import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart'; import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; @@ -51,7 +52,8 @@ class MapStateNotifier extends _$MapStateNotifier { lightStyleFetched: AsyncError(lightResponse.body, StackTrace.current), ); _log.severe( - "Cannot fetch map light style with status - ${lightResponse.statusCode} and response - ${lightResponse.body}", + "Cannot fetch map light style", + lightResponse.toLoggerString(), ); return; } @@ -77,9 +79,7 @@ class MapStateNotifier extends _$MapStateNotifier { state = state.copyWith( darkStyleFetched: AsyncError(darkResponse.body, StackTrace.current), ); - _log.severe( - "Cannot fetch map dark style with status - ${darkResponse.statusCode} and response - ${darkResponse.body}", - ); + _log.severe("Cannot fetch map dark style", darkResponse.toLoggerString()); return; } diff --git a/mobile/lib/modules/map/services/map.service.dart b/mobile/lib/modules/map/services/map.service.dart index b3a904cbf1..0a5036056a 100644 --- a/mobile/lib/modules/map/services/map.service.dart +++ b/mobile/lib/modules/map/services/map.service.dart @@ -28,6 +28,7 @@ class MapSerivce with ErrorLoggerMixin { return markers?.map(MapMarker.fromDto) ?? []; }, defaultValue: [], + errorMessage: "Failed to get map markers", ); } } diff --git a/mobile/lib/modules/map/utils/map_utils.dart b/mobile/lib/modules/map/utils/map_utils.dart index 46af81ce1d..f6e8349f51 100644 --- a/mobile/lib/modules/map/utils/map_utils.dart +++ b/mobile/lib/modules/map/utils/map_utils.dart @@ -105,10 +105,8 @@ class MapUtils { timeLimit: const Duration(seconds: 5), ); return (currentUserLocation, null); - } catch (error) { - _log.severe( - "Cannot get user's current location due to ${error.toString()}", - ); + } catch (error, stack) { + _log.severe("Cannot get user's current location", error, stack); return (null, LocationPermission.unableToDetermine); } } diff --git a/mobile/lib/modules/map/widgets/map_asset_grid.dart b/mobile/lib/modules/map/widgets/map_asset_grid.dart index d1f187e258..ad90d36ed1 100644 --- a/mobile/lib/modules/map/widgets/map_asset_grid.dart +++ b/mobile/lib/modules/map/widgets/map_asset_grid.dart @@ -147,7 +147,7 @@ class MapAssetGrid extends HookConsumerWidget { }, error: (error, stackTrace) { log.warning( - "Cannot get assets in the current map bounds $error", + "Cannot get assets in the current map bounds", error, stackTrace, ); diff --git a/mobile/lib/modules/memories/services/memory.service.dart b/mobile/lib/modules/memories/services/memory.service.dart index 8d2cd226a4..8ee203e6c9 100644 --- a/mobile/lib/modules/memories/services/memory.service.dart +++ b/mobile/lib/modules/memories/services/memory.service.dart @@ -47,7 +47,7 @@ class MemoryService { return memories.isNotEmpty ? memories : null; } catch (error, stack) { - log.severe("Cannot get memories ${error.toString()}", error, stack); + log.severe("Cannot get memories", error, stack); return null; } } diff --git a/mobile/lib/modules/partner/services/partner.service.dart b/mobile/lib/modules/partner/services/partner.service.dart index 32e500353b..d1e40076c7 100644 --- a/mobile/lib/modules/partner/services/partner.service.dart +++ b/mobile/lib/modules/partner/services/partner.service.dart @@ -40,7 +40,7 @@ class PartnerService { return userDtos.map((u) => User.fromPartnerDto(u)).toList(); } } catch (e) { - _log.warning("failed to get partners for direction $direction:\n$e"); + _log.warning("Failed to get partners for direction $direction", e); } return null; } @@ -51,7 +51,7 @@ class PartnerService { partner.isPartnerSharedBy = false; await _db.writeTxn(() => _db.users.put(partner)); } catch (e) { - _log.warning("failed to remove partner ${partner.id}:\n$e"); + _log.warning("Failed to remove partner ${partner.id}", e); return false; } return true; @@ -66,7 +66,7 @@ class PartnerService { return true; } } catch (e) { - _log.warning("failed to add partner ${partner.id}:\n$e"); + _log.warning("Failed to add partner ${partner.id}", e); } return false; } @@ -81,7 +81,7 @@ class PartnerService { return true; } } catch (e) { - _log.warning("failed to update partner ${partner.id}:\n$e"); + _log.warning("Failed to update partner ${partner.id}", e); } return false; } diff --git a/mobile/lib/modules/shared_link/services/shared_link.service.dart b/mobile/lib/modules/shared_link/services/shared_link.service.dart index 3ea1d411b2..62f431580c 100644 --- a/mobile/lib/modules/shared_link/services/shared_link.service.dart +++ b/mobile/lib/modules/shared_link/services/shared_link.service.dart @@ -22,7 +22,7 @@ class SharedLinkService { ? AsyncData(list.map(SharedLink.fromDto).toList()) : const AsyncData([]); } catch (e, stack) { - _log.severe("failed to fetch shared links - $e"); + _log.severe("Failed to fetch shared links", e, stack); return AsyncError(e, stack); } } @@ -31,7 +31,7 @@ class SharedLinkService { try { return await _apiService.sharedLinkApi.removeSharedLink(id); } catch (e) { - _log.severe("failed to delete shared link id - $id with error - $e"); + _log.severe("Failed to delete shared link id - $id", e); } } @@ -81,7 +81,7 @@ class SharedLinkService { } } } catch (e) { - _log.severe("failed to create shared link with error - $e"); + _log.severe("Failed to create shared link", e); } return null; } @@ -113,7 +113,7 @@ class SharedLinkService { return SharedLink.fromDto(responseDto); } } catch (e) { - _log.severe("failed to update shared link id - $id with error - $e"); + _log.severe("Failed to update shared link id - $id", e); } return null; } diff --git a/mobile/lib/modules/trash/providers/trashed_asset.provider.dart b/mobile/lib/modules/trash/providers/trashed_asset.provider.dart index 177e7d2d4c..165d1c0f74 100644 --- a/mobile/lib/modules/trash/providers/trashed_asset.provider.dart +++ b/mobile/lib/modules/trash/providers/trashed_asset.provider.dart @@ -44,7 +44,7 @@ class TrashNotifier extends StateNotifier { .read(syncServiceProvider) .handleRemoteAssetRemoval(idsToRemove.cast().toList()); } catch (error, stack) { - _log.severe("Cannot empty trash ${error.toString()}", error, stack); + _log.severe("Cannot empty trash", error, stack); } } @@ -70,7 +70,7 @@ class TrashNotifier extends StateNotifier { return isRemoved; } catch (error, stack) { - _log.severe("Cannot empty trash ${error.toString()}", error, stack); + _log.severe("Cannot remove assets", error, stack); } return false; } @@ -93,7 +93,7 @@ class TrashNotifier extends StateNotifier { return true; } } catch (error, stack) { - _log.severe("Cannot restore trash ${error.toString()}", error, stack); + _log.severe("Cannot restore assets", error, stack); } return false; } @@ -123,7 +123,7 @@ class TrashNotifier extends StateNotifier { await _db.assets.putAll(updatedAssets); }); } catch (error, stack) { - _log.severe("Cannot restore trash ${error.toString()}", error, stack); + _log.severe("Cannot restore trash", error, stack); } } } diff --git a/mobile/lib/modules/trash/services/trash.service.dart b/mobile/lib/modules/trash/services/trash.service.dart index 9a9ff5d0b6..96b07ca20f 100644 --- a/mobile/lib/modules/trash/services/trash.service.dart +++ b/mobile/lib/modules/trash/services/trash.service.dart @@ -25,7 +25,7 @@ class TrashService { await _apiService.trashApi.restoreAssets(BulkIdsDto(ids: remoteIds)); return true; } catch (error, stack) { - _log.severe("Cannot restore assets ${error.toString()}", error, stack); + _log.severe("Cannot restore assets", error, stack); return false; } } @@ -34,7 +34,7 @@ class TrashService { try { await _apiService.trashApi.emptyTrash(); } catch (error, stack) { - _log.severe("Cannot empty trash ${error.toString()}", error, stack); + _log.severe("Cannot empty trash", error, stack); } } @@ -42,7 +42,7 @@ class TrashService { try { await _apiService.trashApi.restoreTrash(); } catch (error, stack) { - _log.severe("Cannot restore trash ${error.toString()}", error, stack); + _log.severe("Cannot restore trash", error, stack); } } } diff --git a/mobile/lib/shared/models/logger_message.model.dart b/mobile/lib/shared/models/logger_message.model.dart index cb1d45a580..f657257eab 100644 --- a/mobile/lib/shared/models/logger_message.model.dart +++ b/mobile/lib/shared/models/logger_message.model.dart @@ -9,6 +9,7 @@ part 'logger_message.model.g.dart'; class LoggerMessage { Id id = Isar.autoIncrement; String message; + String? details; @Enumerated(EnumType.ordinal) LogLevel level = LogLevel.INFO; DateTime createdAt; @@ -17,6 +18,7 @@ class LoggerMessage { LoggerMessage({ required this.message, + required this.details, required this.level, required this.createdAt, required this.context1, diff --git a/mobile/lib/shared/models/logger_message.model.g.dart b/mobile/lib/shared/models/logger_message.model.g.dart index a6b960eececf0c732ad724d3921acc5f988c147e..76c823704c741047a7ccd2501f0fbd409729f059 100644 GIT binary patch delta 679 zcmZ4aiE+~crVZw->?x@wiJ3XYlP|K!PL5<1g!2tpbSIm$DouXJDmXcdwT01i^Lti( z=Eb=94{DsIHJ5@yc~NFbYLOn8a;hvz)yPjv zD^4vbjy9RRh|3gc;tj44Mwn@nFLEm}8c$Z?@ntlbT*Tu7l-|y>fN`=EANSP_KTur&V{e`y z&xmjmlEh?3#osVRlaa(XzflrFX!vjP53Yz$^%R_qq+xQs`7x~G|I~M2759%qi1S4+ z<%EW?Cosxl@+R-|mxb$!w<(9S@7YX&v*T?FHlK37Ezj-(jcdi!Ah;xBN(@~5KyDaZ zd~agx=B3GB+2N9?n!+aQ<+H)%kTh<#&Ay1xlvz*#bFjM3BsJN|9ECxf`HIi5Ozy8> co4meM6mH*!iUba**VHE$Y8h_6TkgXM03RFy5dZ)H delta 118 zcmV-+0Ez#ypaQA#0kAg(lb{76lUoH5lhXx+0W`B%1}_7%`U!Rc4nlc!WhifEW^-k9 zb6Yc$unRQ-G_&RlQ~{H04MhPnld=s&0W`Ds4WI#&*bixw#}5&cS`Q1eT@daxvnp2G YAG3mY^#`-`fOH45Ux~~Fv*V6W0seL^b^rhX diff --git a/mobile/lib/shared/services/asset.service.dart b/mobile/lib/shared/services/asset.service.dart index 64a0f28ab7..3086ab9246 100644 --- a/mobile/lib/shared/services/asset.service.dart +++ b/mobile/lib/shared/services/asset.service.dart @@ -90,7 +90,7 @@ class AssetService { return allAssets; } catch (error, stack) { log.severe( - 'Error while getting remote assets: ${error.toString()}', + 'Error while getting remote assets', error, stack, ); @@ -117,7 +117,7 @@ class AssetService { ); return true; } catch (error, stack) { - log.severe("Error deleteAssets ${error.toString()}", error, stack); + log.severe("Error while deleting assets", error, stack); } return false; } diff --git a/mobile/lib/shared/services/immich_logger.service.dart b/mobile/lib/shared/services/immich_logger.service.dart index b66177e570..967ab2d5f2 100644 --- a/mobile/lib/shared/services/immich_logger.service.dart +++ b/mobile/lib/shared/services/immich_logger.service.dart @@ -12,7 +12,7 @@ import 'package:share_plus/share_plus.dart'; /// [ImmichLogger] is a custom logger that is built on top of the [logging] package. /// The logs are written to the database and onto console, using `debugPrint` method. /// -/// The logs are deleted when exceeding the `maxLogEntries` (default 200) property +/// The logs are deleted when exceeding the `maxLogEntries` (default 500) property /// in the class. /// /// Logs can be shared by calling the `shareLogs` method, which will open a share dialog @@ -58,6 +58,7 @@ class ImmichLogger { debugPrint('[${record.level.name}] [${record.time}] ${record.message}'); final lm = LoggerMessage( message: record.message, + details: record.error?.toString(), level: record.level.toLogLevel(), createdAt: record.time, context1: record.loggerName, diff --git a/mobile/lib/shared/services/share.service.dart b/mobile/lib/shared/services/share.service.dart index d7daa51b86..be7c0c168d 100644 --- a/mobile/lib/shared/services/share.service.dart +++ b/mobile/lib/shared/services/share.service.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/extensions/response_extensions.dart'; import 'package:immich_mobile/shared/models/asset.dart'; import 'package:immich_mobile/shared/providers/api.provider.dart'; import 'package:logging/logging.dart'; @@ -41,7 +42,8 @@ class ShareService { if (res.statusCode != 200) { _log.severe( - "Asset download failed with status - ${res.statusCode} and response - ${res.body}", + "Asset download for ${asset.fileName} failed", + res.toLoggerString(), ); continue; } @@ -68,7 +70,7 @@ class ShareService { ); return true; } catch (error) { - _log.severe("Share failed with error $error"); + _log.severe("Share failed", error); } return false; } diff --git a/mobile/lib/shared/services/sync.service.dart b/mobile/lib/shared/services/sync.service.dart index d039b34094..a441091d37 100644 --- a/mobile/lib/shared/services/sync.service.dart +++ b/mobile/lib/shared/services/sync.service.dart @@ -140,7 +140,7 @@ class SyncService { try { await _db.writeTxn(() => a.put(_db)); } on IsarError catch (e) { - _log.severe("Failed to put new asset into db: $e"); + _log.severe("Failed to put new asset into db", e); return false; } return true; @@ -173,7 +173,7 @@ class SyncService { } return false; } on IsarError catch (e) { - _log.severe("Failed to sync remote assets to db: $e"); + _log.severe("Failed to sync remote assets to db", e); } return null; } @@ -232,7 +232,7 @@ class SyncService { await _db.writeTxn(() => _db.assets.deleteAll(idsToDelete)); await upsertAssetsWithExif(toAdd + toUpdate); } on IsarError catch (e) { - _log.severe("Failed to sync remote assets to db: $e"); + _log.severe("Failed to sync remote assets to db", e); } await _updateUserAssetsETag(user, now); return true; @@ -364,7 +364,7 @@ class SyncService { }); _log.info("Synced changes of remote album ${album.name} to DB"); } on IsarError catch (e) { - _log.severe("Failed to sync remote album to database $e"); + _log.severe("Failed to sync remote album to database", e); } if (album.shared || dto.shared) { @@ -441,7 +441,7 @@ class SyncService { assert(ok); _log.info("Removed local album $album from DB"); } catch (e) { - _log.severe("Failed to remove local album $album from DB"); + _log.severe("Failed to remove local album $album from DB", e); } } @@ -577,7 +577,7 @@ class SyncService { }); _log.info("Synced changes of local album ${ape.name} to DB"); } on IsarError catch (e) { - _log.severe("Failed to update synced album ${ape.name} in DB: $e"); + _log.severe("Failed to update synced album ${ape.name} in DB", e); } return true; @@ -623,7 +623,7 @@ class SyncService { }); _log.info("Fast synced local album ${ape.name} to DB"); } on IsarError catch (e) { - _log.severe("Failed to fast sync local album ${ape.name} to DB: $e"); + _log.severe("Failed to fast sync local album ${ape.name} to DB", e); return false; } @@ -656,7 +656,7 @@ class SyncService { await _db.writeTxn(() => _db.albums.store(a)); _log.info("Added a new local album to DB: ${ape.name}"); } on IsarError catch (e) { - _log.severe("Failed to add new local album ${ape.name} to DB: $e"); + _log.severe("Failed to add new local album ${ape.name} to DB", e); } } @@ -706,9 +706,7 @@ class SyncService { }); _log.info("Upserted ${assets.length} assets into the DB"); } on IsarError catch (e) { - _log.severe( - "Failed to upsert ${assets.length} assets into the DB: ${e.toString()}", - ); + _log.severe("Failed to upsert ${assets.length} assets into the DB", e); // give details on the errors assets.sort(Asset.compareByOwnerChecksum); final inDb = await _db.assets.getAllByOwnerIdChecksum( @@ -776,7 +774,7 @@ class SyncService { }); return true; } catch (e) { - _log.severe("Failed to remove all local albums and assets: $e"); + _log.severe("Failed to remove all local albums and assets", e); return false; } } diff --git a/mobile/lib/shared/services/user.service.dart b/mobile/lib/shared/services/user.service.dart index 4d398c3a88..ae65ed31db 100644 --- a/mobile/lib/shared/services/user.service.dart +++ b/mobile/lib/shared/services/user.service.dart @@ -42,7 +42,7 @@ class UserService { final dto = await _apiService.userApi.getAllUsers(isAll); return dto?.map(User.fromUserDto).toList(); } catch (e) { - _log.warning("Failed get all users:\n$e"); + _log.warning("Failed get all users", e); return null; } } @@ -65,7 +65,7 @@ class UserService { ), ); } catch (e) { - _log.warning("Failed to upload profile image:\n$e"); + _log.warning("Failed to upload profile image", e); return null; } } diff --git a/mobile/lib/shared/views/app_log_detail_page.dart b/mobile/lib/shared/views/app_log_detail_page.dart index 126f46c8ff..6b99d7f0af 100644 --- a/mobile/lib/shared/views/app_log_detail_page.dart +++ b/mobile/lib/shared/views/app_log_detail_page.dart @@ -15,7 +15,7 @@ class AppLogDetailPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { var isDarkTheme = context.isDarkTheme; - buildStackMessage(String stackTrace) { + buildTextWithCopyButton(String header, String text) { return Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -28,7 +28,7 @@ class AppLogDetailPage extends HookConsumerWidget { Padding( padding: const EdgeInsets.only(bottom: 8.0), child: Text( - "STACK TRACES", + header, style: TextStyle( fontSize: 12.0, color: context.primaryColor, @@ -38,8 +38,7 @@ class AppLogDetailPage extends HookConsumerWidget { ), IconButton( onPressed: () { - Clipboard.setData(ClipboardData(text: stackTrace)) - .then((_) { + Clipboard.setData(ClipboardData(text: text)).then((_) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( @@ -68,73 +67,7 @@ class AppLogDetailPage extends HookConsumerWidget { child: Padding( padding: const EdgeInsets.all(8.0), child: SelectableText( - stackTrace, - style: const TextStyle( - fontSize: 12.0, - fontWeight: FontWeight.bold, - fontFamily: "Inconsolata", - ), - ), - ), - ), - ], - ), - ); - } - - buildLogMessage(String message) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 8.0), - child: Text( - "MESSAGE", - style: TextStyle( - fontSize: 12.0, - color: context.primaryColor, - fontWeight: FontWeight.bold, - ), - ), - ), - IconButton( - onPressed: () { - Clipboard.setData(ClipboardData(text: message)).then((_) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - "Copied to clipboard", - style: context.textTheme.bodyLarge?.copyWith( - color: context.primaryColor, - ), - ), - ), - ); - }); - }, - icon: Icon( - Icons.copy, - size: 16.0, - color: context.primaryColor, - ), - ), - ], - ), - Container( - decoration: BoxDecoration( - color: isDarkTheme ? Colors.grey[900] : Colors.grey[200], - borderRadius: BorderRadius.circular(15.0), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: SelectableText( - message, + text, style: const TextStyle( fontSize: 12.0, fontWeight: FontWeight.bold, @@ -194,11 +127,16 @@ class AppLogDetailPage extends HookConsumerWidget { body: SafeArea( child: ListView( children: [ - buildLogMessage(logMessage.message), + buildTextWithCopyButton("MESSAGE", logMessage.message), + if (logMessage.details != null) + buildTextWithCopyButton("DETAILS", logMessage.details.toString()), if (logMessage.context1 != null) buildLogContext1(logMessage.context1.toString()), if (logMessage.context2 != null) - buildStackMessage(logMessage.context2.toString()), + buildTextWithCopyButton( + "STACK TRACE", + logMessage.context2.toString(), + ), ], ), ), diff --git a/mobile/lib/shared/views/splash_screen.dart b/mobile/lib/shared/views/splash_screen.dart index 8dddb60aaa..3c0d65bde9 100644 --- a/mobile/lib/shared/views/splash_screen.dart +++ b/mobile/lib/shared/views/splash_screen.dart @@ -35,10 +35,10 @@ class SplashScreenPage extends HookConsumerWidget { deviceIsOffline = true; log.fine("Device seems to be offline upon launch"); } else { - log.severe(e); + log.severe("Failed to resolve endpoint", e); } } catch (e) { - log.severe(e); + log.severe("Failed to resolve endpoint", e); } try { @@ -53,7 +53,7 @@ class SplashScreenPage extends HookConsumerWidget { ref.read(authenticationProvider.notifier).logout(); log.severe( - 'Cannot set success login info: $error', + 'Cannot set success login info', error, stackTrace, );