improved error reporting
This commit is contained in:
parent
ec7e4ac2f2
commit
ffbf0bd8f2
15 changed files with 25 additions and 26 deletions
|
@ -32,7 +32,7 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
|
||||||
final appliedModifier = await _applyDateModifierToEntry(userModifier);
|
final appliedModifier = await _applyDateModifierToEntry(userModifier);
|
||||||
if (appliedModifier == null) {
|
if (appliedModifier == null) {
|
||||||
if (isValid && userModifier.action != DateEditAction.copyField) {
|
if (isValid && userModifier.action != DateEditAction.copyField) {
|
||||||
await reportService.recordError('failed to get date for modifier=$userModifier, entry=$this', null);
|
await reportService.recordError('failed to get date for modifier=$userModifier, entry=$this');
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
|
||||||
final shiftedDate = date.add(Duration(seconds: appliedModifier.shiftSeconds!));
|
final shiftedDate = date.add(Duration(seconds: appliedModifier.shiftSeconds!));
|
||||||
editCreateDateXmp(descriptions, shiftedDate);
|
editCreateDateXmp(descriptions, shiftedDate);
|
||||||
} else {
|
} else {
|
||||||
reportService.recordError('failed to parse XMP date=$xmpDate', null);
|
reportService.recordError('failed to parse XMP date=$xmpDate');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case DateEditAction.remove:
|
case DateEditAction.remove:
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/metadata/catalog.dart';
|
|
||||||
import 'package:aves/model/media/video/channel_layouts.dart';
|
import 'package:aves/model/media/video/channel_layouts.dart';
|
||||||
import 'package:aves/model/media/video/codecs.dart';
|
import 'package:aves/model/media/video/codecs.dart';
|
||||||
import 'package:aves/model/media/video/profiles/aac.dart';
|
import 'package:aves/model/media/video/profiles/aac.dart';
|
||||||
import 'package:aves/model/media/video/profiles/h264.dart';
|
import 'package:aves/model/media/video/profiles/h264.dart';
|
||||||
import 'package:aves/model/media/video/profiles/hevc.dart';
|
import 'package:aves/model/media/video/profiles/hevc.dart';
|
||||||
|
import 'package:aves/model/metadata/catalog.dart';
|
||||||
import 'package:aves/ref/languages.dart';
|
import 'package:aves/ref/languages.dart';
|
||||||
import 'package:aves/ref/locales.dart';
|
import 'package:aves/ref/locales.dart';
|
||||||
import 'package:aves/ref/mime_types.dart';
|
import 'package:aves/ref/mime_types.dart';
|
||||||
|
@ -99,7 +99,7 @@ class VideoMetadataFormatter {
|
||||||
if (isDefined(dateString)) {
|
if (isDefined(dateString)) {
|
||||||
dateMillis = parseVideoDate(dateString);
|
dateMillis = parseVideoDate(dateString);
|
||||||
if (dateMillis == null && !isAmbiguousDate(dateString)) {
|
if (dateMillis == null && !isAmbiguousDate(dateString)) {
|
||||||
await reportService.recordError('getCatalogMetadata failed to parse date=$dateString for mimeType=${entry.mimeType} entry=$entry', null);
|
await reportService.recordError('getCatalogMetadata failed to parse date=$dateString for mimeType=${entry.mimeType} entry=$entry');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ class MediaStoreSource extends CollectionSource {
|
||||||
final currentTimeZoneOffset = DateTime.now().timeZoneOffset.inMilliseconds;
|
final currentTimeZoneOffset = DateTime.now().timeZoneOffset.inMilliseconds;
|
||||||
final catalogTimeZoneOffset = settings.catalogTimeZoneOffsetMillis;
|
final catalogTimeZoneOffset = settings.catalogTimeZoneOffsetMillis;
|
||||||
if (currentTimeZoneOffset != catalogTimeZoneOffset) {
|
if (currentTimeZoneOffset != catalogTimeZoneOffset) {
|
||||||
unawaited(reportService.recordError('Time zone offset change: $currentTimeZoneOffset -> $catalogTimeZoneOffset. Clear catalog metadata to get correct date/times.', null));
|
unawaited(reportService.recordError('Time zone offset change: $currentTimeZoneOffset -> $catalogTimeZoneOffset. Clear catalog metadata to get correct date/times.'));
|
||||||
await localMediaDb.clearDates();
|
await localMediaDb.clearDates();
|
||||||
await localMediaDb.clearCatalogMetadata();
|
await localMediaDb.clearCatalogMetadata();
|
||||||
settings.catalogTimeZoneOffsetMillis = currentTimeZoneOffset;
|
settings.catalogTimeZoneOffsetMillis = currentTimeZoneOffset;
|
||||||
|
@ -212,7 +212,7 @@ class MediaStoreSource extends CollectionSource {
|
||||||
// TODO TLAD find duplication cause
|
// TODO TLAD find duplication cause
|
||||||
final duplicates = await localMediaDb.searchLiveDuplicates(EntryOrigins.mediaStoreContent, newEntries);
|
final duplicates = await localMediaDb.searchLiveDuplicates(EntryOrigins.mediaStoreContent, newEntries);
|
||||||
if (duplicates.isNotEmpty) {
|
if (duplicates.isNotEmpty) {
|
||||||
unawaited(reportService.recordError(Exception('Loading entries yielded duplicates=${duplicates.join(', ')}'), StackTrace.current));
|
unawaited(reportService.recordError(Exception('Loading entries yielded duplicates=${duplicates.join(', ')}')));
|
||||||
// post-error cleanup
|
// post-error cleanup
|
||||||
await localMediaDb.removeIds(duplicates.map((v) => v.id).toSet());
|
await localMediaDb.removeIds(duplicates.map((v) => v.id).toSet());
|
||||||
for (final duplicate in duplicates) {
|
for (final duplicate in duplicates) {
|
||||||
|
@ -325,7 +325,7 @@ class MediaStoreSource extends CollectionSource {
|
||||||
// TODO TLAD find duplication cause
|
// TODO TLAD find duplication cause
|
||||||
final duplicates = await localMediaDb.searchLiveDuplicates(EntryOrigins.mediaStoreContent, newEntries);
|
final duplicates = await localMediaDb.searchLiveDuplicates(EntryOrigins.mediaStoreContent, newEntries);
|
||||||
if (duplicates.isNotEmpty) {
|
if (duplicates.isNotEmpty) {
|
||||||
unawaited(reportService.recordError(Exception('Refreshing entries yielded duplicates=${duplicates.join(', ')}'), StackTrace.current));
|
unawaited(reportService.recordError(Exception('Refreshing entries yielded duplicates=${duplicates.join(', ')}')));
|
||||||
// post-error cleanup
|
// post-error cleanup
|
||||||
await localMediaDb.removeIds(duplicates.map((v) => v.id).toSet());
|
await localMediaDb.removeIds(duplicates.map((v) => v.id).toSet());
|
||||||
for (final duplicate in duplicates) {
|
for (final duplicate in duplicates) {
|
||||||
|
|
|
@ -76,7 +76,7 @@ mixin TrashMixin on SourceBase {
|
||||||
sourceEntry.trashDetails = _buildTrashDetails(id);
|
sourceEntry.trashDetails = _buildTrashDetails(id);
|
||||||
newEntries.add(sourceEntry);
|
newEntries.add(sourceEntry);
|
||||||
} else {
|
} else {
|
||||||
await reportService.recordError('Failed to recover untracked bin item at uri=$uri', null);
|
await reportService.recordError('Failed to recover untracked bin item at uri=$uri');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -175,7 +175,7 @@ class Vaults extends ChangeNotifier {
|
||||||
sourceEntry.origin = EntryOrigins.vault;
|
sourceEntry.origin = EntryOrigins.vault;
|
||||||
newEntries.add(sourceEntry);
|
newEntries.add(sourceEntry);
|
||||||
} else {
|
} else {
|
||||||
await reportService.recordError('Failed to recover untracked vault item at uri=$uri', null);
|
await reportService.recordError('Failed to recover untracked vault item at uri=$uri');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,8 @@ import 'package:aves/model/entry/extensions/props.dart';
|
||||||
import 'package:aves/model/metadata/date_modifier.dart';
|
import 'package:aves/model/metadata/date_modifier.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:aves_report/aves_report.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:stack_trace/stack_trace.dart';
|
|
||||||
|
|
||||||
abstract class MetadataEditService {
|
abstract class MetadataEditService {
|
||||||
Future<Map<String, dynamic>> rotate(AvesEntry entry, {required bool clockwise});
|
Future<Map<String, dynamic>> rotate(AvesEntry entry, {required bool clockwise});
|
||||||
|
@ -135,24 +133,22 @@ class PlatformMetadataEditService implements MetadataEditService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StackTrace? _currentStack() => ReportService.buildReportStack(Trace.current(), level: 1);
|
|
||||||
|
|
||||||
// distinct exceptions to convince Crashlytics to split reports into distinct issues
|
// distinct exceptions to convince Crashlytics to split reports into distinct issues
|
||||||
// The distinct debug statement is there to make the body unique, so that the methods are not merged at compile time.
|
// The distinct debug statement is there to make the body unique, so that the methods are not merged at compile time.
|
||||||
|
|
||||||
Future<void> mp4LargeMoov(CustomPlatformException e) {
|
Future<void> mp4LargeMoov(CustomPlatformException e) {
|
||||||
debugPrint('mp4LargeMoov $e');
|
debugPrint('mp4LargeMoov $e');
|
||||||
return reportService.recordError(e, _currentStack());
|
return reportService.recordError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> mp4LargeOther(CustomPlatformException e) {
|
Future<void> mp4LargeOther(CustomPlatformException e) {
|
||||||
debugPrint('mp4LargeOther $e');
|
debugPrint('mp4LargeOther $e');
|
||||||
return reportService.recordError(e, _currentStack());
|
return reportService.recordError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> fileNotFound(CustomPlatformException e) {
|
Future<void> fileNotFound(CustomPlatformException e) {
|
||||||
debugPrint('fileNotFound $e');
|
debugPrint('fileNotFound $e');
|
||||||
return reportService.recordError(e, _currentStack());
|
return reportService.recordError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -693,7 +693,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
_mediaStoreSource.updateDerivedFilters();
|
_mediaStoreSource.updateDerivedFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onError(String? error) => reportService.recordError(error, null);
|
void _onError(String? error) => reportService.recordError(error);
|
||||||
|
|
||||||
void _onAppModeChanged() {
|
void _onAppModeChanged() {
|
||||||
final appMode = _appModeNotifier.value;
|
final appMode = _appModeNotifier.value;
|
||||||
|
|
|
@ -61,8 +61,8 @@ mixin SingleEntryEditorMixin on FeedbackMixin, PermissionAwareMixin {
|
||||||
} else {
|
} else {
|
||||||
showFeedback(context, FeedbackType.warn, l10n.genericFailureFeedback);
|
showFeedback(context, FeedbackType.warn, l10n.genericFailureFeedback);
|
||||||
}
|
}
|
||||||
} catch (error, stack) {
|
} catch (e, stack) {
|
||||||
await reportService.recordError(error, stack);
|
await reportService.recordError(e, stack);
|
||||||
}
|
}
|
||||||
source?.resumeMonitoring();
|
source?.resumeMonitoring();
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,8 +96,8 @@ mixin CastMixin {
|
||||||
);
|
);
|
||||||
debugPrint('cast: play entry=$entry');
|
debugPrint('cast: play entry=$entry');
|
||||||
unawaited(renderer.play());
|
unawaited(renderer.play());
|
||||||
} catch (error, stack) {
|
} catch (e, stack) {
|
||||||
await reportService.recordError(error, stack);
|
await reportService.recordError(e, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ abstract class ReportService {
|
||||||
|
|
||||||
Future<void> setCustomKeys(Map<String, Object> map);
|
Future<void> setCustomKeys(Map<String, Object> map);
|
||||||
|
|
||||||
Future<void> recordError(dynamic exception, StackTrace? stack);
|
Future<void> recordError(dynamic exception, [StackTrace? stack]);
|
||||||
|
|
||||||
Future<void> recordFlutterError(FlutterErrorDetails flutterErrorDetails);
|
Future<void> recordFlutterError(FlutterErrorDetails flutterErrorDetails);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ class PlatformReportService extends ReportService {
|
||||||
Future<void> log(String message) async => debugPrint('Report log with message=$message');
|
Future<void> log(String message) async => debugPrint('Report log with message=$message');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> recordError(dynamic exception, StackTrace? stack) async => debugPrint('Report error with exception=$exception, stack=$stack');
|
Future<void> recordError(dynamic exception, [StackTrace? stack]) async => debugPrint('Report error with exception=$exception, stack=$stack');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> recordFlutterError(FlutterErrorDetails flutterErrorDetails) async => debugPrint('Report Flutter error with details=$flutterErrorDetails');
|
Future<void> recordFlutterError(FlutterErrorDetails flutterErrorDetails) async => debugPrint('Report Flutter error with details=$flutterErrorDetails');
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:stack_trace/stack_trace.dart';
|
||||||
|
|
||||||
class PlatformReportService extends ReportService {
|
class PlatformReportService extends ReportService {
|
||||||
FirebaseCrashlytics? get _instance {
|
FirebaseCrashlytics? get _instance {
|
||||||
|
@ -65,11 +66,12 @@ class PlatformReportService extends ReportService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> recordError(dynamic exception, StackTrace? stack) async {
|
Future<void> recordError(dynamic exception, [StackTrace? stack]) async {
|
||||||
if (exception is PlatformException && stack != null) {
|
if (exception is PlatformException && stack != null) {
|
||||||
stack = ReportService.buildReportStack(stack, level: 2);
|
stack = ReportService.buildReportStack(stack, level: 2);
|
||||||
}
|
}
|
||||||
if (exception is! UnreportedStateError) {
|
if (exception is! UnreportedStateError) {
|
||||||
|
stack ??= ReportService.buildReportStack(Trace.current(), level: 1);
|
||||||
return _instance?.recordError(exception, stack);
|
return _instance?.recordError(exception, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,7 +213,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0"
|
version: "1.10.0"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
|
|
|
@ -14,6 +14,7 @@ dependencies:
|
||||||
# so that the transitive `path` gets upgraded to v1.8.3
|
# so that the transitive `path` gets upgraded to v1.8.3
|
||||||
firebase_core: ">=2.10.0"
|
firebase_core: ">=2.10.0"
|
||||||
firebase_crashlytics:
|
firebase_crashlytics:
|
||||||
|
stack_trace:
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
|
|
|
@ -21,7 +21,7 @@ class FakeReportService extends ReportService {
|
||||||
Future<void> setCustomKeys(Map<String, Object> map) => SynchronousFuture(null);
|
Future<void> setCustomKeys(Map<String, Object> map) => SynchronousFuture(null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> recordError(dynamic exception, StackTrace? stack) => SynchronousFuture(null);
|
Future<void> recordError(dynamic exception, [StackTrace? stack]) => SynchronousFuture(null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> recordFlutterError(FlutterErrorDetails flutterErrorDetails) => SynchronousFuture(null);
|
Future<void> recordFlutterError(FlutterErrorDetails flutterErrorDetails) => SynchronousFuture(null);
|
||||||
|
|
Loading…
Reference in a new issue