mirror of
https://github.com/immich-app/immich.git
synced 2025-04-14 12:08:54 +02:00
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
This commit is contained in:
parent
878932f87e
commit
bc3979029d
@ -30,7 +30,7 @@ extension LogOnError<T> on AsyncValue<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hasError && !hasValue) {
|
if (hasError && !hasValue) {
|
||||||
_asyncErrorLogger.severe("$error", error, stackTrace);
|
_asyncErrorLogger.severe('Could not load value', error, stackTrace);
|
||||||
return onError?.call(error, stackTrace) ??
|
return onError?.call(error, stackTrace) ??
|
||||||
ScaffoldErrorBody(errorMsg: error?.toString());
|
ScaffoldErrorBody(errorMsg: error?.toString());
|
||||||
}
|
}
|
||||||
|
5
mobile/lib/extensions/response_extensions.dart
Normal file
5
mobile/lib/extensions/response_extensions.dart
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import 'package:http/http.dart';
|
||||||
|
|
||||||
|
extension LoggerExtension on Response {
|
||||||
|
String toLoggerString() => "Status: $statusCode $reasonPhrase\n\n$body";
|
||||||
|
}
|
@ -73,15 +73,14 @@ Future<void> initApp() async {
|
|||||||
FlutterError.onError = (details) {
|
FlutterError.onError = (details) {
|
||||||
FlutterError.presentError(details);
|
FlutterError.presentError(details);
|
||||||
log.severe(
|
log.severe(
|
||||||
'FlutterError - Catch all error: ${details.toString()} - ${details.exception} - ${details.library} - ${details.context} - ${details.stack}',
|
'FlutterError - Catch all',
|
||||||
details,
|
"${details.toString()}\nException: ${details.exception}\nLibrary: ${details.library}\nContext: ${details.context}",
|
||||||
details.stack,
|
details.stack,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
PlatformDispatcher.instance.onError = (error, stack) {
|
PlatformDispatcher.instance.onError = (error, stack) {
|
||||||
log.severe('PlatformDispatcher - Catch all error: $error', error, stack);
|
log.severe('PlatformDispatcher - Catch all', error, stack);
|
||||||
debugPrint("PlatformDispatcher - Catch all error: $error $stack");
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,13 +10,14 @@ mixin ErrorLoggerMixin {
|
|||||||
/// Else, logs the error to the overrided logger and returns an AsyncError<>
|
/// Else, logs the error to the overrided logger and returns an AsyncError<>
|
||||||
AsyncFuture<T> guardError<T>(
|
AsyncFuture<T> guardError<T>(
|
||||||
Future<T> Function() fn, {
|
Future<T> Function() fn, {
|
||||||
|
required String errorMessage,
|
||||||
Level logLevel = Level.SEVERE,
|
Level logLevel = Level.SEVERE,
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
final result = await fn();
|
final result = await fn();
|
||||||
return AsyncData(result);
|
return AsyncData(result);
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stackTrace) {
|
||||||
logger.log(logLevel, "$error", error, stackTrace);
|
logger.log(logLevel, errorMessage, error, stackTrace);
|
||||||
return AsyncError(error, stackTrace);
|
return AsyncError(error, stackTrace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,12 +27,13 @@ mixin ErrorLoggerMixin {
|
|||||||
Future<T> logError<T>(
|
Future<T> logError<T>(
|
||||||
Future<T> Function() fn, {
|
Future<T> Function() fn, {
|
||||||
required T defaultValue,
|
required T defaultValue,
|
||||||
|
required String errorMessage,
|
||||||
Level logLevel = Level.SEVERE,
|
Level logLevel = Level.SEVERE,
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
return await fn();
|
return await fn();
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stackTrace) {
|
||||||
logger.log(logLevel, "$error", error, stackTrace);
|
logger.log(logLevel, errorMessage, error, stackTrace);
|
||||||
}
|
}
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ class ActivityService with ErrorLoggerMixin {
|
|||||||
return list != null ? list.map(Activity.fromDto).toList() : [];
|
return list != null ? list.map(Activity.fromDto).toList() : [];
|
||||||
},
|
},
|
||||||
defaultValue: [],
|
defaultValue: [],
|
||||||
|
errorMessage: "Failed to get all activities for album $albumId",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,6 +36,7 @@ class ActivityService with ErrorLoggerMixin {
|
|||||||
return dto?.comments ?? 0;
|
return dto?.comments ?? 0;
|
||||||
},
|
},
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
|
errorMessage: "Failed to statistics for album $albumId",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +47,7 @@ class ActivityService with ErrorLoggerMixin {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
|
errorMessage: "Failed to delete activity",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,21 +57,24 @@ class ActivityService with ErrorLoggerMixin {
|
|||||||
String? assetId,
|
String? assetId,
|
||||||
String? comment,
|
String? comment,
|
||||||
}) async {
|
}) async {
|
||||||
return guardError(() async {
|
return guardError(
|
||||||
final dto = await _apiService.activityApi.createActivity(
|
() async {
|
||||||
ActivityCreateDto(
|
final dto = await _apiService.activityApi.createActivity(
|
||||||
albumId: albumId,
|
ActivityCreateDto(
|
||||||
type: type == ActivityType.comment
|
albumId: albumId,
|
||||||
? ReactionType.comment
|
type: type == ActivityType.comment
|
||||||
: ReactionType.like,
|
? ReactionType.comment
|
||||||
assetId: assetId,
|
: ReactionType.like,
|
||||||
comment: comment,
|
assetId: assetId,
|
||||||
),
|
comment: comment,
|
||||||
);
|
),
|
||||||
if (dto != null) {
|
);
|
||||||
return Activity.fromDto(dto);
|
if (dto != null) {
|
||||||
}
|
return Activity.fromDto(dto);
|
||||||
throw NoResponseDtoError();
|
}
|
||||||
});
|
throw NoResponseDtoError();
|
||||||
|
},
|
||||||
|
errorMessage: "Failed to create $type for album $albumId",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.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/models/asset.dart';
|
||||||
import 'package:immich_mobile/shared/providers/api.provider.dart';
|
import 'package:immich_mobile/shared/providers/api.provider.dart';
|
||||||
import 'package:immich_mobile/shared/services/api.service.dart';
|
import 'package:immich_mobile/shared/services/api.service.dart';
|
||||||
@ -39,7 +40,8 @@ class ImageViewerService {
|
|||||||
final failedResponse =
|
final failedResponse =
|
||||||
imageResponse.statusCode != 200 ? imageResponse : motionReponse;
|
imageResponse.statusCode != 200 ? imageResponse : motionReponse;
|
||||||
_log.severe(
|
_log.severe(
|
||||||
"Motion asset download failed with status - ${failedResponse.statusCode} and response - ${failedResponse.body}",
|
"Motion asset download failed",
|
||||||
|
failedResponse.toLoggerString(),
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -75,9 +77,7 @@ class ImageViewerService {
|
|||||||
.downloadFileWithHttpInfo(asset.remoteId!);
|
.downloadFileWithHttpInfo(asset.remoteId!);
|
||||||
|
|
||||||
if (res.statusCode != 200) {
|
if (res.statusCode != 200) {
|
||||||
_log.severe(
|
_log.severe("Asset download failed", res.toLoggerString());
|
||||||
"Asset download failed with status - ${res.statusCode} and response - ${res.body}",
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ class ImageViewerService {
|
|||||||
return entity != null;
|
return entity != null;
|
||||||
}
|
}
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
_log.severe("Error saving file ${error.toString()}", error, stack);
|
_log.severe("Error saving downloaded asset", error, stack);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
// Clear temp files
|
// Clear temp files
|
||||||
|
@ -48,7 +48,7 @@ class DescriptionInput extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
hasError.value = true;
|
hasError.value = true;
|
||||||
_log.severe("Error updating description $error", error, stack);
|
_log.severe("Error updating description", error, stack);
|
||||||
ImmichToast.show(
|
ImmichToast.show(
|
||||||
context: context,
|
context: context,
|
||||||
msg: "description_input_submit_error".tr(),
|
msg: "description_input_submit_error".tr(),
|
||||||
|
@ -245,7 +245,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
|||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
log.severe(
|
log.severe(
|
||||||
"Failed to get thumbnail for album ${album.name}",
|
"Failed to get thumbnail for album ${album.name}",
|
||||||
e.toString(),
|
e,
|
||||||
stack,
|
stack,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
.then((_) => log.info("Logout was successful for $userEmail"))
|
.then((_) => log.info("Logout was successful for $userEmail"))
|
||||||
.onError(
|
.onError(
|
||||||
(error, stackTrace) =>
|
(error, stackTrace) =>
|
||||||
log.severe("Error logging out $userEmail", error, stackTrace),
|
log.severe("Logout failed for $userEmail", error, stackTrace),
|
||||||
);
|
);
|
||||||
|
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
@ -129,8 +129,8 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
shouldChangePassword: false,
|
shouldChangePassword: false,
|
||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e, stack) {
|
||||||
log.severe("Error logging out $e");
|
log.severe('Logout failed', e, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ class OAuthService {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
log.severe("Error performing oAuthLogin: ${e.toString()}", e, stack);
|
log.severe("OAuth login failed", e, stack);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
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/map/models/map_state.model.dart';
|
||||||
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
|
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
|
||||||
import 'package:immich_mobile/modules/settings/services/app_settings.service.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),
|
lightStyleFetched: AsyncError(lightResponse.body, StackTrace.current),
|
||||||
);
|
);
|
||||||
_log.severe(
|
_log.severe(
|
||||||
"Cannot fetch map light style with status - ${lightResponse.statusCode} and response - ${lightResponse.body}",
|
"Cannot fetch map light style",
|
||||||
|
lightResponse.toLoggerString(),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -77,9 +79,7 @@ class MapStateNotifier extends _$MapStateNotifier {
|
|||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
darkStyleFetched: AsyncError(darkResponse.body, StackTrace.current),
|
darkStyleFetched: AsyncError(darkResponse.body, StackTrace.current),
|
||||||
);
|
);
|
||||||
_log.severe(
|
_log.severe("Cannot fetch map dark style", darkResponse.toLoggerString());
|
||||||
"Cannot fetch map dark style with status - ${darkResponse.statusCode} and response - ${darkResponse.body}",
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ class MapSerivce with ErrorLoggerMixin {
|
|||||||
return markers?.map(MapMarker.fromDto) ?? [];
|
return markers?.map(MapMarker.fromDto) ?? [];
|
||||||
},
|
},
|
||||||
defaultValue: [],
|
defaultValue: [],
|
||||||
|
errorMessage: "Failed to get map markers",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,10 +105,8 @@ class MapUtils {
|
|||||||
timeLimit: const Duration(seconds: 5),
|
timeLimit: const Duration(seconds: 5),
|
||||||
);
|
);
|
||||||
return (currentUserLocation, null);
|
return (currentUserLocation, null);
|
||||||
} catch (error) {
|
} catch (error, stack) {
|
||||||
_log.severe(
|
_log.severe("Cannot get user's current location", error, stack);
|
||||||
"Cannot get user's current location due to ${error.toString()}",
|
|
||||||
);
|
|
||||||
return (null, LocationPermission.unableToDetermine);
|
return (null, LocationPermission.unableToDetermine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ class MapAssetGrid extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
error: (error, stackTrace) {
|
error: (error, stackTrace) {
|
||||||
log.warning(
|
log.warning(
|
||||||
"Cannot get assets in the current map bounds $error",
|
"Cannot get assets in the current map bounds",
|
||||||
error,
|
error,
|
||||||
stackTrace,
|
stackTrace,
|
||||||
);
|
);
|
||||||
|
@ -47,7 +47,7 @@ class MemoryService {
|
|||||||
|
|
||||||
return memories.isNotEmpty ? memories : null;
|
return memories.isNotEmpty ? memories : null;
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
log.severe("Cannot get memories ${error.toString()}", error, stack);
|
log.severe("Cannot get memories", error, stack);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ class PartnerService {
|
|||||||
return userDtos.map((u) => User.fromPartnerDto(u)).toList();
|
return userDtos.map((u) => User.fromPartnerDto(u)).toList();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} 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;
|
return null;
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ class PartnerService {
|
|||||||
partner.isPartnerSharedBy = false;
|
partner.isPartnerSharedBy = false;
|
||||||
await _db.writeTxn(() => _db.users.put(partner));
|
await _db.writeTxn(() => _db.users.put(partner));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_log.warning("failed to remove partner ${partner.id}:\n$e");
|
_log.warning("Failed to remove partner ${partner.id}", e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -66,7 +66,7 @@ class PartnerService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_log.warning("failed to add partner ${partner.id}:\n$e");
|
_log.warning("Failed to add partner ${partner.id}", e);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ class PartnerService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_log.warning("failed to update partner ${partner.id}:\n$e");
|
_log.warning("Failed to update partner ${partner.id}", e);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ class SharedLinkService {
|
|||||||
? AsyncData(list.map(SharedLink.fromDto).toList())
|
? AsyncData(list.map(SharedLink.fromDto).toList())
|
||||||
: const AsyncData([]);
|
: const AsyncData([]);
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
_log.severe("failed to fetch shared links - $e");
|
_log.severe("Failed to fetch shared links", e, stack);
|
||||||
return AsyncError(e, stack);
|
return AsyncError(e, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ class SharedLinkService {
|
|||||||
try {
|
try {
|
||||||
return await _apiService.sharedLinkApi.removeSharedLink(id);
|
return await _apiService.sharedLinkApi.removeSharedLink(id);
|
||||||
} catch (e) {
|
} 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) {
|
} catch (e) {
|
||||||
_log.severe("failed to create shared link with error - $e");
|
_log.severe("Failed to create shared link", e);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ class SharedLinkService {
|
|||||||
return SharedLink.fromDto(responseDto);
|
return SharedLink.fromDto(responseDto);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} 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;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ class TrashNotifier extends StateNotifier<bool> {
|
|||||||
.read(syncServiceProvider)
|
.read(syncServiceProvider)
|
||||||
.handleRemoteAssetRemoval(idsToRemove.cast<String>().toList());
|
.handleRemoteAssetRemoval(idsToRemove.cast<String>().toList());
|
||||||
} catch (error, stack) {
|
} 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<bool> {
|
|||||||
|
|
||||||
return isRemoved;
|
return isRemoved;
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
_log.severe("Cannot empty trash ${error.toString()}", error, stack);
|
_log.severe("Cannot remove assets", error, stack);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -93,7 +93,7 @@ class TrashNotifier extends StateNotifier<bool> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
_log.severe("Cannot restore trash ${error.toString()}", error, stack);
|
_log.severe("Cannot restore assets", error, stack);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ class TrashNotifier extends StateNotifier<bool> {
|
|||||||
await _db.assets.putAll(updatedAssets);
|
await _db.assets.putAll(updatedAssets);
|
||||||
});
|
});
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
_log.severe("Cannot restore trash ${error.toString()}", error, stack);
|
_log.severe("Cannot restore trash", error, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ class TrashService {
|
|||||||
await _apiService.trashApi.restoreAssets(BulkIdsDto(ids: remoteIds));
|
await _apiService.trashApi.restoreAssets(BulkIdsDto(ids: remoteIds));
|
||||||
return true;
|
return true;
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
_log.severe("Cannot restore assets ${error.toString()}", error, stack);
|
_log.severe("Cannot restore assets", error, stack);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ class TrashService {
|
|||||||
try {
|
try {
|
||||||
await _apiService.trashApi.emptyTrash();
|
await _apiService.trashApi.emptyTrash();
|
||||||
} catch (error, stack) {
|
} 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 {
|
try {
|
||||||
await _apiService.trashApi.restoreTrash();
|
await _apiService.trashApi.restoreTrash();
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
_log.severe("Cannot restore trash ${error.toString()}", error, stack);
|
_log.severe("Cannot restore trash", error, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ part 'logger_message.model.g.dart';
|
|||||||
class LoggerMessage {
|
class LoggerMessage {
|
||||||
Id id = Isar.autoIncrement;
|
Id id = Isar.autoIncrement;
|
||||||
String message;
|
String message;
|
||||||
|
String? details;
|
||||||
@Enumerated(EnumType.ordinal)
|
@Enumerated(EnumType.ordinal)
|
||||||
LogLevel level = LogLevel.INFO;
|
LogLevel level = LogLevel.INFO;
|
||||||
DateTime createdAt;
|
DateTime createdAt;
|
||||||
@ -17,6 +18,7 @@ class LoggerMessage {
|
|||||||
|
|
||||||
LoggerMessage({
|
LoggerMessage({
|
||||||
required this.message,
|
required this.message,
|
||||||
|
required this.details,
|
||||||
required this.level,
|
required this.level,
|
||||||
required this.createdAt,
|
required this.createdAt,
|
||||||
required this.context1,
|
required this.context1,
|
||||||
|
220
mobile/lib/shared/models/logger_message.model.g.dart
generated
220
mobile/lib/shared/models/logger_message.model.g.dart
generated
@ -32,14 +32,19 @@ const LoggerMessageSchema = CollectionSchema(
|
|||||||
name: r'createdAt',
|
name: r'createdAt',
|
||||||
type: IsarType.dateTime,
|
type: IsarType.dateTime,
|
||||||
),
|
),
|
||||||
r'level': PropertySchema(
|
r'details': PropertySchema(
|
||||||
id: 3,
|
id: 3,
|
||||||
|
name: r'details',
|
||||||
|
type: IsarType.string,
|
||||||
|
),
|
||||||
|
r'level': PropertySchema(
|
||||||
|
id: 4,
|
||||||
name: r'level',
|
name: r'level',
|
||||||
type: IsarType.byte,
|
type: IsarType.byte,
|
||||||
enumMap: _LoggerMessagelevelEnumValueMap,
|
enumMap: _LoggerMessagelevelEnumValueMap,
|
||||||
),
|
),
|
||||||
r'message': PropertySchema(
|
r'message': PropertySchema(
|
||||||
id: 4,
|
id: 5,
|
||||||
name: r'message',
|
name: r'message',
|
||||||
type: IsarType.string,
|
type: IsarType.string,
|
||||||
)
|
)
|
||||||
@ -76,6 +81,12 @@ int _loggerMessageEstimateSize(
|
|||||||
bytesCount += 3 + value.length * 3;
|
bytesCount += 3 + value.length * 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
final value = object.details;
|
||||||
|
if (value != null) {
|
||||||
|
bytesCount += 3 + value.length * 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
bytesCount += 3 + object.message.length * 3;
|
bytesCount += 3 + object.message.length * 3;
|
||||||
return bytesCount;
|
return bytesCount;
|
||||||
}
|
}
|
||||||
@ -89,8 +100,9 @@ void _loggerMessageSerialize(
|
|||||||
writer.writeString(offsets[0], object.context1);
|
writer.writeString(offsets[0], object.context1);
|
||||||
writer.writeString(offsets[1], object.context2);
|
writer.writeString(offsets[1], object.context2);
|
||||||
writer.writeDateTime(offsets[2], object.createdAt);
|
writer.writeDateTime(offsets[2], object.createdAt);
|
||||||
writer.writeByte(offsets[3], object.level.index);
|
writer.writeString(offsets[3], object.details);
|
||||||
writer.writeString(offsets[4], object.message);
|
writer.writeByte(offsets[4], object.level.index);
|
||||||
|
writer.writeString(offsets[5], object.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoggerMessage _loggerMessageDeserialize(
|
LoggerMessage _loggerMessageDeserialize(
|
||||||
@ -103,9 +115,10 @@ LoggerMessage _loggerMessageDeserialize(
|
|||||||
context1: reader.readStringOrNull(offsets[0]),
|
context1: reader.readStringOrNull(offsets[0]),
|
||||||
context2: reader.readStringOrNull(offsets[1]),
|
context2: reader.readStringOrNull(offsets[1]),
|
||||||
createdAt: reader.readDateTime(offsets[2]),
|
createdAt: reader.readDateTime(offsets[2]),
|
||||||
level: _LoggerMessagelevelValueEnumMap[reader.readByteOrNull(offsets[3])] ??
|
details: reader.readStringOrNull(offsets[3]),
|
||||||
|
level: _LoggerMessagelevelValueEnumMap[reader.readByteOrNull(offsets[4])] ??
|
||||||
LogLevel.ALL,
|
LogLevel.ALL,
|
||||||
message: reader.readString(offsets[4]),
|
message: reader.readString(offsets[5]),
|
||||||
);
|
);
|
||||||
object.id = id;
|
object.id = id;
|
||||||
return object;
|
return object;
|
||||||
@ -125,9 +138,11 @@ P _loggerMessageDeserializeProp<P>(
|
|||||||
case 2:
|
case 2:
|
||||||
return (reader.readDateTime(offset)) as P;
|
return (reader.readDateTime(offset)) as P;
|
||||||
case 3:
|
case 3:
|
||||||
|
return (reader.readStringOrNull(offset)) as P;
|
||||||
|
case 4:
|
||||||
return (_LoggerMessagelevelValueEnumMap[reader.readByteOrNull(offset)] ??
|
return (_LoggerMessagelevelValueEnumMap[reader.readByteOrNull(offset)] ??
|
||||||
LogLevel.ALL) as P;
|
LogLevel.ALL) as P;
|
||||||
case 4:
|
case 5:
|
||||||
return (reader.readString(offset)) as P;
|
return (reader.readString(offset)) as P;
|
||||||
default:
|
default:
|
||||||
throw IsarError('Unknown property with id $propertyId');
|
throw IsarError('Unknown property with id $propertyId');
|
||||||
@ -619,6 +634,160 @@ extension LoggerMessageQueryFilter
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition>
|
||||||
|
detailsIsNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(const FilterCondition.isNull(
|
||||||
|
property: r'details',
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition>
|
||||||
|
detailsIsNotNull() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||||
|
property: r'details',
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition>
|
||||||
|
detailsEqualTo(
|
||||||
|
String? value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.equalTo(
|
||||||
|
property: r'details',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition>
|
||||||
|
detailsGreaterThan(
|
||||||
|
String? value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||||
|
include: include,
|
||||||
|
property: r'details',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition>
|
||||||
|
detailsLessThan(
|
||||||
|
String? value, {
|
||||||
|
bool include = false,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.lessThan(
|
||||||
|
include: include,
|
||||||
|
property: r'details',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition>
|
||||||
|
detailsBetween(
|
||||||
|
String? lower,
|
||||||
|
String? upper, {
|
||||||
|
bool includeLower = true,
|
||||||
|
bool includeUpper = true,
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.between(
|
||||||
|
property: r'details',
|
||||||
|
lower: lower,
|
||||||
|
includeLower: includeLower,
|
||||||
|
upper: upper,
|
||||||
|
includeUpper: includeUpper,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition>
|
||||||
|
detailsStartsWith(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.startsWith(
|
||||||
|
property: r'details',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition>
|
||||||
|
detailsEndsWith(
|
||||||
|
String value, {
|
||||||
|
bool caseSensitive = true,
|
||||||
|
}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.endsWith(
|
||||||
|
property: r'details',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition>
|
||||||
|
detailsContains(String value, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.contains(
|
||||||
|
property: r'details',
|
||||||
|
value: value,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition>
|
||||||
|
detailsMatches(String pattern, {bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.matches(
|
||||||
|
property: r'details',
|
||||||
|
wildcard: pattern,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition>
|
||||||
|
detailsIsEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.equalTo(
|
||||||
|
property: r'details',
|
||||||
|
value: '',
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition>
|
||||||
|
detailsIsNotEmpty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||||
|
property: r'details',
|
||||||
|
value: '',
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition> idEqualTo(
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterFilterCondition> idEqualTo(
|
||||||
Id value) {
|
Id value) {
|
||||||
return QueryBuilder.apply(this, (query) {
|
return QueryBuilder.apply(this, (query) {
|
||||||
@ -913,6 +1082,18 @@ extension LoggerMessageQuerySortBy
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterSortBy> sortByDetails() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'details', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterSortBy> sortByDetailsDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'details', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
QueryBuilder<LoggerMessage, LoggerMessage, QAfterSortBy> sortByLevel() {
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterSortBy> sortByLevel() {
|
||||||
return QueryBuilder.apply(this, (query) {
|
return QueryBuilder.apply(this, (query) {
|
||||||
return query.addSortBy(r'level', Sort.asc);
|
return query.addSortBy(r'level', Sort.asc);
|
||||||
@ -979,6 +1160,18 @@ extension LoggerMessageQuerySortThenBy
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterSortBy> thenByDetails() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'details', Sort.asc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterSortBy> thenByDetailsDesc() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addSortBy(r'details', Sort.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
QueryBuilder<LoggerMessage, LoggerMessage, QAfterSortBy> thenById() {
|
QueryBuilder<LoggerMessage, LoggerMessage, QAfterSortBy> thenById() {
|
||||||
return QueryBuilder.apply(this, (query) {
|
return QueryBuilder.apply(this, (query) {
|
||||||
return query.addSortBy(r'id', Sort.asc);
|
return query.addSortBy(r'id', Sort.asc);
|
||||||
@ -1038,6 +1231,13 @@ extension LoggerMessageQueryWhereDistinct
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, LoggerMessage, QDistinct> distinctByDetails(
|
||||||
|
{bool caseSensitive = true}) {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addDistinctBy(r'details', caseSensitive: caseSensitive);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
QueryBuilder<LoggerMessage, LoggerMessage, QDistinct> distinctByLevel() {
|
QueryBuilder<LoggerMessage, LoggerMessage, QDistinct> distinctByLevel() {
|
||||||
return QueryBuilder.apply(this, (query) {
|
return QueryBuilder.apply(this, (query) {
|
||||||
return query.addDistinctBy(r'level');
|
return query.addDistinctBy(r'level');
|
||||||
@ -1078,6 +1278,12 @@ extension LoggerMessageQueryProperty
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QueryBuilder<LoggerMessage, String?, QQueryOperations> detailsProperty() {
|
||||||
|
return QueryBuilder.apply(this, (query) {
|
||||||
|
return query.addPropertyName(r'details');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
QueryBuilder<LoggerMessage, LogLevel, QQueryOperations> levelProperty() {
|
QueryBuilder<LoggerMessage, LogLevel, QQueryOperations> levelProperty() {
|
||||||
return QueryBuilder.apply(this, (query) {
|
return QueryBuilder.apply(this, (query) {
|
||||||
return query.addPropertyName(r'level');
|
return query.addPropertyName(r'level');
|
||||||
|
@ -90,7 +90,7 @@ class AssetService {
|
|||||||
return allAssets;
|
return allAssets;
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
log.severe(
|
log.severe(
|
||||||
'Error while getting remote assets: ${error.toString()}',
|
'Error while getting remote assets',
|
||||||
error,
|
error,
|
||||||
stack,
|
stack,
|
||||||
);
|
);
|
||||||
@ -117,7 +117,7 @@ class AssetService {
|
|||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
log.severe("Error deleteAssets ${error.toString()}", error, stack);
|
log.severe("Error while deleting assets", error, stack);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -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.
|
/// [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 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.
|
/// in the class.
|
||||||
///
|
///
|
||||||
/// Logs can be shared by calling the `shareLogs` method, which will open a share dialog
|
/// 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}');
|
debugPrint('[${record.level.name}] [${record.time}] ${record.message}');
|
||||||
final lm = LoggerMessage(
|
final lm = LoggerMessage(
|
||||||
message: record.message,
|
message: record.message,
|
||||||
|
details: record.error?.toString(),
|
||||||
level: record.level.toLogLevel(),
|
level: record.level.toLogLevel(),
|
||||||
createdAt: record.time,
|
createdAt: record.time,
|
||||||
context1: record.loggerName,
|
context1: record.loggerName,
|
||||||
|
@ -2,6 +2,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.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/models/asset.dart';
|
||||||
import 'package:immich_mobile/shared/providers/api.provider.dart';
|
import 'package:immich_mobile/shared/providers/api.provider.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
@ -41,7 +42,8 @@ class ShareService {
|
|||||||
|
|
||||||
if (res.statusCode != 200) {
|
if (res.statusCode != 200) {
|
||||||
_log.severe(
|
_log.severe(
|
||||||
"Asset download failed with status - ${res.statusCode} and response - ${res.body}",
|
"Asset download for ${asset.fileName} failed",
|
||||||
|
res.toLoggerString(),
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -68,7 +70,7 @@ class ShareService {
|
|||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
_log.severe("Share failed with error $error");
|
_log.severe("Share failed", error);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ class SyncService {
|
|||||||
try {
|
try {
|
||||||
await _db.writeTxn(() => a.put(_db));
|
await _db.writeTxn(() => a.put(_db));
|
||||||
} on IsarError catch (e) {
|
} 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 false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -173,7 +173,7 @@ class SyncService {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} on IsarError catch (e) {
|
} 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;
|
return null;
|
||||||
}
|
}
|
||||||
@ -232,7 +232,7 @@ class SyncService {
|
|||||||
await _db.writeTxn(() => _db.assets.deleteAll(idsToDelete));
|
await _db.writeTxn(() => _db.assets.deleteAll(idsToDelete));
|
||||||
await upsertAssetsWithExif(toAdd + toUpdate);
|
await upsertAssetsWithExif(toAdd + toUpdate);
|
||||||
} on IsarError catch (e) {
|
} 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);
|
await _updateUserAssetsETag(user, now);
|
||||||
return true;
|
return true;
|
||||||
@ -364,7 +364,7 @@ class SyncService {
|
|||||||
});
|
});
|
||||||
_log.info("Synced changes of remote album ${album.name} to DB");
|
_log.info("Synced changes of remote album ${album.name} to DB");
|
||||||
} on IsarError catch (e) {
|
} 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) {
|
if (album.shared || dto.shared) {
|
||||||
@ -441,7 +441,7 @@ class SyncService {
|
|||||||
assert(ok);
|
assert(ok);
|
||||||
_log.info("Removed local album $album from DB");
|
_log.info("Removed local album $album from DB");
|
||||||
} catch (e) {
|
} 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");
|
_log.info("Synced changes of local album ${ape.name} to DB");
|
||||||
} on IsarError catch (e) {
|
} 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;
|
return true;
|
||||||
@ -623,7 +623,7 @@ class SyncService {
|
|||||||
});
|
});
|
||||||
_log.info("Fast synced local album ${ape.name} to DB");
|
_log.info("Fast synced local album ${ape.name} to DB");
|
||||||
} on IsarError catch (e) {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -656,7 +656,7 @@ class SyncService {
|
|||||||
await _db.writeTxn(() => _db.albums.store(a));
|
await _db.writeTxn(() => _db.albums.store(a));
|
||||||
_log.info("Added a new local album to DB: ${ape.name}");
|
_log.info("Added a new local album to DB: ${ape.name}");
|
||||||
} on IsarError catch (e) {
|
} 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");
|
_log.info("Upserted ${assets.length} assets into the DB");
|
||||||
} on IsarError catch (e) {
|
} on IsarError catch (e) {
|
||||||
_log.severe(
|
_log.severe("Failed to upsert ${assets.length} assets into the DB", e);
|
||||||
"Failed to upsert ${assets.length} assets into the DB: ${e.toString()}",
|
|
||||||
);
|
|
||||||
// give details on the errors
|
// give details on the errors
|
||||||
assets.sort(Asset.compareByOwnerChecksum);
|
assets.sort(Asset.compareByOwnerChecksum);
|
||||||
final inDb = await _db.assets.getAllByOwnerIdChecksum(
|
final inDb = await _db.assets.getAllByOwnerIdChecksum(
|
||||||
@ -776,7 +774,7 @@ class SyncService {
|
|||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ class UserService {
|
|||||||
final dto = await _apiService.userApi.getAllUsers(isAll);
|
final dto = await _apiService.userApi.getAllUsers(isAll);
|
||||||
return dto?.map(User.fromUserDto).toList();
|
return dto?.map(User.fromUserDto).toList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_log.warning("Failed get all users:\n$e");
|
_log.warning("Failed get all users", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ class UserService {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_log.warning("Failed to upload profile image:\n$e");
|
_log.warning("Failed to upload profile image", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ class AppLogDetailPage extends HookConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
var isDarkTheme = context.isDarkTheme;
|
var isDarkTheme = context.isDarkTheme;
|
||||||
|
|
||||||
buildStackMessage(String stackTrace) {
|
buildTextWithCopyButton(String header, String text) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -28,7 +28,7 @@ class AppLogDetailPage extends HookConsumerWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 8.0),
|
padding: const EdgeInsets.only(bottom: 8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
"STACK TRACES",
|
header,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12.0,
|
fontSize: 12.0,
|
||||||
color: context.primaryColor,
|
color: context.primaryColor,
|
||||||
@ -38,8 +38,7 @@ class AppLogDetailPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Clipboard.setData(ClipboardData(text: stackTrace))
|
Clipboard.setData(ClipboardData(text: text)).then((_) {
|
||||||
.then((_) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(
|
content: Text(
|
||||||
@ -68,73 +67,7 @@ class AppLogDetailPage extends HookConsumerWidget {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: SelectableText(
|
child: SelectableText(
|
||||||
stackTrace,
|
text,
|
||||||
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,
|
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12.0,
|
fontSize: 12.0,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -194,11 +127,16 @@ class AppLogDetailPage extends HookConsumerWidget {
|
|||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
children: [
|
children: [
|
||||||
buildLogMessage(logMessage.message),
|
buildTextWithCopyButton("MESSAGE", logMessage.message),
|
||||||
|
if (logMessage.details != null)
|
||||||
|
buildTextWithCopyButton("DETAILS", logMessage.details.toString()),
|
||||||
if (logMessage.context1 != null)
|
if (logMessage.context1 != null)
|
||||||
buildLogContext1(logMessage.context1.toString()),
|
buildLogContext1(logMessage.context1.toString()),
|
||||||
if (logMessage.context2 != null)
|
if (logMessage.context2 != null)
|
||||||
buildStackMessage(logMessage.context2.toString()),
|
buildTextWithCopyButton(
|
||||||
|
"STACK TRACE",
|
||||||
|
logMessage.context2.toString(),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -35,10 +35,10 @@ class SplashScreenPage extends HookConsumerWidget {
|
|||||||
deviceIsOffline = true;
|
deviceIsOffline = true;
|
||||||
log.fine("Device seems to be offline upon launch");
|
log.fine("Device seems to be offline upon launch");
|
||||||
} else {
|
} else {
|
||||||
log.severe(e);
|
log.severe("Failed to resolve endpoint", e);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.severe(e);
|
log.severe("Failed to resolve endpoint", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -53,7 +53,7 @@ class SplashScreenPage extends HookConsumerWidget {
|
|||||||
ref.read(authenticationProvider.notifier).logout();
|
ref.read(authenticationProvider.notifier).logout();
|
||||||
|
|
||||||
log.severe(
|
log.severe(
|
||||||
'Cannot set success login info: $error',
|
'Cannot set success login info',
|
||||||
error,
|
error,
|
||||||
stackTrace,
|
stackTrace,
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user