mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
Add analytics to analyzer-cli and analysis server.
BUG= R=brianwilkerson@google.com, scheglov@google.com, zra@google.com Review-Url: https://codereview.chromium.org/2963323002 .
This commit is contained in:
parent
2bfde5a34e
commit
d4abd49df7
2
DEPS
2
DEPS
|
@ -122,7 +122,7 @@ vars = {
|
|||
"test_tag": "@0.12.18+1",
|
||||
"tuple_tag": "@v1.0.1",
|
||||
"typed_data_tag": "@1.1.3",
|
||||
"usage_tag": "@3.2.0+1",
|
||||
"usage_tag": "@3.3.0",
|
||||
"utf_tag": "@0.9.0+3",
|
||||
"watcher_tag": "@0.9.7+3",
|
||||
"web_components_rev": "@6349e09f9118dce7ae1b309af5763745e25a9d61",
|
||||
|
|
|
@ -11,14 +11,17 @@ dart_package("analysis_server") {
|
|||
|
||||
deps = [
|
||||
"//dart/pkg/analyzer",
|
||||
"//dart/pkg/telemetry",
|
||||
"//dart/third_party/pkg/linter",
|
||||
"//third_party/dart-pkg/pub/args",
|
||||
"//third_party/dart-pkg/pub/dart_style",
|
||||
"//third_party/dart-pkg/pub/intl",
|
||||
"//third_party/dart-pkg/pub/isolate",
|
||||
"//third_party/dart-pkg/pub/logging",
|
||||
"//third_party/dart-pkg/pub/package_config",
|
||||
"//third_party/dart-pkg/pub/path",
|
||||
"//third_party/dart-pkg/pub/plugin",
|
||||
"//third_party/dart-pkg/pub/usage",
|
||||
"//third_party/dart-pkg/pub/watcher",
|
||||
"//third_party/dart-pkg/pub/yaml",
|
||||
]
|
||||
|
|
|
@ -61,6 +61,8 @@ import 'package:front_end/src/base/performace_logger.dart';
|
|||
import 'package:front_end/src/incremental/byte_store.dart';
|
||||
import 'package:front_end/src/incremental/file_byte_store.dart';
|
||||
import 'package:plugin/plugin.dart';
|
||||
import 'package:telemetry/crash_reporting.dart';
|
||||
import 'package:telemetry/telemetry.dart' as telemetry;
|
||||
import 'package:watcher/watcher.dart';
|
||||
|
||||
typedef void OptionUpdater(AnalysisOptionsImpl options);
|
||||
|
@ -778,6 +780,9 @@ class AnalysisServer {
|
|||
new ServerErrorParams(fatal, message, buffer.toString())
|
||||
.toNotification());
|
||||
|
||||
// send to crash reporting
|
||||
options.crashReportSender?.sendReport(exception, stackTrace: stackTrace);
|
||||
|
||||
// remember the last few exceptions
|
||||
if (exception is CaughtException) {
|
||||
stackTrace ??= exception.stackTrace;
|
||||
|
@ -904,8 +909,13 @@ class AnalysisServer {
|
|||
return contextManager.isInAnalysisRoot(file);
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
Future<Null> shutdown() async {
|
||||
running = false;
|
||||
|
||||
await options.analytics
|
||||
?.waitForLastPing(timeout: new Duration(milliseconds: 200));
|
||||
options.analytics?.close();
|
||||
|
||||
// Defer closing the channel and shutting down the instrumentation server so
|
||||
// that the shutdown response can be sent and logged.
|
||||
new Future(() {
|
||||
|
@ -1043,16 +1053,30 @@ class AnalysisServer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Various IDE options.
|
||||
*/
|
||||
class AnalysisServerOptions {
|
||||
bool useAnalysisHighlight2 = false;
|
||||
bool enableVerboseFlutterCompletions = false;
|
||||
|
||||
String fileReadMode = 'as-is';
|
||||
String newAnalysisDriverLog;
|
||||
|
||||
String clientId;
|
||||
String clientVersion;
|
||||
|
||||
// IDE options
|
||||
bool enableVerboseFlutterCompletions = false;
|
||||
/**
|
||||
* The analytics instance; note, this object can be `null`, and should be
|
||||
* accessed via a null-aware operator.
|
||||
*/
|
||||
telemetry.Analytics analytics;
|
||||
|
||||
/**
|
||||
* The crash report sender instance; note, this object can be `null`, and
|
||||
* should be accessed via a null-aware operator.
|
||||
*/
|
||||
CrashReportSender crashReportSender;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -278,6 +278,8 @@ class AnalysisDomainHandler extends AbstractRequestHandler {
|
|||
* Implement the 'analysis.reanalyze' request.
|
||||
*/
|
||||
Response reanalyze(Request request) {
|
||||
server.options.analytics?.sendEvent('analysis', 'reanalyze');
|
||||
|
||||
AnalysisReanalyzeParams params =
|
||||
new AnalysisReanalyzeParams.fromRequest(request);
|
||||
List<String> roots = params.roots;
|
||||
|
@ -314,6 +316,10 @@ class AnalysisDomainHandler extends AbstractRequestHandler {
|
|||
var params = new AnalysisSetAnalysisRootsParams.fromRequest(request);
|
||||
List<String> includedPathList = params.included;
|
||||
List<String> excludedPathList = params.excluded;
|
||||
|
||||
server.options.analytics?.sendEvent('analysis', 'setAnalysisRoots',
|
||||
value: includedPathList.length);
|
||||
|
||||
// validate
|
||||
for (String path in includedPathList) {
|
||||
if (!server.isValidFilePath(path)) {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:analysis_server/protocol/protocol.dart';
|
||||
import 'package:analysis_server/protocol/protocol_constants.dart';
|
||||
import 'package:analysis_server/protocol/protocol_generated.dart';
|
||||
|
@ -39,7 +41,8 @@ class ServerDomainHandler implements RequestHandler {
|
|||
} else if (requestName == SERVER_REQUEST_SET_SUBSCRIPTIONS) {
|
||||
return setSubscriptions(request);
|
||||
} else if (requestName == SERVER_REQUEST_SHUTDOWN) {
|
||||
return shutdown(request);
|
||||
shutdown(request);
|
||||
return Response.DELAYED_RESPONSE;
|
||||
}
|
||||
} on RequestFailure catch (exception) {
|
||||
return exception.response;
|
||||
|
@ -63,9 +66,9 @@ class ServerDomainHandler implements RequestHandler {
|
|||
/**
|
||||
* Cleanly shutdown the analysis server.
|
||||
*/
|
||||
Response shutdown(Request request) {
|
||||
server.shutdown();
|
||||
Future<Null> shutdown(Request request) async {
|
||||
await server.shutdown();
|
||||
Response response = new ServerShutdownResult().toResponse(request.id);
|
||||
return response;
|
||||
server.sendResponse(response);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,8 @@ class EditDomainHandler extends AbstractRequestHandler {
|
|||
}
|
||||
|
||||
Response format(Request request) {
|
||||
server.options.analytics?.sendEvent('edit', 'format');
|
||||
|
||||
EditFormatParams params = new EditFormatParams.fromRequest(request);
|
||||
String file = params.file;
|
||||
|
||||
|
@ -270,6 +272,8 @@ class EditDomainHandler extends AbstractRequestHandler {
|
|||
}
|
||||
|
||||
Future getPostfixCompletion(Request request) async {
|
||||
server.options.analytics?.sendEvent('edit', 'getPostfixCompletion');
|
||||
|
||||
var params = new EditGetPostfixCompletionParams.fromRequest(request);
|
||||
SourceChange change;
|
||||
|
||||
|
@ -448,6 +452,8 @@ class EditDomainHandler extends AbstractRequestHandler {
|
|||
}
|
||||
|
||||
Future<Null> organizeDirectives(Request request) async {
|
||||
server.options.analytics?.sendEvent('edit', 'organizeDirectives');
|
||||
|
||||
var params = new EditOrganizeDirectivesParams.fromRequest(request);
|
||||
// prepare file
|
||||
String file = params.file;
|
||||
|
@ -717,6 +723,12 @@ class _RefactoringManager {
|
|||
EMPTY_PROBLEM_LIST, EMPTY_PROBLEM_LIST, EMPTY_PROBLEM_LIST);
|
||||
// process the request
|
||||
var params = new EditGetRefactoringParams.fromRequest(_request);
|
||||
|
||||
if (params.kind != null) {
|
||||
server.options.analytics
|
||||
?.sendEvent('refactor', params.kind.name.toLowerCase());
|
||||
}
|
||||
|
||||
runZoned(() async {
|
||||
await _init(params.kind, params.file, params.offset, params.length);
|
||||
if (initStatus.hasFatalError) {
|
||||
|
|
|
@ -25,6 +25,8 @@ import 'package:args/args.dart';
|
|||
import 'package:linter/src/rules.dart' as linter;
|
||||
import 'package:plugin/manager.dart';
|
||||
import 'package:plugin/plugin.dart';
|
||||
import 'package:telemetry/crash_reporting.dart';
|
||||
import 'package:telemetry/telemetry.dart' as telemetry;
|
||||
|
||||
/// Commandline argument parser. (Copied from analyzer/lib/options.dart)
|
||||
/// TODO(pquitslund): replaces with a simple [ArgParser] instance
|
||||
|
@ -125,6 +127,10 @@ class CommandLineParser {
|
|||
String arg = args[i];
|
||||
if (arg.startsWith('--') && arg.length > 2) {
|
||||
String option = arg.substring(2);
|
||||
// remove any leading 'no-'
|
||||
if (option.startsWith('no-')) {
|
||||
option = option.substring(3);
|
||||
}
|
||||
// strip the last '=value'
|
||||
int equalsOffset = option.lastIndexOf('=');
|
||||
if (equalsOffset != -1) {
|
||||
|
@ -194,6 +200,16 @@ class Driver implements ServerStarter {
|
|||
*/
|
||||
static const String HELP_OPTION = "help";
|
||||
|
||||
/**
|
||||
* The name of the flag used to configure reporting analytics.
|
||||
*/
|
||||
static const String ANALYTICS_FLAG = "analytics";
|
||||
|
||||
/**
|
||||
* Suppress analytics for this session.
|
||||
*/
|
||||
static const String SUPPRESS_ANALYTICS_FLAG = "suppress-analytics";
|
||||
|
||||
/**
|
||||
* The name of the option used to cause instrumentation to also be written to
|
||||
* a local file.
|
||||
|
@ -232,8 +248,6 @@ class Driver implements ServerStarter {
|
|||
|
||||
/**
|
||||
* The path to the SDK.
|
||||
* TODO(paulberry): get rid of this once the 'analysis.updateSdks' request is
|
||||
* operational.
|
||||
*/
|
||||
static const String SDK_OPTION = "sdk";
|
||||
|
||||
|
@ -284,8 +298,43 @@ class Driver implements ServerStarter {
|
|||
AnalysisServer start(List<String> arguments) {
|
||||
CommandLineParser parser = _createArgParser();
|
||||
ArgResults results = parser.parse(arguments, <String, String>{});
|
||||
|
||||
AnalysisServerOptions analysisServerOptions = new AnalysisServerOptions();
|
||||
analysisServerOptions.useAnalysisHighlight2 =
|
||||
results[USE_ANALYSIS_HIGHLIGHT2];
|
||||
analysisServerOptions.fileReadMode = results[FILE_READ_MODE];
|
||||
analysisServerOptions.newAnalysisDriverLog =
|
||||
results[NEW_ANALYSIS_DRIVER_LOG];
|
||||
analysisServerOptions.clientId = results[CLIENT_ID];
|
||||
analysisServerOptions.clientVersion = results[CLIENT_VERSION];
|
||||
analysisServerOptions.enableVerboseFlutterCompletions =
|
||||
results[VERBOSE_FLUTTER_COMPLETIONS];
|
||||
|
||||
telemetry.Analytics analytics = telemetry.createAnalyticsInstance(
|
||||
'UA-26406144-29', 'analysis-server',
|
||||
disableForSession: results[SUPPRESS_ANALYTICS_FLAG]);
|
||||
analysisServerOptions.analytics = analytics;
|
||||
|
||||
if (analysisServerOptions.clientId != null) {
|
||||
// Record the client name as the application installer ID.
|
||||
analytics.setSessionValue('aiid', analysisServerOptions.clientId);
|
||||
}
|
||||
if (analysisServerOptions.clientVersion != null) {
|
||||
analytics.setSessionValue('cd1', analysisServerOptions.clientVersion);
|
||||
}
|
||||
|
||||
// TODO(devoncarew): Replace with the real crash product ID.
|
||||
analysisServerOptions.crashReportSender =
|
||||
new CrashReportSender('Dart_analysis_server', analytics);
|
||||
|
||||
if (results.wasParsed(ANALYTICS_FLAG)) {
|
||||
analytics.enabled = results[ANALYTICS_FLAG];
|
||||
print(telemetry.createAnalyticsStatusMessage(analytics.enabled));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (results[HELP_OPTION]) {
|
||||
_printUsage(parser.parser);
|
||||
_printUsage(parser.parser, analytics, fromHelp: true);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -298,25 +347,12 @@ class Driver implements ServerStarter {
|
|||
} on FormatException {
|
||||
print('Invalid port number: ${results[PORT_OPTION]}');
|
||||
print('');
|
||||
_printUsage(parser.parser);
|
||||
_printUsage(parser.parser, analytics);
|
||||
exitCode = 1;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
AnalysisServerOptions analysisServerOptions = new AnalysisServerOptions();
|
||||
analysisServerOptions.useAnalysisHighlight2 =
|
||||
results[USE_ANALYSIS_HIGHLIGHT2];
|
||||
analysisServerOptions.fileReadMode = results[FILE_READ_MODE];
|
||||
analysisServerOptions.newAnalysisDriverLog =
|
||||
results[NEW_ANALYSIS_DRIVER_LOG];
|
||||
|
||||
analysisServerOptions.clientId = results[CLIENT_ID];
|
||||
analysisServerOptions.clientVersion = results[CLIENT_VERSION];
|
||||
|
||||
analysisServerOptions.enableVerboseFlutterCompletions =
|
||||
results[VERBOSE_FLUTTER_COMPLETIONS];
|
||||
|
||||
//
|
||||
// Process all of the plugins so that extensions are registered.
|
||||
//
|
||||
|
@ -361,14 +397,17 @@ class Driver implements ServerStarter {
|
|||
new InstrumentationService(instrumentationServer);
|
||||
instrumentationService.logVersion(
|
||||
_readUuid(instrumentationService),
|
||||
results[CLIENT_ID],
|
||||
results[CLIENT_VERSION],
|
||||
analysisServerOptions.clientId,
|
||||
analysisServerOptions.clientVersion,
|
||||
AnalysisServer.VERSION,
|
||||
defaultSdk.sdkVersion);
|
||||
AnalysisEngine.instance.instrumentationService = instrumentationService;
|
||||
|
||||
_DiagnosticServerImpl diagnosticServer = new _DiagnosticServerImpl();
|
||||
|
||||
// Ping analytics with our initial call.
|
||||
analytics.sendScreenView('home');
|
||||
|
||||
//
|
||||
// Create the sockets and start listening for requests.
|
||||
//
|
||||
|
@ -452,8 +491,7 @@ class Driver implements ServerStarter {
|
|||
defaultsTo: false,
|
||||
negatable: false);
|
||||
parser.addOption(INSTRUMENTATION_LOG_FILE,
|
||||
help:
|
||||
"the path of the file to which instrumentation data will be written");
|
||||
help: "write instrumentation data to the given file");
|
||||
parser.addFlag(INTERNAL_PRINT_TO_CONSOLE,
|
||||
help: "enable sending `print` output to the console",
|
||||
defaultsTo: false,
|
||||
|
@ -462,6 +500,10 @@ class Driver implements ServerStarter {
|
|||
help: "set a destination for the new analysis driver's log");
|
||||
parser.addFlag(VERBOSE_FLUTTER_COMPLETIONS,
|
||||
help: "enable verbose code completion for Flutter (experimental)");
|
||||
parser.addFlag(ANALYTICS_FLAG,
|
||||
help: 'enable or disable sending analytics information to Google');
|
||||
parser.addFlag(SUPPRESS_ANALYTICS_FLAG,
|
||||
negatable: false, help: 'suppress analytics for this session');
|
||||
parser.addOption(PORT_OPTION,
|
||||
help: "the http diagnostic port on which the server provides"
|
||||
" status and performance information");
|
||||
|
@ -497,11 +539,21 @@ class Driver implements ServerStarter {
|
|||
/**
|
||||
* Print information about how to use the server.
|
||||
*/
|
||||
void _printUsage(ArgParser parser) {
|
||||
void _printUsage(ArgParser parser, telemetry.Analytics analytics,
|
||||
{bool fromHelp: false}) {
|
||||
print('Usage: $BINARY_NAME [flags]');
|
||||
print('');
|
||||
print('Supported flags are:');
|
||||
print(parser.usage);
|
||||
|
||||
// Print analytics status and information.
|
||||
if (fromHelp) {
|
||||
print('');
|
||||
print(telemetry.analyticsNotice);
|
||||
}
|
||||
print('');
|
||||
print(telemetry.createAnalyticsStatusMessage(analytics.enabled,
|
||||
command: ANALYTICS_FLAG));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,6 +16,8 @@ dependencies:
|
|||
package_config: '>=0.1.5 <2.0.0'
|
||||
path: any
|
||||
plugin: ^0.2.0
|
||||
telemetry: ^0.0.1
|
||||
usage: ^3.2.0+1
|
||||
watcher: any
|
||||
yaml: any
|
||||
dev_dependencies:
|
||||
|
|
|
@ -20,9 +20,10 @@ import 'mocks.dart';
|
|||
main() {
|
||||
AnalysisServer server;
|
||||
ServerDomainHandler handler;
|
||||
MockServerChannel serverChannel;
|
||||
|
||||
setUp(() {
|
||||
var serverChannel = new MockServerChannel();
|
||||
serverChannel = new MockServerChannel();
|
||||
var resourceProvider = new MemoryResourceProvider();
|
||||
ExtensionManager manager = new ExtensionManager();
|
||||
ServerPlugin serverPlugin = new ServerPlugin();
|
||||
|
@ -72,12 +73,13 @@ main() {
|
|||
});
|
||||
});
|
||||
|
||||
test('shutdown', () {
|
||||
test('shutdown', () async {
|
||||
expect(server.running, isTrue);
|
||||
// send request
|
||||
var request = new ServerShutdownParams().toRequest('0');
|
||||
var response = handler.handleRequest(request);
|
||||
var response = await serverChannel.sendRequest(request);
|
||||
expect(response, isResponseSuccess('0'));
|
||||
|
||||
// server is down
|
||||
expect(server.running, isFalse);
|
||||
});
|
||||
|
|
|
@ -694,6 +694,7 @@ class Server {
|
|||
//
|
||||
// Add server arguments.
|
||||
//
|
||||
arguments.add('--suppress-analytics');
|
||||
if (diagnosticPort != null) {
|
||||
arguments.add('--port');
|
||||
arguments.add(diagnosticPort.toString());
|
||||
|
@ -707,11 +708,9 @@ class Server {
|
|||
if (useAnalysisHighlight2) {
|
||||
arguments.add('--useAnalysisHighlight2');
|
||||
}
|
||||
// print('Launching $serverPath');
|
||||
// print('$dartBinary ${arguments.join(' ')}');
|
||||
// TODO(devoncarew): We could experiment with instead launching the analysis
|
||||
// server in a separate isolate. This would make it easier to debug the
|
||||
// integration tests, and would likely speed the tests up as well.
|
||||
// integration tests, and would likely speed up the tests as well.
|
||||
_process = await Process.start(dartBinary, arguments);
|
||||
_process.exitCode.then((int code) {
|
||||
if (code != 0) {
|
||||
|
|
|
@ -11,6 +11,7 @@ dart_package("analyzer_cli") {
|
|||
|
||||
deps = [
|
||||
"//dart/pkg/analyzer",
|
||||
"//dart/pkg/telemetry",
|
||||
"//dart/third_party/pkg/linter",
|
||||
"//third_party/dart-pkg/pub/args",
|
||||
"//third_party/dart-pkg/pub/bazel_worker",
|
||||
|
|
|
@ -8,3 +8,4 @@ linter:
|
|||
- empty_statements
|
||||
- unnecessary_brace_in_string_interps
|
||||
- valid_regexps
|
||||
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
import 'package:analyzer_cli/starter.dart';
|
||||
|
||||
/// The entry point for the command-line analyzer.
|
||||
void main(List<String> args) {
|
||||
main(List<String> args) async {
|
||||
CommandLineStarter starter = new CommandLineStarter();
|
||||
starter.start(args);
|
||||
|
||||
// Wait for the starter to complete.
|
||||
await starter.start(args);
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ class AnalyzerWorkerLoop extends SyncWorkerLoop {
|
|||
}
|
||||
// Prepare options.
|
||||
CommandLineOptions options =
|
||||
CommandLineOptions.parse(arguments, (String msg) {
|
||||
CommandLineOptions.parse(arguments, printAndFail: (String msg) {
|
||||
throw new ArgumentError(msg);
|
||||
});
|
||||
// Analyze and respond.
|
||||
|
|
|
@ -42,6 +42,7 @@ import 'package:analyzer_cli/starter.dart' show CommandLineStarter;
|
|||
import 'package:front_end/src/base/performace_logger.dart';
|
||||
import 'package:front_end/src/incremental/byte_store.dart';
|
||||
import 'package:linter/src/rules.dart' as linter;
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:package_config/discovery.dart' as pkg_discovery;
|
||||
import 'package:package_config/packages.dart' show Packages;
|
||||
import 'package:package_config/packages_file.dart' as pkgfile show parse;
|
||||
|
@ -49,16 +50,16 @@ import 'package:package_config/src/packages_impl.dart' show MapPackages;
|
|||
import 'package:path/path.dart' as path;
|
||||
import 'package:plugin/manager.dart';
|
||||
import 'package:plugin/plugin.dart';
|
||||
import 'package:telemetry/crash_reporting.dart';
|
||||
import 'package:telemetry/telemetry.dart' as telemetry;
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
/// Shared IO sink for standard error reporting.
|
||||
///
|
||||
/// *Visible for testing.*
|
||||
@visibleForTesting
|
||||
StringSink errorSink = io.stderr;
|
||||
|
||||
/// Shared IO sink for standard out reporting.
|
||||
///
|
||||
/// *Visible for testing.*
|
||||
@visibleForTesting
|
||||
StringSink outSink = io.stdout;
|
||||
|
||||
/// Test this option map to see if it specifies lint rules.
|
||||
|
@ -67,6 +68,26 @@ bool containsLintRuleEntry(Map<String, YamlNode> options) {
|
|||
return linterNode is YamlMap && linterNode.containsKey('rules');
|
||||
}
|
||||
|
||||
telemetry.Analytics _analytics;
|
||||
|
||||
const _analyticsID = 'UA-26406144-28';
|
||||
|
||||
/// The analytics instance for analyzer-cli.
|
||||
telemetry.Analytics get analytics => (_analytics ??=
|
||||
telemetry.createAnalyticsInstance(_analyticsID, 'analyzer-cli'));
|
||||
|
||||
/// Make sure that we create an analytics instance that doesn't send for this
|
||||
/// session.
|
||||
void disableAnalyticsForSession() {
|
||||
_analytics = telemetry.createAnalyticsInstance(_analyticsID, 'analyzer-cli',
|
||||
disableForSession: true);
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
void setAnalytics(telemetry.Analytics replacementAnalytics) {
|
||||
_analytics = replacementAnalytics;
|
||||
}
|
||||
|
||||
class Driver implements CommandLineStarter {
|
||||
static final PerformanceTag _analyzeAllTag =
|
||||
new PerformanceTag("Driver._analyzeAll");
|
||||
|
@ -109,9 +130,24 @@ class Driver implements CommandLineStarter {
|
|||
/// Collected analysis statistics.
|
||||
final AnalysisStats stats = new AnalysisStats();
|
||||
|
||||
/// This Driver's current analysis context.
|
||||
CrashReportSender _crashReportSender;
|
||||
|
||||
// TODO(devoncarew): Replace with the real crash product ID.
|
||||
/// The crash reporting instance for analyzer-cli.
|
||||
CrashReportSender get crashReportSender => (_crashReportSender ??=
|
||||
new CrashReportSender('Dart_analyzer_cli', analytics));
|
||||
|
||||
/// Create a new Driver instance.
|
||||
///
|
||||
/// *Visible for testing.*
|
||||
/// [isTesting] is true if we're running in a test environment.
|
||||
Driver({bool isTesting: false}) {
|
||||
if (isTesting) {
|
||||
disableAnalyticsForSession();
|
||||
}
|
||||
}
|
||||
|
||||
/// This Driver's current analysis context.
|
||||
@visibleForTesting
|
||||
AnalysisContext get context => _context;
|
||||
|
||||
@override
|
||||
|
@ -133,6 +169,15 @@ class Driver implements CommandLineStarter {
|
|||
// Parse commandline options.
|
||||
CommandLineOptions options = CommandLineOptions.parse(args);
|
||||
|
||||
if (options.batchMode || options.buildMode) {
|
||||
disableAnalyticsForSession();
|
||||
}
|
||||
|
||||
// Ping analytics with our initial call.
|
||||
analytics.sendScreenView('home');
|
||||
|
||||
var timer = analytics.startTimer('analyze');
|
||||
|
||||
// Do analysis.
|
||||
if (options.buildMode) {
|
||||
ErrorSeverity severity = _buildModeAnalyze(options);
|
||||
|
@ -140,7 +185,7 @@ class Driver implements CommandLineStarter {
|
|||
if (_shouldBeFatal(severity, options)) {
|
||||
io.exitCode = severity.ordinal;
|
||||
}
|
||||
} else if (options.shouldBatch) {
|
||||
} else if (options.batchMode) {
|
||||
BatchRunner batchRunner = new BatchRunner(outSink, errorSink);
|
||||
batchRunner.runAsBatch(args, (List<String> args) async {
|
||||
CommandLineOptions options = CommandLineOptions.parse(args);
|
||||
|
@ -158,17 +203,30 @@ class Driver implements CommandLineStarter {
|
|||
_analyzedFileCount += _context.sources.length;
|
||||
}
|
||||
|
||||
// Send how long analysis took.
|
||||
timer.finish();
|
||||
|
||||
// Send how many files were analyzed.
|
||||
analytics.sendEvent('analyze', 'fileCount', value: _analyzedFileCount);
|
||||
|
||||
if (options.perfReport != null) {
|
||||
String json = makePerfReport(
|
||||
startTime, currentTimeMillis, options, _analyzedFileCount, stats);
|
||||
new io.File(options.perfReport).writeAsStringSync(json);
|
||||
}
|
||||
|
||||
// Wait a brief time for any analytics calls to finish.
|
||||
await analytics.waitForLastPing(timeout: new Duration(milliseconds: 200));
|
||||
analytics.close();
|
||||
}
|
||||
|
||||
Future<ErrorSeverity> _analyzeAll(CommandLineOptions options) async {
|
||||
PerformanceTag previous = _analyzeAllTag.makeCurrent();
|
||||
try {
|
||||
return await _analyzeAllImpl(options);
|
||||
} catch (e, st) {
|
||||
crashReportSender.sendReport(e, stackTrace: st);
|
||||
rethrow;
|
||||
} finally {
|
||||
previous.makeCurrent();
|
||||
}
|
||||
|
@ -322,7 +380,7 @@ class Driver implements CommandLineStarter {
|
|||
/// [AnalyzeFunctionBodiesPredicate] that implements this policy.
|
||||
AnalyzeFunctionBodiesPredicate _chooseDietParsingPolicy(
|
||||
CommandLineOptions options) {
|
||||
if (options.shouldBatch) {
|
||||
if (options.batchMode) {
|
||||
// As analyzer is currently implemented, once a file has been diet
|
||||
// parsed, it can't easily be un-diet parsed without creating a brand new
|
||||
// context and losing caching. In batch mode, we can't predict which
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:analyzer/src/util/sdk.dart';
|
|||
import 'package:analyzer_cli/src/ansi.dart' as ansi;
|
||||
import 'package:analyzer_cli/src/driver.dart';
|
||||
import 'package:args/args.dart';
|
||||
import 'package:telemetry/telemetry.dart' as telemetry;
|
||||
|
||||
const _binaryName = 'dartanalyzer';
|
||||
|
||||
|
@ -115,7 +116,7 @@ class CommandLineOptions {
|
|||
final String perfReport;
|
||||
|
||||
/// Batch mode (for unit testing)
|
||||
final bool shouldBatch;
|
||||
final bool batchMode;
|
||||
|
||||
/// Whether to show package: warnings
|
||||
final bool showPackageWarnings;
|
||||
|
@ -184,7 +185,7 @@ class CommandLineOptions {
|
|||
log = args['log'],
|
||||
machineFormat = args['format'] == 'machine',
|
||||
perfReport = args['x-perf-report'],
|
||||
shouldBatch = args['batch'],
|
||||
batchMode = args['batch'],
|
||||
showPackageWarnings = args['show-package-warnings'] ||
|
||||
args['package-warnings'] ||
|
||||
args['x-package-warnings-prefix'] != null,
|
||||
|
@ -238,8 +239,14 @@ class CommandLineOptions {
|
|||
/// analyzer options. In case of a format error, calls [printAndFail], which
|
||||
/// by default prints an error message to stderr and exits.
|
||||
static CommandLineOptions parse(List<String> args,
|
||||
[printAndFail(String msg) = printAndFail]) {
|
||||
{printAndFail(String msg) = printAndFail}) {
|
||||
CommandLineOptions options = _parse(args);
|
||||
|
||||
/// Only happens in testing.
|
||||
if (options == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check SDK.
|
||||
if (!options.buildModePersistentWorker) {
|
||||
// Infer if unspecified.
|
||||
|
@ -346,6 +353,8 @@ class CommandLineOptions {
|
|||
help: 'Treat non-type warnings as fatal.',
|
||||
defaultsTo: false,
|
||||
negatable: false)
|
||||
..addFlag('analytics',
|
||||
help: 'Enable or disable sending analytics information to Google.')
|
||||
..addFlag('help',
|
||||
abbr: 'h',
|
||||
help:
|
||||
|
@ -528,15 +537,25 @@ class CommandLineOptions {
|
|||
|
||||
// Help requests.
|
||||
if (results['help']) {
|
||||
_showUsage(parser);
|
||||
_showUsage(parser, analytics, fromHelp: true);
|
||||
exitHandler(0);
|
||||
return null; // Only reachable in testing.
|
||||
}
|
||||
|
||||
// Enable / disable analytics.
|
||||
if (results.wasParsed('analytics')) {
|
||||
analytics.enabled = results['analytics'];
|
||||
outSink
|
||||
.writeln(telemetry.createAnalyticsStatusMessage(analytics.enabled));
|
||||
exitHandler(0);
|
||||
return null; // Only reachable in testing.
|
||||
}
|
||||
|
||||
// Batch mode and input files.
|
||||
if (results['batch']) {
|
||||
if (results.rest.isNotEmpty) {
|
||||
errorSink.writeln('No source files expected in the batch mode.');
|
||||
_showUsage(parser);
|
||||
_showUsage(parser, analytics);
|
||||
exitHandler(15);
|
||||
return null; // Only reachable in testing.
|
||||
}
|
||||
|
@ -544,7 +563,7 @@ class CommandLineOptions {
|
|||
if (results.rest.isNotEmpty) {
|
||||
errorSink.writeln(
|
||||
'No source files expected in the persistent worker mode.');
|
||||
_showUsage(parser);
|
||||
_showUsage(parser, analytics);
|
||||
exitHandler(15);
|
||||
return null; // Only reachable in testing.
|
||||
}
|
||||
|
@ -554,7 +573,7 @@ class CommandLineOptions {
|
|||
return null; // Only reachable in testing.
|
||||
} else {
|
||||
if (results.rest.isEmpty && !results['build-mode']) {
|
||||
_showUsage(parser);
|
||||
_showUsage(parser, analytics, fromHelp: true);
|
||||
exitHandler(15);
|
||||
return null; // Only reachable in testing.
|
||||
}
|
||||
|
@ -562,21 +581,46 @@ class CommandLineOptions {
|
|||
return new CommandLineOptions._fromArgs(results);
|
||||
} on FormatException catch (e) {
|
||||
errorSink.writeln(e.message);
|
||||
_showUsage(parser);
|
||||
_showUsage(parser, null);
|
||||
exitHandler(15);
|
||||
return null; // Only reachable in testing.
|
||||
}
|
||||
}
|
||||
|
||||
static _showUsage(ArgParser parser) {
|
||||
static _showUsage(ArgParser parser, telemetry.Analytics analytics,
|
||||
{bool fromHelp: false}) {
|
||||
void printAnalyticsInfo() {
|
||||
if (fromHelp) {
|
||||
errorSink.writeln('');
|
||||
errorSink.writeln(telemetry.analyticsNotice);
|
||||
}
|
||||
|
||||
if (analytics != null) {
|
||||
errorSink.writeln('');
|
||||
errorSink.writeln(telemetry.createAnalyticsStatusMessage(
|
||||
analytics.enabled,
|
||||
command: 'analytics'));
|
||||
}
|
||||
}
|
||||
|
||||
errorSink.writeln(
|
||||
'Usage: $_binaryName [options...] <directory or list of files>');
|
||||
|
||||
// If it's our first run, we display the analytics info more prominently.
|
||||
if (analytics != null && analytics.firstRun) {
|
||||
printAnalyticsInfo();
|
||||
}
|
||||
|
||||
errorSink.writeln('');
|
||||
errorSink.writeln(parser.usage);
|
||||
|
||||
if (analytics != null && !analytics.firstRun) {
|
||||
printAnalyticsInfo();
|
||||
}
|
||||
|
||||
errorSink.writeln('');
|
||||
errorSink.writeln('''
|
||||
Run "dartanalyzer -h -v" for verbose help output, including less commonly used options.
|
||||
For more information, see http://www.dartlang.org/tools/analyzer.
|
||||
''');
|
||||
For more information, see https://www.dartlang.org/tools/analyzer.\n''');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
library analyzer_cli.starter;
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:analyzer/plugin/resolver_provider.dart';
|
||||
import 'package:analyzer_cli/src/driver.dart';
|
||||
import 'package:plugin/plugin.dart';
|
||||
|
@ -36,5 +38,5 @@ abstract class CommandLineStarter {
|
|||
/**
|
||||
* Use the given command-line [arguments] to start this analyzer.
|
||||
*/
|
||||
void start(List<String> arguments);
|
||||
Future<Null> start(List<String> arguments);
|
||||
}
|
||||
|
|
|
@ -14,8 +14,10 @@ dependencies:
|
|||
package_config: '>=0.1.5 <2.0.0'
|
||||
plugin: '>=0.1.0 <0.3.0'
|
||||
protobuf: ^0.5.0
|
||||
telemetry: ^0.0.1
|
||||
yaml: ^2.1.2
|
||||
dev_dependencies:
|
||||
test_reflective_loader: ^0.1.0
|
||||
typed_mock: '>=0.0.4 <1.0.0'
|
||||
test: ^0.12.0
|
||||
usage: ^3.2.0+1
|
||||
|
|
|
@ -72,7 +72,7 @@ class _Runner {
|
|||
String get stdout => _stdout.toString();
|
||||
|
||||
Future<Null> run2(List<String> args) async {
|
||||
await new Driver().start(args);
|
||||
await new Driver(isTesting: true).start(args);
|
||||
if (stderr.isNotEmpty) {
|
||||
fail("Unexpected output to stderr:\n$stderr");
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ main() {
|
|||
});
|
||||
|
||||
test('non-dangling part file', () async {
|
||||
Driver driver = new Driver();
|
||||
Driver driver = new Driver(isTesting: true);
|
||||
await driver.start([
|
||||
path.join(testDirectory, 'data/library_and_parts/lib.dart'),
|
||||
path.join(testDirectory, 'data/library_and_parts/part1.dart')
|
||||
|
@ -120,7 +120,7 @@ main() {
|
|||
});
|
||||
|
||||
test('extra part file', () async {
|
||||
Driver driver = new Driver();
|
||||
Driver driver = new Driver(isTesting: true);
|
||||
await driver.start([
|
||||
path.join(testDirectory, 'data/library_and_parts/lib.dart'),
|
||||
path.join(testDirectory, 'data/library_and_parts/part1.dart'),
|
||||
|
@ -140,7 +140,7 @@ main() {
|
|||
Directory origWorkingDir = Directory.current;
|
||||
try {
|
||||
Directory.current = path.join(tempDirPath, 'proj');
|
||||
Driver driver = new Driver();
|
||||
Driver driver = new Driver(isTesting: true);
|
||||
try {
|
||||
await driver.start([
|
||||
path.join('lib', 'file.dart'),
|
||||
|
@ -551,7 +551,7 @@ String adjustFileSpec(String fileSpec) {
|
|||
Future<Null> drive(String source,
|
||||
{String options: emptyOptionsFile,
|
||||
List<String> args: const <String>[]}) async {
|
||||
driver = new Driver();
|
||||
driver = new Driver(isTesting: true);
|
||||
var cmd = [
|
||||
'--options',
|
||||
path.join(testDirectory, options),
|
||||
|
|
|
@ -33,7 +33,7 @@ main() {
|
|||
|
||||
test('resolution', wrap(() async {
|
||||
var testDir = path.join(testDirectory, 'data', 'embedder_client');
|
||||
await new Driver().start([
|
||||
await new Driver(isTesting: true).start([
|
||||
'--packages',
|
||||
path.join(testDir, '_packages'),
|
||||
path.join(testDir, 'embedder_yaml_user.dart')
|
||||
|
@ -45,7 +45,7 @@ main() {
|
|||
|
||||
test('sdk setup', wrap(() async {
|
||||
var testDir = path.join(testDirectory, 'data', 'embedder_client');
|
||||
Driver driver = new Driver();
|
||||
Driver driver = new Driver(isTesting: true);
|
||||
await driver.start([
|
||||
'--packages',
|
||||
path.join(testDir, '_packages'),
|
||||
|
|
|
@ -41,7 +41,7 @@ class ErrorsReportedOnceTest {
|
|||
|
||||
test_once() async {
|
||||
String testDir = path.join(testDirectory, 'data', 'errors_reported_once');
|
||||
Driver driver = new Driver();
|
||||
Driver driver = new Driver(isTesting: true);
|
||||
await driver.start(
|
||||
[path.join(testDir, 'foo.dart'), path.join(testDir, 'bar.dart')]);
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ class ErrorUpgradeFailsCli {
|
|||
test_once() async {
|
||||
String testDir =
|
||||
path.join(testDirectory, 'data', 'error_upgrade_fails_cli');
|
||||
Driver driver = new Driver();
|
||||
Driver driver = new Driver(isTesting: true);
|
||||
await driver.start([path.join(testDir, 'foo.dart')]);
|
||||
|
||||
expect(exitCode, 3);
|
||||
|
|
|
@ -9,11 +9,39 @@ import 'dart:io';
|
|||
import 'package:analyzer_cli/src/driver.dart';
|
||||
import 'package:analyzer_cli/src/options.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:usage/usage.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
main() {
|
||||
group('CommandLineOptions', () {
|
||||
group('parse', () {
|
||||
int lastExitHandlerCode;
|
||||
StringBuffer outStringBuffer = new StringBuffer();
|
||||
StringBuffer errorStringBuffer = new StringBuffer();
|
||||
|
||||
StringSink savedOutSink, savedErrorSink;
|
||||
int savedExitCode;
|
||||
ExitHandler savedExitHandler;
|
||||
|
||||
setUp(() {
|
||||
savedOutSink = outSink;
|
||||
savedErrorSink = errorSink;
|
||||
savedExitHandler = exitHandler;
|
||||
savedExitCode = exitCode;
|
||||
exitHandler = (int code) {
|
||||
lastExitHandlerCode = code;
|
||||
};
|
||||
outSink = outStringBuffer;
|
||||
errorSink = errorStringBuffer;
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
outSink = savedOutSink;
|
||||
errorSink = savedErrorSink;
|
||||
exitCode = savedExitCode;
|
||||
exitHandler = savedExitHandler;
|
||||
});
|
||||
|
||||
test('defaults', () {
|
||||
CommandLineOptions options =
|
||||
CommandLineOptions.parse(['--dart-sdk', '.', 'foo.dart']);
|
||||
|
@ -41,7 +69,7 @@ main() {
|
|||
expect(options.log, isFalse);
|
||||
expect(options.machineFormat, isFalse);
|
||||
expect(options.packageRootPath, isNull);
|
||||
expect(options.shouldBatch, isFalse);
|
||||
expect(options.batchMode, isFalse);
|
||||
expect(options.showPackageWarnings, isFalse);
|
||||
expect(options.showSdkWarnings, isFalse);
|
||||
expect(options.sourceFiles, equals(['foo.dart']));
|
||||
|
@ -53,7 +81,7 @@ main() {
|
|||
test('batch', () {
|
||||
CommandLineOptions options =
|
||||
CommandLineOptions.parse(['--dart-sdk', '.', '--batch']);
|
||||
expect(options.shouldBatch, isTrue);
|
||||
expect(options.batchMode, isTrue);
|
||||
});
|
||||
|
||||
test('defined variables', () {
|
||||
|
@ -195,17 +223,35 @@ main() {
|
|||
var failureMessage;
|
||||
CommandLineOptions.parse(
|
||||
['--package-root', '.', '--packages', '.', 'foo.dart'],
|
||||
(msg) => failureMessage = msg);
|
||||
printAndFail: (msg) => failureMessage = msg);
|
||||
expect(failureMessage,
|
||||
equals("Cannot specify both '--package-root' and '--packages."));
|
||||
});
|
||||
|
||||
test("bad SDK dir", () {
|
||||
var failureMessage;
|
||||
CommandLineOptions.parse(
|
||||
['--dart-sdk', '&&&&&', 'foo.dart'], (msg) => failureMessage = msg);
|
||||
CommandLineOptions.parse(['--dart-sdk', '&&&&&', 'foo.dart'],
|
||||
printAndFail: (msg) => failureMessage = msg);
|
||||
expect(failureMessage, equals('Invalid Dart SDK path: &&&&&'));
|
||||
});
|
||||
|
||||
test('--analytics', () {
|
||||
AnalyticsMock mock = new AnalyticsMock()..enabled = false;
|
||||
setAnalytics(mock);
|
||||
CommandLineOptions.parse(['--analytics']);
|
||||
expect(mock.enabled, true);
|
||||
expect(lastExitHandlerCode, 0);
|
||||
expect(outStringBuffer.toString(), contains('Analytics are currently'));
|
||||
});
|
||||
|
||||
test('--no-analytics', () {
|
||||
AnalyticsMock mock = new AnalyticsMock()..enabled = false;
|
||||
setAnalytics(mock);
|
||||
CommandLineOptions.parse(['--no-analytics']);
|
||||
expect(mock.enabled, false);
|
||||
expect(lastExitHandlerCode, 0);
|
||||
expect(outStringBuffer.toString(), contains('Analytics are currently'));
|
||||
});
|
||||
});
|
||||
});
|
||||
defineReflectiveTests(CommandLineOptionsTest);
|
||||
|
|
|
@ -61,7 +61,7 @@ class _Runner {
|
|||
String get stdout => _stdout.toString();
|
||||
|
||||
Future<Null> run2(List<String> args) async {
|
||||
await new Driver().start(args);
|
||||
await new Driver(isTesting: true).start(args);
|
||||
if (stderr.isNotEmpty) {
|
||||
fail("Unexpected output to stderr:\n$stderr");
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ main() {
|
|||
|
||||
test('.packages file specified', () async {
|
||||
String testDir = path.join(testDirectory, 'data', 'packages_file');
|
||||
Driver driver = new Driver();
|
||||
Driver driver = new Driver(isTesting: true);
|
||||
await driver.start([
|
||||
'--packages',
|
||||
path.join(testDir, '_packages'),
|
||||
|
|
|
@ -43,7 +43,8 @@ not_main() {
|
|||
|
||||
test('produces stricter errors', () async {
|
||||
var testPath = path.join(testDirectory, 'data/strong_example.dart');
|
||||
new Driver().start(['--options', emptyOptionsFile, '--strong', testPath]);
|
||||
new Driver(isTesting: true)
|
||||
.start(['--options', emptyOptionsFile, '--strong', testPath]);
|
||||
|
||||
expect(exitCode, 3);
|
||||
var stdout = outSink.toString();
|
||||
|
|
|
@ -43,7 +43,7 @@ void main() {
|
|||
|
||||
test('produces errors when option absent', () async {
|
||||
var testPath = path.join(testDirectory, 'data/super_mixin_example.dart');
|
||||
await new Driver().start([testPath]);
|
||||
await new Driver(isTesting: true).start([testPath]);
|
||||
|
||||
expect(exitCode, 3);
|
||||
var stdout = outSink.toString();
|
||||
|
@ -61,7 +61,7 @@ void main() {
|
|||
|
||||
test('produces no errors when option present', () async {
|
||||
var testPath = path.join(testDirectory, 'data/super_mixin_example.dart');
|
||||
await new Driver().start(['--supermixin', testPath]);
|
||||
await new Driver(isTesting: true).start(['--supermixin', testPath]);
|
||||
|
||||
expect(exitCode, 0);
|
||||
var stdout = outSink.toString();
|
||||
|
|
18
pkg/telemetry/BUILD.gn
Normal file
18
pkg/telemetry/BUILD.gn
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
# for details. All rights reserved. Use of this source code is governed by a
|
||||
# BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import("//build/dart/dart_package.gni")
|
||||
|
||||
dart_package("telemetry") {
|
||||
package_name = "telemetry"
|
||||
|
||||
disable_analysis = true
|
||||
|
||||
deps = [
|
||||
"//third_party/dart-pkg/pub/http",
|
||||
"//third_party/dart-pkg/pub/path",
|
||||
"//third_party/dart-pkg/pub/stack_trace",
|
||||
"//third_party/dart-pkg/pub/usage",
|
||||
]
|
||||
}
|
|
@ -32,12 +32,14 @@ class CrashReportSender {
|
|||
static final Uri _baseUri = new Uri(
|
||||
scheme: 'https', host: _crashServerHost, path: _crashEndpointPath);
|
||||
|
||||
final String crashProductId;
|
||||
final Analytics analytics;
|
||||
final http.Client _httpClient;
|
||||
|
||||
/// Create a new [CrashReportSender], using the data from the given
|
||||
/// [Analytics] instance.
|
||||
CrashReportSender(this.analytics, {http.Client httpClient})
|
||||
CrashReportSender(this.crashProductId, this.analytics,
|
||||
{http.Client httpClient})
|
||||
: _httpClient = httpClient ?? new http.Client();
|
||||
|
||||
/// Sends one crash report.
|
||||
|
@ -58,7 +60,7 @@ class CrashReportSender {
|
|||
|
||||
final http.MultipartRequest req = new http.MultipartRequest('POST', uri);
|
||||
req.fields['uuid'] = analytics.clientId;
|
||||
req.fields['product'] = analytics.trackingId;
|
||||
req.fields['product'] = crashProductId;
|
||||
req.fields['version'] = analytics.applicationVersion;
|
||||
req.fields['osName'] = Platform.operatingSystem;
|
||||
// TODO(devoncarew): Report the operating system version when we're able.
|
||||
|
|
|
@ -11,6 +11,11 @@ import 'package:usage/src/usage_impl_io.dart' as usage_io show getDartVersion;
|
|||
import 'package:usage/usage.dart';
|
||||
import 'package:usage/usage_io.dart';
|
||||
|
||||
export 'package:usage/usage.dart' show Analytics;
|
||||
|
||||
// TODO(devoncarew): Hard-coded to off for now. Remove when we're ready to ship.
|
||||
final bool _HARD_CODE_OFF = true;
|
||||
|
||||
final String _dartDirectoryName = '.dart';
|
||||
final String _settingsFileName = 'analytics.json';
|
||||
|
||||
|
@ -21,9 +26,24 @@ final String _settingsFileName = 'analytics.json';
|
|||
///
|
||||
/// `Analytics are currently enabled (and can be disabled with --no-analytics).`
|
||||
final String analyticsNotice =
|
||||
"Dart SDK tools anonymously report feature usage statistics and basic "
|
||||
"crash reports to help improve Dart tools over time. See Google's privacy "
|
||||
"policy: https://www.google.com/intl/en/policies/privacy/.";
|
||||
"Dart SDK tools anonymously report feature usage statistics and basic crash\n"
|
||||
"reports to help improve Dart tools over time. See Google's privacy policy:\n"
|
||||
"https://www.google.com/intl/en/policies/privacy/.";
|
||||
|
||||
/// Return a customized message for command-line tools to display about the
|
||||
/// state of analytics, and how users can enabled or disable analytics.
|
||||
///
|
||||
/// An example return value might be `'Analytics are currently enabled (and can
|
||||
/// be disabled with --no-analytics).'`
|
||||
String createAnalyticsStatusMessage(bool enabled,
|
||||
{String command: 'analytics'}) {
|
||||
String currentState = enabled ? 'enabled' : 'disabled';
|
||||
String toggleState = enabled ? 'disabled' : 'enabled';
|
||||
String commandToggle = enabled ? 'no-$command' : command;
|
||||
|
||||
return 'Analytics are currently $currentState '
|
||||
'(and can be $toggleState with --$commandToggle).';
|
||||
}
|
||||
|
||||
/// Create an [Analytics] instance with the given trackingID and
|
||||
/// applicationName.
|
||||
|
@ -37,6 +57,10 @@ Analytics createAnalyticsInstance(String trackingId, String applicationName,
|
|||
dir.createSync();
|
||||
}
|
||||
|
||||
if (_HARD_CODE_OFF) {
|
||||
disableForSession = true;
|
||||
}
|
||||
|
||||
File file = new File(path.join(dir.path, _settingsFileName));
|
||||
return new _TelemetryAnalytics(
|
||||
trackingId, applicationName, getDartVersion(), file, disableForSession);
|
||||
|
@ -77,14 +101,14 @@ class _TelemetryAnalytics extends AnalyticsImpl {
|
|||
|
||||
@override
|
||||
bool get enabled {
|
||||
if (disableForSession || _isRunningOnBot()) {
|
||||
if (disableForSession || isRunningOnBot()) {
|
||||
return false;
|
||||
}
|
||||
return super.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
bool _isRunningOnBot() {
|
||||
bool isRunningOnBot() {
|
||||
// - https://docs.travis-ci.com/user/environment-variables/
|
||||
// - https://www.appveyor.com/docs/environment-variables/
|
||||
// - CHROME_HEADLESS and BUILDBOT_BUILDERNAME are properties on Chrome infra
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: telemetry
|
||||
description: A library to facilitate reporting analytics and crash reports.
|
||||
version: 0.0.1-dev
|
||||
version: 0.0.1
|
||||
author: Dart Team <misc@dartlang.org>
|
||||
|
||||
environment:
|
||||
|
|
|
@ -24,9 +24,10 @@ void main() {
|
|||
});
|
||||
|
||||
test('CrashReportSender', () async {
|
||||
AnalyticsMock analytics = new AnalyticsMock();
|
||||
CrashReportSender sender =
|
||||
new CrashReportSender(analytics, httpClient: mockClient);
|
||||
AnalyticsMock analytics = new AnalyticsMock()..enabled = false;
|
||||
CrashReportSender sender = new CrashReportSender(
|
||||
analytics.trackingId, analytics,
|
||||
httpClient: mockClient);
|
||||
|
||||
await sender.sendReport('test-error', stackTrace: StackTrace.current);
|
||||
|
||||
|
|
Loading…
Reference in a new issue