Null safety migration

This commit is contained in:
Neeraj Gupta
2023-04-08 17:26:28 +05:30
parent 537b3d2e4d
commit 84bf988de4
2 changed files with 72 additions and 81 deletions

View File

@@ -1,5 +1,3 @@
// @dart=2.9
library super_logging;
import 'dart:async';
@@ -8,6 +6,7 @@ import 'dart:core';
import 'dart:io';
import 'package:ente_auth/core/logging/tunneled_transport.dart';
import 'package:ente_auth/models/typedefs.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
@@ -20,8 +19,6 @@ import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uuid/uuid.dart';
typedef FutureOrVoidCallback = FutureOr<void> Function();
extension SuperString on String {
Iterable<String> chunked(int chunkSize) sync* {
var start = 0;
@@ -40,7 +37,7 @@ extension SuperString on String {
}
extension SuperLogRecord on LogRecord {
String toPrettyString([String extraLines]) {
String toPrettyString([String? extraLines]) {
final header = "[$loggerName] [$level] [$time]";
var msg = "$header $message";
@@ -78,9 +75,9 @@ class LogConfig {
/// ```
///
/// If this is [null], Sentry logger is completely disabled (default).
String sentryDsn;
String? sentryDsn;
String tunnel;
String? tunnel;
/// A built-in retry mechanism for sending errors to sentry.
///
@@ -97,7 +94,7 @@ class LogConfig {
/// A non-empty string will be treated as an explicit path to a directory.
///
/// The chosen directory can be accessed using [SuperLogging.logFile.parent].
String logDirPath;
String? logDirPath;
/// The maximum number of log files inside [logDirPath].
///
@@ -115,12 +112,12 @@ class LogConfig {
/// any uncaught errors during its execution will be reported.
///
/// Works by using [FlutterError.onError] and [runZoned].
FutureOrVoidCallback body;
FutureOrVoidCallback? body;
/// The date format for storing log files.
///
/// `DateFormat('y-M-d')` by default.
DateFormat dateFmt;
DateFormat? dateFmt;
String prefix;
@@ -144,77 +141,78 @@ class SuperLogging {
static final $ = Logger('ente_logging');
/// The current super logging configuration
static LogConfig config;
static late LogConfig config;
static SharedPreferences _preferences;
static late SharedPreferences _preferences;
static const keyShouldReportErrors = "should_report_errors";
static const keyAnonymousUserID = "anonymous_user_id";
static Future<void> main([LogConfig config]) async {
config ??= LogConfig();
SuperLogging.config = config;
static Future<void> main([LogConfig? appConfig]) async {
appConfig ??= LogConfig();
SuperLogging.config = appConfig;
WidgetsFlutterBinding.ensureInitialized();
_preferences = await SharedPreferences.getInstance();
appVersion ??= await getAppVersion();
final loggingEnabled = config.enableInDebugMode || kReleaseMode;
final enable = appConfig.enableInDebugMode || kReleaseMode;
sentryIsEnabled =
loggingEnabled && config.sentryDsn != null && shouldReportErrors();
fileIsEnabled = loggingEnabled && config.logDirPath != null;
enable && appConfig.sentryDsn != null && shouldReportErrors();
fileIsEnabled = enable && appConfig.logDirPath != null;
if (fileIsEnabled) {
await setupLogDir();
}
if (sentryIsEnabled) {
setupSentry();
}
Logger.root.level = Level.ALL;
Logger.root.onRecord.listen(onLogRecord);
if (sentryIsEnabled) {
setupSentry();
} else {
$.info("Sentry is disabled");
}
if (!loggingEnabled) {
if (!enable) {
$.info("detected debug mode; sentry & file logging disabled.");
}
if (fileIsEnabled) {
$.info("log file for today: $logFile with prefix ${config.prefix}");
$.info("log file for today: $logFile with prefix ${appConfig.prefix}");
}
if (sentryIsEnabled) {
$.info("sentry uploader started");
}
if (config.body == null) return;
if (appConfig.body == null) return;
if (loggingEnabled && sentryIsEnabled) {
if (enable && sentryIsEnabled) {
await SentryFlutter.init(
(options) {
options.dsn = config.sentryDsn;
options.dsn = appConfig!.sentryDsn;
options.httpClient = http.Client();
if (config.tunnel != null) {
if (appConfig.tunnel != null) {
options.transport =
TunneledTransport(Uri.parse(config.tunnel), options);
TunneledTransport(Uri.parse(appConfig.tunnel!), options);
}
},
appRunner: () => config.body(),
appRunner: () => appConfig!.body!(),
);
} else {
await config.body();
await appConfig.body!();
}
}
static void setUserID(String userID) async {
if (config?.sentryDsn != null) {
if (config.sentryDsn != null) {
Sentry.configureScope((scope) => scope.user = SentryUser(id: userID));
$.info("setting sentry user ID to: $userID");
}
}
static Future<void> _sendErrorToSentry(Object error, StackTrace stack) async {
static Future<void> _sendErrorToSentry(
Object error,
StackTrace? stack,
) async {
try {
await Sentry.captureException(
error,
@@ -230,14 +228,14 @@ class SuperLogging {
static Future onLogRecord(LogRecord rec) async {
// log misc info if it changed
String extraLines = "app version: '$appVersion'\n";
String? extraLines = "app version: '$appVersion'\n";
if (extraLines != _lastExtraLines) {
_lastExtraLines = extraLines;
} else {
extraLines = null;
}
final str = config.prefix + " " + rec.toPrettyString(extraLines);
final str = (config.prefix) + " " + rec.toPrettyString(extraLines);
// write to stdout
printLog(str);
@@ -251,16 +249,8 @@ class SuperLogging {
}
// add error to sentry queue
if (sentryIsEnabled) {
if (rec.error != null) {
_sendErrorToSentry(rec.error, null);
} else if (rec.level == Level.SEVERE || rec.level == Level.SHOUT) {
if (rec.error != null) {
_sendErrorToSentry(rec.error, null);
} else {
_sendErrorToSentry(rec.message, null);
}
}
if (sentryIsEnabled && rec.error != null) {
_sendErrorToSentry(rec.error!, null);
}
}
@@ -268,12 +258,12 @@ class SuperLogging {
static bool isFlushing = false;
static void flushQueue() async {
if (isFlushing) {
if (isFlushing || logFile == null) {
return;
}
isFlushing = true;
final entry = fileQueueEntries.removeFirst();
await logFile.writeAsString(entry, mode: FileMode.append, flush: true);
await logFile!.writeAsString(entry, mode: FileMode.append, flush: true);
isFlushing = false;
if (fileQueueEntries.isNotEmpty) {
flushQueue();
@@ -292,7 +282,7 @@ class SuperLogging {
static final sentryQueueControl = StreamController<Error>();
/// Whether sentry logging is currently enabled or not.
static bool sentryIsEnabled;
static bool sentryIsEnabled = false;
static Future<void> setupSentry() async {
$.info("Setting up sentry");
@@ -318,7 +308,7 @@ class SuperLogging {
static bool shouldReportErrors() {
if (_preferences.containsKey(keyShouldReportErrors)) {
return _preferences.getBool(keyShouldReportErrors);
return _preferences.getBool(keyShouldReportErrors)!;
} else {
return false;
}
@@ -333,22 +323,22 @@ class SuperLogging {
//ignore: prefer_const_constructors
await _preferences.setString(keyAnonymousUserID, Uuid().v4());
}
return _preferences.getString(keyAnonymousUserID);
return _preferences.getString(keyAnonymousUserID)!;
}
/// The log file currently in use.
static File logFile;
static File? logFile;
/// Whether file logging is currently enabled or not.
static bool fileIsEnabled;
static bool fileIsEnabled = false;
static Future<void> setupLogDir() async {
var dirPath = config.logDirPath;
// choose [logDir]
if (dirPath.isEmpty) {
if (dirPath == null || dirPath.isEmpty) {
final root = await getExternalStorageDirectory();
dirPath = '${root.path}/logs';
dirPath = '${root!.path}/logs';
}
// create [logDir]
@@ -361,16 +351,19 @@ class SuperLogging {
// collect all log files with valid names
await for (final file in dir.list()) {
try {
final date = config.dateFmt.parse(basename(file.path));
final date = config.dateFmt!.parse(basename(file.path));
dates[file as File] = date;
files.add(file);
} on FormatException {}
}
final nowTime = DateTime.now();
// delete old log files, if [maxLogFiles] is exceeded.
if (files.length > config.maxLogFiles) {
// sort files based on ascending order of date (older first)
files.sort((a, b) => dates[a].compareTo(dates[b]));
files.sort(
(a, b) => (dates[a] ?? nowTime).compareTo((dates[b] ?? nowTime)),
);
final extra = files.length - config.maxLogFiles;
final toDelete = files.sublist(0, extra);
@@ -385,13 +378,13 @@ class SuperLogging {
}
}
logFile = File("$dirPath/${config.dateFmt.format(DateTime.now())}.txt");
logFile = File("$dirPath/${config.dateFmt!.format(DateTime.now())}.txt");
}
/// Current app version, obtained from package_info plugin.
///
/// See: [getAppVersion]
static String appVersion;
static String? appVersion;
static Future<String> getAppVersion() async {
final pkgInfo = await PackageInfo.fromPlatform();

View File

@@ -1,5 +1,3 @@
// @dart=2.9
import 'dart:convert';
import 'package:http/http.dart';
@@ -10,9 +8,9 @@ class TunneledTransport implements Transport {
final Uri _tunnel;
final SentryOptions _options;
final Dsn _dsn;
final Dsn? _dsn;
_CredentialBuilder _credentialBuilder;
_CredentialBuilder? _credentialBuilder;
final Map<String, String> _headers;
@@ -21,7 +19,7 @@ class TunneledTransport implements Transport {
}
TunneledTransport._(this._tunnel, this._options)
: _dsn = Dsn.parse(_options.dsn),
: _dsn = _options.dsn != null ? Dsn.parse(_options.dsn!) : null,
_headers = _buildHeaders(
_options.platformChecker.isWeb,
_options.sdk.identifier,
@@ -34,7 +32,7 @@ class TunneledTransport implements Transport {
}
@override
Future<SentryId> send(SentryEnvelope envelope) async {
Future<SentryId?> send(SentryEnvelope envelope) async {
final streamedRequest = await _createStreamedRequest(envelope);
final response = await _options.httpClient
.send(streamedRequest)
@@ -47,7 +45,7 @@ class TunneledTransport implements Transport {
_options.logger(
SentryLevel.error,
'API returned an error, statusCode = ${response.statusCode}, '
'body = ${response.body}',
'body = ${response.body}',
);
}
return const SentryId.empty();
@@ -66,15 +64,15 @@ class TunneledTransport implements Transport {
}
Future<StreamedRequest> _createStreamedRequest(
SentryEnvelope envelope,
) async {
SentryEnvelope envelope,
) async {
final streamedRequest = StreamedRequest('POST', _tunnel);
envelope
.envelopeStream(_options)
.listen(streamedRequest.sink.add)
.onDone(streamedRequest.sink.close);
streamedRequest.headers.addAll(_credentialBuilder.configure(_headers));
streamedRequest.headers.addAll(_credentialBuilder!.configure(_headers));
return streamedRequest;
}
@@ -92,13 +90,13 @@ class _CredentialBuilder {
_clock = clock;
factory _CredentialBuilder(
Dsn dsn,
String sdkIdentifier,
ClockProvider clock,
) {
Dsn? dsn,
String sdkIdentifier,
ClockProvider clock,
) {
final authHeader = _buildAuthHeader(
publicKey: dsn.publicKey,
secretKey: dsn.secretKey,
publicKey: dsn?.publicKey,
secretKey: dsn?.secretKey,
sdkIdentifier: sdkIdentifier,
);
@@ -106,9 +104,9 @@ class _CredentialBuilder {
}
static String _buildAuthHeader({
String publicKey,
String secretKey,
String sdkIdentifier,
String? publicKey,
String? secretKey,
String? sdkIdentifier,
}) {
var header = 'Sentry sentry_version=7, sentry_client=$sdkIdentifier, '
'sentry_key=$publicKey';