Change initialization and logging

This commit is contained in:
problematicconsumer
2023-12-22 14:16:24 +03:30
parent defca7de5e
commit 6219663a4c
22 changed files with 409 additions and 277 deletions

View File

@@ -1,10 +1,14 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_loggy/flutter_loggy.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:hiddify/core/analytics/analytics_controller.dart';
import 'package:hiddify/core/app_info/app_info_provider.dart';
import 'package:hiddify/core/directories/directories_provider.dart';
import 'package:hiddify/core/logger/logger.dart';
import 'package:hiddify/core/logger/logger_controller.dart';
import 'package:hiddify/core/model/environment.dart';
import 'package:hiddify/core/preferences/general_preferences.dart';
import 'package:hiddify/core/preferences/preferences_migration.dart';
@@ -18,7 +22,6 @@ import 'package:hiddify/features/profile/notifier/active_profile_notifier.dart';
import 'package:hiddify/features/system_tray/system_tray_controller.dart';
import 'package:hiddify/services/auto_start_service.dart';
import 'package:hiddify/services/deep_link_service.dart';
import 'package:hiddify/services/service_providers.dart';
import 'package:hiddify/singbox/service/singbox_service_provider.dart';
import 'package:hiddify/utils/utils.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -26,20 +29,20 @@ import 'package:loggy/loggy.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:window_manager/window_manager.dart';
final _logger = Loggy('bootstrap');
const _testCrashReport = false;
final _loggers = MultiLogPrinter(const PrettyPrinter(), []);
Future<void> lazyBootstrap(
WidgetsBinding widgetsBinding,
Environment env,
) async {
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
if (PlatformUtils.isDesktop) await windowManager.ensureInitialized();
final sentryLogger = SentryLoggyIntegration();
_loggers.addPrinter(sentryLogger);
Loggy.initLoggy();
Loggy.initLoggy(logPrinter: const PrettyDeveloperPrinter());
FlutterError.onError = Logger.logFlutterError;
WidgetsBinding.instance.platformDispatcher.onError =
Logger.logPlatformDispatcherError;
final stopWatch = Stopwatch()..start();
if (PlatformUtils.isDesktop) await windowManager.ensureInitialized();
final container = ProviderContainer(
overrides: [
@@ -47,65 +50,65 @@ Future<void> lazyBootstrap(
],
);
final appInfo = await container.read(appInfoProvider.future);
await container.read(sharedPreferencesProvider.future);
final enableAnalytics = container.read(enableAnalyticsProvider);
await SentryFlutter.init(
(options) {
if ((enableAnalytics && !kDebugMode) || _testCrashReport) {
options.dsn = Environment.sentryDSN;
} else {
options.dsn = "";
}
options.environment = env.name;
options.dist = appInfo.release.name;
options.debug = kDebugMode;
options.enableNativeCrashHandling = true;
options.enableNdkScopeSync = true;
options.attachThreads = true;
options.tracesSampleRate = 0.25;
options.enableUserInteractionTracing = true;
options.addIntegration(sentryLogger);
options.beforeSend = sentryBeforeSend;
options.logger = (level, message, {exception, logger, stackTrace}) {
if (level == SentryLevel.fatal) {
_logger.debug(message);
}
};
},
appRunner: () => _lazyBootstrap(widgetsBinding, container, env),
await _init(
"directories",
() => container.read(appDirectoriesProvider.future),
);
}
LoggerController.init(container.read(logPathResolverProvider).appFile().path);
Future<void> _lazyBootstrap(
WidgetsBinding widgetsBinding,
ProviderContainer container,
Environment env,
) async {
try {
await PreferencesMigration(
sharedPreferences: container.read(sharedPreferencesProvider).requireValue,
).migrate();
} catch (e) {
_logger.error("preferences migration failed", e);
if (env == Environment.dev) rethrow;
_logger.info("clearing preferences");
await container.read(sharedPreferencesProvider).requireValue.clear();
final appInfo = await _init(
"app info",
() => container.read(appInfoProvider.future),
);
await _init(
"preferences",
() => container.read(sharedPreferencesProvider.future),
);
final enableAnalytics = container.read(analyticsControllerProvider);
if (enableAnalytics) {
await _init(
"analytics",
() => container
.read(analyticsControllerProvider.notifier)
.enableAnalytics(),
);
}
await _init(
"preferences migration",
() async {
try {
await PreferencesMigration(
sharedPreferences:
container.read(sharedPreferencesProvider).requireValue,
).migrate();
} catch (e, stackTrace) {
Logger.bootstrap.error("preferences migration failed", e, stackTrace);
if (env == Environment.dev) rethrow;
Logger.bootstrap.info("clearing preferences");
await container.read(sharedPreferencesProvider).requireValue.clear();
}
},
);
final debug = container.read(debugModeNotifierProvider) || kDebugMode;
final filesEditor = container.read(filesEditorServiceProvider);
await filesEditor.init();
await container.read(logRepositoryProvider.future);
await container.read(geoAssetRepositoryProvider.future);
await container.read(profileRepositoryProvider.future);
await _init(
"logs repository",
() => container.read(logRepositoryProvider.future),
);
await _init("logger controller", () => LoggerController.postInit(debug));
Logger.bootstrap.info(appInfo.format());
initLoggers(container.read, debug);
_logger.info(container.read(appInfoProvider).requireValue.format());
await _init(
"geo assets repository",
() => container.read(geoAssetRepositoryProvider.future),
);
await _init(
"profile repository",
() => container.read(profileRepositoryProvider.future),
);
final silentStart = container.read(silentStartNotifierProvider);
if (silentStart) {
@@ -113,31 +116,41 @@ Future<void> _lazyBootstrap(
}
if (PlatformUtils.isDesktop) {
_logger.debug("initializing [Auto Start Service] and [Window Controller]");
await container.read(autoStartServiceProvider.future);
await container.read(windowControllerProvider.future);
await _init(
"auto start service",
() => container.read(autoStartServiceProvider.future),
);
await _init(
"window controller",
() => container.read(windowControllerProvider.future),
);
}
await container.read(singboxServiceProvider).init();
_logger.debug("initialized [Singbox Service]");
await _init(
"sing-box",
() => container.read(singboxServiceProvider).init(),
);
await _safeInit(
"active profile",
() => container.read(activeProfileProvider.future),
);
await _init(
"deep link service",
() => container.read(deepLinkServiceProvider.future),
);
await container.read(activeProfileProvider.future);
await container.read(deepLinkServiceProvider.future);
if (PlatformUtils.isDesktop) {
try {
await container
.read(systemTrayControllerProvider.future)
.timeout(const Duration(seconds: 1));
_logger.debug("initialized [System Tray Controller]");
} catch (error, stackTrace) {
_logger.warning(
"error initializing [System Tray Controller]",
error,
stackTrace,
);
}
await _safeInit(
"system tray",
() => container.read(systemTrayControllerProvider.future),
timeout: 1000,
);
}
Logger.bootstrap.info("bootstrap took [${stopWatch.elapsedMilliseconds}ms]");
stopWatch.stop();
runApp(
ProviderScope(
parent: container,
@@ -150,19 +163,36 @@ Future<void> _lazyBootstrap(
if (!silentStart) FlutterNativeSplash.remove();
}
void initLoggers(
Result Function<Result>(ProviderListenable<Result>) read,
bool debug,
) {
final logLevel = debug ? LogLevel.all : LogLevel.info;
final logToFile = debug || (!Platform.isAndroid && !Platform.isIOS);
if (logToFile) {
_loggers.addPrinter(
FileLogPrinter(read(logPathResolverProvider).appFile().path),
);
Future<T> _init<T>(
String name,
Future<T> Function() initializer, {
int? timeout,
}) async {
final stopWatch = Stopwatch()..start();
Future<T> func() => timeout != null
? initializer().timeout(Duration(milliseconds: timeout))
: initializer();
try {
final result = await func();
Logger.bootstrap
.debug("[$name] initialized in ${stopWatch.elapsedMilliseconds}ms");
return result;
} catch (e, stackTrace) {
Logger.bootstrap.error("[$name] error initializing", e, stackTrace);
rethrow;
} finally {
stopWatch.stop();
}
}
Future<T?> _safeInit<T>(
String name,
Future<T> Function() initializer, {
int? timeout,
}) async {
try {
return await _init(name, initializer, timeout: timeout);
} catch (_) {
return null;
}
Loggy.initLoggy(
logPrinter: _loggers,
logOptions: LogOptions(logLevel),
);
}