Swap crash reporting with unified analytics (#148525)

Fixes: https://github.com/flutter/flutter/issues/147260

(this is a remake of https://github.com/flutter/flutter/pull/147296; in hindsight I could have force-pushed there instead but 🤷)
This commit is contained in:
Andrew Kolos 2024-05-17 18:30:13 -07:00 committed by GitHub
parent 4c35ab5879
commit ac6409b311
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 27 additions and 23 deletions

View File

@ -201,10 +201,10 @@ Future<int> _handleToolError(
globals.analytics.send(Event.exception(exception: error.runtimeType.toString())); globals.analytics.send(Event.exception(exception: error.runtimeType.toString()));
await asyncGuard(() async { await asyncGuard(() async {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
usage: globals.flutterUsage,
platform: globals.platform, platform: globals.platform,
logger: globals.logger, logger: globals.logger,
operatingSystemUtils: globals.os, operatingSystemUtils: globals.os,
analytics: globals.analytics,
); );
await crashReportSender.sendReport( await crashReportSender.sendReport(
error: error, error: error,

View File

@ -6,6 +6,7 @@ import 'dart:async';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:unified_analytics/unified_analytics.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart'; import '../base/io.dart';
@ -15,7 +16,6 @@ import '../base/platform.dart';
import '../doctor.dart'; import '../doctor.dart';
import '../project.dart'; import '../project.dart';
import 'github_template.dart'; import 'github_template.dart';
import 'reporting.dart';
/// Tells crash backend that the error is from the Flutter CLI. /// Tells crash backend that the error is from the Flutter CLI.
const String _kProductId = 'Flutter_Tools'; const String _kProductId = 'Flutter_Tools';
@ -105,21 +105,21 @@ class CrashReporter {
class CrashReportSender { class CrashReportSender {
CrashReportSender({ CrashReportSender({
http.Client? client, http.Client? client,
required Usage usage,
required Platform platform, required Platform platform,
required Logger logger, required Logger logger,
required OperatingSystemUtils operatingSystemUtils, required OperatingSystemUtils operatingSystemUtils,
required Analytics analytics,
}) : _client = client ?? http.Client(), }) : _client = client ?? http.Client(),
_usage = usage,
_platform = platform, _platform = platform,
_logger = logger, _logger = logger,
_operatingSystemUtils = operatingSystemUtils; _operatingSystemUtils = operatingSystemUtils,
_analytics = analytics;
final http.Client _client; final http.Client _client;
final Usage _usage;
final Platform _platform; final Platform _platform;
final Logger _logger; final Logger _logger;
final OperatingSystemUtils _operatingSystemUtils; final OperatingSystemUtils _operatingSystemUtils;
final Analytics _analytics;
bool _crashReportSent = false; bool _crashReportSent = false;
@ -154,7 +154,7 @@ class CrashReportSender {
final String flutterVersion = getFlutterVersion(); final String flutterVersion = getFlutterVersion();
// We don't need to report exceptions happening on user branches // We don't need to report exceptions happening on user branches
if (_usage.suppressAnalytics || RegExp(r'^\[user-branch\]\/').hasMatch(flutterVersion)) { if (!_analytics.okToSend || RegExp(r'^\[user-branch\]\/').hasMatch(flutterVersion)) {
return; return;
} }
@ -168,7 +168,7 @@ class CrashReportSender {
); );
final http.MultipartRequest req = http.MultipartRequest('POST', uri); final http.MultipartRequest req = http.MultipartRequest('POST', uri);
req.fields['uuid'] = _usage.clientId; req.fields['uuid'] = _analytics.clientId;
req.fields['product'] = _kProductId; req.fields['product'] = _kProductId;
req.fields['version'] = flutterVersion; req.fields['version'] = flutterVersion;
req.fields['osName'] = _platform.operatingSystem; req.fields['osName'] = _platform.operatingSystem;

View File

@ -13,26 +13,30 @@ import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/crash_reporting.dart'; import 'package:flutter_tools/src/reporting/crash_reporting.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:http/testing.dart'; import 'package:http/testing.dart';
import 'package:test/fake.dart'; import 'package:test/fake.dart';
import 'package:unified_analytics/unified_analytics.dart';
import '../src/common.dart'; import '../src/common.dart';
import '../src/fake_process_manager.dart'; import '../src/fake_process_manager.dart';
import '../src/fakes.dart';
void main() { void main() {
late BufferLogger logger; late BufferLogger logger;
late FileSystem fs; late MemoryFileSystem fs;
late TestUsage testUsage;
late Platform platform; late Platform platform;
late OperatingSystemUtils operatingSystemUtils; late OperatingSystemUtils operatingSystemUtils;
late StackTrace stackTrace; late StackTrace stackTrace;
late FakeAnalytics fakeAnalytics;
setUp(() async { setUp(() async {
logger = BufferLogger.test(); logger = BufferLogger.test();
fs = MemoryFileSystem.test(); fs = MemoryFileSystem.test();
testUsage = TestUsage(); fakeAnalytics = getInitializedFakeAnalyticsInstance(
fs: fs,
fakeFlutterVersion: FakeFlutterVersion(),
);
platform = FakePlatform(environment: <String, String>{}); platform = FakePlatform(environment: <String, String>{});
operatingSystemUtils = OperatingSystemUtils( operatingSystemUtils = OperatingSystemUtils(
@ -63,7 +67,7 @@ void main() {
'version': 'test-version', 'version': 'test-version',
}, },
)); ));
expect(crashInfo.fields?['uuid'], testUsage.clientId); expect(crashInfo.fields?['uuid'], fakeAnalytics.clientId);
expect(crashInfo.fields?['product'], 'Flutter_Tools'); expect(crashInfo.fields?['product'], 'Flutter_Tools');
expect(crashInfo.fields?['version'], 'test-version'); expect(crashInfo.fields?['version'], 'test-version');
expect(crashInfo.fields?['osName'], 'linux'); expect(crashInfo.fields?['osName'], 'linux');
@ -104,14 +108,14 @@ void main() {
}); });
testWithoutContext('suppress analytics', () async { testWithoutContext('suppress analytics', () async {
testUsage.suppressAnalytics = true; fakeAnalytics.suppressTelemetry();
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: CrashingCrashReportSender(const SocketException('no internets')), client: CrashingCrashReportSender(const SocketException('no internets')),
usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
analytics: fakeAnalytics,
); );
await crashReportSender.sendReport( await crashReportSender.sendReport(
@ -126,7 +130,7 @@ void main() {
group('allow analytics', () { group('allow analytics', () {
setUp(() async { setUp(() async {
testUsage.suppressAnalytics = false; await fakeAnalytics.setTelemetry(true);
}); });
testWithoutContext('should send crash reports', () async { testWithoutContext('should send crash reports', () async {
@ -134,10 +138,10 @@ void main() {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: MockCrashReportSender(requestInfo), client: MockCrashReportSender(requestInfo),
usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
analytics: fakeAnalytics,
); );
await crashReportSender.sendReport( await crashReportSender.sendReport(
@ -153,10 +157,10 @@ void main() {
testWithoutContext('should print an explanatory message when there is a SocketException', () async { testWithoutContext('should print an explanatory message when there is a SocketException', () async {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: CrashingCrashReportSender(const SocketException('no internets')), client: CrashingCrashReportSender(const SocketException('no internets')),
usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
analytics: fakeAnalytics,
); );
await crashReportSender.sendReport( await crashReportSender.sendReport(
@ -172,10 +176,10 @@ void main() {
testWithoutContext('should print an explanatory message when there is an HttpException', () async { testWithoutContext('should print an explanatory message when there is an HttpException', () async {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: CrashingCrashReportSender(const HttpException('no internets')), client: CrashingCrashReportSender(const HttpException('no internets')),
usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
analytics: fakeAnalytics,
); );
await crashReportSender.sendReport( await crashReportSender.sendReport(
@ -191,10 +195,10 @@ void main() {
testWithoutContext('should print an explanatory message when there is a ClientException', () async { testWithoutContext('should print an explanatory message when there is a ClientException', () async {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: CrashingCrashReportSender(const HttpException('no internets')), client: CrashingCrashReportSender(const HttpException('no internets')),
usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
analytics: fakeAnalytics,
); );
await crashReportSender.sendReport( await crashReportSender.sendReport(
@ -212,10 +216,10 @@ void main() {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: MockCrashReportSender(requestInfo), client: MockCrashReportSender(requestInfo),
usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
analytics: fakeAnalytics,
); );
await crashReportSender.sendReport( await crashReportSender.sendReport(
@ -266,10 +270,10 @@ void main() {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: mockClient, client: mockClient,
usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
analytics: fakeAnalytics,
); );
await crashReportSender.sendReport( await crashReportSender.sendReport(
@ -303,10 +307,10 @@ void main() {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: mockClient, client: mockClient,
usage: testUsage,
platform: environmentPlatform, platform: environmentPlatform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
analytics: fakeAnalytics,
); );
await crashReportSender.sendReport( await crashReportSender.sendReport(