Fix log and analytics bugs
This commit is contained in:
@@ -67,12 +67,7 @@ Future<void> lazyBootstrap(
|
|||||||
options.tracesSampleRate = 0.25;
|
options.tracesSampleRate = 0.25;
|
||||||
options.enableUserInteractionTracing = true;
|
options.enableUserInteractionTracing = true;
|
||||||
options.addIntegration(sentryLogger);
|
options.addIntegration(sentryLogger);
|
||||||
options.beforeSend = (event, {hint}) {
|
options.beforeSend = sentryBeforeSend;
|
||||||
return switch (event.throwable) {
|
|
||||||
ExpectedException _ => null,
|
|
||||||
_ => event,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
options.logger = (level, message, {exception, logger, stackTrace}) {
|
options.logger = (level, message, {exception, logger, stackTrace}) {
|
||||||
if (level == SentryLevel.fatal) {
|
if (level == SentryLevel.fatal) {
|
||||||
_logger.debug(message);
|
_logger.debug(message);
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class ProfilesRepositoryImpl
|
|||||||
() async {
|
() async {
|
||||||
final existingProfile = await profilesDao.getProfileByUrl(url);
|
final existingProfile = await profilesDao.getProfileByUrl(url);
|
||||||
if (existingProfile case RemoteProfile()) {
|
if (existingProfile case RemoteProfile()) {
|
||||||
loggy.info("profile with url[$url] already exists, updating");
|
loggy.info("profile with same url already exists, updating");
|
||||||
final baseProfile = markAsActive
|
final baseProfile = markAsActive
|
||||||
? existingProfile.copyWith(active: true)
|
? existingProfile.copyWith(active: true)
|
||||||
: existingProfile;
|
: existingProfile;
|
||||||
@@ -120,9 +120,9 @@ class ProfilesRepositoryImpl
|
|||||||
final parseResult =
|
final parseResult =
|
||||||
await singbox.parseConfig(path, tempPath, false).run();
|
await singbox.parseConfig(path, tempPath, false).run();
|
||||||
return parseResult.fold(
|
return parseResult.fold(
|
||||||
(l) async {
|
(err) async {
|
||||||
loggy.warning("error parsing config: $l");
|
loggy.warning("error parsing config", err);
|
||||||
return left(ProfileFailure.invalidConfig(l.msg));
|
return left(ProfileFailure.invalidConfig(err.msg));
|
||||||
},
|
},
|
||||||
(_) async {
|
(_) async {
|
||||||
final profile = LocalProfile(
|
final profile = LocalProfile(
|
||||||
@@ -267,9 +267,9 @@ class ProfilesRepositoryImpl
|
|||||||
final parseResult =
|
final parseResult =
|
||||||
await singbox.parseConfig(path, tempPath, false).run();
|
await singbox.parseConfig(path, tempPath, false).run();
|
||||||
return parseResult.fold(
|
return parseResult.fold(
|
||||||
(l) async {
|
(err) async {
|
||||||
loggy.warning("error parsing config: $l");
|
loggy.warning("error parsing config", err);
|
||||||
return left(ProfileFailure.invalidConfig(l.msg));
|
return left(ProfileFailure.invalidConfig(err.msg));
|
||||||
},
|
},
|
||||||
(_) async {
|
(_) async {
|
||||||
final profile = Profile.fromResponse(url, headers);
|
final profile = Profile.fromResponse(url, headers);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ part 'app_failure.freezed.dart';
|
|||||||
sealed class AppFailure with _$AppFailure, Failure {
|
sealed class AppFailure with _$AppFailure, Failure {
|
||||||
const AppFailure._();
|
const AppFailure._();
|
||||||
|
|
||||||
|
@With<UnexpectedFailure>()
|
||||||
const factory AppFailure.unexpected([
|
const factory AppFailure.unexpected([
|
||||||
Object? error,
|
Object? error,
|
||||||
StackTrace? stackTrace,
|
StackTrace? stackTrace,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ part 'connection_failure.freezed.dart';
|
|||||||
sealed class ConnectionFailure with _$ConnectionFailure, Failure {
|
sealed class ConnectionFailure with _$ConnectionFailure, Failure {
|
||||||
const ConnectionFailure._();
|
const ConnectionFailure._();
|
||||||
|
|
||||||
|
@With<UnexpectedFailure>()
|
||||||
const factory ConnectionFailure.unexpected([
|
const factory ConnectionFailure.unexpected([
|
||||||
Object? error,
|
Object? error,
|
||||||
StackTrace? stackTrace,
|
StackTrace? stackTrace,
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ part 'core_service_failure.freezed.dart';
|
|||||||
sealed class CoreServiceFailure with _$CoreServiceFailure, Failure {
|
sealed class CoreServiceFailure with _$CoreServiceFailure, Failure {
|
||||||
const CoreServiceFailure._();
|
const CoreServiceFailure._();
|
||||||
|
|
||||||
|
@With<UnexpectedFailure>()
|
||||||
const factory CoreServiceFailure.unexpected(
|
const factory CoreServiceFailure.unexpected(
|
||||||
Object error,
|
Object? error,
|
||||||
StackTrace stackTrace,
|
StackTrace? stackTrace,
|
||||||
) = UnexpectedCoreServiceFailure;
|
) = UnexpectedCoreServiceFailure;
|
||||||
|
|
||||||
@With<ExpectedException>()
|
@With<ExpectedException>()
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ mixin Failure {
|
|||||||
({String type, String? message}) present(TranslationsEn t);
|
({String type, String? message}) present(TranslationsEn t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mixin UnexpectedFailure {
|
||||||
|
Object? get error;
|
||||||
|
StackTrace? get stackTrace;
|
||||||
|
}
|
||||||
|
|
||||||
/// failures ignored by analytics service etc.
|
/// failures ignored by analytics service etc.
|
||||||
mixin ExpectedException {}
|
mixin ExpectedException {}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ part 'profiles_failure.freezed.dart';
|
|||||||
sealed class ProfileFailure with _$ProfileFailure, Failure {
|
sealed class ProfileFailure with _$ProfileFailure, Failure {
|
||||||
const ProfileFailure._();
|
const ProfileFailure._();
|
||||||
|
|
||||||
|
@With<UnexpectedFailure>()
|
||||||
const factory ProfileFailure.unexpected([
|
const factory ProfileFailure.unexpected([
|
||||||
Object? error,
|
Object? error,
|
||||||
StackTrace? stackTrace,
|
StackTrace? stackTrace,
|
||||||
|
|||||||
@@ -50,16 +50,16 @@ class AppUpdateNotifier extends _$AppUpdateNotifier with AppLogger {
|
|||||||
)
|
)
|
||||||
.match(
|
.match(
|
||||||
(err) {
|
(err) {
|
||||||
loggy.warning("failed to get latest version, $err");
|
loggy.warning("failed to get latest version", err);
|
||||||
return state = AppUpdateState.error(err);
|
return state = AppUpdateState.error(err);
|
||||||
},
|
},
|
||||||
(remote) {
|
(remote) {
|
||||||
if (remote.version.compareTo(currentVersion) > 0) {
|
if (remote.version.compareTo(currentVersion) > 0) {
|
||||||
loggy.info("new version available: $remote");
|
loggy.debug("new version available: $remote");
|
||||||
return state = AppUpdateState.available(remote);
|
return state = AppUpdateState.available(remote);
|
||||||
}
|
}
|
||||||
loggy.info(
|
loggy.info(
|
||||||
"already using latest version[$currentVersion], remote: $remote",
|
"already using latest version[$currentVersion], remote: [${remote.version}]",
|
||||||
);
|
);
|
||||||
return state = const AppUpdateState.notAvailable();
|
return state = const AppUpdateState.notAvailable();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -47,9 +47,9 @@ class ConnectivityController extends _$ConnectivityController with AppLogger {
|
|||||||
return _disconnect();
|
return _disconnect();
|
||||||
}
|
}
|
||||||
loggy.debug("reconnecting, profile: [$profileId]");
|
loggy.debug("reconnecting, profile: [$profileId]");
|
||||||
await _core.restart(profileId).mapLeft((l) {
|
await _core.restart(profileId).mapLeft((err) {
|
||||||
loggy.warning("error reconnecting: $l");
|
loggy.warning("error reconnecting", err);
|
||||||
state = AsyncError(l, StackTrace.current);
|
state = AsyncError(err, StackTrace.current);
|
||||||
}).run();
|
}).run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,16 +67,16 @@ class ConnectivityController extends _$ConnectivityController with AppLogger {
|
|||||||
|
|
||||||
Future<void> _connect() async {
|
Future<void> _connect() async {
|
||||||
final activeProfile = await ref.read(activeProfileProvider.future);
|
final activeProfile = await ref.read(activeProfileProvider.future);
|
||||||
await _core.start(activeProfile!.id).mapLeft((l) {
|
await _core.start(activeProfile!.id).mapLeft((err) {
|
||||||
loggy.warning("error connecting: $l");
|
loggy.warning("error connecting", err);
|
||||||
state = AsyncError(l, StackTrace.current);
|
state = AsyncError(err, StackTrace.current);
|
||||||
}).run();
|
}).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _disconnect() async {
|
Future<void> _disconnect() async {
|
||||||
await _core.stop().mapLeft((l) {
|
await _core.stop().mapLeft((err) {
|
||||||
loggy.warning("error disconnecting: $l");
|
loggy.warning("error disconnecting", err);
|
||||||
state = AsyncError(l, StackTrace.current);
|
state = AsyncError(err, StackTrace.current);
|
||||||
}).run();
|
}).run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ class ProfileDetailNotifier extends _$ProfileDetailNotifier with AppLogger {
|
|||||||
}
|
}
|
||||||
final failureOrProfile = await _profilesRepo.get(id).run();
|
final failureOrProfile = await _profilesRepo.get(id).run();
|
||||||
return failureOrProfile.match(
|
return failureOrProfile.match(
|
||||||
(l) {
|
(err) {
|
||||||
loggy.warning('failed to load profile, $l');
|
loggy.warning('failed to load profile', err);
|
||||||
throw l;
|
throw err;
|
||||||
},
|
},
|
||||||
(profile) {
|
(profile) {
|
||||||
if (profile == null) {
|
if (profile == null) {
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ class ProfilesNotifier extends _$ProfilesNotifier with AppLogger {
|
|||||||
|
|
||||||
Future<Unit> selectActiveProfile(String id) async {
|
Future<Unit> selectActiveProfile(String id) async {
|
||||||
loggy.debug('changing active profile to: [$id]');
|
loggy.debug('changing active profile to: [$id]');
|
||||||
return _profilesRepo.setAsActive(id).getOrElse((f) {
|
return _profilesRepo.setAsActive(id).getOrElse((err) {
|
||||||
loggy.warning('failed to set [$id] as active profile, $f');
|
loggy.warning('failed to set [$id] as active profile', err);
|
||||||
throw f;
|
throw err;
|
||||||
}).run();
|
}).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,9 +58,9 @@ class ProfilesNotifier extends _$ProfilesNotifier with AppLogger {
|
|||||||
return ref
|
return ref
|
||||||
.read(profilesRepositoryProvider)
|
.read(profilesRepositoryProvider)
|
||||||
.addByUrl(link.url, markAsActive: markAsActive)
|
.addByUrl(link.url, markAsActive: markAsActive)
|
||||||
.getOrElse((l) {
|
.getOrElse((err) {
|
||||||
loggy.warning("failed to add profile: $l");
|
loggy.warning("failed to add profile", err);
|
||||||
throw l;
|
throw err;
|
||||||
}).run();
|
}).run();
|
||||||
} else if (LinkParser.protocol(rawInput) case (final parsed)?) {
|
} else if (LinkParser.protocol(rawInput) case (final parsed)?) {
|
||||||
loggy.debug("adding profile, content");
|
loggy.debug("adding profile, content");
|
||||||
@@ -71,9 +71,9 @@ class ProfilesNotifier extends _$ProfilesNotifier with AppLogger {
|
|||||||
name: parsed.name,
|
name: parsed.name,
|
||||||
markAsActive: markAsActive,
|
markAsActive: markAsActive,
|
||||||
)
|
)
|
||||||
.getOrElse((l) {
|
.getOrElse((err) {
|
||||||
loggy.warning("failed to add profile: $l");
|
loggy.warning("failed to add profile", err);
|
||||||
throw l;
|
throw err;
|
||||||
}).run();
|
}).run();
|
||||||
} else {
|
} else {
|
||||||
loggy.debug("invalid content");
|
loggy.debug("invalid content");
|
||||||
@@ -93,9 +93,9 @@ class ProfilesNotifier extends _$ProfilesNotifier with AppLogger {
|
|||||||
Future<void> deleteProfile(Profile profile) async {
|
Future<void> deleteProfile(Profile profile) async {
|
||||||
loggy.debug('deleting profile: ${profile.name}');
|
loggy.debug('deleting profile: ${profile.name}');
|
||||||
await _profilesRepo.delete(profile.id).mapLeft(
|
await _profilesRepo.delete(profile.id).mapLeft(
|
||||||
(f) {
|
(err) {
|
||||||
loggy.warning('failed to delete profile, $f');
|
loggy.warning('failed to delete profile', err);
|
||||||
throw f;
|
throw err;
|
||||||
},
|
},
|
||||||
).run();
|
).run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,9 +60,9 @@ class ProxiesNotifier extends _$ProxiesNotifier with AppLogger {
|
|||||||
.watchOutbounds()
|
.watchOutbounds()
|
||||||
.map(
|
.map(
|
||||||
(event) => event.getOrElse(
|
(event) => event.getOrElse(
|
||||||
(f) {
|
(err) {
|
||||||
loggy.warning("error receiving proxies: $f");
|
loggy.warning("error receiving proxies", err);
|
||||||
throw f;
|
throw err;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -105,9 +105,9 @@ class ProxiesNotifier extends _$ProxiesNotifier with AppLogger {
|
|||||||
await ref
|
await ref
|
||||||
.read(coreFacadeProvider)
|
.read(coreFacadeProvider)
|
||||||
.selectOutbound(groupTag, outboundTag)
|
.selectOutbound(groupTag, outboundTag)
|
||||||
.getOrElse((l) {
|
.getOrElse((err) {
|
||||||
loggy.warning("error selecting outbound", l);
|
loggy.warning("error selecting outbound", err);
|
||||||
throw l;
|
throw err;
|
||||||
}).run();
|
}).run();
|
||||||
state = AsyncData(
|
state = AsyncData(
|
||||||
[
|
[
|
||||||
@@ -122,9 +122,9 @@ class ProxiesNotifier extends _$ProxiesNotifier with AppLogger {
|
|||||||
Future<void> urlTest(String groupTag) async {
|
Future<void> urlTest(String groupTag) async {
|
||||||
loggy.debug("testing group: [$groupTag]");
|
loggy.debug("testing group: [$groupTag]");
|
||||||
if (state case AsyncData()) {
|
if (state case AsyncData()) {
|
||||||
await ref.read(coreFacadeProvider).urlTest(groupTag).getOrElse((l) {
|
await ref.read(coreFacadeProvider).urlTest(groupTag).getOrElse((err) {
|
||||||
loggy.warning("error testing group", l);
|
loggy.warning("error testing group", err);
|
||||||
throw l;
|
throw err;
|
||||||
}).run();
|
}).run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ Future<List<InstalledPackageInfo>> installedPackagesInfo(
|
|||||||
return ref
|
return ref
|
||||||
.watch(platformSettingsProvider)
|
.watch(platformSettingsProvider)
|
||||||
.getInstalledPackages()
|
.getInstalledPackages()
|
||||||
.getOrElse((l) {
|
.getOrElse((err) {
|
||||||
_logger.warning("error getting installed packages: $l");
|
_logger.warning("error getting installed packages", err);
|
||||||
throw l;
|
throw err;
|
||||||
}).run();
|
}).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,9 +40,9 @@ Future<ImageProvider> packageIcon(
|
|||||||
final bytes = await ref
|
final bytes = await ref
|
||||||
.watch(platformSettingsProvider)
|
.watch(platformSettingsProvider)
|
||||||
.getPackageIcon(packageName)
|
.getPackageIcon(packageName)
|
||||||
.getOrElse((l) {
|
.getOrElse((err) {
|
||||||
_logger.warning("error getting package icon: $l");
|
_logger.warning("error getting package icon", err);
|
||||||
throw l;
|
throw err;
|
||||||
}).run();
|
}).run();
|
||||||
return MemoryImage(bytes);
|
return MemoryImage(bytes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:hiddify/utils/sentry_utils.dart';
|
||||||
import 'package:loggy/loggy.dart';
|
import 'package:loggy/loggy.dart';
|
||||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
|
|
||||||
@@ -33,6 +34,8 @@ class SentryLoggyIntegration extends LoggyPrinter
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> onLog(LogRecord record) async {
|
Future<void> onLog(LogRecord record) async {
|
||||||
|
if (!canSendEvent(record.error)) return;
|
||||||
|
|
||||||
if (_shouldLog(record.level, _minEventLevel)) {
|
if (_shouldLog(record.level, _minEventLevel)) {
|
||||||
await _hub.captureEvent(
|
await _hub.captureEvent(
|
||||||
record.toEvent(),
|
record.toEvent(),
|
||||||
|
|||||||
21
lib/utils/sentry_utils.dart
Normal file
21
lib/utils/sentry_utils.dart
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:hiddify/domain/failures.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
|
|
||||||
|
FutureOr<SentryEvent?> sentryBeforeSend(SentryEvent event, {Hint? hint}) {
|
||||||
|
if (canSendEvent(event.throwable)) return event;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canSendEvent(dynamic throwable) {
|
||||||
|
return switch (throwable) {
|
||||||
|
UnexpectedFailure(:final error) => canSendEvent(error),
|
||||||
|
DioException _ => false,
|
||||||
|
SocketException _ => false,
|
||||||
|
ExpectedException _ => false,
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ export 'placeholders.dart';
|
|||||||
export 'platform_utils.dart';
|
export 'platform_utils.dart';
|
||||||
export 'sentry_loggy_integration.dart';
|
export 'sentry_loggy_integration.dart';
|
||||||
export 'sentry_riverpod_observer.dart';
|
export 'sentry_riverpod_observer.dart';
|
||||||
|
export 'sentry_utils.dart';
|
||||||
export 'text_utils.dart';
|
export 'text_utils.dart';
|
||||||
export 'uri_utils.dart';
|
export 'uri_utils.dart';
|
||||||
export 'validators.dart';
|
export 'validators.dart';
|
||||||
|
|||||||
Reference in New Issue
Block a user