2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-27 04:56:48 +00:00
Oliver b02dc5bac7
Simplify DSN file (#475)
* Add checks for empty sentry DSN

* Add default DSN key

* Fix CI workflows
2024-03-06 21:09:06 +11:00

230 lines
6.1 KiB
Dart

import "dart:io";
import "package:device_info_plus/device_info_plus.dart";
import "package:one_context/one_context.dart";
import "package:package_info_plus/package_info_plus.dart";
import "package:sentry_flutter/sentry_flutter.dart";
import "package:inventree/api.dart";
import "package:inventree/dsn.dart";
import "package:inventree/preferences.dart";
Future<Map<String, dynamic>> getDeviceInfo() async {
// Extract device information
final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
Map<String, dynamic> device_info = {};
// Extract some platform information
if (Platform.isIOS) {
final iosDeviceInfo = await deviceInfo.iosInfo;
device_info = {
"name": iosDeviceInfo.name,
"model": iosDeviceInfo.model,
"systemName": iosDeviceInfo.systemName,
"systemVersion": iosDeviceInfo.systemVersion,
"localizedModel": iosDeviceInfo.localizedModel,
"utsname": iosDeviceInfo.utsname.sysname,
"identifierForVendor": iosDeviceInfo.identifierForVendor,
"isPhysicalDevice": iosDeviceInfo.isPhysicalDevice,
};
} else if (Platform.isAndroid) {
final androidDeviceInfo = await deviceInfo.androidInfo;
device_info = {
"type": androidDeviceInfo.type,
"model": androidDeviceInfo.model,
"device": androidDeviceInfo.device,
"id": androidDeviceInfo.id,
"androidId": androidDeviceInfo.id,
"brand": androidDeviceInfo.brand,
"display": androidDeviceInfo.display,
"hardware": androidDeviceInfo.hardware,
"manufacturer": androidDeviceInfo.manufacturer,
"product": androidDeviceInfo.product,
"systemVersion": androidDeviceInfo.version.release,
"supported32BitAbis": androidDeviceInfo.supported32BitAbis,
"supported64BitAbis": androidDeviceInfo.supported64BitAbis,
"supportedAbis": androidDeviceInfo.supportedAbis,
"isPhysicalDevice": androidDeviceInfo.isPhysicalDevice,
};
}
return device_info;
}
Map<String, dynamic> getServerInfo() => {
"version": InvenTreeAPI().serverVersion,
"apiVersion": InvenTreeAPI().apiVersion,
};
Future<Map<String, dynamic>> getAppInfo() async {
// Add app info
final package_info = await PackageInfo.fromPlatform();
return {
"name": package_info.appName,
"build": package_info.buildNumber,
"version": package_info.version,
"package": package_info.packageName,
};
}
bool isInDebugMode() {
bool inDebugMode = false;
assert(inDebugMode = true);
return inDebugMode;
}
Future<bool> sentryReportMessage(String message, {Map<String, String>? context}) async {
if (SENTRY_DSN_KEY.isEmpty) {
return false;
}
final server_info = getServerInfo();
final app_info = await getAppInfo();
final device_info = await getDeviceInfo();
// Remove any sensitive information from a URL
if (context != null) {
if (context.containsKey("url")) {
final String url = context["url"] ?? "";
try {
final uri = Uri.parse(url);
// We don't care about the server address, only the path and query parameters!
// Overwrite the provided URL
context["url"] = uri.path + "?" + uri.query;
} catch (error) {
// Ignore if any errors are thrown here
}
}
}
print("Sending user message to Sentry: ${message}, ${context}");
if (isInDebugMode()) {
print("----- In dev mode. Not sending message to Sentry.io -----");
return true;
}
final upload = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool;
if (!upload) {
print("----- Error reporting disabled -----");
return true;
}
Sentry.configureScope((scope) {
scope.setExtra("server", server_info);
scope.setExtra("app", app_info);
scope.setExtra("device", device_info);
if (context != null) {
scope.setExtra("context", context);
}
// Catch stacktrace data if possible
scope.setExtra("stacktrace", StackTrace.current.toString());
});
try {
await Sentry.captureMessage(message);
return true;
} catch (error) {
print("Error uploading sentry messages...");
print(error);
return false;
}
}
/*
* Report an error message to sentry.io
*/
Future<void> sentryReportError(String source, dynamic error, StackTrace? stackTrace, {Map<String, String> context = const {}}) async {
print("----- Sentry Intercepted error: $error -----");
print(stackTrace);
// Errors thrown in development mode are unlikely to be interesting. You can
// check if you are running in dev mode using an assertion and omit sending
// the report.
if (isInDebugMode()) {
print("----- In dev mode. Not sending report to Sentry.io -----");
return;
}
if (SENTRY_DSN_KEY.isEmpty) {
return;
}
final upload = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool;
if (!upload) {
print("----- Error reporting disabled -----");
return;
}
// Some errors are outside our control, and we do not want to "pollute" the uploaded data
if (source == "FlutterError.onError") {
String errorString = error.toString();
// Missing media file
if (errorString.contains("HttpException") && errorString.contains("404") && errorString.contains("/media/")) {
return;
}
// Local file system exception
if (errorString.contains("FileSystemException")) {
return;
}
}
final server_info = getServerInfo();
final app_info = await getAppInfo();
final device_info = await getDeviceInfo();
// Ensure we pass the 'source' of the error
context["source"] = source;
if (OneContext.hasContext) {
final ctx = OneContext().context;
if (ctx != null) {
context["widget"] = ctx.widget.toString();
context["widgetType"] = ctx.widget.runtimeType.toString();
}
}
Sentry.configureScope((scope) {
scope.setExtra("server", server_info);
scope.setExtra("app", app_info);
scope.setExtra("device", device_info);
scope.setExtra("context", context);
});
Sentry.captureException(error, stackTrace: stackTrace).catchError((error) {
print("Error uploading information to Sentry.io:");
print(error);
return SentryId.empty();
}).then((response) {
print("Uploaded information to Sentry.io : ${response.toString()}");
});
}