main function
Entry point of this application.
Implementation
Future<void> main() async {
await runZonedGuarded(
() async {
final Stopwatch watch = Stopwatch()..start();
await Config.init();
me.Log.options = me.LogOptions(
level: Config.logLevel,
// Browsers collect timestamps for log themselves.
timeStamp: !PlatformUtils.isWeb,
dateStamp: !PlatformUtils.isWeb,
);
Log.maxLogs = Config.logAmount;
// No need to initialize the Sentry if no DSN is provided, otherwise
// useless messages are printed to the console every time the application
// starts.
if (Config.sentryDsn.isEmpty || kDebugMode) {
return _runApp();
}
await SentryFlutter.init((options) {
options.dsn = Config.sentryDsn;
options.tracesSampleRate = 1.0;
options.sampleRate = 1.0;
options.release = '${Pubspec.name}@${Pubspec.ref}';
options.diagnosticLevel = SentryLevel.info;
options.enablePrintBreadcrumbs = true;
options.maxBreadcrumbs = 512;
options.enableTimeToFullDisplayTracing = true;
options.enableAppHangTracking = true;
options.enableLogs = true;
options.beforeSend = (SentryEvent event, Hint? hint) {
// Modules are meaningless in Flutter.
event.modules = {};
final SentryException? sentryException =
event.exceptions?.firstOrNull;
final dynamic exception = sentryException?.throwable;
// Connection related exceptions shouldn't be logged.
if (exception is Exception && exception.isNetworkRelated) {
final Exception unreachable = UnreachableException();
return SentryEvent(
eventId: event.eventId,
timestamp: event.timestamp,
modules: event.modules,
tags: event.tags,
fingerprint: event.fingerprint,
breadcrumbs: event.breadcrumbs,
exceptions: [
SentryException(
type: 'UnreachableException',
value: unreachable.toString(),
stackTrace: sentryException?.stackTrace,
mechanism: sentryException?.mechanism,
throwable: unreachable,
),
],
threads: event.threads,
sdk: event.sdk,
platform: event.platform,
logger: event.logger,
serverName: event.serverName,
release: event.release,
dist: event.dist,
environment: event.environment,
message: event.message,
transaction: event.transaction,
throwable: event.throwable,
level: event.level,
culprit: event.culprit,
user: event.user,
contexts: event.contexts,
request: event.request,
debugMeta: event.debugMeta,
type: event.type,
);
}
// [Backoff] related exceptions shouldn't be logged.
if (exception is OperationCanceledException ||
exception.toString() == 'Data is not loaded') {
return null;
}
return event;
};
});
// Transaction indicating Flutter engine has rasterized the first frame.
final ISentrySpan ready = Sentry.startTransaction(
'ui.app.ready',
'ui',
autoFinishAfter: const Duration(minutes: 2),
startTimestamp: DateTime.now().subtract(watch.elapsed),
)..startChild('ready');
WidgetsBinding.instance.waitUntilFirstFrameRasterized.then(
(_) => ready.finish(),
);
await _runApp();
},
(error, stackTrace) {
// If Sentry is enabled, then report the exception.
if (Config.sentryDsn.isNotEmpty && !kDebugMode) {
WebUtils.consoleError(
'Uncaught (in promise) DartError: $error\n'
'${stackTrace.toString().split('\n').where((e) => e.isNotEmpty).map((e) => ' at $e\n').join()}',
);
Sentry.captureException(error, stackTrace: stackTrace);
}
// Otherwise rethrow the exception to the parent `Zone`.
else {
Zone.root.handleUncaughtError(error, stackTrace);
}
},
);
}